@azure-devops/mcp 2.4.0-nightly.20260222 → 2.4.0-nightly.20260224

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT License.
3
- import { PullRequestStatus, GitVersionType, GitPullRequestQueryType, CommentThreadStatus, GitPullRequestMergeStrategy, } from "azure-devops-node-api/interfaces/GitInterfaces.js";
3
+ import { PullRequestStatus, GitVersionType, GitPullRequestQueryType, CommentThreadStatus, GitPullRequestMergeStrategy, VersionControlRecursionType, } from "azure-devops-node-api/interfaces/GitInterfaces.js";
4
4
  import { z } from "zod";
5
5
  import { getCurrentUserDetails, getUserIdFromEmail } from "./auth.js";
6
6
  import { getEnumKeys } from "../utils.js";
@@ -23,6 +23,8 @@ const REPO_TOOLS = {
23
23
  update_pull_request_thread: "repo_update_pull_request_thread",
24
24
  search_commits: "repo_search_commits",
25
25
  list_pull_requests_by_commits: "repo_list_pull_requests_by_commits",
26
+ vote_pull_request: "repo_vote_pull_request",
27
+ list_directory: "repo_list_directory",
26
28
  };
27
29
  function branchesFilterOutIrrelevantProperties(branches, top) {
28
30
  return branches
@@ -103,6 +105,21 @@ function trimPullRequest(pr, includeDescription = false) {
103
105
  project: pr.repository?.project?.name,
104
106
  };
105
107
  }
108
+ // Helper function to build a version descriptor from branch or commit
109
+ function buildVersionDescriptor(version, versionType) {
110
+ if (!version) {
111
+ return undefined;
112
+ }
113
+ const versionTypeMap = {
114
+ Branch: GitVersionType.Branch,
115
+ Commit: GitVersionType.Commit,
116
+ Tag: GitVersionType.Tag,
117
+ };
118
+ return {
119
+ version: version,
120
+ versionType: versionTypeMap[versionType || "Branch"] ?? GitVersionType.Branch,
121
+ };
122
+ }
106
123
  function configureRepoTools(server, tokenProvider, connectionProvider, userAgentProvider) {
107
124
  server.tool(REPO_TOOLS.create_pull_request, "Create a new pull request.", {
108
125
  repositoryId: z.string().describe("The ID of the repository where the pull request will be created."),
@@ -1150,5 +1167,100 @@ function configureRepoTools(server, tokenProvider, connectionProvider, userAgent
1150
1167
  };
1151
1168
  }
1152
1169
  });
1170
+ server.tool(REPO_TOOLS.vote_pull_request, "Cast a vote on a pull request. Automatically adds the current user as a reviewer if they are not already one.", {
1171
+ repositoryId: z.string().describe("The ID of the repository."),
1172
+ pullRequestId: z.number().describe("The ID of the pull request."),
1173
+ vote: z.enum(["Approved", "ApprovedWithSuggestions", "NoVote", "WaitingForAuthor", "Rejected"]).describe("The vote to cast: Approved(10), Suggestions(5), None(0), Waiting(-5), Rejected(-10)."),
1174
+ }, async ({ repositoryId, pullRequestId, vote }) => {
1175
+ const connection = await connectionProvider();
1176
+ const gitApi = await connection.getGitApi();
1177
+ const userDetails = await getCurrentUserDetails(tokenProvider, connectionProvider, userAgentProvider);
1178
+ const userId = userDetails.authenticatedUser.id;
1179
+ if (!userId) {
1180
+ throw new Error("Could not determine authenticated user ID.");
1181
+ }
1182
+ const voteMap = {
1183
+ Approved: 10,
1184
+ ApprovedWithSuggestions: 5,
1185
+ NoVote: 0,
1186
+ WaitingForAuthor: -5,
1187
+ Rejected: -10,
1188
+ };
1189
+ await gitApi.createPullRequestReviewer({ vote: voteMap[vote], id: userId }, repositoryId, pullRequestId, userId);
1190
+ return {
1191
+ content: [
1192
+ {
1193
+ type: "text",
1194
+ text: `Successfully cast vote '${vote}' on PR #${pullRequestId}.`,
1195
+ },
1196
+ ],
1197
+ };
1198
+ });
1199
+ server.tool(REPO_TOOLS.list_directory, "List files and folders in a directory within a repository. Useful for exploring the structure of a codebase or finding related files.", {
1200
+ repositoryId: z.string().describe("The ID or name of the repository."),
1201
+ path: z.string().optional().default("/").describe("The directory path to list (e.g., '/src' or '/src/components'). Defaults to repository root."),
1202
+ project: z.string().optional().describe("Project ID or name. Required if repositoryId is a name rather than a GUID."),
1203
+ version: z.string().optional().describe("The version identifier - branch name (e.g., 'main'), tag name, or commit SHA. Defaults to the repository's default branch."),
1204
+ versionType: z.enum(["Branch", "Commit", "Tag"]).optional().default("Branch").describe("The type of version identifier: 'Branch', 'Commit', or 'Tag'. Defaults to 'Branch'."),
1205
+ recursive: z.boolean().optional().default(false).describe("Whether to list items recursively. Defaults to false."),
1206
+ recursionDepth: z.number().optional().default(1).describe("Maximum depth for recursive listing (1-10). Only applies when recursive is true. Defaults to 1."),
1207
+ }, async ({ repositoryId, path, project, version, versionType, recursive, recursionDepth }) => {
1208
+ try {
1209
+ const connection = await connectionProvider();
1210
+ const gitApi = await connection.getGitApi();
1211
+ const versionDescriptor = buildVersionDescriptor(version, versionType);
1212
+ const clampedDepth = Math.min(Math.max(recursionDepth || 1, 1), 10);
1213
+ let recursionType = VersionControlRecursionType.OneLevel;
1214
+ if (recursive) {
1215
+ recursionType = VersionControlRecursionType.Full;
1216
+ }
1217
+ const items = await gitApi.getItems(repositoryId, project, path, recursionType, true, false, false, false, versionDescriptor);
1218
+ if (!items || items.length === 0) {
1219
+ return {
1220
+ content: [{ type: "text", text: `No items found at path: ${path}` }],
1221
+ };
1222
+ }
1223
+ let filteredItems = items;
1224
+ if (recursive && clampedDepth < 10) {
1225
+ const basePath = path === "/" ? "" : path;
1226
+ const baseDepth = basePath.split("/").filter((p) => p).length;
1227
+ filteredItems = items.filter((item) => {
1228
+ if (!item.path)
1229
+ return false;
1230
+ const itemDepth = item.path.split("/").filter((p) => p).length;
1231
+ return itemDepth <= baseDepth + clampedDepth;
1232
+ });
1233
+ }
1234
+ const formattedItems = filteredItems.map((item) => ({
1235
+ path: item.path,
1236
+ isFolder: item.isFolder,
1237
+ gitObjectType: item.gitObjectType,
1238
+ commitId: item.commitId,
1239
+ contentMetadata: item.contentMetadata
1240
+ ? {
1241
+ contentType: item.contentMetadata.contentType,
1242
+ fileName: item.contentMetadata.fileName,
1243
+ }
1244
+ : undefined,
1245
+ }));
1246
+ const response = {
1247
+ count: formattedItems.length,
1248
+ path: path,
1249
+ recursive: recursive,
1250
+ recursionDepth: recursive ? clampedDepth : undefined,
1251
+ items: formattedItems,
1252
+ };
1253
+ return {
1254
+ content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
1255
+ };
1256
+ }
1257
+ catch (error) {
1258
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
1259
+ return {
1260
+ content: [{ type: "text", text: `Error listing directory: ${errorMessage}` }],
1261
+ isError: true,
1262
+ };
1263
+ }
1264
+ });
1153
1265
  }
1154
1266
  export { REPO_TOOLS, configureRepoTools };
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const packageVersion = "2.4.0-nightly.20260222";
1
+ export const packageVersion = "2.4.0-nightly.20260224";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-devops/mcp",
3
- "version": "2.4.0-nightly.20260222",
3
+ "version": "2.4.0-nightly.20260224",
4
4
  "mcpName": "microsoft.com/azure-devops",
5
5
  "description": "MCP server for interacting with Azure DevOps",
6
6
  "license": "MIT",
@@ -39,8 +39,8 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@azure/identity": "^4.10.0",
42
- "@azure/msal-node": "^3.6.0",
43
- "@modelcontextprotocol/sdk": "1.26.0",
42
+ "@azure/msal-node": "^5.0.4",
43
+ "@modelcontextprotocol/sdk": "1.27.0",
44
44
  "azure-devops-extension-api": "^4.264.0",
45
45
  "azure-devops-extension-sdk": "^4.0.2",
46
46
  "azure-devops-node-api": "^15.1.2",