Skip to main content
Glama
kornbed

Jira MCP Server for Cursor

get_ticket

Retrieve details for a specific Jira ticket by entering its ID to view status, description, and other information directly within your editor.

Instructions

Get details of a specific Jira ticket

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
ticketIdYesThe Jira ticket ID (e.g., PROJECT-123)

Implementation Reference

  • The main handler function for the 'get_ticket' tool. It validates configuration, fetches the ticket details from Jira API including summary, status, type, description (parsed from ADF), parent, and linked issues, then formats and returns them.
    async ({ ticketId }: { ticketId: string }) => { const configError = validateJiraConfig(); if (configError) { return { content: [{ type: "text", text: `Configuration error: ${configError}` }], }; } try { const ticket = await jira.issues.getIssue({ issueIdOrKey: ticketId, fields: ['summary', 'status', 'issuetype', 'description', 'parent', 'issuelinks'], }); const formattedTicket = [ `Key: ${ticket.key}`, `Summary: ${ticket.fields?.summary || 'No summary'}`, `Status: ${ticket.fields?.status?.name || 'Unknown status'}`, `Type: ${ticket.fields?.issuetype?.name || 'Unknown type'}`, `Description:\n${extractTextFromADF(ticket.fields?.description) || 'No description'}`, `Parent: ${ticket.fields?.parent?.key || 'No parent'}` ]; // Linked Issues Section const links = ticket.fields?.issuelinks || []; if (Array.isArray(links) && links.length > 0) { formattedTicket.push('\nLinked Issues:'); for (const link of links) { // Outward (this issue is the source) if (link.outwardIssue) { const key = link.outwardIssue.key; const summary = link.outwardIssue.fields?.summary || 'No summary'; const type = link.type?.outward || link.type?.name || 'Related'; formattedTicket.push(`- [${type}] ${key}: ${summary}`); } // Inward (this issue is the target) if (link.inwardIssue) { const key = link.inwardIssue.key; const summary = link.inwardIssue.fields?.summary || 'No summary'; const type = link.type?.inward || link.type?.name || 'Related'; formattedTicket.push(`- [${type}] ${key}: ${summary}`); } } } else { formattedTicket.push('\nLinked Issues: None'); } return { content: [{ type: "text", text: formattedTicket.join('\n') }], }; } catch (error) { return { content: [{ type: "text", text: `Failed to fetch ticket: ${(error as Error).message}` }], }; } }
  • Input schema for the 'get_ticket' tool, using Zod to validate the 'ticketId' parameter.
    { ticketId: z.string().describe("The Jira ticket ID (e.g., PROJECT-123)"), },
  • src/server.ts:159-221 (registration)
    Registration of the 'get_ticket' tool on the MCP server, specifying name, description, input schema, and handler function.
    server.tool( "get_ticket", "Get details of a specific Jira ticket", { ticketId: z.string().describe("The Jira ticket ID (e.g., PROJECT-123)"), }, async ({ ticketId }: { ticketId: string }) => { const configError = validateJiraConfig(); if (configError) { return { content: [{ type: "text", text: `Configuration error: ${configError}` }], }; } try { const ticket = await jira.issues.getIssue({ issueIdOrKey: ticketId, fields: ['summary', 'status', 'issuetype', 'description', 'parent', 'issuelinks'], }); const formattedTicket = [ `Key: ${ticket.key}`, `Summary: ${ticket.fields?.summary || 'No summary'}`, `Status: ${ticket.fields?.status?.name || 'Unknown status'}`, `Type: ${ticket.fields?.issuetype?.name || 'Unknown type'}`, `Description:\n${extractTextFromADF(ticket.fields?.description) || 'No description'}`, `Parent: ${ticket.fields?.parent?.key || 'No parent'}` ]; // Linked Issues Section const links = ticket.fields?.issuelinks || []; if (Array.isArray(links) && links.length > 0) { formattedTicket.push('\nLinked Issues:'); for (const link of links) { // Outward (this issue is the source) if (link.outwardIssue) { const key = link.outwardIssue.key; const summary = link.outwardIssue.fields?.summary || 'No summary'; const type = link.type?.outward || link.type?.name || 'Related'; formattedTicket.push(`- [${type}] ${key}: ${summary}`); } // Inward (this issue is the target) if (link.inwardIssue) { const key = link.inwardIssue.key; const summary = link.inwardIssue.fields?.summary || 'No summary'; const type = link.type?.inward || link.type?.name || 'Related'; formattedTicket.push(`- [${type}] ${key}: ${summary}`); } } } else { formattedTicket.push('\nLinked Issues: None'); } return { content: [{ type: "text", text: formattedTicket.join('\n') }], }; } catch (error) { return { content: [{ type: "text", text: `Failed to fetch ticket: ${(error as Error).message}` }], }; } } );
  • Helper function to recursively extract plain text from Jira's ADF (Atlassian Document Format) used in 'get_ticket' to parse ticket description and linked issue summaries.
    function extractTextFromADF(node: any): string { if (!node) { return ''; } // Handle text nodes directly if (node.type === 'text' && node.text) { return node.text; } let text = ''; // Handle block nodes like paragraph, heading, etc. if (node.content && Array.isArray(node.content)) { text = node.content.map(extractTextFromADF).join(''); // Add a newline after paragraphs for better formatting if (node.type === 'paragraph') { text += '\n'; } } return text; }
  • Helper function to validate required Jira environment variables, called at the start of the 'get_ticket' handler.
    function validateJiraConfig(): string | null { if (!process.env.JIRA_HOST) return "JIRA_HOST environment variable is not set"; if (!process.env.JIRA_EMAIL) return "JIRA_EMAIL environment variable is not set"; if (!process.env.JIRA_API_TOKEN) return "JIRA_API_TOKEN environment variable is not set"; return null; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kornbed/jira-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server