@azure-devops/mcp 2.4.0-nightly.20260310 → 2.4.0-nightly.20260312

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.
@@ -12,8 +12,8 @@ function filterProjectsByName(projects, projectNameFilter) {
12
12
  return projects.filter((project) => project.name?.toLowerCase().includes(lowerCaseFilter));
13
13
  }
14
14
  function configureCoreTools(server, tokenProvider, connectionProvider, userAgentProvider) {
15
- server.tool(CORE_TOOLS.list_project_teams, "Retrieve a list of teams for the specified Azure DevOps project.", {
16
- project: z.string().describe("The name or ID of the Azure DevOps project."),
15
+ server.tool(CORE_TOOLS.list_project_teams, "Retrieve a list of teams for an Azure DevOps project. If a project is not specified, you will be prompted to select one.", {
16
+ project: z.string().optional().describe("The name or ID of the Azure DevOps project. If not provided, a project selection prompt will be shown."),
17
17
  mine: z.boolean().optional().describe("If true, only return teams that the authenticated user is a member of."),
18
18
  top: z.number().optional().describe("The maximum number of teams to return. Defaults to 100."),
19
19
  skip: z.number().optional().describe("The number of teams to skip for pagination. Defaults to 0."),
@@ -21,7 +21,37 @@ function configureCoreTools(server, tokenProvider, connectionProvider, userAgent
21
21
  try {
22
22
  const connection = await connectionProvider();
23
23
  const coreApi = await connection.getCoreApi();
24
- const teams = await coreApi.getTeams(project, mine, top, skip, false);
24
+ let resolvedProject = project;
25
+ if (!resolvedProject) {
26
+ const projects = await coreApi.getProjects("wellFormed", 100, 0, undefined, false);
27
+ if (!projects || projects.length === 0) {
28
+ return { content: [{ type: "text", text: "No projects found to select from." }], isError: true };
29
+ }
30
+ const result = await server.server.elicitInput({
31
+ mode: "form",
32
+ message: "Select the Azure DevOps project to list teams for.",
33
+ requestedSchema: {
34
+ type: "object",
35
+ properties: {
36
+ project: {
37
+ type: "string",
38
+ title: "Project",
39
+ description: "The Azure DevOps project to list teams for.",
40
+ oneOf: projects.map((p) => ({
41
+ const: p.name ?? p.id ?? "",
42
+ title: p.name ?? p.id ?? "Unknown project",
43
+ })),
44
+ },
45
+ },
46
+ required: ["project"],
47
+ },
48
+ });
49
+ if (result.action !== "accept" || !result.content?.project) {
50
+ return { content: [{ type: "text", text: "Project selection cancelled." }] };
51
+ }
52
+ resolvedProject = String(result.content.project);
53
+ }
54
+ const teams = await coreApi.getTeams(resolvedProject, mine, top, skip, false);
25
55
  if (!teams) {
26
56
  return { content: [{ type: "text", text: "No teams found" }], isError: true };
27
57
  }
@@ -767,15 +767,18 @@ function configureRepoTools(server, tokenProvider, connectionProvider, userAgent
767
767
  }
768
768
  });
769
769
  server.tool(REPO_TOOLS.get_pull_request_by_id, "Get a pull request by its ID.", {
770
- repositoryId: z.string().describe("The ID of the repository where the pull request is located."),
770
+ repositoryId: z
771
+ .string()
772
+ .describe("The ID or name of the repository where the pull request is located. When using a repository name instead of a GUID, the project parameter must also be provided."),
771
773
  pullRequestId: z.number().describe("The ID of the pull request to retrieve."),
774
+ project: z.string().optional().describe("Project ID or project name. Required when repositoryId is a repository name instead of a GUID."),
772
775
  includeWorkItemRefs: z.boolean().optional().default(false).describe("Whether to reference work items associated with the pull request."),
773
776
  includeLabels: z.boolean().optional().default(false).describe("Whether to include a summary of labels in the response."),
774
- }, async ({ repositoryId, pullRequestId, includeWorkItemRefs, includeLabels }) => {
777
+ }, async ({ repositoryId, pullRequestId, project, includeWorkItemRefs, includeLabels }) => {
775
778
  try {
776
779
  const connection = await connectionProvider();
777
780
  const gitApi = await connection.getGitApi();
778
- const pullRequest = await gitApi.getPullRequest(repositoryId, pullRequestId, undefined, undefined, undefined, undefined, undefined, includeWorkItemRefs);
781
+ const pullRequest = await gitApi.getPullRequest(repositoryId, pullRequestId, project, undefined, undefined, undefined, undefined, includeWorkItemRefs);
779
782
  if (includeLabels) {
780
783
  try {
781
784
  const projectId = pullRequest.repository?.project?.id;
@@ -16,6 +16,7 @@ const WORKITEM_TOOLS = {
16
16
  list_work_item_revisions: "wit_list_work_item_revisions",
17
17
  get_work_items_for_iteration: "wit_get_work_items_for_iteration",
18
18
  add_work_item_comment: "wit_add_work_item_comment",
19
+ update_work_item_comment: "wit_update_work_item_comment",
19
20
  add_child_work_items: "wit_add_child_work_items",
20
21
  link_work_item_to_pull_request: "wit_link_work_item_to_pull_request",
21
22
  get_work_item_type: "wit_get_work_item_type",
@@ -259,6 +260,44 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
259
260
  };
260
261
  }
261
262
  });
263
+ server.tool(WORKITEM_TOOLS.update_work_item_comment, "Update an existing comment on a work item by ID.", {
264
+ project: z.string().describe("The name or ID of the Azure DevOps project."),
265
+ workItemId: z.number().describe("The ID of the work item."),
266
+ commentId: z.number().describe("The ID of the comment to update."),
267
+ text: z.string().describe("The updated comment text."),
268
+ format: z.enum(["markdown", "html"]).optional().default("html"),
269
+ }, async ({ project, workItemId, commentId, text, format }) => {
270
+ try {
271
+ const connection = await connectionProvider();
272
+ const orgUrl = connection.serverUrl;
273
+ const accessToken = await tokenProvider();
274
+ const body = { text };
275
+ const formatParameter = format === "markdown" ? 0 : 1;
276
+ const response = await fetch(`${orgUrl}/${project}/_apis/wit/workItems/${workItemId}/comments/${commentId}?format=${formatParameter}&api-version=${markdownCommentsApiVersion}`, {
277
+ method: "PATCH",
278
+ headers: {
279
+ "Authorization": `Bearer ${accessToken}`,
280
+ "Content-Type": "application/json",
281
+ "User-Agent": userAgentProvider(),
282
+ },
283
+ body: JSON.stringify(body),
284
+ });
285
+ if (!response.ok) {
286
+ throw new Error(`Failed to update work item comment: ${response.statusText}`);
287
+ }
288
+ const updatedComment = await response.text();
289
+ return {
290
+ content: [{ type: "text", text: updatedComment }],
291
+ };
292
+ }
293
+ catch (error) {
294
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
295
+ return {
296
+ content: [{ type: "text", text: `Error updating work item comment: ${errorMessage}` }],
297
+ isError: true,
298
+ };
299
+ }
300
+ });
262
301
  server.tool(WORKITEM_TOOLS.list_work_item_revisions, "Retrieve list of revisions for a work item by ID.", {
263
302
  project: z.string().describe("The name or ID of the Azure DevOps project."),
264
303
  workItemId: z.number().describe("The ID of the work item to retrieve revisions for."),
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const packageVersion = "2.4.0-nightly.20260310";
1
+ export const packageVersion = "2.4.0-nightly.20260312";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-devops/mcp",
3
- "version": "2.4.0-nightly.20260310",
3
+ "version": "2.4.0-nightly.20260312",
4
4
  "mcpName": "microsoft.com/azure-devops",
5
5
  "description": "MCP server for interacting with Azure DevOps",
6
6
  "license": "MIT",