@azure-devops/mcp 1.1.0 → 1.2.0-daily.20250715

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.
package/README.md CHANGED
@@ -47,6 +47,7 @@ Interact with these Azure DevOps services:
47
47
 
48
48
  - **core_list_project_teams**: Retrieve a list of teams for the specified Azure DevOps project.
49
49
  - **core_list_projects**: Retrieve a list of projects in your Azure DevOps organization.
50
+ - **core_get_identity_ids**: Retrieve Azure DevOps identity IDs for a list of unique names.
50
51
 
51
52
  ### ⚒️ Work
52
53
 
@@ -94,6 +95,7 @@ Interact with these Azure DevOps services:
94
95
  - **repo_get_pull_request_by_id**: Get a pull request by its ID.
95
96
  - **repo_create_pull_request**: Create a new pull request.
96
97
  - **repo_update_pull_request_status**: Update status of an existing pull request to active or abandoned.
98
+ - **repo_update_pull_request_reviewers**: Add or remove reviewers for an existing pull request.
97
99
  - **repo_reply_to_comment**: Replies to a specific comment on a pull request.
98
100
  - **repo_resolve_comment**: Resolves a specific comment thread on a pull request.
99
101
  - **repo_search_commits**: Searches for commits.
package/dist/index.js CHANGED
@@ -17,7 +17,12 @@ if (args.length === 0) {
17
17
  export const orgName = args[0];
18
18
  const orgUrl = "https://dev.azure.com/" + orgName;
19
19
  async function getAzureDevOpsToken() {
20
- process.env.AZURE_TOKEN_CREDENTIALS = "dev";
20
+ if (process.env.ADO_MCP_AZURE_TOKEN_CREDENTIALS) {
21
+ process.env.AZURE_TOKEN_CREDENTIALS = process.env.ADO_MCP_AZURE_TOKEN_CREDENTIALS;
22
+ }
23
+ else {
24
+ process.env.AZURE_TOKEN_CREDENTIALS = "dev";
25
+ }
21
26
  const credential = new DefaultAzureCredential(); // CodeQL [SM05138] resolved by explicitly setting AZURE_TOKEN_CREDENTIALS
22
27
  const token = await credential.getToken("499b84ac-1321-427f-aa17-267ca6975798/.default");
23
28
  return token;
@@ -1,9 +1,11 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT License.
3
3
  import { z } from "zod";
4
+ import { apiVersion } from "../utils.js";
4
5
  const CORE_TOOLS = {
5
6
  list_project_teams: "core_list_project_teams",
6
7
  list_projects: "core_list_projects",
8
+ get_identity_ids: "core_get_identity_ids",
7
9
  };
8
10
  function filterProjectsByName(projects, projectNameFilter) {
9
11
  const lowerCaseFilter = projectNameFilter.toLowerCase();
@@ -62,5 +64,51 @@ function configureCoreTools(server, tokenProvider, connectionProvider) {
62
64
  };
63
65
  }
64
66
  });
67
+ server.tool(CORE_TOOLS.get_identity_ids, "Retrieve Azure DevOps identity IDs for a provided search filter.", {
68
+ searchFilter: z.string().describe("Search filter (unique namme, display name, email) to retrieve identity IDs for."),
69
+ }, async ({ searchFilter }) => {
70
+ try {
71
+ const token = await tokenProvider();
72
+ const connection = await connectionProvider();
73
+ const orgName = connection.serverUrl.split("/")[3];
74
+ const baseUrl = `https://vssps.dev.azure.com/${orgName}/_apis/identities`;
75
+ const params = new URLSearchParams({
76
+ "api-version": apiVersion,
77
+ "searchFilter": "General",
78
+ "filterValue": searchFilter,
79
+ });
80
+ const response = await fetch(`${baseUrl}?${params}`, {
81
+ headers: {
82
+ "Authorization": `Bearer ${token.token}`,
83
+ "Content-Type": "application/json",
84
+ },
85
+ });
86
+ if (!response.ok) {
87
+ const errorText = await response.text();
88
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
89
+ }
90
+ const identities = await response.json();
91
+ if (!identities || identities.value?.length === 0) {
92
+ return { content: [{ type: "text", text: "No identities found" }], isError: true };
93
+ }
94
+ const identitiesTrimmed = identities.value?.map((identity) => {
95
+ return {
96
+ id: identity.id,
97
+ displayName: identity.providerDisplayName,
98
+ descriptor: identity.descriptor,
99
+ };
100
+ });
101
+ return {
102
+ content: [{ type: "text", text: JSON.stringify(identitiesTrimmed, null, 2) }],
103
+ };
104
+ }
105
+ catch (error) {
106
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
107
+ return {
108
+ content: [{ type: "text", text: `Error fetching identities: ${errorMessage}` }],
109
+ isError: true,
110
+ };
111
+ }
112
+ });
65
113
  }
66
114
  export { CORE_TOOLS, configureCoreTools };
@@ -16,6 +16,7 @@ const REPO_TOOLS = {
16
16
  get_pull_request_by_id: "repo_get_pull_request_by_id",
17
17
  create_pull_request: "repo_create_pull_request",
18
18
  update_pull_request_status: "repo_update_pull_request_status",
19
+ update_pull_request_reviewers: "repo_update_pull_request_reviewers",
19
20
  reply_to_comment: "repo_reply_to_comment",
20
21
  resolve_comment: "repo_resolve_comment",
21
22
  search_commits: "repo_search_commits",
@@ -88,6 +89,30 @@ function configureRepoTools(server, tokenProvider, connectionProvider) {
88
89
  content: [{ type: "text", text: JSON.stringify(updatedPullRequest, null, 2) }],
89
90
  };
90
91
  });
92
+ server.tool(REPO_TOOLS.update_pull_request_reviewers, "Add or remove reviewers for an existing pull request.", {
93
+ repositoryId: z.string().describe("The ID of the repository where the pull request exists."),
94
+ pullRequestId: z.number().describe("The ID of the pull request to update."),
95
+ reviewerIds: z.array(z.string()).describe("List of reviewer ids to add or remove from the pull request."),
96
+ action: z.enum(["add", "remove"]).describe("Action to perform on the reviewers. Can be 'add' or 'remove'."),
97
+ }, async ({ repositoryId, pullRequestId, reviewerIds, action }) => {
98
+ const connection = await connectionProvider();
99
+ const gitApi = await connection.getGitApi();
100
+ let updatedPullRequest;
101
+ if (action === "add") {
102
+ updatedPullRequest = await gitApi.createPullRequestReviewers(reviewerIds.map((id) => ({ id: id })), repositoryId, pullRequestId);
103
+ return {
104
+ content: [{ type: "text", text: JSON.stringify(updatedPullRequest, null, 2) }],
105
+ };
106
+ }
107
+ else {
108
+ for (const reviewerId of reviewerIds) {
109
+ await gitApi.deletePullRequestReviewer(repositoryId, pullRequestId, reviewerId);
110
+ }
111
+ return {
112
+ content: [{ type: "text", text: `Reviewers with IDs ${reviewerIds.join(", ")} removed from pull request ${pullRequestId}.` }],
113
+ };
114
+ }
115
+ });
91
116
  server.tool(REPO_TOOLS.list_repos_by_project, "Retrieve a list of repositories for a given project", {
92
117
  project: z.string().describe("The name or ID of the Azure DevOps project."),
93
118
  top: z.number().default(100).describe("The maximum number of repositories to return."),
package/dist/useragent.js CHANGED
@@ -1,3 +1,5 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
1
3
  class UserAgentComposer {
2
4
  _userAgent;
3
5
  _mcpClientInfoAppended;
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const packageVersion = "1.1.0";
1
+ export const packageVersion = "1.2.0-daily.20250715";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-devops/mcp",
3
- "version": "1.1.0",
3
+ "version": "1.2.0-daily.20250715",
4
4
  "description": "MCP server for interacting with Azure DevOps",
5
5
  "license": "MIT",
6
6
  "author": "Microsoft Corporation",