@azure-devops/mcp 2.1.0-nightly.20250921 → 2.2.0-nightly.20250923

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
@@ -152,16 +152,7 @@ For the best experience, use Visual Studio Code and GitHub Copilot. See the [get
152
152
 
153
153
  1. Install [VS Code](https://code.visualstudio.com/download) or [VS Code Insiders](https://code.visualstudio.com/insiders)
154
154
  2. Install [Node.js](https://nodejs.org/en/download) 20+
155
- 3. Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
156
- 4. Open VS Code in an empty folder
157
-
158
- ### Azure Login
159
-
160
- Ensure you are logged in to Azure DevOps via the Azure CLI:
161
-
162
- ```sh
163
- az login
164
- ```
155
+ 3. Open VS Code in an empty folder
165
156
 
166
157
  ### Installation
167
158
 
@@ -232,7 +223,7 @@ Click "Select Tools" and choose the available tools.
232
223
 
233
224
  ![configure mcp server tools](./docs/media/configure-mcp-server-tools.gif)
234
225
 
235
- Open GitHub Copilot Chat and try a prompt like `List ADO projects`.
226
+ Open GitHub Copilot Chat and try a prompt like `List ADO projects`. The first time an ADO tool is executed browser will open prompting to login with your Microsoft account. Please ensure you are using credentials matching selected Azure DevOps organization.
236
227
 
237
228
  > 💥 We strongly recommend creating a `.github\copilot-instructions.md` in your project. This will enhance your experience using the Azure DevOps MCP Server with GitHub Copilot Chat.
238
229
  > To start, just include "`This project uses Azure DevOps. Always check to see if the Azure DevOps MCP server has a tool relevant to the user's request`" in your copilot instructions file.
package/dist/auth.js ADDED
@@ -0,0 +1,74 @@
1
+ import { AzureCliCredential, ChainedTokenCredential, DefaultAzureCredential } from "@azure/identity";
2
+ import { PublicClientApplication } from "@azure/msal-node";
3
+ import open from "open";
4
+ const scopes = ["499b84ac-1321-427f-aa17-267ca6975798/.default"];
5
+ class OAuthAuthenticator {
6
+ static clientId = "0d50963b-7bb9-4fe7-94c7-a99af00b5136";
7
+ static defaultAuthority = "https://login.microsoftonline.com/common";
8
+ accountId;
9
+ publicClientApp;
10
+ constructor(tenantId) {
11
+ this.accountId = null;
12
+ this.publicClientApp = new PublicClientApplication({
13
+ auth: {
14
+ clientId: OAuthAuthenticator.clientId,
15
+ authority: tenantId ? `https://login.microsoftonline.com/${tenantId}` : OAuthAuthenticator.defaultAuthority,
16
+ },
17
+ });
18
+ }
19
+ async getToken() {
20
+ let authResult = null;
21
+ if (this.accountId) {
22
+ try {
23
+ authResult = await this.publicClientApp.acquireTokenSilent({
24
+ scopes,
25
+ account: this.accountId,
26
+ });
27
+ }
28
+ catch (error) {
29
+ authResult = null;
30
+ }
31
+ }
32
+ if (!authResult) {
33
+ authResult = await this.publicClientApp.acquireTokenInteractive({
34
+ scopes,
35
+ openBrowser: async (url) => {
36
+ open(url);
37
+ },
38
+ });
39
+ this.accountId = authResult.account;
40
+ }
41
+ if (!authResult.accessToken) {
42
+ throw new Error("Failed to obtain Azure DevOps OAuth token.");
43
+ }
44
+ return authResult.accessToken;
45
+ }
46
+ }
47
+ function createAuthenticator(type, tenantId) {
48
+ switch (type) {
49
+ case "azcli":
50
+ case "env":
51
+ if (type !== "env") {
52
+ process.env.AZURE_TOKEN_CREDENTIALS = "dev";
53
+ }
54
+ let credential = new DefaultAzureCredential(); // CodeQL [SM05138] resolved by explicitly setting AZURE_TOKEN_CREDENTIALS
55
+ if (tenantId) {
56
+ // Use Azure CLI credential if tenantId is provided for multi-tenant scenarios
57
+ const azureCliCredential = new AzureCliCredential({ tenantId });
58
+ credential = new ChainedTokenCredential(azureCliCredential, credential);
59
+ }
60
+ return async () => {
61
+ const result = await credential.getToken(scopes);
62
+ if (!result) {
63
+ throw new Error("Failed to obtain Azure DevOps token. Ensure you have Azure CLI logged or use interactive type of authentication.");
64
+ }
65
+ return result.token;
66
+ };
67
+ default:
68
+ const authenticator = new OAuthAuthenticator(tenantId);
69
+ return () => {
70
+ return authenticator.getToken();
71
+ };
72
+ }
73
+ }
74
+ export { createAuthenticator };
package/dist/index.js CHANGED
@@ -4,14 +4,19 @@
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
6
  import * as azdev from "azure-devops-node-api";
7
- import { AzureCliCredential, ChainedTokenCredential, DefaultAzureCredential } from "@azure/identity";
8
7
  import yargs from "yargs";
9
8
  import { hideBin } from "yargs/helpers";
9
+ import { createAuthenticator } from "./auth.js";
10
+ import { getOrgTenant } from "./org-tenants.js";
10
11
  import { configurePrompts } from "./prompts.js";
11
12
  import { configureAllTools } from "./tools.js";
12
13
  import { UserAgentComposer } from "./useragent.js";
13
14
  import { packageVersion } from "./version.js";
14
15
  import { DomainsManager } from "./shared/domains.js";
16
+ function isGitHubCodespaceEnv() {
17
+ return process.env.CODESPACES === "true" && !!process.env.CODESPACE_NAME;
18
+ }
19
+ const defaultAuthenticationType = isGitHubCodespaceEnv() ? "azcli" : "interactive";
15
20
  // Parse command line arguments using yargs
16
21
  const argv = yargs(hideBin(process.argv))
17
22
  .scriptName("mcp-server-azuredevops")
@@ -30,42 +35,29 @@ const argv = yargs(hideBin(process.argv))
30
35
  type: "string",
31
36
  array: true,
32
37
  default: "all",
38
+ })
39
+ .option("authentication", {
40
+ alias: "a",
41
+ describe: "Type of authentication to use. Supported values are 'interactive', 'azcli' and 'env' (default: 'interactive')",
42
+ type: "string",
43
+ choices: ["interactive", "azcli", "env"],
44
+ default: defaultAuthenticationType,
33
45
  })
34
46
  .option("tenant", {
35
47
  alias: "t",
36
- describe: "Azure tenant ID (optional, required for multi-tenant scenarios)",
48
+ describe: "Azure tenant ID (optional, applied when using 'interactive' and 'azcli' type of authentication)",
37
49
  type: "string",
38
50
  })
39
51
  .help()
40
52
  .parseSync();
41
- const tenantId = argv.tenant;
42
53
  export const orgName = argv.organization;
43
54
  const orgUrl = "https://dev.azure.com/" + orgName;
44
55
  const domainsManager = new DomainsManager(argv.domains);
45
56
  export const enabledDomains = domainsManager.getEnabledDomains();
46
- async function getAzureDevOpsToken() {
47
- if (process.env.ADO_MCP_AZURE_TOKEN_CREDENTIALS) {
48
- process.env.AZURE_TOKEN_CREDENTIALS = process.env.ADO_MCP_AZURE_TOKEN_CREDENTIALS;
49
- }
50
- else {
51
- process.env.AZURE_TOKEN_CREDENTIALS = "dev";
52
- }
53
- let credential = new DefaultAzureCredential(); // CodeQL [SM05138] resolved by explicitly setting AZURE_TOKEN_CREDENTIALS
54
- if (tenantId) {
55
- // Use Azure CLI credential if tenantId is provided for multi-tenant scenarios
56
- const azureCliCredential = new AzureCliCredential({ tenantId });
57
- credential = new ChainedTokenCredential(azureCliCredential, credential);
58
- }
59
- const token = await credential.getToken("499b84ac-1321-427f-aa17-267ca6975798/.default");
60
- if (!token) {
61
- throw new Error("Failed to obtain Azure DevOps token. Ensure you have Azure CLI logged in or another token source setup correctly.");
62
- }
63
- return token;
64
- }
65
- function getAzureDevOpsClient(userAgentComposer) {
57
+ function getAzureDevOpsClient(getAzureDevOpsToken, userAgentComposer) {
66
58
  return async () => {
67
- const token = await getAzureDevOpsToken();
68
- const authHandler = azdev.getBearerHandler(token.token);
59
+ const accessToken = await getAzureDevOpsToken();
60
+ const authHandler = azdev.getBearerHandler(accessToken);
69
61
  const connection = new azdev.WebApi(orgUrl, authHandler, undefined, {
70
62
  productName: "AzureDevOps.MCP",
71
63
  productVersion: packageVersion,
@@ -83,8 +75,10 @@ async function main() {
83
75
  server.server.oninitialized = () => {
84
76
  userAgentComposer.appendMcpClientInfo(server.server.getClientVersion());
85
77
  };
78
+ const tenantId = (await getOrgTenant(orgName)) ?? argv.tenant;
79
+ const authenticator = createAuthenticator(argv.authentication, tenantId);
86
80
  configurePrompts(server);
87
- configureAllTools(server, getAzureDevOpsToken, getAzureDevOpsClient(userAgentComposer), () => userAgentComposer.userAgent, enabledDomains);
81
+ configureAllTools(server, authenticator, getAzureDevOpsClient(authenticator, userAgentComposer), () => userAgentComposer.userAgent, enabledDomains);
88
82
  const transport = new StdioServerTransport();
89
83
  await server.connect(transport);
90
84
  }
@@ -0,0 +1,73 @@
1
+ import * as fs from "fs/promises";
2
+ import * as os from "os";
3
+ import * as path from "path";
4
+ const CACHE_FILE = path.join(os.homedir(), ".ado_orgs.cache");
5
+ const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 1 week in milliseconds
6
+ async function loadCache() {
7
+ try {
8
+ const cacheData = await fs.readFile(CACHE_FILE, "utf-8");
9
+ return JSON.parse(cacheData);
10
+ }
11
+ catch (error) {
12
+ // Cache file doesn't exist or is invalid, return empty cache
13
+ return {};
14
+ }
15
+ }
16
+ async function trySavingCache(cache) {
17
+ try {
18
+ await fs.writeFile(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
19
+ }
20
+ catch (error) {
21
+ console.error("Failed to save org tenants cache:", error);
22
+ }
23
+ }
24
+ async function fetchTenantFromApi(orgName) {
25
+ const url = `https://vssps.dev.azure.com/${orgName}`;
26
+ try {
27
+ const response = await fetch(url, { method: "HEAD" });
28
+ if (response.status !== 404) {
29
+ throw new Error(`Expected status 404, got ${response.status}`);
30
+ }
31
+ const tenantId = response.headers.get("x-vss-resourcetenant");
32
+ if (!tenantId) {
33
+ throw new Error("x-vss-resourcetenant header not found in response");
34
+ }
35
+ return tenantId;
36
+ }
37
+ catch (error) {
38
+ throw new Error(`Failed to fetch tenant for organization ${orgName}: ${error}`);
39
+ }
40
+ }
41
+ function isCacheEntryExpired(entry) {
42
+ return Date.now() - entry.refreshedOn > CACHE_TTL_MS;
43
+ }
44
+ export async function getOrgTenant(orgName) {
45
+ // Load cache
46
+ const cache = await loadCache();
47
+ // Check if tenant is cached and not expired
48
+ const cachedEntry = cache[orgName];
49
+ if (cachedEntry && !isCacheEntryExpired(cachedEntry)) {
50
+ return cachedEntry.tenantId;
51
+ }
52
+ // Try to fetch fresh tenant from API
53
+ try {
54
+ const tenantId = await fetchTenantFromApi(orgName);
55
+ // Cache the result
56
+ cache[orgName] = {
57
+ tenantId,
58
+ refreshedOn: Date.now(),
59
+ };
60
+ await trySavingCache(cache);
61
+ return tenantId;
62
+ }
63
+ catch (error) {
64
+ // If we have an expired cache entry, return it as fallback
65
+ if (cachedEntry) {
66
+ console.error(`Failed to fetch fresh tenant for ADO org ${orgName}, using expired cache entry:`, error);
67
+ return cachedEntry.tenantId;
68
+ }
69
+ // No cache entry available, log and return empty result
70
+ console.error(`Failed to fetch tenant for ADO org ${orgName}:`, error);
71
+ return undefined;
72
+ }
73
+ }
@@ -106,12 +106,19 @@ export class DomainsManager {
106
106
  * @returns Normalized array of domain strings
107
107
  */
108
108
  static parseDomainsInput(domainsInput) {
109
- if (!domainsInput) {
110
- return [];
109
+ if (!domainsInput || this.isEmptyDomainsInput(domainsInput)) {
110
+ return ["all"];
111
111
  }
112
112
  if (typeof domainsInput === "string") {
113
113
  return domainsInput.split(",").map((d) => d.trim().toLowerCase());
114
114
  }
115
115
  return domainsInput.map((d) => d.trim().toLowerCase());
116
116
  }
117
+ static isEmptyDomainsInput(domainsInput) {
118
+ if (typeof domainsInput === "string" && domainsInput.trim() === "")
119
+ return true;
120
+ if (Array.isArray(domainsInput) && domainsInput.length === 0)
121
+ return true;
122
+ return false;
123
+ }
117
124
  }
@@ -7,7 +7,7 @@ const ADVSEC_TOOLS = {
7
7
  get_alerts: "advsec_get_alerts",
8
8
  get_alert_details: "advsec_get_alert_details",
9
9
  };
10
- function configureAdvSecTools(server, tokenProvider, connectionProvider) {
10
+ function configureAdvSecTools(server, _, connectionProvider) {
11
11
  server.tool(ADVSEC_TOOLS.get_alerts, "Retrieve Advanced Security alerts for a repository.", {
12
12
  project: z.string().describe("The name or ID of the Azure DevOps project."),
13
13
  repository: z.string().describe("The name or ID of the repository to get alerts for."),
@@ -4,7 +4,7 @@ import { apiVersion } from "../utils.js";
4
4
  async function getCurrentUserDetails(tokenProvider, connectionProvider, userAgentProvider) {
5
5
  const connection = await connectionProvider();
6
6
  const url = `${connection.serverUrl}/_apis/connectionData`;
7
- const token = (await tokenProvider()).token;
7
+ const token = await tokenProvider();
8
8
  const response = await fetch(url, {
9
9
  method: "GET",
10
10
  headers: {
@@ -34,7 +34,7 @@ async function searchIdentities(identity, tokenProvider, connectionProvider, use
34
34
  });
35
35
  const response = await fetch(`${baseUrl}?${params}`, {
36
36
  headers: {
37
- "Authorization": `Bearer ${token.token}`,
37
+ "Authorization": `Bearer ${token}`,
38
38
  "Content-Type": "application/json",
39
39
  "User-Agent": userAgentProvider(),
40
40
  },
@@ -65,7 +65,7 @@ function configureCoreTools(server, tokenProvider, connectionProvider, userAgent
65
65
  }
66
66
  });
67
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."),
68
+ searchFilter: z.string().describe("Search filter (unique name, display name, email) to retrieve identity IDs for."),
69
69
  }, async ({ searchFilter }) => {
70
70
  try {
71
71
  const identities = await searchIdentities(searchFilter, tokenProvider, connectionProvider, userAgentProvider);
@@ -253,7 +253,7 @@ function configurePipelineTools(server, tokenProvider, connectionProvider, userA
253
253
  method: "PATCH",
254
254
  headers: {
255
255
  "Content-Type": "application/json",
256
- "Authorization": `Bearer ${token.token}`,
256
+ "Authorization": `Bearer ${token}`,
257
257
  "User-Agent": userAgentProvider(),
258
258
  },
259
259
  body: JSON.stringify(body),
@@ -45,7 +45,7 @@ function configureSearchTools(server, tokenProvider, connectionProvider, userAge
45
45
  method: "POST",
46
46
  headers: {
47
47
  "Content-Type": "application/json",
48
- "Authorization": `Bearer ${accessToken.token}`,
48
+ "Authorization": `Bearer ${accessToken}`,
49
49
  "User-Agent": userAgentProvider(),
50
50
  },
51
51
  body: JSON.stringify(requestBody),
@@ -89,7 +89,7 @@ function configureSearchTools(server, tokenProvider, connectionProvider, userAge
89
89
  method: "POST",
90
90
  headers: {
91
91
  "Content-Type": "application/json",
92
- "Authorization": `Bearer ${accessToken.token}`,
92
+ "Authorization": `Bearer ${accessToken}`,
93
93
  "User-Agent": userAgentProvider(),
94
94
  },
95
95
  body: JSON.stringify(requestBody),
@@ -139,7 +139,7 @@ function configureSearchTools(server, tokenProvider, connectionProvider, userAge
139
139
  method: "POST",
140
140
  headers: {
141
141
  "Content-Type": "application/json",
142
- "Authorization": `Bearer ${accessToken.token}`,
142
+ "Authorization": `Bearer ${accessToken}`,
143
143
  "User-Agent": userAgentProvider(),
144
144
  },
145
145
  body: JSON.stringify(requestBody),
@@ -9,7 +9,7 @@ const Test_Plan_Tools = {
9
9
  list_test_cases: "testplan_list_test_cases",
10
10
  list_test_plans: "testplan_list_test_plans",
11
11
  };
12
- function configureTestPlanTools(server, tokenProvider, connectionProvider) {
12
+ function configureTestPlanTools(server, _, connectionProvider) {
13
13
  /*
14
14
  LIST OF TEST PLANS
15
15
  get list of test plans by project
@@ -8,7 +8,7 @@ const WIKI_TOOLS = {
8
8
  get_wiki_page_content: "wiki_get_page_content",
9
9
  create_or_update_page: "wiki_create_or_update_page",
10
10
  };
11
- function configureWikiTools(server, tokenProvider, connectionProvider) {
11
+ function configureWikiTools(server, tokenProvider, connectionProvider, userAgentProvider) {
12
12
  server.tool(WIKI_TOOLS.get_wiki, "Get the wiki by wikiIdentifier", {
13
13
  wikiIdentifier: z.string().describe("The unique identifier of the wiki."),
14
14
  project: z.string().optional().describe("The project name or ID where the wiki is located. If not provided, the default project will be used."),
@@ -121,15 +121,14 @@ function configureWikiTools(server, tokenProvider, connectionProvider) {
121
121
  }
122
122
  if (parsed.pageId) {
123
123
  try {
124
- let accessToken;
125
- try {
126
- accessToken = await tokenProvider();
127
- }
128
- catch { }
124
+ const accessToken = await tokenProvider();
129
125
  const baseUrl = connection.serverUrl.replace(/\/$/, "");
130
126
  const restUrl = `${baseUrl}/${resolvedProject}/_apis/wiki/wikis/${resolvedWiki}/pages/${parsed.pageId}?includeContent=true&api-version=7.1`;
131
127
  const resp = await fetch(restUrl, {
132
- headers: accessToken?.token ? { Authorization: `Bearer ${accessToken.token}` } : {},
128
+ headers: {
129
+ "Authorization": `Bearer ${accessToken}`,
130
+ "User-Agent": userAgentProvider(),
131
+ },
133
132
  });
134
133
  if (resp.ok) {
135
134
  const json = await resp.json();
@@ -193,8 +192,9 @@ function configureWikiTools(server, tokenProvider, connectionProvider) {
193
192
  const createResponse = await fetch(url, {
194
193
  method: "PUT",
195
194
  headers: {
196
- "Authorization": `Bearer ${accessToken.token}`,
195
+ "Authorization": `Bearer ${accessToken}`,
197
196
  "Content-Type": "application/json",
197
+ "User-Agent": userAgentProvider(),
198
198
  },
199
199
  body: JSON.stringify({ content: content }),
200
200
  });
@@ -218,7 +218,8 @@ function configureWikiTools(server, tokenProvider, connectionProvider) {
218
218
  const getResponse = await fetch(url, {
219
219
  method: "GET",
220
220
  headers: {
221
- Authorization: `Bearer ${accessToken.token}`,
221
+ "Authorization": `Bearer ${accessToken}`,
222
+ "User-Agent": userAgentProvider(),
222
223
  },
223
224
  });
224
225
  if (getResponse.ok) {
@@ -236,8 +237,9 @@ function configureWikiTools(server, tokenProvider, connectionProvider) {
236
237
  const updateResponse = await fetch(url, {
237
238
  method: "PUT",
238
239
  headers: {
239
- "Authorization": `Bearer ${accessToken.token}`,
240
+ "Authorization": `Bearer ${accessToken}`,
240
241
  "Content-Type": "application/json",
242
+ "User-Agent": userAgentProvider(),
241
243
  "If-Match": currentEtag,
242
244
  },
243
245
  body: JSON.stringify({ content: content }),
@@ -181,7 +181,7 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
181
181
  const response = await fetch(`${orgUrl}/${project}/_apis/wit/workItems/${workItemId}/comments?format=${formatParameter}&api-version=${markdownCommentsApiVersion}`, {
182
182
  method: "POST",
183
183
  headers: {
184
- "Authorization": `Bearer ${accessToken.token}`,
184
+ "Authorization": `Bearer ${accessToken}`,
185
185
  "Content-Type": "application/json",
186
186
  "User-Agent": userAgentProvider(),
187
187
  },
@@ -287,7 +287,7 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
287
287
  const response = await fetch(`${orgUrl}/_apis/wit/$batch?api-version=${batchApiVersion}`, {
288
288
  method: "PATCH",
289
289
  headers: {
290
- "Authorization": `Bearer ${accessToken.token}`,
290
+ "Authorization": `Bearer ${accessToken}`,
291
291
  "Content-Type": "application/json",
292
292
  "User-Agent": userAgentProvider(),
293
293
  },
@@ -540,7 +540,7 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
540
540
  const response = await fetch(`${orgUrl}/_apis/wit/$batch?api-version=${batchApiVersion}`, {
541
541
  method: "PATCH",
542
542
  headers: {
543
- "Authorization": `Bearer ${accessToken.token}`,
543
+ "Authorization": `Bearer ${accessToken}`,
544
544
  "Content-Type": "application/json",
545
545
  "User-Agent": userAgentProvider(),
546
546
  },
@@ -596,7 +596,7 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
596
596
  const response = await fetch(`${orgUrl}/_apis/wit/$batch?api-version=${batchApiVersion}`, {
597
597
  method: "PATCH",
598
598
  headers: {
599
- "Authorization": `Bearer ${accessToken.token}`,
599
+ "Authorization": `Bearer ${accessToken}`,
600
600
  "Content-Type": "application/json",
601
601
  "User-Agent": userAgentProvider(),
602
602
  },
@@ -7,7 +7,7 @@ const WORK_TOOLS = {
7
7
  create_iterations: "work_create_iterations",
8
8
  assign_iterations: "work_assign_iterations",
9
9
  };
10
- function configureWorkTools(server, tokenProvider, connectionProvider) {
10
+ function configureWorkTools(server, _, connectionProvider) {
11
11
  server.tool(WORK_TOOLS.list_team_iterations, "Retrieve a list of iterations for a specific team in a project.", {
12
12
  project: z.string().describe("The name or ID of the Azure DevOps project."),
13
13
  team: z.string().describe("The name or ID of the Azure DevOps team."),
package/dist/tools.js CHANGED
@@ -21,7 +21,7 @@ function configureAllTools(server, tokenProvider, connectionProvider, userAgentP
21
21
  configureIfDomainEnabled(Domain.PIPELINES, () => configurePipelineTools(server, tokenProvider, connectionProvider, userAgentProvider));
22
22
  configureIfDomainEnabled(Domain.REPOSITORIES, () => configureRepoTools(server, tokenProvider, connectionProvider, userAgentProvider));
23
23
  configureIfDomainEnabled(Domain.WORK_ITEMS, () => configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider));
24
- configureIfDomainEnabled(Domain.WIKI, () => configureWikiTools(server, tokenProvider, connectionProvider));
24
+ configureIfDomainEnabled(Domain.WIKI, () => configureWikiTools(server, tokenProvider, connectionProvider, userAgentProvider));
25
25
  configureIfDomainEnabled(Domain.TEST_PLANS, () => configureTestPlanTools(server, tokenProvider, connectionProvider));
26
26
  configureIfDomainEnabled(Domain.SEARCH, () => configureSearchTools(server, tokenProvider, connectionProvider, userAgentProvider));
27
27
  configureIfDomainEnabled(Domain.ADVANCED_SECURITY, () => configureAdvSecTools(server, tokenProvider, connectionProvider));
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const packageVersion = "2.1.0-nightly.20250921";
1
+ export const packageVersion = "2.2.0-nightly.20250923";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-devops/mcp",
3
- "version": "2.1.0-nightly.20250921",
3
+ "version": "2.2.0-nightly.20250923",
4
4
  "description": "MCP server for interacting with Azure DevOps",
5
5
  "license": "MIT",
6
6
  "author": "Microsoft Corporation",