@fitchmultz/pi-mcp-adapter 8.0.6 → 8.0.7

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.
Files changed (87) hide show
  1. package/CHANGELOG.md +128 -8
  2. package/OAUTH.md +13 -16
  3. package/README.md +8 -8
  4. package/cli.js +67 -28
  5. package/dist/abort.js +18 -9
  6. package/dist/client-operations.js +4 -2
  7. package/dist/commands.js +77 -43
  8. package/dist/config.js +194 -105
  9. package/dist/connection-runtime.d.ts +2 -2
  10. package/dist/connection-runtime.js +29 -18
  11. package/dist/consent-manager.d.ts +2 -2
  12. package/dist/consent-manager.js +5 -2
  13. package/dist/direct-tools.d.ts +1 -1
  14. package/dist/direct-tools.js +13 -7
  15. package/dist/elicitation-handler.d.ts +2 -3
  16. package/dist/elicitation-handler.js +113 -58
  17. package/dist/gateway-arguments.d.ts +1 -1
  18. package/dist/gateway-arguments.js +90 -23
  19. package/dist/glimpse-ui.js +10 -5
  20. package/dist/host-html-template.d.ts +3 -1
  21. package/dist/host-html-template.js +9 -12
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +264 -119
  24. package/dist/init.d.ts +1 -3
  25. package/dist/init.js +91 -51
  26. package/dist/legacy-migration.d.ts +1 -1
  27. package/dist/legacy-migration.js +17 -12
  28. package/dist/lifecycle.d.ts +3 -3
  29. package/dist/lifecycle.js +33 -17
  30. package/dist/logger.d.ts +2 -2
  31. package/dist/logger.js +4 -2
  32. package/dist/mcp-auth-flow.js +150 -58
  33. package/dist/mcp-auth.d.ts +7 -7
  34. package/dist/mcp-auth.js +189 -138
  35. package/dist/mcp-callback-server.js +19 -8
  36. package/dist/mcp-code.js +168 -54
  37. package/dist/mcp-keyring-helper.cjs +57 -23
  38. package/dist/mcp-oauth-provider.d.ts +6 -7
  39. package/dist/mcp-oauth-provider.js +146 -72
  40. package/dist/mcp-oauth-runtime.js +29 -16
  41. package/dist/mcp-output-guard.js +193 -65
  42. package/dist/mcp-output-preview.js +41 -20
  43. package/dist/mcp-panel.d.ts +9 -9
  44. package/dist/mcp-panel.js +141 -70
  45. package/dist/mcp-script-worker.mjs +135 -43
  46. package/dist/mcp-setup-panel.d.ts +8 -8
  47. package/dist/mcp-setup-panel.js +130 -44
  48. package/dist/mcp-status.js +14 -7
  49. package/dist/mcp-trace.d.ts +10 -5
  50. package/dist/mcp-trace.js +127 -61
  51. package/dist/metadata-cache.d.ts +3 -4
  52. package/dist/metadata-cache.js +83 -43
  53. package/dist/npx-resolver.js +101 -60
  54. package/dist/onboarding-state.js +4 -2
  55. package/dist/plain-result-reader.js +78 -31
  56. package/dist/prompts.js +36 -20
  57. package/dist/proxy-modes.js +670 -193
  58. package/dist/resource-tools.js +30 -9
  59. package/dist/runtime-owner.js +36 -18
  60. package/dist/sampling-handler.d.ts +1 -2
  61. package/dist/sampling-handler.js +41 -21
  62. package/dist/search-ranking.d.ts +1 -1
  63. package/dist/search-ranking.js +67 -34
  64. package/dist/server-manager.d.ts +11 -11
  65. package/dist/server-manager.js +283 -166
  66. package/dist/session-recovery.js +113 -61
  67. package/dist/tool-approval.js +9 -3
  68. package/dist/tool-loader.js +154 -55
  69. package/dist/tool-metadata.d.ts +1 -1
  70. package/dist/tool-metadata.js +51 -23
  71. package/dist/tool-registrar.js +32 -10
  72. package/dist/tool-result-renderer.js +58 -33
  73. package/dist/types.d.ts +2 -2
  74. package/dist/types.js +39 -18
  75. package/dist/ui-message-history.js +33 -13
  76. package/dist/ui-resource-handler.d.ts +3 -3
  77. package/dist/ui-resource-handler.js +37 -21
  78. package/dist/ui-server.js +101 -43
  79. package/dist/ui-session.js +66 -29
  80. package/dist/ui-stream-types.js +14 -4
  81. package/dist/ui-tool-visibility.js +12 -6
  82. package/dist/unix-socket-transport.d.ts +1 -2
  83. package/dist/unix-socket-transport.js +19 -12
  84. package/dist/utils.d.ts +2 -0
  85. package/dist/utils.js +60 -35
  86. package/package.json +26 -2
  87. package/skills/mcp-scripting/SKILL.md +6 -6
@@ -5,11 +5,11 @@
5
5
  */
6
6
  import { auth as runSdkAuth, extractWWWAuthenticateParams, UnauthorizedError, Client, StreamableHTTPClientTransport, validateAuthorizationResponseIssuer, InsufficientScopeError, SdkHttpError, computeScopeUnion, isStrictScopeSuperset, } from "@modelcontextprotocol/client";
7
7
  import open from "open";
8
- import { McpOAuthProvider, issuersMatch, loopbackRedirectsMatch, validateOAuthClientMetadataUrl, validateOAuthPrivateKeyJwt, validateOAuthCrossAppAccess } from "./mcp-oauth-provider.js";
8
+ import { McpOAuthProvider, issuersMatch, loopbackRedirectsMatch, validateOAuthClientMetadataUrl, validateOAuthPrivateKeyJwt, validateOAuthCrossAppAccess, } from "./mcp-oauth-provider.js";
9
9
  import { ensureCallbackServer, waitForCallback, cancelPendingCallback, releaseCallbackServer, takeCallbackResult, } from "./mcp-callback-server.js";
10
10
  import { getAuthForUrl, clearAllCredentials, clearClientInfo, clearTokens, clearCodeVerifier, getOAuthState, clearOAuthState, getAuthBaseDir, } from "./mcp-auth.js";
11
- import { isServerDisabled, isNonInteractiveOAuth, validateServerProtocolConfig } from "./types.js";
12
- import { ADAPTER_VERSION, formatTerminalError, interpolateEnvRecord, interpolateEnvVars, normalizeRequestTimeoutMs } from "./utils.js";
11
+ import { isServerDisabled, isNonInteractiveOAuth, validateServerProtocolConfig, } from "./types.js";
12
+ import { ADAPTER_VERSION, formatTerminalError, interpolateEnvRecord, interpolateEnvVars, normalizeRequestTimeoutMs, } from "./utils.js";
13
13
  import { abortable, throwIfAborted } from "./abort.js";
14
14
  import { combineAbortSignals, isAbortError } from "./runtime-owner.js";
15
15
  import { clearPendingAuth, getPendingAuthKey, getRuntime, getRuntimeState, legacyRuntime, } from "./mcp-oauth-runtime.js";
@@ -18,7 +18,9 @@ function applyConfiguredScope(discovery, config) {
18
18
  return {
19
19
  ...discovery,
20
20
  ...(config.scope !== undefined ? { scope: config.scope } : {}),
21
- ...(config.skipIssuerMetadataValidation !== undefined ? { skipIssuerMetadataValidation: config.skipIssuerMetadataValidation } : {}),
21
+ ...(config.skipIssuerMetadataValidation !== undefined
22
+ ? { skipIssuerMetadataValidation: config.skipIssuerMetadataValidation }
23
+ : {}),
22
24
  };
23
25
  }
24
26
  function validateCallbackIssuer(serverName, context, response) {
@@ -26,7 +28,11 @@ function validateCallbackIssuer(serverName, context, response) {
26
28
  throw new Error("Cannot verify the OAuth error callback issuer");
27
29
  }
28
30
  try {
29
- validateAuthorizationResponseIssuer({ expectedIssuer: context.expectedIssuer ?? context.fallbackIssuer, issParameterSupported: context.issParameterSupported === true, iss: response.iss });
31
+ validateAuthorizationResponseIssuer({
32
+ expectedIssuer: context.expectedIssuer ?? context.fallbackIssuer,
33
+ issParameterSupported: context.issParameterSupported === true,
34
+ iss: response.iss,
35
+ });
30
36
  }
31
37
  catch {
32
38
  if (response.iss === undefined && context.issParameterSupported) {
@@ -37,32 +43,39 @@ function validateCallbackIssuer(serverName, context, response) {
37
43
  }
38
44
  }
39
45
  export function isOAuthChallenge(error) {
40
- return error instanceof InsufficientScopeError || error instanceof UnauthorizedError
41
- || (error instanceof SdkHttpError && error.status === 401);
46
+ return (error instanceof InsufficientScopeError ||
47
+ error instanceof UnauthorizedError ||
48
+ (error instanceof SdkHttpError && error.status === 401));
42
49
  }
43
50
  export function getOAuthRequest(serverName, serverUrl, storageBase, runtime = legacyRuntime) {
44
- if (runtime.signal.aborted)
51
+ if (runtime.signal.aborted) {
45
52
  return undefined;
53
+ }
46
54
  const request = getRuntimeState(runtime).requests.get(JSON.stringify([serverName, storageBase]));
47
55
  return request?.serverUrl === serverUrl ? request : undefined;
48
56
  }
49
57
  /** Observe native challenges only; no credential reads or auth work here. */
50
58
  export function recordOAuthChallenge(serverName, serverUrl, storageBase, error, runtime = legacyRuntime) {
51
- if (runtime.signal.aborted || !isOAuthChallenge(error))
59
+ if (runtime.signal.aborted || !isOAuthChallenge(error)) {
52
60
  return;
61
+ }
53
62
  const previous = getOAuthRequest(serverName, serverUrl, storageBase, runtime);
54
63
  const request = { ...previous, serverName, serverUrl };
55
64
  if (error instanceof InsufficientScopeError) {
56
65
  const requiredScope = computeScopeUnion(previous?.challenge?.requiredScope, error.requiredScope);
57
66
  const resourceMetadataUrl = error.resourceMetadataUrl ?? previous?.challenge?.resourceMetadataUrl;
58
- request.challenge = { ...(requiredScope ? { requiredScope } : {}), ...(resourceMetadataUrl ? { resourceMetadataUrl } : {}) };
67
+ request.challenge = {
68
+ ...(requiredScope ? { requiredScope } : {}),
69
+ ...(resourceMetadataUrl ? { resourceMetadataUrl } : {}),
70
+ };
59
71
  }
60
72
  getRuntimeState(runtime).requests.set(JSON.stringify([serverName, storageBase]), request);
61
73
  }
62
74
  export function bindOAuthRequestIssuer(serverName, serverUrl, storageBase, issuer, runtime = legacyRuntime) {
63
75
  const request = getOAuthRequest(serverName, serverUrl, storageBase, runtime);
64
- if (!request)
76
+ if (!request) {
65
77
  return;
78
+ }
66
79
  if (request.issuer && !issuersMatch(request.issuer, issuer)) {
67
80
  throw new Error(`OAuth authorization server issuer changed for ${serverName}; clear credentials before authenticating again`);
68
81
  }
@@ -87,18 +100,22 @@ export function extractOAuthConfig(definition) {
87
100
  return {};
88
101
  }
89
102
  const config = {};
90
- if (definition.oauth?.skipIssuerMetadataValidation !== undefined)
103
+ if (definition.oauth?.skipIssuerMetadataValidation !== undefined) {
91
104
  config.skipIssuerMetadataValidation = definition.oauth.skipIssuerMetadataValidation;
92
- if (definition.oauth?.grantType !== undefined)
105
+ }
106
+ if (definition.oauth?.grantType !== undefined) {
93
107
  config.grantType = definition.oauth.grantType;
108
+ }
94
109
  if (definition.oauth?.clientId !== undefined) {
95
- if (typeof definition.oauth.clientId !== "string")
110
+ if (typeof definition.oauth.clientId !== "string") {
96
111
  throw new Error("OAuth clientId must be a string");
112
+ }
97
113
  config.clientId = interpolateEnvVars(definition.oauth.clientId);
98
114
  }
99
115
  if (definition.oauth?.clientSecret !== undefined) {
100
- if (typeof definition.oauth.clientSecret !== "string")
116
+ if (typeof definition.oauth.clientSecret !== "string") {
101
117
  throw new Error("OAuth clientSecret must be a string");
118
+ }
102
119
  // Preserve command expressions for the provider; interpolation remains eager for ordinary values.
103
120
  config.clientSecret = definition.oauth.clientSecret.startsWith("!")
104
121
  ? definition.oauth.clientSecret
@@ -106,8 +123,9 @@ export function extractOAuthConfig(definition) {
106
123
  }
107
124
  if (definition.oauth?.clientMetadataUrl !== undefined) {
108
125
  const value = definition.oauth.clientMetadataUrl;
109
- if (value !== false && typeof value !== "string")
126
+ if (value !== false && typeof value !== "string") {
110
127
  throw new Error("OAuth clientMetadataUrl must be a string or false");
128
+ }
111
129
  config.clientMetadataUrl = value === false ? false : interpolateEnvVars(value);
112
130
  validateOAuthClientMetadataUrl(config.clientMetadataUrl);
113
131
  }
@@ -115,13 +133,15 @@ export function extractOAuthConfig(definition) {
115
133
  // Keep environment and command sources lazy; each authentication resolves its own key.
116
134
  config.privateKeyJwt = definition.oauth.privateKeyJwt;
117
135
  }
118
- if (definition.oauth?.crossAppAccess !== undefined)
136
+ if (definition.oauth?.crossAppAccess !== undefined) {
119
137
  config.crossAppAccess = definition.oauth.crossAppAccess;
138
+ }
120
139
  validateOAuthPrivateKeyJwt(config);
121
140
  validateOAuthCrossAppAccess(config);
122
141
  if (definition.oauth?.scope !== undefined) {
123
- if (typeof definition.oauth.scope !== "string")
142
+ if (typeof definition.oauth.scope !== "string") {
124
143
  throw new Error("OAuth scope must be a string");
144
+ }
125
145
  config.scope = interpolateEnvVars(definition.oauth.scope);
126
146
  }
127
147
  if (definition.oauth?.authorizationParams !== undefined) {
@@ -131,10 +151,12 @@ export function extractOAuthConfig(definition) {
131
151
  }
132
152
  config.authorizationParams = {};
133
153
  for (const [key, value] of Object.entries(params)) {
134
- if (!key)
154
+ if (!key) {
135
155
  throw new Error("OAuth authorizationParams keys must not be empty");
136
- if (typeof value !== "string")
156
+ }
157
+ if (typeof value !== "string") {
137
158
  throw new Error(`OAuth authorizationParams.${key} must be a string`);
159
+ }
138
160
  config.authorizationParams[key] = interpolateEnvVars(value);
139
161
  }
140
162
  }
@@ -182,15 +204,26 @@ async function probeAuthDiscovery(serverUrl, definition, signal) {
182
204
  const client = new Client({ name: "pi-mcp-auth-discovery", version: ADAPTER_VERSION }, {
183
205
  versionNegotiation: { mode: definition?.protocolVersion ?? "auto" },
184
206
  ...(isNonInteractiveOAuth(definition?.oauth)
185
- ? { capabilities: { extensions: { [definition?.oauth && definition.oauth.crossAppAccess
186
- ? "io.modelcontextprotocol/enterprise-managed-authorization" : "io.modelcontextprotocol/oauth-client-credentials"]: {} } } } : {}),
207
+ ? {
208
+ capabilities: {
209
+ extensions: {
210
+ [definition?.oauth && definition.oauth.crossAppAccess
211
+ ? "io.modelcontextprotocol/enterprise-managed-authorization"
212
+ : "io.modelcontextprotocol/oauth-client-credentials"]: {},
213
+ },
214
+ },
215
+ }
216
+ : {}),
187
217
  });
188
218
  const transport = new StreamableHTTPClientTransport(new URL(serverUrl), {
189
219
  requestInit: { headers },
190
220
  fetch: async (input, init) => {
191
221
  const response = await fetch(input, init);
192
222
  const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
193
- discovery = { ...(resourceMetadataUrl ? { resourceMetadataUrl } : {}), ...(scope ? { scope } : {}) };
223
+ discovery = {
224
+ ...(resourceMetadataUrl ? { resourceMetadataUrl } : {}),
225
+ ...(scope ? { scope } : {}),
226
+ };
194
227
  return response;
195
228
  },
196
229
  });
@@ -198,8 +231,9 @@ async function probeAuthDiscovery(serverUrl, definition, signal) {
198
231
  await abortable(client.connect(transport, { timeout }), discoverySignal);
199
232
  }
200
233
  catch (error) {
201
- if (signal?.aborted)
234
+ if (signal?.aborted) {
202
235
  throwIfAborted(signal);
236
+ }
203
237
  }
204
238
  finally {
205
239
  await (client.transport ? client.close() : transport.close());
@@ -215,7 +249,10 @@ function parseOAuthRedirectUri(redirectUri) {
215
249
  throw new Error(`Invalid OAuth redirectUri: ${redirectUri}`, { cause: error });
216
250
  }
217
251
  const hostname = url.hostname.toLowerCase();
218
- const isLocalhost = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1";
252
+ const isLocalhost = hostname === "localhost" ||
253
+ hostname === "127.0.0.1" ||
254
+ hostname === "[::1]" ||
255
+ hostname === "::1";
219
256
  if (url.protocol !== "http:" || !isLocalhost) {
220
257
  throw new Error("OAuth redirectUri must be an http:// localhost or loopback URI");
221
258
  }
@@ -240,8 +277,9 @@ function parseOAuthRedirectUri(redirectUri) {
240
277
  * Returns the authorization URL when browser authorization is required.
241
278
  */
242
279
  export async function startAuth(serverName, serverUrl, definition, options = {}) {
243
- if (isServerDisabled(definition))
280
+ if (isServerDisabled(definition)) {
244
281
  throw new Error(`MCP server "${serverName}" is disabled`);
282
+ }
245
283
  const runtime = getRuntime(options);
246
284
  const runtimeState = getRuntimeState(runtime);
247
285
  const config = definition ? extractOAuthConfig(definition) : {};
@@ -251,7 +289,10 @@ export async function startAuth(serverName, serverUrl, definition, options = {})
251
289
  throwIfAborted(signal);
252
290
  if (isNonInteractiveOAuth(config)) {
253
291
  const storedAuth = await getAuthForUrl(serverName, serverUrl, authStorageOptions);
254
- if (!config.crossAppAccess && storedAuth?.clientInfo && !storedAuth.tokens && !config.clientId) {
292
+ if (!config.crossAppAccess &&
293
+ storedAuth?.clientInfo &&
294
+ !storedAuth.tokens &&
295
+ !config.clientId) {
255
296
  clearClientInfo(serverName, authStorageOptions);
256
297
  clearCodeVerifier(serverName, authStorageOptions);
257
298
  await clearOAuthState(serverName, authStorageOptions);
@@ -289,8 +330,14 @@ export async function startAuth(serverName, serverUrl, definition, options = {})
289
330
  strictPort: Boolean(config.clientId) || config.redirectUri !== undefined,
290
331
  oauthState,
291
332
  reserveState: true,
292
- validate: response => validateCallbackIssuer(serverName, callbackIssuer, response),
293
- ...(redirectCallback ? { port: redirectCallback.port, callbackHost: redirectCallback.callbackHost, callbackPath: redirectCallback.callbackPath } : {}),
333
+ validate: (response) => validateCallbackIssuer(serverName, callbackIssuer, response),
334
+ ...(redirectCallback
335
+ ? {
336
+ port: redirectCallback.port,
337
+ callbackHost: redirectCallback.callbackHost,
338
+ callbackPath: redirectCallback.callbackPath,
339
+ }
340
+ : {}),
294
341
  });
295
342
  throwIfAborted(signal);
296
343
  }
@@ -311,28 +358,41 @@ export async function startAuth(serverName, serverUrl, definition, options = {})
311
358
  let discovery = applyConfiguredScope(await probeAuthDiscovery(serverUrl, definition, signal), config);
312
359
  if (request?.challenge) {
313
360
  const scope = computeScopeUnion(discovery.scope, request.requestedScope, storedAuth?.tokens?.scope, request.challenge.requiredScope);
314
- discovery = { ...discovery, ...(scope ? { scope } : {}), ...(request.challenge.resourceMetadataUrl ? { resourceMetadataUrl: request.challenge.resourceMetadataUrl } : {}) };
361
+ discovery = {
362
+ ...discovery,
363
+ ...(scope ? { scope } : {}),
364
+ ...(request.challenge.resourceMetadataUrl
365
+ ? { resourceMetadataUrl: request.challenge.resourceMetadataUrl }
366
+ : {}),
367
+ };
315
368
  }
316
369
  throwIfAborted(signal);
317
- const flowConfig = { ...config, ...(request?.challenge && discovery.scope ? { scope: discovery.scope } : {}) };
370
+ const flowConfig = {
371
+ ...config,
372
+ ...(request?.challenge && discovery.scope ? { scope: discovery.scope } : {}),
373
+ };
318
374
  authProvider = new McpOAuthProvider(serverName, serverUrl, flowConfig, {
319
- onRedirect: url => {
375
+ onRedirect: (url) => {
320
376
  capturedUrl = url;
321
377
  const requestedScope = url.searchParams.get("scope") ?? undefined;
322
378
  if (requestedScope) {
323
379
  discovery = { ...discovery, scope: requestedScope };
324
- if (request?.challenge)
380
+ if (request?.challenge) {
325
381
  flowConfig.scope = requestedScope;
382
+ }
326
383
  }
327
384
  const current = getOAuthRequest(serverName, serverUrl, storageBase, runtime);
328
385
  const scope = computeScopeUnion(current?.requestedScope, requestedScope);
329
- if (current && scope)
386
+ if (current && scope) {
330
387
  current.requestedScope = scope;
388
+ }
331
389
  },
332
- onDiscoveryState: state => {
390
+ onDiscoveryState: (state) => {
333
391
  callbackIssuer.expectedIssuer = state.authorizationServerMetadata?.issuer;
334
392
  callbackIssuer.fallbackIssuer = state.authorizationServerUrl;
335
- callbackIssuer.issParameterSupported = state.authorizationServerMetadata?.authorization_response_iss_parameter_supported === true;
393
+ callbackIssuer.issParameterSupported =
394
+ state.authorizationServerMetadata?.authorization_response_iss_parameter_supported ===
395
+ true;
336
396
  bindOAuthRequestIssuer(serverName, serverUrl, storageBase, callbackIssuer.expectedIssuer ?? state.authorizationServerUrl, runtime);
337
397
  },
338
398
  }, authStorageOptions, runtime.signal, oauthState);
@@ -345,9 +405,10 @@ export async function startAuth(serverName, serverUrl, definition, options = {})
345
405
  else {
346
406
  const redirectUris = storedAuth.clientInfo.redirectUris;
347
407
  const redirectUrl = authProvider.redirectUrl ?? "";
348
- const matchesRedirect = Array.isArray(redirectUris) && (redirectUris.includes(redirectUrl)
349
- || (storedAuth.clientInfo.registrationType === "cimd"
350
- && redirectUris.some(uri => loopbackRedirectsMatch(redirectUrl, uri))));
408
+ const matchesRedirect = Array.isArray(redirectUris) &&
409
+ (redirectUris.includes(redirectUrl) ||
410
+ (storedAuth.clientInfo.registrationType === "cimd" &&
411
+ redirectUris.some((uri) => loopbackRedirectsMatch(redirectUrl, uri))));
351
412
  if (!matchesRedirect) {
352
413
  clearClientInfo(serverName, authStorageOptions);
353
414
  clearTokens(serverName, authStorageOptions);
@@ -358,8 +419,13 @@ export async function startAuth(serverName, serverUrl, definition, options = {})
358
419
  }
359
420
  throwIfAborted(signal);
360
421
  const result = await abortable(runSdkAuth(authProvider, {
361
- serverUrl, ...discovery,
362
- ...(request?.challenge ? { forceReauthorization: isStrictScopeSuperset(discovery.scope, storedAuth?.tokens?.scope) } : {}),
422
+ serverUrl,
423
+ ...discovery,
424
+ ...(request?.challenge
425
+ ? {
426
+ forceReauthorization: isStrictScopeSuperset(discovery.scope, storedAuth?.tokens?.scope),
427
+ }
428
+ : {}),
363
429
  }), signal);
364
430
  throwIfAborted(signal);
365
431
  if (result === "AUTHORIZED") {
@@ -371,7 +437,16 @@ export async function startAuth(serverName, serverUrl, definition, options = {})
371
437
  if (!capturedUrl) {
372
438
  throw new UnauthorizedError("OAuth authorization URL was not provided");
373
439
  }
374
- await setPendingAuth(runtime, serverName, { serverName, authProvider, serverUrl, authorizationUrl: capturedUrl.toString(), discovery, callbackIssuer: { ...callbackIssuer }, authStorageOptions, ...(request ? { request } : {}) }, oauthState, signal, generation);
440
+ await setPendingAuth(runtime, serverName, {
441
+ serverName,
442
+ authProvider,
443
+ serverUrl,
444
+ authorizationUrl: capturedUrl.toString(),
445
+ discovery,
446
+ callbackIssuer: { ...callbackIssuer },
447
+ authStorageOptions,
448
+ ...(request ? { request } : {}),
449
+ }, oauthState, signal, generation);
375
450
  return { authorizationUrl: capturedUrl.toString() };
376
451
  }
377
452
  catch (error) {
@@ -390,12 +465,13 @@ async function setPendingAuth(runtime, serverName, pendingAuth, oauthState, sign
390
465
  const key = getPendingAuthKey(serverName, pendingAuth.authStorageOptions);
391
466
  await clearPendingAuth(runtime, serverName, undefined, pendingAuth.authStorageOptions);
392
467
  throwIfAborted(signal);
393
- if (generation !== state.generation)
468
+ if (generation !== state.generation) {
394
469
  throw new Error("OAuth runtime stopped");
470
+ }
395
471
  state.pendingAuths.set(key, pendingAuth);
396
472
  state.pendingAuthStates.set(key, oauthState);
397
473
  const cleanupTimer = setTimeout(() => {
398
- void clearPendingAuth(runtime, serverName, oauthState, pendingAuth.authStorageOptions).catch(error => {
474
+ void clearPendingAuth(runtime, serverName, oauthState, pendingAuth.authStorageOptions).catch((error) => {
399
475
  console.error(`MCP Auth: Timed-out flow cleanup failed: ${formatTerminalError(error)}`);
400
476
  });
401
477
  }, MANUAL_AUTH_TIMEOUT_MS);
@@ -410,8 +486,9 @@ function getSearchParamsFromInput(input) {
410
486
  const hash = url.hash.startsWith("#") ? url.hash.slice(1) : url.hash;
411
487
  const hashParams = new URLSearchParams(hash);
412
488
  for (const [key, value] of hashParams) {
413
- if (!params.has(key))
489
+ if (!params.has(key)) {
414
490
  params.set(key, value);
491
+ }
415
492
  }
416
493
  }
417
494
  return params;
@@ -440,7 +517,11 @@ export function parseAuthorizationRedirectInput(input, expectedState) {
440
517
  if (error) {
441
518
  const description = params.get("error_description");
442
519
  const iss = params.get("iss");
443
- return { error, ...(description !== null ? { errorDescription: description } : {}), ...(iss !== null ? { iss } : {}) };
520
+ return {
521
+ error,
522
+ ...(description !== null ? { errorDescription: description } : {}),
523
+ ...(iss !== null ? { iss } : {}),
524
+ };
444
525
  }
445
526
  const code = params.get("code");
446
527
  if (code) {
@@ -485,21 +566,25 @@ export async function completeAuth(serverName, authorizationCode, options = {})
485
566
  }
486
567
  const oauthState = runtimeState.pendingAuthStates.get(key);
487
568
  throwIfAborted(signal);
488
- const response = typeof authorizationCode === "string" ? { code: authorizationCode }
489
- : authorizationCode ?? (oauthState ? takeCallbackResult(oauthState) : undefined);
569
+ const response = typeof authorizationCode === "string"
570
+ ? { code: authorizationCode }
571
+ : (authorizationCode ?? (oauthState ? takeCallbackResult(oauthState) : undefined));
490
572
  if (!response) {
491
573
  throw new Error(`No OAuth callback received yet for ${serverName}. Finish authorization in the browser, then retry auth-complete. ` +
492
- "If the browser cannot reach this Pi session's callback, pass args: { redirectUrl: \"FULL_REDIRECT_URL\" } instead.");
574
+ 'If the browser cannot reach this Pi session\'s callback, pass args: { redirectUrl: "FULL_REDIRECT_URL" } instead.');
493
575
  }
494
576
  const { iss } = response;
495
577
  let keepPendingForRetry = false;
496
578
  let caughtError;
497
579
  try {
498
- keepPendingForRetry = iss === undefined && pendingAuth.callbackIssuer.issParameterSupported === true;
580
+ keepPendingForRetry =
581
+ iss === undefined && pendingAuth.callbackIssuer.issParameterSupported === true;
499
582
  validateCallbackIssuer(serverName, pendingAuth.callbackIssuer, response);
500
583
  if ("error" in response) {
501
584
  keepPendingForRetry = true;
502
- throw new Error(response.errorDescription ? `${response.error}: ${response.errorDescription}` : response.error);
585
+ throw new Error(response.errorDescription
586
+ ? `${response.error}: ${response.errorDescription}`
587
+ : response.error);
503
588
  }
504
589
  const result = await abortable(runSdkAuth(pendingAuth.authProvider, {
505
590
  serverUrl: pendingAuth.serverUrl,
@@ -512,11 +597,14 @@ export async function completeAuth(serverName, authorizationCode, options = {})
512
597
  throw new UnauthorizedError("Failed to authorize");
513
598
  }
514
599
  const request = pendingAuth.request;
515
- if (request?.challenge?.requiredScope
516
- && request === getOAuthRequest(serverName, pendingAuth.serverUrl, getAuthBaseDir(authStorageOptions), runtime)) {
600
+ if (request?.challenge?.requiredScope &&
601
+ request ===
602
+ getOAuthRequest(serverName, pendingAuth.serverUrl, getAuthBaseDir(authStorageOptions), runtime)) {
517
603
  const issuedScope = (await getAuthForUrl(serverName, pendingAuth.serverUrl, authStorageOptions))?.tokens?.scope;
518
- if (issuedScope !== undefined && !isStrictScopeSuperset(request.challenge.requiredScope, issuedScope))
604
+ if (issuedScope !== undefined &&
605
+ !isStrictScopeSuperset(request.challenge.requiredScope, issuedScope)) {
519
606
  delete request.challenge;
607
+ }
520
608
  }
521
609
  return "authenticated";
522
610
  }
@@ -547,8 +635,9 @@ export async function completeAuth(serverName, authorizationCode, options = {})
547
635
  * @returns The final auth status
548
636
  */
549
637
  export async function authenticate(serverName, serverUrl, definition, options = {}) {
550
- if (isServerDisabled(definition))
638
+ if (isServerDisabled(definition)) {
551
639
  throw new Error(`MCP server "${serverName}" is disabled`);
640
+ }
552
641
  const runtime = getRuntime(options);
553
642
  const runtimeState = getRuntimeState(runtime);
554
643
  const authStorageOptions = options.authStorageOptions ?? {};
@@ -595,8 +684,9 @@ export async function authenticate(serverName, serverUrl, definition, options =
595
684
  await abortable(open(authorizationUrl), signal);
596
685
  }
597
686
  catch (error) {
598
- if (isAbortError(error, signal))
687
+ if (isAbortError(error, signal)) {
599
688
  throw error;
689
+ }
600
690
  console.warn(`MCP Auth: Failed to open browser for ${serverName}; waiting for manual callback`, { error });
601
691
  }
602
692
  // Wait for callback
@@ -611,8 +701,9 @@ export async function authenticate(serverName, serverUrl, definition, options =
611
701
  });
612
702
  }
613
703
  catch (error) {
614
- if (oauthState)
704
+ if (oauthState) {
615
705
  cancelPendingCallback(oauthState);
706
+ }
616
707
  try {
617
708
  await clearPendingAuth(runtime, serverName, oauthState, authStorageOptions);
618
709
  }
@@ -650,8 +741,9 @@ export async function removeAuth(serverName, options = {}) {
650
741
  await clearPendingAuth(runtime, serverName, oauthState, authStorageOptions);
651
742
  throwIfAborted(signal);
652
743
  for (const [key, request] of getRuntimeState(runtime).requests) {
653
- if (request.serverName === serverName)
744
+ if (request.serverName === serverName) {
654
745
  getRuntimeState(runtime).requests.delete(key);
746
+ }
655
747
  }
656
748
  clearAllCredentials(serverName, authStorageOptions);
657
749
  await clearOAuthState(serverName, authStorageOptions);
@@ -52,16 +52,16 @@ export interface AuthStorageOptions {
52
52
  }
53
53
  export declare class OAuthCredentialStoreError extends Error {
54
54
  readonly code = "OAUTH_CREDENTIAL_STORE_UNAVAILABLE";
55
- readonly operation: 'read' | 'write' | 'remove';
56
- constructor(message: string, operation: 'read' | 'write' | 'remove', cause: unknown);
55
+ readonly operation: "read" | "write" | "remove";
56
+ constructor(message: string, operation: "read" | "write" | "remove", cause: unknown);
57
57
  }
58
58
  export type OAuthCredentialStatus = {
59
- status: 'present';
59
+ status: "present";
60
60
  entry: AuthEntry;
61
61
  } | {
62
- status: 'absent';
62
+ status: "absent";
63
63
  } | {
64
- status: 'unavailable';
64
+ status: "unavailable";
65
65
  message: string;
66
66
  };
67
67
  export declare function formatOAuthCredentialStoreUnavailable(error: OAuthCredentialStoreError): string;
@@ -70,9 +70,9 @@ export declare function getAuthBaseDir(options?: AuthStorageOptions): string;
70
70
  /**
71
71
  * Get the legacy plaintext tokens file path for a server.
72
72
  */
73
- export declare function getAuthEntryFilePath(serverName: string, options?: AuthStorageOptions): string;
73
+ export declare function getAuthEntryFilePath(serverName: unknown, options?: AuthStorageOptions): string;
74
74
  /** Explicit copy-only upgrade. Normal reads and logout never access the old service. */
75
- export declare function migrateLegacyAuthEntry(serverName: string, legacyDirectory?: string): 'copied' | 'existing' | 'absent';
75
+ export declare function migrateLegacyAuthEntry(serverName: string, legacyDirectory?: string): "copied" | "existing" | "absent";
76
76
  /**
77
77
  * Get auth entry for a server.
78
78
  */