add_comment
Add a comment to a Linear ticket by specifying the ticket ID and comment text. Use this tool to provide updates, feedback, or additional details on existing tickets.
Instructions
Add a comment to a specific Linear ticket. This tool is useful for providing feedback, status updates, or additional information on existing tickets.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| comment | Yes | The comment text to add to the ticket | |
| debug | No | Debug mode to show extra diagnostics | |
| ticketId | Yes | The ID of the Linear ticket to comment on |
Implementation Reference
- src/tools/add-comment.js:129-251 (handler)The main handler function for the 'add_comment' tool. It processes input parameters, creates a Linear client, calls the addComment helper, formats the success response or detailed error message, and returns MCP-compatible content.const handler = async (ctx, { ticketId, comment, debug }) => { const logger = ctx.effects.logger; try { // Log details about config and parameters logger.debug('Add comment called with parameters:', { ticketId, commentLength: comment?.length, debug, }); // Debug log for API key (masked) const apiKey = ctx.config.linearApiKey || ''; const maskedKey = apiKey ? apiKey.substring(0, 4) + '...' + apiKey.substring(apiKey.length - 4) : '<not set>'; logger.debug(`Using Linear API key: ${maskedKey}`); if (!ctx.config.linearApiKey) { throw new Error('LINEAR_API_KEY is not configured'); } // Create a Linear client using our effect logger.debug('Creating Linear client'); const linearClient = ctx.effects.linear.createClient( ctx.config.linearApiKey ); // Add the comment using the Linear SDK client logger.debug('Executing Linear API to add comment'); const result = await addComment(linearClient, ticketId, comment, logger); // Log that we created the comment logger.info(`Added comment to ticket ID: ${ticketId}`); // Format the output const formatDate = timestamp => { if (!timestamp) return 'Just now'; const date = new Date(timestamp); return date.toLocaleString(); }; let responseText = ''; responseText += `✅ Comment added successfully to ticket ${ticketId}\n\n`; // Add comment details responseText += `**Comment ID:** ${result.id}\n`; if (result.user) { responseText += `**Posted by:** ${result.user.name}\n`; } responseText += `**Posted at:** ${formatDate(result.createdAt)}\n\n`; responseText += `**Comment:**\n${result.body}\n`; logger.debug('Returning formatted comment result'); return { content: [{ type: 'text', text: responseText }], }; } catch (error) { logger.error(`Error adding comment: ${error.message}`); logger.error(error.stack); // Create a user-friendly error message with troubleshooting guidance let errorMessage = `Error adding comment: ${error.message}`; // Add detailed diagnostic information if in debug mode if (debug) { errorMessage += '\n\n=== DETAILED DEBUG INFORMATION ==='; // Add parameters that were used errorMessage += `\nParameters: - ticketId: ${ticketId} - comment length: ${comment?.length} characters`; // Check if API key is configured const apiKey = ctx.config.linearApiKey || ''; const keyStatus = apiKey ? `API key is configured (${apiKey.substring( 0, 4 )}...${apiKey.substring(apiKey.length - 4)})` : 'API key is NOT configured - set LINEAR_API_KEY'; errorMessage += `\n\nLinear API Status: ${keyStatus}`; // Add error details if (error.name) { errorMessage += `\nError type: ${error.name}`; } if (error.code) { errorMessage += `\nError code: ${error.code}`; } if (error.stack) { errorMessage += `\n\nStack trace: ${error.stack .split('\n') .slice(0, 3) .join('\n')}`; } // Add Linear API info for manual testing errorMessage += `\n\nLinear API: Using official Linear SDK (@linear/sdk) For manual testing, try using the SDK directly or the Linear API Explorer in the Linear UI.`; } // Add a note that debug mode can be enabled for more details if (!debug) { errorMessage += `\n\nFor more detailed diagnostics, retry with debug:true in the input.`; } return { content: [ { type: 'text', text: errorMessage, }, ], isError: true, }; } };
- src/tools/add-comment.js:22-29 (schema)Zod input schema defining parameters for the add_comment tool: ticketId (string), comment (string), debug (boolean, optional).const AddCommentInputSchema = z.object({ ticketId: z.string().describe('The ID of the Linear ticket to comment on'), comment: z.string().describe('The comment text to add to the ticket'), debug: z .boolean() .default(false) .describe('Debug mode to show extra diagnostics'), });
- src/tools/add-comment.js:256-262 (registration)Tool factory using create_tool() that registers the 'add_comment' tool with its name, description, input schema, and handler function.export const AddComment = create_tool({ name: 'add_comment', description: 'Add a comment to a specific Linear ticket. This tool is useful for providing feedback, status updates, or additional information on existing tickets.', inputSchema: AddCommentInputSchema, handler, });
- src/tools/add-comment.js:40-123 (helper)Helper function that performs the actual Linear API call to add a comment to a ticket using the Linear SDK, including validation and error handling.async function addComment(client, ticketId, comment, logger) { try { logger?.debug(`Adding comment to Linear issue with ID: ${ticketId}`); // First verify the issue exists const issue = await client.issue(ticketId); if (!issue) { logger?.error(`Issue with ID ${ticketId} not found`); throw new Error(`Issue with ID ${ticketId} not found`); } logger?.debug(`Successfully found issue: ${issue.id}, adding comment`); // Create the comment using the Linear SDK // The Linear SDK expects a CommentCreateInput object const commentResult = await client.createComment({ // The issueId property is part of CommentCreateInput issueId: ticketId, // The body property is part of CommentCreateInput body: comment, }); if (!commentResult) { throw new Error('Failed to create comment, received null response'); } // CommentPayload contains a comment property that's a promise const commentData = await commentResult.comment; if (!commentData) { throw new Error('Failed to retrieve comment data from response'); } logger?.debug(`Successfully added comment: ${commentData.id}`); // Get current user information for the response const me = await client.viewer; let userData = undefined; if (me) { userData = { id: me.id, name: me.name, email: me.email, }; } // Process and validate the comment data using our schema const processedComment = CommentSchema.parse({ id: commentData.id, body: commentData.body, user: userData, createdAt: commentData.createdAt instanceof Date ? commentData.createdAt.toISOString() : commentData.createdAt, updatedAt: commentData.updatedAt instanceof Date ? commentData.updatedAt.toISOString() : commentData.updatedAt, }); return processedComment; } catch (error) { // Enhanced error logging logger?.error(`Error adding comment to Linear issue: ${error.message}`, { ticketId, commentLength: comment?.length, stack: error.stack, }); // Check if it's a Zod validation error (formatted differently) if (error.name === 'ZodError') { logger?.error( 'Zod validation error details:', JSON.stringify(error.errors, null, 2) ); } // Rethrow the error for the tool to handle throw error; } }
- src/index.js:109-149 (registration)Instantiation of the AddComment tool instance with context and registration loop that adds all tools (including add_comment) to the MCP server using server.tool().const all_tools = [ new tools.ListIssues(toolContext), new tools.GetIssue(toolContext), new tools.ListMembers(toolContext), new tools.ListProjects(toolContext), new tools.GetProject(toolContext), new tools.ListTeams(toolContext), new tools.AddComment(toolContext), new tools.CreateIssue(toolContext), ]; // Register tools with the MCP server for (const tool of all_tools) { server.tool( tool.name, tool.description, tool.inputSchema.shape ?? {}, async args => { try { // Call our tool const result = await tool.call(args); // Return format expected by MCP SDK return { content: result.content, error: result.isError ? { message: result.content[0]?.text || 'An error occurred', } : undefined, }; } catch (error) { logger.error(`Error executing tool ${tool.name}: ${error.message}`); return { content: [{ type: 'text', text: `Error: ${error.message}` }], error: { message: error.message }, }; } } ); }