@azure-devops/mcp 2.5.0-nightly.20260414 → 2.5.0-nightly.20260415

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/dist/auth.js CHANGED
@@ -71,6 +71,19 @@ class OAuthAuthenticator {
71
71
  function createAuthenticator(type, tenantId) {
72
72
  logger.debug(`Creating authenticator of type '${type}' with tenantId='${tenantId ?? "undefined"}'`);
73
73
  switch (type) {
74
+ case "pat":
75
+ logger.debug(`Authenticator: Using PAT authentication (PERSONAL_ACCESS_TOKEN)`);
76
+ return async () => {
77
+ logger.debug(`${type}: Reading token from PERSONAL_ACCESS_TOKEN environment variable`);
78
+ const b64Pat = process.env["PERSONAL_ACCESS_TOKEN"];
79
+ if (!b64Pat) {
80
+ logger.error(`${type}: PERSONAL_ACCESS_TOKEN environment variable is not set or empty`);
81
+ throw new Error("Environment variable 'PERSONAL_ACCESS_TOKEN' is not set or empty. Please set it with a valid base64-encoded Azure DevOps Personal Access Token.");
82
+ }
83
+ // Return base64 value as-is — caller uses it directly as the Basic auth credential
84
+ logger.debug(`${type}: Successfully retrieved PAT from environment variable`);
85
+ return b64Pat;
86
+ };
74
87
  case "envvar":
75
88
  logger.debug(`Authenticator: Using environment variable authentication (ADO_MCP_AUTH_TOKEN)`);
76
89
  // Read token from fixed environment variable
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // Licensed under the MIT License.
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
- import { getBearerHandler, WebApi } from "azure-devops-node-api";
6
+ import { getBearerHandler, getPersonalAccessTokenHandler, WebApi } from "azure-devops-node-api";
7
7
  import yargs from "yargs";
8
8
  import { hideBin } from "yargs/helpers";
9
9
  import { createAuthenticator } from "./auth.js";
@@ -41,7 +41,7 @@ const argv = yargs(hideBin(process.argv))
41
41
  alias: "a",
42
42
  describe: "Type of authentication to use",
43
43
  type: "string",
44
- choices: ["interactive", "azcli", "env", "envvar"],
44
+ choices: ["interactive", "azcli", "env", "envvar", "pat"],
45
45
  default: defaultAuthenticationType,
46
46
  })
47
47
  .option("tenant", {
@@ -55,10 +55,12 @@ export const orgName = argv.organization;
55
55
  const orgUrl = "https://dev.azure.com/" + orgName;
56
56
  const domainsManager = new DomainsManager(argv.domains);
57
57
  export const enabledDomains = domainsManager.getEnabledDomains();
58
- function getAzureDevOpsClient(getAzureDevOpsToken, userAgentComposer) {
58
+ function getAzureDevOpsClient(getAzureDevOpsToken, userAgentComposer, authType) {
59
59
  return async () => {
60
60
  const accessToken = await getAzureDevOpsToken();
61
- const authHandler = getBearerHandler(accessToken);
61
+ // For pat, accessToken is base64("{email}:{token}"). Decode to extract the token part,
62
+ // since getPersonalAccessTokenHandler prepends ":" internally and just needs the raw token.
63
+ const authHandler = authType === "pat" ? getPersonalAccessTokenHandler(Buffer.from(accessToken, "base64").toString("utf8").split(":").slice(1).join(":")) : getBearerHandler(accessToken);
62
64
  const connection = new WebApi(orgUrl, authHandler, undefined, {
63
65
  productName: "AzureDevOps.MCP",
64
66
  productVersion: packageVersion,
@@ -93,9 +95,25 @@ async function main() {
93
95
  };
94
96
  const tenantId = (await getOrgTenant(orgName)) ?? argv.tenant;
95
97
  const authenticator = createAuthenticator(argv.authentication, tenantId);
98
+ if (argv.authentication === "pat") {
99
+ const basicValue = await authenticator();
100
+ // basicValue is already base64("{email}:{token}") — use it directly in the Authorization header
101
+ const _originalFetch = globalThis.fetch;
102
+ globalThis.fetch = async (input, init) => {
103
+ if (init?.headers) {
104
+ const headers = new Headers(init.headers);
105
+ if (headers.get("Authorization")?.startsWith("Bearer ")) {
106
+ headers.set("Authorization", `Basic ${basicValue}`);
107
+ init = { ...init, headers };
108
+ }
109
+ }
110
+ return _originalFetch(input, init);
111
+ };
112
+ logger.debug("PAT mode: global fetch interceptor installed to rewrite Bearer -> Basic auth headers");
113
+ }
96
114
  // removing prompts untill further notice
97
115
  // configurePrompts(server);
98
- configureAllTools(server, authenticator, getAzureDevOpsClient(authenticator, userAgentComposer), () => userAgentComposer.userAgent, enabledDomains);
116
+ configureAllTools(server, authenticator, getAzureDevOpsClient(authenticator, userAgentComposer, argv.authentication), () => userAgentComposer.userAgent, enabledDomains);
99
117
  const transport = new StdioServerTransport();
100
118
  await server.connect(transport);
101
119
  }
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const packageVersion = "2.5.0-nightly.20260414";
1
+ export const packageVersion = "2.5.0-nightly.20260415";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-devops/mcp",
3
- "version": "2.5.0-nightly.20260414",
3
+ "version": "2.5.0-nightly.20260415",
4
4
  "mcpName": "microsoft.com/azure-devops",
5
5
  "description": "MCP server for interacting with Azure DevOps",
6
6
  "license": "MIT",
@@ -59,7 +59,7 @@
59
59
  "jest": "^30.0.2",
60
60
  "jest-extended": "^7.0.0",
61
61
  "lint-staged": "^16.2.7",
62
- "prettier": "3.8.2",
62
+ "prettier": "3.8.3",
63
63
  "shx": "^0.4.0",
64
64
  "ts-jest": "^29.4.6",
65
65
  "tsconfig-paths": "^4.2.0",