@mcp-apps/azure-devops-mcp-server
Version:
A Model Context Protocol (MCP) server for Azure DevOps integration
157 lines (154 loc) • 7.68 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.addPullRequestCommentTool = void 0;
const zod_1 = require("zod");
const azure_devops_client_1 = require("../utils/azure-devops-client");
const GitInterfaces = __importStar(require("azure-devops-node-api/interfaces/GitInterfaces"));
const STATUS_MAP = {
active: GitInterfaces.CommentThreadStatus.Active,
fixed: GitInterfaces.CommentThreadStatus.Fixed,
"won't-fix": GitInterfaces.CommentThreadStatus.WontFix,
closed: GitInterfaces.CommentThreadStatus.Closed,
"by-design": GitInterfaces.CommentThreadStatus.ByDesign,
pending: GitInterfaces.CommentThreadStatus.Pending,
};
exports.addPullRequestCommentTool = {
name: "git-add-pr-comment",
description: `
Adds a new comment thread to a pull request. The thread can be a general PR-level
comment (omit filePath) or an inline review comment anchored to a file/line range
in the new (right) version of the diff.
IMPORTANT — filePath format:
- Must be repo-root relative AND start with a leading '/'.
- Correct: "/src/app.ts"
- Incorrect: "src/app.ts" (Azure DevOps will reject or silently ignore the anchor)
Thread status values (controls how the comment appears in the PR review UI):
- "active": Open / unresolved. Default for new feedback.
- "pending": Draft visible only to the author until published; rarely needed.
- "fixed": Resolved as fixed (typical "resolve" status after a code change).
- "closed": Discussion ended without explicit resolution.
- "won't-fix": Acknowledged but won't be addressed.
- "by-design": Behavior is intentional; not a bug.
Parameters:
- organizationUrl: Azure DevOps organization URL
- project: Project name
- repositoryName: Repository name
- pullRequestId: Pull request ID
- content: The comment text (Markdown supported)
- status: Initial thread status (default "active")
- filePath: Optional file path starting with '/' to anchor the comment
(e.g. "/src/app.ts"). Required for inline comments.
- rightStartLine / rightStartColumn / rightEndLine / rightEndColumn: Optional
1-based line/column range in the right (new) version of the file. Provide at
least rightStartLine to create an inline review comment.
`,
parameters: {
organizationUrl: zod_1.z.string().describe("Azure DevOps organization URL"),
project: zod_1.z.string().describe("Project name"),
repositoryName: zod_1.z.string().describe("Repository name"),
pullRequestId: zod_1.z.number().int().describe("Pull request ID"),
content: zod_1.z.string().describe("Comment content (Markdown supported)"),
status: zod_1.z
.enum(["active", "fixed", "won't-fix", "closed", "by-design", "pending"])
.default("active")
.describe("Initial thread status"),
filePath: zod_1.z.string().optional().describe("Optional file path (e.g. '/src/app.ts') to anchor the comment"),
rightStartLine: zod_1.z.number().int().optional().describe("1-based start line in the right (new) file version"),
rightStartColumn: zod_1.z.number().int().optional().describe("1-based start column in the right file version"),
rightEndLine: zod_1.z.number().int().optional().describe("1-based end line in the right file version"),
rightEndColumn: zod_1.z.number().int().optional().describe("1-based end column in the right file version"),
},
handler: async ({ organizationUrl, project, repositoryName, pullRequestId, content, status, filePath, rightStartLine, rightStartColumn, rightEndLine, rightEndColumn, }) => {
try {
const gitApi = await (0, azure_devops_client_1.getGitApi)(organizationUrl);
const repositories = await gitApi.getRepositories(project);
const repository = repositories.find((r) => r.name && r.name.toLowerCase() === repositoryName.toLowerCase());
if (!repository?.id) {
return {
content: [{
type: "text",
text: `Repository "${repositoryName}" not found in project "${project}".`,
}],
};
}
const thread = {
status: STATUS_MAP[status],
comments: [
{
parentCommentId: 0,
content,
commentType: GitInterfaces.CommentType.Text,
},
],
};
if (filePath) {
const startLine = rightStartLine ?? 1;
const endLine = rightEndLine ?? startLine;
const startCol = rightStartColumn ?? 1;
const endCol = rightEndColumn ?? Math.max(startCol, 1);
thread.threadContext = {
filePath,
rightFileStart: { line: startLine, offset: startCol },
rightFileEnd: { line: endLine, offset: endCol },
};
}
const created = await gitApi.createThread(thread, repository.id, pullRequestId, project);
return {
content: [{
type: "text",
text: JSON.stringify({
pullRequestId,
threadId: created?.id,
commentId: created?.comments?.[0]?.id,
status: created?.status,
filePath: created?.threadContext?.filePath ?? null,
createdBy: created?.comments?.[0]?.author?.displayName,
}, null, 2),
}],
};
}
catch (error) {
const msg = error instanceof Error ? error.message : String(error);
return {
content: [{
type: "text",
text: `Error adding pull request comment: ${msg}`,
}],
};
}
},
};
//# sourceMappingURL=git-add-pr-comment.js.map