@sonyjv/azure-devops-mcp 2.9.0-onprem.1 → 2.9.0-onprem.2

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
@@ -2,7 +2,6 @@
2
2
  // Licensed under the MIT License.
3
3
  import { AzureCliCredential, ChainedTokenCredential, DefaultAzureCredential } from "@azure/identity";
4
4
  import { PublicClientApplication } from "@azure/msal-node";
5
- import { NativeBrokerPlugin } from "@azure/msal-node-extensions";
6
5
  import open from "open";
7
6
  import { logger } from "./logger.js";
8
7
  const scopes = ["499b84ac-1321-427f-aa17-267ca6975798/.default"];
@@ -52,78 +51,104 @@ class OAuthAuthenticator {
52
51
  static defaultAuthority = "https://login.microsoftonline.com/common";
53
52
  static zeroTenantId = "00000000-0000-0000-0000-000000000000";
54
53
  accountId;
55
- publicClientApp;
54
+ authority;
56
55
  publicClientAppFallback;
56
+ // undefined = not yet attempted; null = attempted and unavailable.
57
+ brokerClientApp;
57
58
  constructor(tenantId) {
58
59
  this.accountId = null;
59
- let authority = OAuthAuthenticator.defaultAuthority;
60
60
  if (tenantId && tenantId !== OAuthAuthenticator.zeroTenantId) {
61
- authority = `https://login.microsoftonline.com/${tenantId}`;
61
+ this.authority = `https://login.microsoftonline.com/${tenantId}`;
62
62
  logger.debug(`OAuthAuthenticator: Using tenant-specific authority for tenantId='${tenantId}'`);
63
63
  }
64
64
  else {
65
+ this.authority = OAuthAuthenticator.defaultAuthority;
65
66
  logger.debug(`OAuthAuthenticator: Using default common authority`);
66
67
  }
67
- this.publicClientApp = new PublicClientApplication({
68
- auth: {
69
- clientId: OAuthAuthenticator.clientId,
70
- authority,
71
- },
72
- broker: {
73
- nativeBrokerPlugin: new NativeBrokerPlugin(),
74
- },
75
- system: {
76
- loggerOptions: {
77
- loggerCallback: (level, message) => {
78
- logger.debug(`MSALClient[${level}]: ${message}`);
79
- },
80
- },
81
- },
82
- });
83
68
  this.publicClientAppFallback = new PublicClientApplication({
84
69
  auth: {
85
70
  clientId: OAuthAuthenticator.clientId,
86
- authority,
71
+ authority: this.authority,
87
72
  },
88
73
  });
89
74
  logger.debug(`OAuthAuthenticator: Initialized with clientId='${OAuthAuthenticator.clientId}'`);
90
75
  }
76
+ /**
77
+ * Lazily builds the broker-enabled MSAL client. @azure/msal-node-extensions (and its
78
+ * native keytar dependency) is an optional dependency: on a machine where that native
79
+ * binding failed to install — a missing prebuilt binary, a blocked/unapproved install
80
+ * script, no native build toolchain — this returns null instead of throwing, so every
81
+ * auth type keeps working via the always-available non-broker client below rather than
82
+ * every auth type (including 'pat') crashing at startup over an interactive-only feature.
83
+ */
84
+ async getBrokerClient() {
85
+ if (this.brokerClientApp !== undefined)
86
+ return this.brokerClientApp;
87
+ try {
88
+ const { NativeBrokerPlugin } = await import("@azure/msal-node-extensions");
89
+ this.brokerClientApp = new PublicClientApplication({
90
+ auth: {
91
+ clientId: OAuthAuthenticator.clientId,
92
+ authority: this.authority,
93
+ },
94
+ broker: {
95
+ nativeBrokerPlugin: new NativeBrokerPlugin(),
96
+ },
97
+ system: {
98
+ loggerOptions: {
99
+ loggerCallback: (level, message) => {
100
+ logger.debug(`MSALClient[${level}]: ${message}`);
101
+ },
102
+ },
103
+ },
104
+ });
105
+ logger.debug(`OAuthAuthenticator: Native broker plugin loaded successfully`);
106
+ }
107
+ catch (error) {
108
+ logger.debug(`OAuthAuthenticator: Native broker plugin unavailable, continuing without it: ${error instanceof Error ? error.message : String(error)}`);
109
+ this.brokerClientApp = null;
110
+ }
111
+ return this.brokerClientApp;
112
+ }
91
113
  async getToken() {
92
114
  let authResult = null;
93
- if (this.accountId) {
94
- logger.debug(`OAuthAuthenticator: Attempting silent token acquisition for cached account`);
95
- try {
96
- authResult = await this.publicClientApp.acquireTokenSilent({
97
- scopes,
98
- account: this.accountId,
99
- });
100
- logger.debug(`OAuthAuthenticator: Successfully acquired token silently`);
115
+ const brokerClient = await this.getBrokerClient();
116
+ if (brokerClient) {
117
+ if (this.accountId) {
118
+ logger.debug(`OAuthAuthenticator: Attempting silent token acquisition for cached account`);
119
+ try {
120
+ authResult = await brokerClient.acquireTokenSilent({
121
+ scopes,
122
+ account: this.accountId,
123
+ });
124
+ logger.debug(`OAuthAuthenticator: Successfully acquired token silently`);
125
+ }
126
+ catch (error) {
127
+ logger.debug(`OAuthAuthenticator: Silent token acquisition failed: ${error instanceof Error ? error.message : String(error)}`);
128
+ authResult = null;
129
+ }
101
130
  }
102
- catch (error) {
103
- logger.debug(`OAuthAuthenticator: Silent token acquisition failed: ${error instanceof Error ? error.message : String(error)}`);
104
- authResult = null;
131
+ else {
132
+ logger.debug(`OAuthAuthenticator: No cached account available, interactive auth required`);
105
133
  }
106
- }
107
- else {
108
- logger.debug(`OAuthAuthenticator: No cached account available, interactive auth required`);
109
- }
110
- if (!authResult) {
111
- logger.debug(`OAuthAuthenticator: Starting interactive token acquisition`);
112
- try {
113
- authResult = await this.publicClientApp.acquireTokenInteractive({
114
- scopes,
115
- openBrowser: async (url) => {
116
- logger.debug(`OAuthAuthenticator: Opening browser for authentication with target URL: ${url}`);
117
- open(url);
118
- },
119
- });
120
- this.accountId = authResult.account;
121
- logger.debug(`OAuthAuthenticator: Successfully acquired token interactively, account cached`);
122
- }
123
- catch (error) {
124
- const msalErrorMessage = error.platformBrokerError ? JSON.stringify(error.platformBrokerError) : "";
125
- logger.debug(`OAuthAuthenticator: Interactive token acquisition failed: ${error instanceof Error ? error.message + msalErrorMessage : String(error)}`);
126
- authResult = null;
134
+ if (!authResult) {
135
+ logger.debug(`OAuthAuthenticator: Starting interactive token acquisition`);
136
+ try {
137
+ authResult = await brokerClient.acquireTokenInteractive({
138
+ scopes,
139
+ openBrowser: async (url) => {
140
+ logger.debug(`OAuthAuthenticator: Opening browser for authentication with target URL: ${url}`);
141
+ open(url);
142
+ },
143
+ });
144
+ this.accountId = authResult.account;
145
+ logger.debug(`OAuthAuthenticator: Successfully acquired token interactively, account cached`);
146
+ }
147
+ catch (error) {
148
+ const msalErrorMessage = error.platformBrokerError ? JSON.stringify(error.platformBrokerError) : "";
149
+ logger.debug(`OAuthAuthenticator: Interactive token acquisition failed: ${error instanceof Error ? error.message + msalErrorMessage : String(error)}`);
150
+ authResult = null;
151
+ }
127
152
  }
128
153
  }
129
154
  if (!authResult) {
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const packageVersion = "2.9.0-onprem.1";
1
+ export const packageVersion = "2.9.0-onprem.2";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonyjv/azure-devops-mcp",
3
- "version": "2.9.0-onprem.1",
3
+ "version": "2.9.0-onprem.2",
4
4
  "mcpName": "io.github.sonyjv/azure-devops-mcp",
5
5
  "description": "MCP server for interacting with Azure DevOps",
6
6
  "license": "MIT",
@@ -40,7 +40,6 @@
40
40
  "@azure/identity": "^4.13.0",
41
41
  "@azure/logger": "^1.3.0",
42
42
  "@azure/msal-node": "^5.5.0",
43
- "@azure/msal-node-extensions": "^5.3.5",
44
43
  "@modelcontextprotocol/sdk": "1.29.0",
45
44
  "azure-devops-extension-api": "^5.272.3",
46
45
  "azure-devops-extension-sdk": "^4.0.2",
@@ -51,6 +50,9 @@
51
50
  "zod": "^3.25.63",
52
51
  "zod-to-json-schema": "^3.24.5"
53
52
  },
53
+ "optionalDependencies": {
54
+ "@azure/msal-node-extensions": "^5.3.5"
55
+ },
54
56
  "devDependencies": {
55
57
  "@types/jest": "^30.0.0",
56
58
  "@types/node": "^22.19.1",
@@ -75,6 +77,6 @@
75
77
  },
76
78
  "allowScripts": {
77
79
  "keytar@7.9.0": true,
78
- "@azure/msal-node-extensions@5.3.5": true
80
+ "@azure/msal-node-extensions@5.5.0": true
79
81
  }
80
82
  }