add_pull_request_comment
Add comments to Azure DevOps pull requests to provide feedback, reply to existing discussions, or create new threads on specific code lines.
Instructions
Add a comment to a pull request (reply to existing comments or create new threads)
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectId | No | The ID or name of the project (Default: MyProject) | |
| organizationId | No | The ID or name of the organization (Default: mycompany) | |
| repositoryId | Yes | The ID or name of the repository | |
| pullRequestId | Yes | The ID of the pull request | |
| content | Yes | The content of the comment in markdown | |
| threadId | No | The ID of the thread to add the comment to | |
| parentCommentId | No | ID of the parent comment when replying to an existing comment | |
| filePath | No | The path of the file to comment on (for new thread on file) | |
| lineNumber | No | The line number to comment on (for new thread on file) | |
| status | No | The status to set for a new thread |
Implementation Reference
- Core handler function that executes the logic to add a comment to an Azure DevOps pull request, either as a reply to an existing thread or as a new thread with optional file context and status.export async function addPullRequestComment( connection: WebApi, projectId: string, repositoryId: string, pullRequestId: number, options: AddPullRequestCommentOptions, ): Promise<AddCommentResponse> { try { const gitApi = await connection.getGitApi(); // Create comment object const comment: Comment = { content: options.content, commentType: CommentType.Text, // Default to Text type parentCommentId: options.parentCommentId, }; // Case 1: Add comment to an existing thread if (options.threadId) { const createdComment = await gitApi.createComment( comment, repositoryId, pullRequestId, options.threadId, projectId, ); if (!createdComment) { throw new Error('Failed to create pull request comment'); } return { comment: { ...createdComment, commentType: transformCommentType(createdComment.commentType), }, }; } // Case 2: Create new thread with comment else { // Map status string to CommentThreadStatus enum let threadStatus: CommentThreadStatus | undefined; if (options.status) { switch (options.status) { case 'active': threadStatus = CommentThreadStatus.Active; break; case 'fixed': threadStatus = CommentThreadStatus.Fixed; break; case 'wontFix': threadStatus = CommentThreadStatus.WontFix; break; case 'closed': threadStatus = CommentThreadStatus.Closed; break; case 'pending': threadStatus = CommentThreadStatus.Pending; break; case 'byDesign': threadStatus = CommentThreadStatus.ByDesign; break; case 'unknown': threadStatus = CommentThreadStatus.Unknown; break; } } // Create thread with comment const thread: GitPullRequestCommentThread = { comments: [comment], status: threadStatus, }; // Add file context if specified (file comment) if (options.filePath) { thread.threadContext = { filePath: options.filePath, // Only add line information if provided rightFileStart: options.lineNumber ? { line: options.lineNumber, offset: 1, // Default to start of line } : undefined, rightFileEnd: options.lineNumber ? { line: options.lineNumber, offset: 1, // Default to start of line } : undefined, }; } const createdThread = await gitApi.createThread( thread, repositoryId, pullRequestId, projectId, ); if ( !createdThread || !createdThread.comments || createdThread.comments.length === 0 ) { throw new Error('Failed to create pull request comment thread'); } return { comment: { ...createdThread.comments[0], commentType: transformCommentType( createdThread.comments[0].commentType, ), }, thread: { ...createdThread, status: transformCommentThreadStatus(createdThread.status), comments: createdThread.comments?.map((comment) => ({ ...comment, commentType: transformCommentType(comment.commentType), })), }, }; } } catch (error) { if (error instanceof AzureDevOpsError) { throw error; } throw new Error( `Failed to add pull request comment: ${error instanceof Error ? error.message : String(error)}`, ); } }
- Zod input schema for validating tool parameters, with custom validation requiring status for new threads.export const AddPullRequestCommentSchema = z .object({ projectId: z .string() .optional() .describe(`The ID or name of the project (Default: ${defaultProject})`), organizationId: z .string() .optional() .describe(`The ID or name of the organization (Default: ${defaultOrg})`), repositoryId: z.string().describe('The ID or name of the repository'), pullRequestId: z.number().describe('The ID of the pull request'), content: z.string().describe('The content of the comment in markdown'), threadId: z .number() .optional() .describe('The ID of the thread to add the comment to'), parentCommentId: z .number() .optional() .describe( 'ID of the parent comment when replying to an existing comment', ), filePath: z .string() .optional() .describe('The path of the file to comment on (for new thread on file)'), lineNumber: z .number() .optional() .describe('The line number to comment on (for new thread on file)'), status: z .enum([ 'active', 'fixed', 'wontFix', 'closed', 'pending', 'byDesign', 'unknown', ]) .optional() .describe('The status to set for a new thread'), }) .superRefine((data, ctx) => { // If we're creating a new thread (no threadId), status is required if (!data.threadId && !data.status) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Status is required when creating a new thread', path: ['status'], }); } });
- src/features/pull-requests/tool-definitions.ts:33-38 (registration)MCP tool definition registration including name, description, and JSON schema derived from Zod schema.{ name: 'add_pull_request_comment', description: 'Add a comment to a pull request (reply to existing comments or create new threads)', inputSchema: zodToJsonSchema(AddPullRequestCommentSchema), },
- Request handler switch case that parses arguments and invokes the core addPullRequestComment function for MCP tool calls.case 'add_pull_request_comment': { const params = AddPullRequestCommentSchema.parse( request.params.arguments, ); const result = await addPullRequestComment( connection, params.projectId ?? defaultProject, params.repositoryId, params.pullRequestId, { projectId: params.projectId ?? defaultProject, repositoryId: params.repositoryId, pullRequestId: params.pullRequestId, content: params.content, threadId: params.threadId, parentCommentId: params.parentCommentId, filePath: params.filePath, lineNumber: params.lineNumber, status: params.status, }, ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; }