@duo-director/cli 0.2.1 → 0.2.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.
Files changed (81) hide show
  1. package/dist/THIRD_PARTY_NOTICES.md +3 -3
  2. package/dist/{cli-WTCBCBVN.js → cli-QTN5SRNE.js} +61 -15
  3. package/dist/duoctl.js +1 -1
  4. package/dist/runtime-tree.json +12 -12
  5. package/dist/ui/app.js +2 -2
  6. package/node_modules/@modelcontextprotocol/client/dist/{index-CEk3qkZM.d.cts → index-D_CiY-T3.d.cts} +3 -1
  7. package/node_modules/@modelcontextprotocol/client/dist/index-D_CiY-T3.d.cts.map +1 -0
  8. package/node_modules/@modelcontextprotocol/client/dist/{index-BCtJi0p5.d.mts → index-D_QDtbiv.d.mts} +3 -1
  9. package/node_modules/@modelcontextprotocol/client/dist/index-D_QDtbiv.d.mts.map +1 -0
  10. package/node_modules/@modelcontextprotocol/client/dist/index.cjs +100 -55
  11. package/node_modules/@modelcontextprotocol/client/dist/index.cjs.map +1 -1
  12. package/node_modules/@modelcontextprotocol/client/dist/index.d.cts +157 -30
  13. package/node_modules/@modelcontextprotocol/client/dist/index.d.cts.map +1 -1
  14. package/node_modules/@modelcontextprotocol/client/dist/index.d.mts +157 -30
  15. package/node_modules/@modelcontextprotocol/client/dist/index.d.mts.map +1 -1
  16. package/node_modules/@modelcontextprotocol/client/dist/index.mjs +100 -55
  17. package/node_modules/@modelcontextprotocol/client/dist/index.mjs.map +1 -1
  18. package/node_modules/@modelcontextprotocol/client/dist/shimsWorkerd.cjs +1 -1
  19. package/node_modules/@modelcontextprotocol/client/dist/shimsWorkerd.mjs +1 -1
  20. package/node_modules/@modelcontextprotocol/client/dist/{src-D0qEN74R.cjs → src-oZBjf3U1.cjs} +21 -4
  21. package/node_modules/@modelcontextprotocol/client/dist/src-oZBjf3U1.cjs.map +1 -0
  22. package/node_modules/@modelcontextprotocol/client/dist/{src-DDAAhLnO.mjs → src-xKF0PJN-.mjs} +16 -5
  23. package/node_modules/@modelcontextprotocol/client/dist/src-xKF0PJN-.mjs.map +1 -0
  24. package/node_modules/@modelcontextprotocol/client/dist/stdio.cjs +1 -1
  25. package/node_modules/@modelcontextprotocol/client/dist/stdio.d.cts +1 -1
  26. package/node_modules/@modelcontextprotocol/client/dist/stdio.d.mts +1 -1
  27. package/node_modules/@modelcontextprotocol/client/dist/stdio.mjs +1 -1
  28. package/node_modules/@modelcontextprotocol/client/package.json +3 -3
  29. package/node_modules/@modelcontextprotocol/core/dist/{auth--n_Yzytt.d.cts → auth-Anm-lwWi.d.mts} +9 -8
  30. package/node_modules/@modelcontextprotocol/core/dist/{auth--n_Yzytt.d.cts.map → auth-Anm-lwWi.d.mts.map} +1 -1
  31. package/node_modules/@modelcontextprotocol/core/dist/{auth-CGP0BDVq.mjs → auth-BNDyLTqp.mjs} +5 -3
  32. package/node_modules/@modelcontextprotocol/core/dist/{auth-CGP0BDVq.mjs.map → auth-BNDyLTqp.mjs.map} +1 -1
  33. package/node_modules/@modelcontextprotocol/core/dist/{auth-4-zilcqg.cjs → auth-D1CeV_Jr.cjs} +5 -3
  34. package/node_modules/@modelcontextprotocol/core/dist/{auth-4-zilcqg.cjs.map → auth-D1CeV_Jr.cjs.map} +1 -1
  35. package/node_modules/@modelcontextprotocol/core/dist/{auth-YUQV3RRv.d.mts → auth-V9XJSCfa.d.cts} +9 -8
  36. package/node_modules/@modelcontextprotocol/core/dist/{auth-YUQV3RRv.d.mts.map → auth-V9XJSCfa.d.cts.map} +1 -1
  37. package/node_modules/@modelcontextprotocol/core/dist/index.cjs +1 -1
  38. package/node_modules/@modelcontextprotocol/core/dist/index.d.cts +1 -1
  39. package/node_modules/@modelcontextprotocol/core/dist/index.d.mts +1 -1
  40. package/node_modules/@modelcontextprotocol/core/dist/index.mjs +1 -1
  41. package/node_modules/@modelcontextprotocol/core/dist/internal.cjs +1 -1
  42. package/node_modules/@modelcontextprotocol/core/dist/internal.d.cts +1 -1
  43. package/node_modules/@modelcontextprotocol/core/dist/internal.d.mts +1 -1
  44. package/node_modules/@modelcontextprotocol/core/dist/internal.mjs +1 -1
  45. package/node_modules/@modelcontextprotocol/core/package.json +1 -1
  46. package/node_modules/@modelcontextprotocol/server/dist/{createMcpHandler-Bt6U_Fqb.d.mts → createMcpHandler-CfX6zgs1.d.mts} +3 -1
  47. package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-CfX6zgs1.d.mts.map +1 -0
  48. package/node_modules/@modelcontextprotocol/server/dist/{createMcpHandler-BLVe3qmU.d.cts → createMcpHandler-LSKhyqpU.d.cts} +3 -1
  49. package/node_modules/@modelcontextprotocol/server/dist/{createMcpHandler-BLVe3qmU.d.cts.map → createMcpHandler-LSKhyqpU.d.cts.map} +1 -1
  50. package/node_modules/@modelcontextprotocol/server/dist/index.cjs +5 -3
  51. package/node_modules/@modelcontextprotocol/server/dist/index.cjs.map +1 -1
  52. package/node_modules/@modelcontextprotocol/server/dist/index.d.cts +1 -1
  53. package/node_modules/@modelcontextprotocol/server/dist/index.d.mts +1 -1
  54. package/node_modules/@modelcontextprotocol/server/dist/index.d.mts.map +1 -1
  55. package/node_modules/@modelcontextprotocol/server/dist/index.mjs +5 -3
  56. package/node_modules/@modelcontextprotocol/server/dist/index.mjs.map +1 -1
  57. package/node_modules/@modelcontextprotocol/server/dist/{mcp-Dw2OlZ1f.mjs → mcp-DYuW2ZSs.mjs} +6 -2
  58. package/node_modules/@modelcontextprotocol/server/dist/mcp-DYuW2ZSs.mjs.map +1 -0
  59. package/node_modules/@modelcontextprotocol/server/dist/{mcp-DUcCQSTW.cjs → mcp-TfXCpFsH.cjs} +6 -2
  60. package/node_modules/@modelcontextprotocol/server/dist/mcp-TfXCpFsH.cjs.map +1 -0
  61. package/node_modules/@modelcontextprotocol/server/dist/shimsWorkerd.cjs +1 -1
  62. package/node_modules/@modelcontextprotocol/server/dist/shimsWorkerd.mjs +1 -1
  63. package/node_modules/@modelcontextprotocol/server/dist/{src-D-y6h4N7.mjs → src-BHSMhZ_W.mjs} +8 -4
  64. package/node_modules/@modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs.map +1 -0
  65. package/node_modules/@modelcontextprotocol/server/dist/{src-CgFsfg3E.cjs → src-BtQ5YSyq.cjs} +8 -4
  66. package/node_modules/@modelcontextprotocol/server/dist/src-BtQ5YSyq.cjs.map +1 -0
  67. package/node_modules/@modelcontextprotocol/server/dist/stdio.cjs +2 -2
  68. package/node_modules/@modelcontextprotocol/server/dist/stdio.d.cts +1 -1
  69. package/node_modules/@modelcontextprotocol/server/dist/stdio.d.mts +1 -1
  70. package/node_modules/@modelcontextprotocol/server/dist/stdio.mjs +2 -2
  71. package/node_modules/@modelcontextprotocol/server/package.json +3 -3
  72. package/package.json +3 -3
  73. package/node_modules/@modelcontextprotocol/client/dist/index-BCtJi0p5.d.mts.map +0 -1
  74. package/node_modules/@modelcontextprotocol/client/dist/index-CEk3qkZM.d.cts.map +0 -1
  75. package/node_modules/@modelcontextprotocol/client/dist/src-D0qEN74R.cjs.map +0 -1
  76. package/node_modules/@modelcontextprotocol/client/dist/src-DDAAhLnO.mjs.map +0 -1
  77. package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-Bt6U_Fqb.d.mts.map +0 -1
  78. package/node_modules/@modelcontextprotocol/server/dist/mcp-DUcCQSTW.cjs.map +0 -1
  79. package/node_modules/@modelcontextprotocol/server/dist/mcp-Dw2OlZ1f.mjs.map +0 -1
  80. package/node_modules/@modelcontextprotocol/server/dist/src-CgFsfg3E.cjs.map +0 -1
  81. package/node_modules/@modelcontextprotocol/server/dist/src-D-y6h4N7.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { $ as legacyProtocolVersions, A as isInitializeRequest, At as SdkErrorCode, B as DiscoverResultSchema, C as mcpNameSource, Ct as OAuthClientInformationFullSchema, D as assertCompleteRequestPrompt, Dt as OAuthTokensSchema, E as scanXMcpHeaderDeclarations, Et as OAuthProtectedResourceMetadataSchema, F as isJSONRPCRequest, Ft as stampErrorBrands, G as MissingRequiredClientCapabilityError, H as ListChangedOptionsBaseSchema, I as isJSONRPCResponse, J as UnsupportedProtocolVersionError, K as ProtocolError, L as isJSONRPCResultResponse, M as isInputRequiredResult, Mt as OAuthError, N as isJSONRPCErrorResponse, Nt as OAuthErrorCode, O as assertCompleteRequestResourceTemplate, Ot as OpenIdProviderDiscoveryMetadataSchema, P as isJSONRPCNotification, Pt as brandedHasInstance, Q as isModernProtocolVersion, R as isTaskAugmentedRequestParams, S as HEADER_MISMATCH_ERROR_CODE, St as IdJagTokenExchangeResponseSchema, T as encodeMcpParamValue, Tt as OAuthMetadataSchema, U as MODERN_WIRE_REVISION, V as JSONRPCMessageSchema, W as codecForVersion, X as ProtocolErrorCode, Y as UrlElicitationRequiredError, Z as SUPPORTED_MODERN_PROTOCOL_VERSIONS, _ as isSpecType, _t as SUPPORTED_PROTOCOL_VERSIONS, a as createFetchWithInit, at as INTERNAL_ERROR, b as withInputRequired, bt as checkResourceAllowed, c as deserializeMessage, ct as JSONRPC_VERSION, d as isJsonContentType, dt as METHOD_NOT_FOUND, et as modernProtocolVersions, f as mediaTypeEssence, ft as PARSE_ERROR, g as mergeCapabilities, gt as SUBSCRIPTION_ID_META_KEY, h as Protocol, ht as SERVER_INFO_META_KEY, i as UriTemplate, it as DEFAULT_NEGOTIATED_PROTOCOL_VERSION, j as isInitializedNotification, jt as SdkHttpError, k as isCallToolResult, kt as SdkError, l as serializeMessage, lt as LATEST_PROTOCOL_VERSION, m as DEFAULT_REQUEST_TIMEOUT_MSEC, mt as RELATED_TASK_META_KEY, n as preloadSchemas, nt as CLIENT_CAPABILITIES_META_KEY, o as ReadBuffer, ot as INVALID_PARAMS, p as runInputRequiredFlow, pt as PROTOCOL_VERSION_META_KEY, q as ResourceNotFoundError, r as InMemoryTransport, rt as CLIENT_INFO_META_KEY, s as STDIO_DEFAULT_MAX_BUFFER_SIZE, st as INVALID_REQUEST, t as fromJsonSchema$1, tt as BAGGAGE_META_KEY, u as getDisplayName, ut as LOG_LEVEL_META_KEY, v as specTypeSchemas, vt as TRACEPARENT_META_KEY, w as buildMcpParamHeaders, wt as OAuthErrorResponseSchema, x as parseSchema, xt as resourceUrlFromServerUrl, y as resolveInputRequiredDriverConfig, yt as TRACESTATE_META_KEY, z as parseJSONRPCMessage } from "./src-DDAAhLnO.mjs";
1
+ import { $ as legacyProtocolVersions, A as isInitializeRequest, At as SdkError, B as DiscoverResultSchema, C as mcpNameSource, Ct as IdJagTokenExchangeResponseSchema, D as assertCompleteRequestPrompt, Dt as OAuthProtectedResourceMetadataSchema, E as scanXMcpHeaderDeclarations, Et as OAuthMetadataSchema, F as isJSONRPCRequest, Ft as brandedHasInstance, G as MissingRequiredClientCapabilityError, H as ListChangedOptionsBaseSchema, I as isJSONRPCResponse, It as stampErrorBrands, J as UnsupportedProtocolVersionError, K as ProtocolError, L as isJSONRPCResultResponse, M as isInputRequiredResult, Mt as SdkHttpError, N as isJSONRPCErrorResponse, Nt as OAuthError, O as assertCompleteRequestResourceTemplate, Ot as OAuthTokensSchema, P as isJSONRPCNotification, Pt as OAuthErrorCode, Q as isModernProtocolVersion, R as isTaskAugmentedRequestParams, S as HEADER_MISMATCH_ERROR_CODE, St as withoutIssuer, T as encodeMcpParamValue, Tt as OAuthErrorResponseSchema, U as MODERN_WIRE_REVISION, V as JSONRPCMessageSchema, W as codecForVersion, X as ProtocolErrorCode, Y as UrlElicitationRequiredError, Z as SUPPORTED_MODERN_PROTOCOL_VERSIONS, _ as isSpecType, _t as SUPPORTED_PROTOCOL_VERSIONS, a as createFetchWithInit, at as INTERNAL_ERROR, b as withInputRequired, bt as checkResourceAllowed, c as deserializeMessage, ct as JSONRPC_VERSION, d as isJsonContentType, dt as METHOD_NOT_FOUND, et as modernProtocolVersions, f as mediaTypeEssence, ft as PARSE_ERROR, g as mergeCapabilities, gt as SUBSCRIPTION_ID_META_KEY, h as Protocol, ht as SERVER_INFO_META_KEY, i as UriTemplate, it as DEFAULT_NEGOTIATED_PROTOCOL_VERSION, j as isInitializedNotification, jt as SdkErrorCode, k as isCallToolResult, kt as OpenIdProviderDiscoveryMetadataSchema, l as serializeMessage, lt as LATEST_PROTOCOL_VERSION, m as DEFAULT_REQUEST_TIMEOUT_MSEC, mt as RELATED_TASK_META_KEY, n as preloadSchemas, nt as CLIENT_CAPABILITIES_META_KEY, o as ReadBuffer, ot as INVALID_PARAMS, p as runInputRequiredFlow, pt as PROTOCOL_VERSION_META_KEY, q as ResourceNotFoundError, r as InMemoryTransport, rt as CLIENT_INFO_META_KEY, s as STDIO_DEFAULT_MAX_BUFFER_SIZE, st as INVALID_REQUEST, t as fromJsonSchema$1, tt as BAGGAGE_META_KEY, u as getDisplayName, ut as LOG_LEVEL_META_KEY, v as specTypeSchemas, vt as TRACEPARENT_META_KEY, w as buildMcpParamHeaders, wt as OAuthClientInformationFullSchema, x as parseSchema, xt as resourceUrlFromServerUrl, y as resolveInputRequiredDriverConfig, yt as TRACESTATE_META_KEY, z as parseJSONRPCMessage } from "./src-xKF0PJN-.mjs";
2
2
  import { CORS_IS_POSSIBLE, DefaultJsonSchemaValidator } from "@modelcontextprotocol/client/_shims";
3
3
  import pkceChallenge from "pkce-challenge";
4
4
  import { EventSource } from "eventsource";
@@ -112,10 +112,12 @@ var RegistrationRejectedError = class extends OAuthClientFlowError {
112
112
  };
113
113
  /**
114
114
  * Thrown by the token-exchange and refresh paths when the resolved token
115
- * endpoint is not `https:` and is not a loopback host (SEP-2207). This is a
116
- * configuration error — re-authorizing cannot fix it — so it intentionally does
117
- * **not** extend `OAuthError` and `auth()`'s refresh branch rethrows it instead
118
- * of falling through to a fresh `/authorize` redirect.
115
+ * endpoint is not `https:` and is not a loopback host. The MCP authorization
116
+ * specification requires authorization server endpoints to use HTTPS; loopback
117
+ * hosts are exempt here for local development. This is a configuration error —
118
+ * re-authorizing cannot fix it — so it intentionally does **not** extend
119
+ * `OAuthError` and `auth()`'s refresh branch rethrows it instead of falling
120
+ * through to a fresh `/authorize` redirect.
119
121
  */
120
122
  var InsecureTokenEndpointError = class extends OAuthClientFlowError {
121
123
  static {
@@ -124,7 +126,7 @@ var InsecureTokenEndpointError = class extends OAuthClientFlowError {
124
126
  /** The token endpoint URL that was rejected. */
125
127
  tokenEndpoint;
126
128
  constructor(tokenEndpoint) {
127
- super(`Refusing to send credentials to non-https token endpoint '${tokenEndpoint}'. OAuth token requests MUST use TLS (localhost / 127.0.0.1 / ::1 are exempt).`);
129
+ super(`Refusing to send credentials to non-https token endpoint '${tokenEndpoint}'. OAuth token requests MUST use TLS (localhost / *.localhost / 127.0.0.1 / ::1 are exempt).`);
128
130
  this.tokenEndpoint = tokenEndpoint;
129
131
  }
130
132
  };
@@ -149,21 +151,25 @@ var InsecureTokenEndpointError = class extends OAuthClientFlowError {
149
151
  * `requiredScope`, which appears in the error message).
150
152
  */
151
153
  /**
152
- * Thrown by `auth()` on the authorization-code callback leg when the
153
- * authorization server resolved by discovery differs from the one recorded in
154
- * `discoveryState()` at redirect time. The `authorization_code` and PKCE
155
- * `code_verifier` are bound to the AS that minted the code (RFC 7636); sending
156
- * them to a different AS's token endpoint is a credential-exfiltration vector.
157
- *
158
- * This is the only runtime check left in the SEP-2352 model — stored tokens and
159
- * client credentials are protected structurally by the `issuer` stamp instead.
154
+ * Thrown by `auth()` and `fetchToken()` when the authorization server in use differs
155
+ * from the one a credential is bound to and the flow cannot simply start over:
156
+ *
157
+ * - on the authorization-code callback leg, when it differs from the one recorded
158
+ * in `discoveryState()` at redirect time — the `authorization_code` and PKCE
159
+ * `code_verifier` are bound to the AS that minted the code (RFC 7636);
160
+ * - for client information whose `issuer` stamp names a different authorization
161
+ * server on a provider that cannot re-register (no `saveClientInformation()`,
162
+ * e.g. the bundled static-credential providers); `fetchToken()` throws for any provider.
163
+ *
164
+ * Stored tokens and re-registrable client information are protected structurally
165
+ * by the `issuer` stamp instead (they read back as absent).
160
166
  */
161
167
  var AuthorizationServerMismatchError = class extends OAuthClientFlowError {
162
168
  static {
163
169
  Object.defineProperty(this, "mcpBrand", { value: "mcp.AuthorizationServerMismatchError" });
164
170
  }
165
171
  constructor(recordedIssuer, currentIssuer) {
166
- super(`Authorization server changed between redirect and callback (redirected to ${JSON.stringify(recordedIssuer)}, callback resolved ${JSON.stringify(currentIssuer)}); refusing to send authorization_code/code_verifier to a different token endpoint`);
172
+ super(`Authorization server mismatch: credentials are bound to ${JSON.stringify(recordedIssuer)} but this call resolved ${JSON.stringify(currentIssuer)}; refusing to present them to a different authorization server`);
167
173
  this.recordedIssuer = recordedIssuer;
168
174
  this.currentIssuer = currentIssuer;
169
175
  }
@@ -207,10 +213,13 @@ var InsufficientScopeError = class extends OAuthClientFlowError {
207
213
  * "binding on first use" claim would be false and would fire on every call.
208
214
  */
209
215
  function discardIfIssuerMismatch(stored, issuer, opts) {
210
- if (stored === void 0) return void 0;
211
- if (stored.issuer === void 0) {
216
+ if (!stored) return void 0;
217
+ if (typeof stored.issuer !== "string") {
212
218
  if (opts?.canPersistStamp !== false) console.warn("[mcp-sdk] SEP-2352: stored OAuth credential has no 'issuer' stamp (pre-upgrade storage or provider not round-tripping the value). SEP-2352 isolation is inactive for this read; ensure your provider round-trips the issuer field.");
213
- return stored;
219
+ return stored.issuer === void 0 ? stored : {
220
+ ...stored,
221
+ issuer: void 0
222
+ };
214
223
  }
215
224
  return issuersMatch(stored.issuer, issuer) ? stored : void 0;
216
225
  }
@@ -518,13 +527,19 @@ function applyPostAuth(clientId, clientSecret, params) {
518
527
  function applyPublicAuth(clientId, params) {
519
528
  params.set("client_id", clientId);
520
529
  }
521
- /** Loopback hosts exempt from the in-transit `https:` requirement (RFC 8252 §7.3). */
530
+ /**
531
+ * Loopback hosts exempt from the in-transit `https:` requirement (RFC 8252 §7.3).
532
+ * Includes bare `localhost` and any name ending in `.localhost` (RFC 6761 §6.3).
533
+ */
522
534
  function isLoopbackHost(hostname) {
523
- return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1";
535
+ return hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1";
524
536
  }
525
537
  /**
526
- * SEP-2207: refuse to send credentials to a non-TLS, non-loopback token endpoint.
527
- * Throws {@linkcode InsecureTokenEndpointError}. Loopback hosts are exempt.
538
+ * Refuse to send credentials to a non-TLS token endpoint. The MCP authorization
539
+ * specification requires authorization server endpoints to use HTTPS. Loopback
540
+ * hosts are exempt here for local development.
541
+ *
542
+ * @throws {@linkcode InsecureTokenEndpointError} if the endpoint is insecure.
528
543
  */
529
544
  function assertSecureTokenEndpoint(tokenEndpoint) {
530
545
  const url = new URL(String(tokenEndpoint));
@@ -1265,7 +1280,7 @@ async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequ
1265
1280
  if (!response.ok) throw await parseErrorResponse(response);
1266
1281
  const json = await response.json();
1267
1282
  try {
1268
- return OAuthTokensSchema.parse(json);
1283
+ return OAuthTokensSchema.parse(withoutIssuer(json));
1269
1284
  } catch (parseError) {
1270
1285
  if (typeof json === "object" && json !== null && "error" in json) throw await parseErrorResponse(JSON.stringify(json));
1271
1286
  throw parseError;
@@ -1361,6 +1376,14 @@ async function fetchToken(provider, authorizationServerUrl, { metadata, resource
1361
1376
  expectedIssuer: metadata?.issuer,
1362
1377
  issParameterSupported: isIssParameterSupported(metadata)
1363
1378
  });
1379
+ const issuer = metadata?.issuer ?? String(authorizationServerUrl);
1380
+ const readClientInformation = async () => {
1381
+ const rawClientInfo = await provider.clientInformation({ issuer });
1382
+ const checked = discardIfIssuerMismatch(rawClientInfo, issuer, { canPersistStamp: false });
1383
+ if (rawClientInfo && checked === void 0) throw new AuthorizationServerMismatchError(String(rawClientInfo.issuer), issuer);
1384
+ return checked;
1385
+ };
1386
+ let clientInformation = await readClientInformation();
1364
1387
  const effectiveScope = scope ?? provider.clientMetadata.scope;
1365
1388
  let tokenRequestParams;
1366
1389
  if (provider.prepareTokenRequest) tokenRequestParams = await provider.prepareTokenRequest(effectiveScope);
@@ -1369,11 +1392,11 @@ async function fetchToken(provider, authorizationServerUrl, { metadata, resource
1369
1392
  if (!provider.redirectUrl) throw new Error("redirectUrl is required for authorization_code flow");
1370
1393
  tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, await provider.codeVerifier(), provider.redirectUrl);
1371
1394
  }
1372
- const clientInformation = await provider.clientInformation({ issuer: metadata?.issuer ?? String(authorizationServerUrl) });
1395
+ clientInformation ??= await readClientInformation();
1373
1396
  return executeTokenRequest(authorizationServerUrl, {
1374
1397
  metadata,
1375
1398
  tokenRequestParams,
1376
- clientInformation: clientInformation ?? void 0,
1399
+ clientInformation,
1377
1400
  addClientAuthentication: provider.addClientAuthentication,
1378
1401
  resource,
1379
1402
  dpop: await provider.dpop?.(),
@@ -1389,10 +1412,17 @@ async function fetchToken(provider, authorizationServerUrl, { metadata, resource
1389
1412
  * consistently across both DCR and the subsequent authorization request.
1390
1413
  *
1391
1414
  * @deprecated Dynamic Client Registration is deprecated as of protocol version
1392
- * 2026-07-28 (SEP-2577) in favor of Client ID Metadata Documents (SEP-991).
1393
- * Remains functional during the deprecation window (at least twelve months).
1394
- * Prefer a CIMD URL `client_id` when the authorization server advertises
1395
- * `client_id_metadata_document_supported`; the SDK already gates on this for you.
1415
+ * 2026-07-28 in favor of Client ID Metadata Documents (SEP-991); the deprecation
1416
+ * landed via spec PR
1417
+ * {@link https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2858 | modelcontextprotocol#2858}
1418
+ * (SEP-2577 is the separate roots/sampling/logging deprecation). Remains
1419
+ * functional during the deprecation window — at least twelve months under the
1420
+ * feature lifecycle policy (SEP-2596), so 2027-07-28 is the earliest possible
1421
+ * removal date. Prefer a CIMD URL `client_id` when the authorization server
1422
+ * advertises `client_id_metadata_document_supported`: the built-in `auth()` flow
1423
+ * skips registration for you when that capability is advertised AND your
1424
+ * provider supplies `clientMetadataUrl`, but `registerClient` itself does not
1425
+ * gate — calling it directly always sends the registration request.
1396
1426
  */
1397
1427
  async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
1398
1428
  let registrationUrl;
@@ -1414,7 +1444,7 @@ async function registerClient(authorizationServerUrl, { metadata, clientMetadata
1414
1444
  body: await response.text(),
1415
1445
  submittedMetadata
1416
1446
  });
1417
- return OAuthClientInformationFullSchema.parse(await response.json());
1447
+ return OAuthClientInformationFullSchema.parse(withoutIssuer(await response.json()));
1418
1448
  }
1419
1449
 
1420
1450
  //#endregion
@@ -1469,6 +1499,15 @@ function createPrivateKeyJwtAuth(options) {
1469
1499
  };
1470
1500
  }
1471
1501
  /**
1502
+ * The `issuer` stamp for constructor-supplied client information. Omitting `expectedIssuer` is
1503
+ * deprecated: nothing else says which authorization server such credentials belong to.
1504
+ */
1505
+ function checkedExpectedIssuer(expectedIssuer) {
1506
+ if (expectedIssuer === void 0) console.warn("[mcp-sdk] Omitting `expectedIssuer` is deprecated. Without it, the MCP server decides which authorization server receives this client's credentials; pass your authorization server's issuer URL as `expectedIssuer` so they are only sent there.");
1507
+ else if (typeof expectedIssuer !== "string" || !expectedIssuer) throw new Error("expectedIssuer must be the authorization server's issuer URL");
1508
+ return expectedIssuer;
1509
+ }
1510
+ /**
1472
1511
  * OAuth provider for `client_credentials` grant with `client_secret_basic` authentication.
1473
1512
  *
1474
1513
  * This provider is designed for machine-to-machine authentication where
@@ -1478,7 +1517,8 @@ function createPrivateKeyJwtAuth(options) {
1478
1517
  * ```ts source="./authExtensions.examples.ts#ClientCredentialsProvider_basicUsage"
1479
1518
  * const provider = new ClientCredentialsProvider({
1480
1519
  * clientId: 'my-client',
1481
- * clientSecret: 'my-secret'
1520
+ * clientSecret: 'my-secret',
1521
+ * expectedIssuer: 'https://auth.example.com'
1482
1522
  * });
1483
1523
  *
1484
1524
  * const transport = new StreamableHTTPClientTransport(serverUrl, {
@@ -1494,7 +1534,7 @@ var ClientCredentialsProvider = class {
1494
1534
  this._clientInfo = {
1495
1535
  client_id: options.clientId,
1496
1536
  client_secret: options.clientSecret,
1497
- issuer: options.expectedIssuer
1537
+ issuer: checkedExpectedIssuer(options.expectedIssuer)
1498
1538
  };
1499
1539
  this._clientMetadata = {
1500
1540
  client_name: options.clientName ?? "client-credentials-client",
@@ -1542,7 +1582,8 @@ var ClientCredentialsProvider = class {
1542
1582
  * const provider = new PrivateKeyJwtProvider({
1543
1583
  * clientId: 'my-client',
1544
1584
  * privateKey: pemEncodedPrivateKey,
1545
- * algorithm: 'RS256'
1585
+ * algorithm: 'RS256',
1586
+ * expectedIssuer: 'https://auth.example.com'
1546
1587
  * });
1547
1588
  *
1548
1589
  * const transport = new StreamableHTTPClientTransport(serverUrl, {
@@ -1558,7 +1599,7 @@ var PrivateKeyJwtProvider = class {
1558
1599
  constructor(options) {
1559
1600
  this._clientInfo = {
1560
1601
  client_id: options.clientId,
1561
- issuer: options.expectedIssuer
1602
+ issuer: checkedExpectedIssuer(options.expectedIssuer)
1562
1603
  };
1563
1604
  this._clientMetadata = {
1564
1605
  client_name: options.clientName ?? "private-key-jwt-client",
@@ -1617,7 +1658,7 @@ var StaticPrivateKeyJwtProvider = class {
1617
1658
  constructor(options) {
1618
1659
  this._clientInfo = {
1619
1660
  client_id: options.clientId,
1620
- issuer: options.expectedIssuer
1661
+ issuer: checkedExpectedIssuer(options.expectedIssuer)
1621
1662
  };
1622
1663
  this._clientMetadata = {
1623
1664
  client_name: options.clientName ?? "static-private-key-jwt-client",
@@ -1689,7 +1730,8 @@ var StaticPrivateKeyJwtProvider = class {
1689
1730
  * return result.jwtAuthGrant;
1690
1731
  * },
1691
1732
  * clientId: 'my-mcp-client',
1692
- * clientSecret: 'my-mcp-secret'
1733
+ * clientSecret: 'my-mcp-secret',
1734
+ * expectedIssuer: 'https://auth.example.com'
1693
1735
  * });
1694
1736
  *
1695
1737
  * const transport = new StreamableHTTPClientTransport(serverUrl, {
@@ -1710,7 +1752,7 @@ var CrossAppAccessProvider = class {
1710
1752
  this._clientInfo = {
1711
1753
  client_id: options.clientId,
1712
1754
  client_secret: options.clientSecret,
1713
- issuer: options.expectedIssuer
1755
+ issuer: checkedExpectedIssuer(options.expectedIssuer)
1714
1756
  };
1715
1757
  this._clientMetadata = {
1716
1758
  client_name: options.clientName ?? "cross-app-access-client",
@@ -3632,7 +3674,7 @@ var Client = class extends Protocol {
3632
3674
  }, options);
3633
3675
  const hit = await this._serveFromCache("prompts/list", void 0, options);
3634
3676
  if (hit !== void 0) return hit;
3635
- return this._listAllPages("prompts/list", params, options, (acc, page) => acc.prompts.push(...page.prompts));
3677
+ return this._listAllPages("prompts/list", params, options, (r) => r.prompts);
3636
3678
  }
3637
3679
  /**
3638
3680
  * Lists available resources.
@@ -3671,7 +3713,7 @@ var Client = class extends Protocol {
3671
3713
  }, options);
3672
3714
  const hit = await this._serveFromCache("resources/list", void 0, options);
3673
3715
  if (hit !== void 0) return hit;
3674
- return this._listAllPages("resources/list", params, options, (acc, page) => acc.resources.push(...page.resources));
3716
+ return this._listAllPages("resources/list", params, options, (r) => r.resources);
3675
3717
  }
3676
3718
  /**
3677
3719
  * Lists available resource URI templates for dynamic resources.
@@ -3696,7 +3738,7 @@ var Client = class extends Protocol {
3696
3738
  }, options);
3697
3739
  const hit = await this._serveFromCache("resources/templates/list", void 0, options);
3698
3740
  if (hit !== void 0) return hit;
3699
- return this._listAllPages("resources/templates/list", params, options, (acc, page) => acc.resourceTemplates.push(...page.resourceTemplates));
3741
+ return this._listAllPages("resources/templates/list", params, options, (r) => r.resourceTemplates);
3700
3742
  }
3701
3743
  /**
3702
3744
  * Walk every page of a paginated list verb, aggregate, and write ONE
@@ -3704,8 +3746,7 @@ var Client = class extends Protocol {
3704
3746
  * methods' no-`cursor` auto-aggregate path. Page 1's result object is
3705
3747
  * mutated in place (its items array is extended; `nextCursor` is
3706
3748
  * cleared); page-1 metadata (`ttlMs`, `cacheScope`, `_meta`) is preserved.
3707
- * A `nextCursor` that repeats stops the walk (defence against a
3708
- * non-converging server, mcp.d's `drainList` guard);
3749
+ * A page with the same items and `nextCursor` as the previous page ends the walk;
3709
3750
  * {@linkcode ClientOptions.listMaxPages} is a hard cap — hitting it
3710
3751
  * throws, so a partial aggregate is never cached. The
3711
3752
  * captured-generation guard skips the write when a `list_changed` landed
@@ -3720,7 +3761,7 @@ var Client = class extends Protocol {
3720
3761
  * trace context) supplied to the public `list*()` reaches every wire
3721
3762
  * request the walk issues.
3722
3763
  */
3723
- async _listAllPages(method, baseParams, options, append, finalize) {
3764
+ async _listAllPages(method, baseParams, options, items, finalize) {
3724
3765
  const bypass = options?.cacheMode === "bypass";
3725
3766
  const generation = this._cache.captureGeneration(method);
3726
3767
  const acc = await this.request({
@@ -3728,14 +3769,13 @@ var Client = class extends Protocol {
3728
3769
  ...baseParams && { params: { ...baseParams } }
3729
3770
  }, options);
3730
3771
  let cursor = acc.nextCursor;
3731
- const seen = /* @__PURE__ */ new Set();
3772
+ let previous = acc;
3732
3773
  let pages = 1;
3733
- while (cursor !== void 0 && !seen.has(cursor)) {
3774
+ while (cursor !== void 0) {
3734
3775
  if (this._listMaxPages !== 0 && pages >= this._listMaxPages) throw new SdkError(SdkErrorCode.ListPaginationExceeded, `${method}: exceeded listMaxPages (${this._listMaxPages}); server pagination did not terminate`, {
3735
3776
  method,
3736
3777
  listMaxPages: this._listMaxPages
3737
3778
  });
3738
- seen.add(cursor);
3739
3779
  const page = await this.request({
3740
3780
  method,
3741
3781
  params: {
@@ -3743,7 +3783,9 @@ var Client = class extends Protocol {
3743
3783
  cursor
3744
3784
  }
3745
3785
  }, options);
3746
- append(acc, page);
3786
+ if (page.nextCursor === cursor && JSON.stringify(items(page)) === JSON.stringify(items(previous))) break;
3787
+ items(acc).push(...items(page));
3788
+ previous = page;
3747
3789
  cursor = page.nextCursor;
3748
3790
  pages++;
3749
3791
  }
@@ -4004,19 +4046,22 @@ var Client = class extends Protocol {
4004
4046
  notifications: filter
4005
4047
  }
4006
4048
  };
4049
+ const routeSendFailure = (error) => {
4050
+ settle({
4051
+ cause: "remote",
4052
+ error: error instanceof Error ? error : new Error(String(error))
4053
+ });
4054
+ };
4007
4055
  try {
4008
- await this.transport.send(jsonrpcRequest, {
4056
+ this.transport.send(jsonrpcRequest, {
4009
4057
  requestSignal: requestAbort.signal,
4010
4058
  onRequestStreamEnd: () => settle({
4011
4059
  cause: "remote",
4012
4060
  error: /* @__PURE__ */ new Error("subscriptions/listen: stream ended")
4013
4061
  })
4014
- });
4062
+ }).catch(routeSendFailure);
4015
4063
  } catch (error) {
4016
- settle({
4017
- cause: "remote",
4018
- error: error instanceof Error ? error : new Error(String(error))
4019
- });
4064
+ routeSendFailure(error);
4020
4065
  }
4021
4066
  return {
4022
4067
  honoredFilter: await opening,
@@ -4268,7 +4313,7 @@ var Client = class extends Protocol {
4268
4313
  }
4269
4314
  const hit = await this._serveFromCache("tools/list", void 0, options);
4270
4315
  if (hit !== void 0) return hit;
4271
- return this._listAllPages("tools/list", params, options, (acc, page) => acc.tools.push(...page.tools), (acc) => this._excludeInvalidXMcpHeaderTools(acc));
4316
+ return this._listAllPages("tools/list", params, options, (r) => r.tools, (acc) => this._excludeInvalidXMcpHeaderTools(acc));
4272
4317
  }
4273
4318
  /**
4274
4319
  * SEP-2243 (protocol revision 2026-07-28): a Streamable HTTP client MUST
@@ -4489,7 +4534,7 @@ async function exchangeJwtAuthGrant(options) {
4489
4534
  throw new Error(`JWT grant exchange failed with status ${response.status}: ${JSON.stringify(errorBody)}`);
4490
4535
  }
4491
4536
  const responseBody = await response.json();
4492
- const parseResult = OAuthTokensSchema.safeParse(responseBody);
4537
+ const parseResult = OAuthTokensSchema.safeParse(withoutIssuer(responseBody));
4493
4538
  if (!parseResult.success) throw new Error(`Invalid token response: ${parseResult.error.message}`);
4494
4539
  return parseResult.data;
4495
4540
  }