Skip to main content
Glama
kornbed

Jira MCP Server for Cursor

by kornbed

get_comments

Retrieve comments for a Jira ticket to track discussions and updates directly within your editor.

Instructions

Get comments for a specific Jira ticket

Input Schema

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

Implementation Reference

  • The handler function for the 'get_comments' tool. It validates Jira configuration, fetches comments using the Jira API, formats them with author, date, and extracted text body using the extractTextFromADF helper, and handles errors including 404 for non-existent tickets.
    async ({ ticketId }: { ticketId: string }) => {
      const configError = validateJiraConfig();
      if (configError) {
        return {
          content: [{ type: "text", text: `Configuration error: ${configError}` }],
        };
      }
    
      try {
        const commentsResult = await jira.issueComments.getComments({ issueIdOrKey: ticketId });
        
        if (!commentsResult.comments || commentsResult.comments.length === 0) {
          return {
            content: [{ type: "text", text: "No comments found for this ticket." }],
          };
        }
    
        const formattedComments = commentsResult.comments.map(comment => {
          const author = comment.author?.displayName || 'Unknown Author';
          // Comments also use ADF, so we need to parse them
          const body = extractTextFromADF(comment.body) || 'No comment body'; 
          const createdDate = comment.created ? new Date(comment.created).toLocaleString() : 'Unknown date';
          return `[${createdDate}] ${author}:\n${body.trim()}\n---`; // Added trim() and separator
        }).join('\n\n'); // Separate comments with double newline
    
        return {
          content: [{ type: "text", text: formattedComments }],
        };
      } catch (error) {
        // Handle cases where the ticket might not exist or other API errors
        if ((error as any).response?.status === 404) {
            return {
                content: [{ type: "text", text: `Ticket ${ticketId} not found.` }],
            };
        }
        return {
          content: [{ type: "text", text: `Failed to fetch comments: ${(error as Error).message}` }],
        };
      }
    }
  • Input schema for the 'get_comments' tool, defining the required 'ticketId' parameter as a string with description.
    {
      ticketId: z.string().describe("The Jira ticket ID (e.g., PROJECT-123)"),
    },
  • src/server.ts:223-269 (registration)
    Registration of the 'get_comments' tool using server.tool(), including name, description, input schema, and handler function.
    server.tool(
      "get_comments",
      "Get comments for 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 commentsResult = await jira.issueComments.getComments({ issueIdOrKey: ticketId });
          
          if (!commentsResult.comments || commentsResult.comments.length === 0) {
            return {
              content: [{ type: "text", text: "No comments found for this ticket." }],
            };
          }
    
          const formattedComments = commentsResult.comments.map(comment => {
            const author = comment.author?.displayName || 'Unknown Author';
            // Comments also use ADF, so we need to parse them
            const body = extractTextFromADF(comment.body) || 'No comment body'; 
            const createdDate = comment.created ? new Date(comment.created).toLocaleString() : 'Unknown date';
            return `[${createdDate}] ${author}:\n${body.trim()}\n---`; // Added trim() and separator
          }).join('\n\n'); // Separate comments with double newline
    
          return {
            content: [{ type: "text", text: formattedComments }],
          };
        } catch (error) {
          // Handle cases where the ticket might not exist or other API errors
          if ((error as any).response?.status === 404) {
              return {
                  content: [{ type: "text", text: `Ticket ${ticketId} not found.` }],
              };
          }
          return {
            content: [{ type: "text", text: `Failed to fetch comments: ${(error as Error).message}` }],
          };
        }
      }
    );
  • Helper function to recursively extract plain text from Jira's ADF (Atlassian Document Format) structures, used to parse comment bodies in the handler.
    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;
    }

Schema Changelog

Changes observed during successful MCP inspections.

  1. Addedv1.0.0

TDQS

B3.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, and the description does not disclose any behavioral traits such as read-only nature, authentication requirements, rate limits, or pagination. The agent has no additional context beyond the operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, clear sentence with no wasted words. It is front-loaded and efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read tool with one parameter, the description is mostly complete. However, it lacks any mention of return format or potential limitations (e.g., pagination, ordering), but given the simplicity, a 4 is reasonable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents the ticketId parameter. The description does not add extra meaning beyond what the schema provides, which is acceptable for a simple parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Get' and the resource 'comments for a specific Jira ticket', which distinguishes it from sibling tools like add_comment or delete_comment.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives (e.g., get_worklog for worklogs, or add_comment for adding). The description only states what it does, with no exclusions or context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.