@azure-devops/mcp 1.3.1-nightly.20250810 → 1.3.1-nightly.20250812

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
@@ -16,7 +16,7 @@ This TypeScript project provides a **local** MCP server for Azure DevOps, enabli
16
16
  3. [⚙️ Supported Tools](#️-supported-tools)
17
17
  4. [🔌 Installation & Getting Started](#-installation--getting-started)
18
18
  5. [📝 Troubleshooting](#-troubleshooting)
19
- 6. [🎩 Examples & Best Practices](#-samples--best-practices)
19
+ 6. [🎩 Examples & Best Practices](#-examples--best-practices)
20
20
  7. [🙋‍♀️ Frequently Asked Questions](#️-frequently-asked-questions)
21
21
  8. [📌 Contributing](#-contributing)
22
22
 
@@ -198,13 +198,13 @@ In your project, add a `.vscode\mcp.json` file with the following content:
198
198
 
199
199
  Save the file, then click 'Start'.
200
200
 
201
- <img src="./docs/media/start-mcp-server.gif" alt="start mcp server" width="250"/>
201
+ ![start mcp server](./docs/media/start-mcp-server.gif)
202
202
 
203
203
  In chat, switch to [Agent Mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode).
204
204
 
205
205
  Click "Select Tools" and choose the available tools.
206
206
 
207
- <img src="./docs/media/configure-mcp-server-tools.gif" alt="configure mcp server tools" width="300"/>
207
+ ![configure mcp server tools](./docs/media/configure-mcp-server-tools.gif)
208
208
 
209
209
  Open GitHub Copilot Chat and try a prompt like `List ADO projects`.
210
210
 
@@ -23,6 +23,7 @@ const WORKITEM_TOOLS = {
23
23
  update_work_items_batch: "wit_update_work_items_batch",
24
24
  work_items_link: "wit_work_items_link",
25
25
  work_item_unlink: "wit_work_item_unlink",
26
+ add_artifact_link: "wit_add_artifact_link",
26
27
  };
27
28
  function getLinkTypeFromName(name) {
28
29
  switch (name.toLowerCase()) {
@@ -129,7 +130,7 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
129
130
  .enum(["all", "fields", "links", "none", "relations"])
130
131
  .describe("Optional expand parameter to include additional details in the response.")
131
132
  .optional()
132
- .describe("Expand options include 'all', 'fields', 'links', 'none', and 'relations'. Defaults to 'none'."),
133
+ .describe("Expand options include 'all', 'fields', 'links', 'none', and 'relations'. Relations can be used to get child workitems. Defaults to 'none'."),
133
134
  }, async ({ id, project, fields, asOf, expand }) => {
134
135
  const connection = await connectionProvider();
135
136
  const workItemApi = await connection.getWorkItemTrackingApi();
@@ -658,5 +659,137 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
658
659
  };
659
660
  }
660
661
  });
662
+ server.tool(WORKITEM_TOOLS.add_artifact_link, "Add artifact links (repository, branch, commit, builds) to work items. You can either provide the full vstfs URI or the individual components to build it automatically.", {
663
+ workItemId: z.number().describe("The ID of the work item to add the artifact link to."),
664
+ project: z.string().describe("The name or ID of the Azure DevOps project."),
665
+ // Option 1: Provide full URI directly
666
+ artifactUri: z.string().optional().describe("The complete VSTFS URI of the artifact to link. If provided, individual component parameters are ignored."),
667
+ // Option 2: Provide individual components to build URI automatically based on linkType
668
+ projectId: z.string().optional().describe("The project ID (GUID) containing the artifact. Required for Git artifacts when artifactUri is not provided."),
669
+ repositoryId: z.string().optional().describe("The repository ID (GUID) containing the artifact. Required for Git artifacts when artifactUri is not provided."),
670
+ branchName: z.string().optional().describe("The branch name (e.g., 'main'). Required when linkType is 'Branch'."),
671
+ commitId: z.string().optional().describe("The commit SHA hash. Required when linkType is 'Fixed in Commit'."),
672
+ pullRequestId: z.number().optional().describe("The pull request ID. Required when linkType is 'Pull Request'."),
673
+ buildId: z.number().optional().describe("The build ID. Required when linkType is 'Build', 'Found in build', or 'Integrated in build'."),
674
+ linkType: z
675
+ .enum([
676
+ "Branch",
677
+ "Build",
678
+ "Fixed in Changeset",
679
+ "Fixed in Commit",
680
+ "Found in build",
681
+ "Integrated in build",
682
+ "Model Link",
683
+ "Pull Request",
684
+ "Related Workitem",
685
+ "Result Attachment",
686
+ "Source Code File",
687
+ "Tag",
688
+ "Test Result",
689
+ "Wiki",
690
+ ])
691
+ .default("Branch")
692
+ .describe("Type of artifact link, defaults to 'Branch'. This determines both the link type and how to build the VSTFS URI from individual components."),
693
+ comment: z.string().optional().describe("Comment to include with the artifact link."),
694
+ }, async ({ workItemId, project, artifactUri, projectId, repositoryId, branchName, commitId, pullRequestId, buildId, linkType, comment }) => {
695
+ try {
696
+ const connection = await connectionProvider();
697
+ const workItemTrackingApi = await connection.getWorkItemTrackingApi();
698
+ let finalArtifactUri;
699
+ if (artifactUri) {
700
+ // Use the provided full URI
701
+ finalArtifactUri = artifactUri;
702
+ }
703
+ else {
704
+ // Build the URI from individual components based on linkType
705
+ switch (linkType) {
706
+ case "Branch":
707
+ if (!projectId || !repositoryId || !branchName) {
708
+ return {
709
+ content: [{ type: "text", text: "For 'Branch' links, 'projectId', 'repositoryId', and 'branchName' are required." }],
710
+ isError: true,
711
+ };
712
+ }
713
+ finalArtifactUri = `vstfs:///Git/Ref/${encodeURIComponent(projectId)}%2F${encodeURIComponent(repositoryId)}%2FGB${encodeURIComponent(branchName)}`;
714
+ break;
715
+ case "Fixed in Commit":
716
+ if (!projectId || !repositoryId || !commitId) {
717
+ return {
718
+ content: [{ type: "text", text: "For 'Fixed in Commit' links, 'projectId', 'repositoryId', and 'commitId' are required." }],
719
+ isError: true,
720
+ };
721
+ }
722
+ finalArtifactUri = `vstfs:///Git/Commit/${encodeURIComponent(projectId)}%2F${encodeURIComponent(repositoryId)}%2F${encodeURIComponent(commitId)}`;
723
+ break;
724
+ case "Pull Request":
725
+ if (!projectId || !repositoryId || pullRequestId === undefined) {
726
+ return {
727
+ content: [{ type: "text", text: "For 'Pull Request' links, 'projectId', 'repositoryId', and 'pullRequestId' are required." }],
728
+ isError: true,
729
+ };
730
+ }
731
+ finalArtifactUri = `vstfs:///Git/PullRequestId/${encodeURIComponent(projectId)}%2F${encodeURIComponent(repositoryId)}%2F${encodeURIComponent(pullRequestId.toString())}`;
732
+ break;
733
+ case "Build":
734
+ case "Found in build":
735
+ case "Integrated in build":
736
+ if (buildId === undefined) {
737
+ return {
738
+ content: [{ type: "text", text: `For '${linkType}' links, 'buildId' is required.` }],
739
+ isError: true,
740
+ };
741
+ }
742
+ finalArtifactUri = `vstfs:///Build/Build/${encodeURIComponent(buildId.toString())}`;
743
+ break;
744
+ default:
745
+ return {
746
+ content: [{ type: "text", text: `URI building from components is not supported for link type '${linkType}'. Please provide the full 'artifactUri' instead.` }],
747
+ isError: true,
748
+ };
749
+ }
750
+ }
751
+ // Create the patch document for adding an artifact link relation
752
+ const patchDocument = [
753
+ {
754
+ op: "add",
755
+ path: "/relations/-",
756
+ value: {
757
+ rel: "ArtifactLink",
758
+ url: finalArtifactUri,
759
+ attributes: {
760
+ name: linkType,
761
+ ...(comment && { comment }),
762
+ },
763
+ },
764
+ },
765
+ ];
766
+ // Use the WorkItem API to update the work item with the new relation
767
+ const workItem = await workItemTrackingApi.updateWorkItem({}, patchDocument, workItemId, project);
768
+ if (!workItem) {
769
+ return { content: [{ type: "text", text: "Work item update failed" }], isError: true };
770
+ }
771
+ return {
772
+ content: [
773
+ {
774
+ type: "text",
775
+ text: JSON.stringify({
776
+ workItemId,
777
+ artifactUri: finalArtifactUri,
778
+ linkType,
779
+ comment: comment || null,
780
+ success: true,
781
+ }, null, 2),
782
+ },
783
+ ],
784
+ };
785
+ }
786
+ catch (error) {
787
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
788
+ return {
789
+ content: [{ type: "text", text: `Error adding artifact link to work item: ${errorMessage}` }],
790
+ isError: true,
791
+ };
792
+ }
793
+ });
661
794
  }
662
795
  export { WORKITEM_TOOLS, configureWorkItemTools };
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const packageVersion = "1.3.1-nightly.20250810";
1
+ export const packageVersion = "1.3.1-nightly.20250812";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-devops/mcp",
3
- "version": "1.3.1-nightly.20250810",
3
+ "version": "1.3.1-nightly.20250812",
4
4
  "description": "MCP server for interacting with Azure DevOps",
5
5
  "license": "MIT",
6
6
  "author": "Microsoft Corporation",