UNPKG

@pavi_thran_7/jira-mcp-server

Version:

MCP server for Jira integration with ticket creation and time logging

173 lines (156 loc) 4.84 kB
/** * @fileoverview Discovery tools for Jira MCP server */ /** * @typedef {import('../types/jira.js').McpToolResult} McpToolResult * @typedef {import('../jira-client.js').JiraClient} JiraClient */ /** * List all projects accessible to the user * @param {JiraClient} jiraClient - Jira client instance * @returns {Promise<McpToolResult>} Projects list result */ export async function listProjects(jiraClient) { try { const projectsResult = await jiraClient.getProjects(); if (!projectsResult.success) { return { content: [ { type: 'text', text: `Error getting projects: ${projectsResult.error}`, }, ], isError: true, }; } const projects = projectsResult.data.values; if (!projects || projects.length === 0) { return { content: [ { type: 'text', text: 'No projects found. You may not have access to any projects.', }, ], isError: false, }; } // Format projects list const projectsList = projects.map(project => { const projectType = project.projectTypeKey || 'Unknown'; return `- **${project.key}**: ${project.name} (${projectType})`; }).join('\n'); return { content: [ { type: 'text', text: `📁 **Available Projects (${projects.length})** ${projectsList} **Usage:** - Use the project key (e.g., "${projects[0].key}") when creating tickets - Use list_boards with a project key to see available boards for that project`, }, ], isError: false, }; } catch (error) { return { content: [ { type: 'text', text: `Error listing projects: ${error.message}`, }, ], isError: true, }; } } /** * List boards for a project * @param {JiraClient} jiraClient - Jira client instance * @param {Object} params - Parameters * @param {string} [params.projectKey] - Project key to filter boards * @returns {Promise<McpToolResult>} Boards list result */ export async function listBoards(jiraClient, params = {}) { try { const boardsResult = await jiraClient.getBoards(params.projectKey); if (!boardsResult.success) { return { content: [ { type: 'text', text: `Error getting boards: ${boardsResult.error}`, }, ], isError: true, }; } const boards = boardsResult.data.values; if (!boards || boards.length === 0) { const projectFilter = params.projectKey ? ` for project "${params.projectKey}"` : ''; return { content: [ { type: 'text', text: `No boards found${projectFilter}. You may not have access to any boards or the project may not exist.`, }, ], isError: false, }; } // Group boards by project if no project filter is specified const boardsByProject = {}; boards.forEach(board => { const projectKey = board.location?.projectKey || 'Unknown'; if (!boardsByProject[projectKey]) { boardsByProject[projectKey] = []; } boardsByProject[projectKey].push(board); }); // Format boards list let boardsList = ''; if (params.projectKey) { // Single project view boardsList = boards.map(board => { const boardType = board.type || 'Unknown'; return `- **${board.id}**: ${board.name} (${boardType})`; }).join('\n'); } else { // Multi-project view boardsList = Object.entries(boardsByProject).map(([projectKey, projectBoards]) => { const boardItems = projectBoards.map(board => { const boardType = board.type || 'Unknown'; return ` - **${board.id}**: ${board.name} (${boardType})`; }).join('\n'); return `**${projectKey}:**\n${boardItems}`; }).join('\n\n'); } const projectFilter = params.projectKey ? ` for project "${params.projectKey}"` : ''; const totalBoards = boards.length; return { content: [ { type: 'text', text: `📋 **Available Boards${projectFilter} (${totalBoards})** ${boardsList} **Usage:** - Use the board ID (e.g., "${boards[0].id}") when creating tickets to assign them to a specific board - Board types: Scrum (for sprint-based work), Kanban (for continuous flow)`, }, ], isError: false, }; } catch (error) { return { content: [ { type: 'text', text: `Error listing boards: ${error.message}`, }, ], isError: true, }; } }