Skip to content

Commit c750a38

Browse files
PlaySkyHDdanhellem
andauthored
feat: add create pull request thread tool (#260)
Hey, i added the **create_pull_request_thread** functionality to initiate a new comment thread on a pull request. ## GitHub issue number #231 ## **Associated Risks** / ## ✅ **PR Checklist** - [x] **I have read the [contribution guidelines](https://github.com/microsoft/azure-devops-mcp/blob/main/CONTRIBUTING.md)** - [x] **I have read the [code of conduct guidelines](https://github.com/microsoft/azure-devops-mcp/blob/main/CODE_OF_CONDUCT.md)** - [x] Title of the pull request is clear and informative. - [x] 👌 Code hygiene - [x] 🔭 Telemetry added, updated, or N/A - [x] 📄 Documentation added, updated, or N/A - [x] 🛡️ Automated tests added, or N/A ## 🧪 **How did you test it?** Model: Claude Sonnet 4 Prompt: ``` ## Code Review Expert: Detailed Analysis and Best Practices As a senior software engineer with expertise in code quality, security, and performance optimization, perform a code review of the provided git diff. Focus on delivering actionable feedback in the following areas: Critical Issues: - Security vulnerabilities and potential exploits - Runtime errors and logic bugs - Performance bottlenecks and optimization opportunities - Memory management and resource utilization - Threading and concurrency issues - Input validation and error handling Code Quality: - Adherence to language-specific conventions and best practices - Design patterns and architectural considerations - Code organization and modularity - Naming conventions and code readability - Documentation completeness and clarity - Test coverage and testing approach Maintainability: - Code duplication and reusability - Complexity metrics (cyclomatic complexity, cognitive complexity) - Dependencies and coupling - Extensibility and future-proofing - Technical debt implications Provide specific recommendations with: - Code examples for suggested improvements - References to relevant documentation or standards - Rationale for suggested changes - Impact assessment of proposed modifications Format your review using clear sections and bullet points. Include inline code references where applicable. Note: This review should comply with the project's established coding standards and architectural guidelines. ### Context: - **DevOps-Project**: z - **Repository**: y - **PR number**: x ### Instructions: 1. **Use Azure DevOps integration**: - Connect to Azure DevOps via MCP Tools - Load PR details, commits and existing comments - Analyze the changed files and code diffs 2 **Code standards check against**: - Copilot Instructions 3. **Sarcastic review style**: - Be precise but biting in criticism - Repeat similar issues for multiple files - Create separate comment threads for each issue - If possible, always link the file in the comment as well as the line and offset 4. **Azure DevOps Actions**: - Use `mcp_ado_repo_create_pull_request_thread` for new comments - Create specific comment threads with file/line references (for the line and offset: rightFileStartLine, rightFileStartOffset, rightFileEndLine, rightFileEndOffset) - Link specific lines of code and offsets - Set review priority based on issue severity 5. **Extra information**: - Ignore deleted comments - Ignore deleted files - Always perform a review, even if you think the PR has already been reviewed. Please proceed in such a way that you ignore the old review and start again. - PullRequest-Status Enum(NotSet = 0, Active = 1, Abandoned = 2, Completed = 3, All = 4) - Only look at the diffs from the PullRequest 6. **Qualtity**: 1. **Specify filePath** - Full path to the file 2. **Specify rightFileStartLine** - Start line of the problem 3. **Specify rightFileEndLine** - End line of the problem 4. **Specify rightFileStartOffset** - Start offset 5. **Specify rightFileEndOffset** - End offset ### Expected result: - Each comment with specific file/line reference - Sarcastic but constructive tone - Specific recommendations for improvement - create new short review comments with specific line references - Reviewing the diffs between the source branch and target branch ``` <img width="1396" height="851" alt="grafik" src="https://github.com/user-attachments/assets/8aaec603-b890-4a6c-8d04-399a9cc4da18" /> --------- Co-authored-by: Dan Hellem <[email protected]>
1 parent 79ad732 commit c750a38

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,10 @@ Interact with these Azure DevOps services:
9696
- **repo_create_pull_request**: Create a new pull request.
9797
- **repo_update_pull_request_status**: Update the status of an existing pull request to active or abandoned.
9898
- **repo_update_pull_request_reviewers**: Add or remove reviewers for an existing pull request.
99-
- **repo_reply_to_comment**: Reply to a specific comment on a pull request.
100-
- **repo_resolve_comment**: Resolve a specific comment thread on a pull request.
101-
- **repo_search_commits**: Search for commits.
99+
- **repo_reply_to_comment**: Replies to a specific comment on a pull request.
100+
- **repo_resolve_comment**: Resolves a specific comment thread on a pull request.
101+
- **repo_search_commits**: Searches for commits.
102+
- **repo_create_pull_request_thread**: Creates a new comment thread on a pull request.
102103

103104
### 🛰️ Builds
104105

src/tools/repos.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
GitPullRequestQuery,
1414
GitPullRequestQueryInput,
1515
GitPullRequestQueryType,
16+
CommentThreadContext,
1617
} from "azure-devops-node-api/interfaces/GitInterfaces.js";
1718
import { z } from "zod";
1819
import { getCurrentUserDetails } from "./auth.js";
@@ -34,6 +35,7 @@ const REPO_TOOLS = {
3435
update_pull_request_status: "repo_update_pull_request_status",
3536
update_pull_request_reviewers: "repo_update_pull_request_reviewers",
3637
reply_to_comment: "repo_reply_to_comment",
38+
create_pull_request_thread: "repo_create_pull_request_thread",
3739
resolve_comment: "repo_resolve_comment",
3840
search_commits: "repo_search_commits",
3941
list_pull_requests_by_commits: "repo_list_pull_requests_by_commits",
@@ -518,6 +520,85 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<Acce
518520
}
519521
);
520522

523+
server.tool(
524+
REPO_TOOLS.create_pull_request_thread,
525+
"Creates a new comment thread on a pull request.",
526+
{
527+
repositoryId: z.string().describe("The ID of the repository where the pull request is located."),
528+
pullRequestId: z.number().describe("The ID of the pull request where the comment thread exists."),
529+
content: z.string().describe("The content of the comment to be added."),
530+
project: z.string().optional().describe("Project ID or project name (optional)"),
531+
filePath: z.string().optional().describe("The path of the file where the comment thread will be created. (optional)"),
532+
rightFileStartLine: z.number().optional().describe("Position of first character of the thread's span in right file. The line number of a thread's position. Starts at 1. (optional)"),
533+
rightFileStartOffset: z
534+
.number()
535+
.optional()
536+
.describe(
537+
"Position of first character of the thread's span in right file. The line number of a thread's position. The character offset of a thread's position inside of a line. Starts at 1. Must only be set if rightFileStartLine is also specified. (optional)"
538+
),
539+
rightFileEndLine: z
540+
.number()
541+
.optional()
542+
.describe(
543+
"Position of last character of the thread's span in right file. The line number of a thread's position. Starts at 1. Must only be set if rightFileStartLine is also specified. (optional)"
544+
),
545+
rightFileEndOffset: z
546+
.number()
547+
.optional()
548+
.describe(
549+
"Position of last character of the thread's span in right file. The character offset of a thread's position inside of a line. Must only be set if rightFileEndLine is also specified. (optional)"
550+
),
551+
},
552+
async ({ repositoryId, pullRequestId, content, project, filePath, rightFileStartLine, rightFileStartOffset, rightFileEndLine, rightFileEndOffset }) => {
553+
const connection = await connectionProvider();
554+
const gitApi = await connection.getGitApi();
555+
556+
const threadContext: CommentThreadContext = { filePath: filePath };
557+
558+
if (rightFileStartLine !== undefined) {
559+
if (rightFileStartLine < 1) {
560+
throw new Error("rightFileStartLine must be greater than or equal to 1.");
561+
}
562+
563+
threadContext.rightFileStart = { line: rightFileStartLine };
564+
565+
if (rightFileStartOffset !== undefined) {
566+
if (rightFileStartOffset < 1) {
567+
throw new Error("rightFileStartOffset must be greater than or equal to 1.");
568+
}
569+
570+
threadContext.rightFileStart.offset = rightFileStartOffset;
571+
}
572+
}
573+
574+
if (rightFileEndLine !== undefined) {
575+
if (rightFileStartLine === undefined) {
576+
throw new Error("rightFileEndLine must only be specified if rightFileStartLine is also specified.");
577+
}
578+
579+
if (rightFileEndLine < 1) {
580+
throw new Error("rightFileEndLine must be greater than or equal to 1.");
581+
}
582+
583+
threadContext.rightFileEnd = { line: rightFileEndLine };
584+
585+
if (rightFileEndOffset !== undefined) {
586+
if (rightFileEndOffset < 1) {
587+
throw new Error("rightFileEndOffset must be greater than or equal to 1.");
588+
}
589+
590+
threadContext.rightFileEnd.offset = rightFileEndOffset;
591+
}
592+
}
593+
594+
const thread = await gitApi.createThread({ comments: [{ content: content }], threadContext: threadContext }, repositoryId, pullRequestId, project);
595+
596+
return {
597+
content: [{ type: "text", text: JSON.stringify(thread, null, 2) }],
598+
};
599+
}
600+
);
601+
521602
server.tool(
522603
REPO_TOOLS.resolve_comment,
523604
"Resolves a specific comment thread on a pull request.",

0 commit comments

Comments
 (0)