deadbyte-mcp 0.15.49 → 0.15.51

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 (99) hide show
  1. package/MANIFEST.SHA256 +88 -81
  2. package/PROVENANCE.json +17 -9
  3. package/README.txt +18 -18
  4. package/RELEASE.json +379 -368
  5. package/SBOM.cdx.json +9 -4
  6. package/TEST-MATRIX.json +17 -2
  7. package/docs/R130-SDK-SECURITY-PATCH.md +34 -0
  8. package/docs/R132-MANIFEST-PORTABILITY.md +23 -0
  9. package/node_modules/@modelcontextprotocol/client/README.md +1 -7
  10. package/node_modules/@modelcontextprotocol/client/dist/{index-BCtJi0p5.d.mts → index-B-4n9P0J.d.mts} +5 -1
  11. package/node_modules/@modelcontextprotocol/client/dist/index-B-4n9P0J.d.mts.map +1 -0
  12. package/node_modules/@modelcontextprotocol/client/dist/{index-CEk3qkZM.d.cts → index-J2FaQ-KY.d.cts} +5 -1
  13. package/node_modules/@modelcontextprotocol/client/dist/index-J2FaQ-KY.d.cts.map +1 -0
  14. package/node_modules/@modelcontextprotocol/client/dist/index.cjs +175 -76
  15. package/node_modules/@modelcontextprotocol/client/dist/index.cjs.map +1 -1
  16. package/node_modules/@modelcontextprotocol/client/dist/index.d.cts +214 -35
  17. package/node_modules/@modelcontextprotocol/client/dist/index.d.cts.map +1 -1
  18. package/node_modules/@modelcontextprotocol/client/dist/index.d.mts +214 -35
  19. package/node_modules/@modelcontextprotocol/client/dist/index.d.mts.map +1 -1
  20. package/node_modules/@modelcontextprotocol/client/dist/index.mjs +175 -76
  21. package/node_modules/@modelcontextprotocol/client/dist/index.mjs.map +1 -1
  22. package/node_modules/@modelcontextprotocol/client/dist/shimsWorkerd.cjs +1 -1
  23. package/node_modules/@modelcontextprotocol/client/dist/shimsWorkerd.mjs +1 -1
  24. package/node_modules/@modelcontextprotocol/client/dist/{src-D0qEN74R.cjs → src-DpAS0jfg.cjs} +125 -11
  25. package/node_modules/@modelcontextprotocol/client/dist/src-DpAS0jfg.cjs.map +1 -0
  26. package/node_modules/@modelcontextprotocol/client/dist/{src-DDAAhLnO.mjs → src-WCy6ifGf.mjs} +102 -12
  27. package/node_modules/@modelcontextprotocol/client/dist/src-WCy6ifGf.mjs.map +1 -0
  28. package/node_modules/@modelcontextprotocol/client/dist/stdio.cjs +1 -1
  29. package/node_modules/@modelcontextprotocol/client/dist/stdio.d.cts +1 -1
  30. package/node_modules/@modelcontextprotocol/client/dist/stdio.d.mts +1 -1
  31. package/node_modules/@modelcontextprotocol/client/dist/stdio.mjs +1 -1
  32. package/node_modules/@modelcontextprotocol/client/package.json +5 -5
  33. package/node_modules/@modelcontextprotocol/core/dist/{auth--n_Yzytt.d.cts → auth-Anm-lwWi.d.mts} +9 -8
  34. package/node_modules/@modelcontextprotocol/core/dist/{auth--n_Yzytt.d.cts.map → auth-Anm-lwWi.d.mts.map} +1 -1
  35. package/node_modules/@modelcontextprotocol/core/dist/{auth-CGP0BDVq.mjs → auth-BNDyLTqp.mjs} +5 -3
  36. package/node_modules/@modelcontextprotocol/core/dist/{auth-CGP0BDVq.mjs.map → auth-BNDyLTqp.mjs.map} +1 -1
  37. package/node_modules/@modelcontextprotocol/core/dist/{auth-4-zilcqg.cjs → auth-D1CeV_Jr.cjs} +5 -3
  38. package/node_modules/@modelcontextprotocol/core/dist/{auth-4-zilcqg.cjs.map → auth-D1CeV_Jr.cjs.map} +1 -1
  39. package/node_modules/@modelcontextprotocol/core/dist/{auth-YUQV3RRv.d.mts → auth-V9XJSCfa.d.cts} +9 -8
  40. package/node_modules/@modelcontextprotocol/core/dist/{auth-YUQV3RRv.d.mts.map → auth-V9XJSCfa.d.cts.map} +1 -1
  41. package/node_modules/@modelcontextprotocol/core/dist/index.cjs +1 -1
  42. package/node_modules/@modelcontextprotocol/core/dist/index.d.cts +1 -1
  43. package/node_modules/@modelcontextprotocol/core/dist/index.d.mts +1 -1
  44. package/node_modules/@modelcontextprotocol/core/dist/index.mjs +1 -1
  45. package/node_modules/@modelcontextprotocol/core/dist/internal.cjs +1 -1
  46. package/node_modules/@modelcontextprotocol/core/dist/internal.d.cts +1 -1
  47. package/node_modules/@modelcontextprotocol/core/dist/internal.d.mts +1 -1
  48. package/node_modules/@modelcontextprotocol/core/dist/internal.mjs +1 -1
  49. package/node_modules/@modelcontextprotocol/core/package.json +2 -2
  50. package/node_modules/@modelcontextprotocol/server/README.md +1 -7
  51. package/node_modules/@modelcontextprotocol/server/dist/{createMcpHandler-Bt6U_Fqb.d.mts → createMcpHandler-D4NN8WsG.d.mts} +35 -13
  52. package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-D4NN8WsG.d.mts.map +1 -0
  53. package/node_modules/@modelcontextprotocol/server/dist/{createMcpHandler-BLVe3qmU.d.cts → createMcpHandler-DZmmlN8e.d.cts} +35 -13
  54. package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-DZmmlN8e.d.cts.map +1 -0
  55. package/node_modules/@modelcontextprotocol/server/dist/index.cjs +32 -5
  56. package/node_modules/@modelcontextprotocol/server/dist/index.cjs.map +1 -1
  57. package/node_modules/@modelcontextprotocol/server/dist/index.d.cts +41 -5
  58. package/node_modules/@modelcontextprotocol/server/dist/index.d.cts.map +1 -1
  59. package/node_modules/@modelcontextprotocol/server/dist/index.d.mts +41 -5
  60. package/node_modules/@modelcontextprotocol/server/dist/index.d.mts.map +1 -1
  61. package/node_modules/@modelcontextprotocol/server/dist/index.mjs +32 -5
  62. package/node_modules/@modelcontextprotocol/server/dist/index.mjs.map +1 -1
  63. package/node_modules/@modelcontextprotocol/server/dist/{mcp-DUcCQSTW.cjs → mcp-BumlNux0.cjs} +73 -23
  64. package/node_modules/@modelcontextprotocol/server/dist/mcp-BumlNux0.cjs.map +1 -0
  65. package/node_modules/@modelcontextprotocol/server/dist/{mcp-Dw2OlZ1f.mjs → mcp-DIH4cS6P.mjs} +73 -23
  66. package/node_modules/@modelcontextprotocol/server/dist/mcp-DIH4cS6P.mjs.map +1 -0
  67. package/node_modules/@modelcontextprotocol/server/dist/shimsWorkerd.cjs +1 -1
  68. package/node_modules/@modelcontextprotocol/server/dist/shimsWorkerd.mjs +1 -1
  69. package/node_modules/@modelcontextprotocol/server/dist/{src-CgFsfg3E.cjs → src-BhnGYybN.cjs} +29 -11
  70. package/node_modules/@modelcontextprotocol/server/dist/src-BhnGYybN.cjs.map +1 -0
  71. package/node_modules/@modelcontextprotocol/server/dist/{src-D-y6h4N7.mjs → src-Cqbh3MYc.mjs} +29 -11
  72. package/node_modules/@modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs.map +1 -0
  73. package/node_modules/@modelcontextprotocol/server/dist/stdio.cjs +2 -2
  74. package/node_modules/@modelcontextprotocol/server/dist/stdio.d.cts +1 -1
  75. package/node_modules/@modelcontextprotocol/server/dist/stdio.d.mts +1 -1
  76. package/node_modules/@modelcontextprotocol/server/dist/stdio.mjs +2 -2
  77. package/node_modules/@modelcontextprotocol/server/package.json +4 -4
  78. package/node_modules/which/CHANGELOG.md +166 -0
  79. package/package.json +3 -3
  80. package/scripts/npm-prepublish-contract-r74.mjs +8 -2
  81. package/scripts/release-manifest.mjs +15 -1
  82. package/src/release-slot.mjs +13 -3
  83. package/src/version.mjs +1 -1
  84. package/test/r129-sdk-security-baseline.test.mjs +38 -0
  85. package/test/r130-release-security-contract.test.mjs +28 -0
  86. package/test/r131-installed-manifest-boundary.test.mjs +65 -0
  87. package/test/r132-release-identity.test.mjs +44 -0
  88. package/test/r59-tool-surface-compat.test.mjs +1 -1
  89. package/test/r74-prepublish-contract.test.mjs +5 -3
  90. package/node_modules/@modelcontextprotocol/client/dist/index-BCtJi0p5.d.mts.map +0 -1
  91. package/node_modules/@modelcontextprotocol/client/dist/index-CEk3qkZM.d.cts.map +0 -1
  92. package/node_modules/@modelcontextprotocol/client/dist/src-D0qEN74R.cjs.map +0 -1
  93. package/node_modules/@modelcontextprotocol/client/dist/src-DDAAhLnO.mjs.map +0 -1
  94. package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-BLVe3qmU.d.cts.map +0 -1
  95. package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-Bt6U_Fqb.d.mts.map +0 -1
  96. package/node_modules/@modelcontextprotocol/server/dist/mcp-DUcCQSTW.cjs.map +0 -1
  97. package/node_modules/@modelcontextprotocol/server/dist/mcp-Dw2OlZ1f.mjs.map +0 -1
  98. package/node_modules/@modelcontextprotocol/server/dist/src-CgFsfg3E.cjs.map +0 -1
  99. 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 ProtocolErrorCode, A as assertCompleteRequestPrompt, At as OAuthProtectedResourceMetadataSchema, B as isJSONRPCResultResponse, C as withInputRequired, Ct as checkResourceAllowed, D as buildMcpParamHeaders, Dt as OAuthClientInformationFullSchema, E as mcpNameSource, Et as IdJagTokenExchangeResponseSchema, F as isInputRequiredResult, Ft as SdkHttpError, G as ListChangedOptionsBaseSchema, H as parseJSONRPCMessage, I as isJSONRPCErrorResponse, It as OAuthError, J as MissingRequiredClientCapabilityError, K as MODERN_WIRE_REVISION, L as isJSONRPCNotification, Lt as OAuthErrorCode, M as isCallToolResult, Mt as OpenIdProviderDiscoveryMetadataSchema, N as isInitializeRequest, Nt as SdkError, O as encodeMcpParamValue, Ot as OAuthErrorResponseSchema, P as isInitializedNotification, Pt as SdkErrorCode, Q as UrlElicitationRequiredError, R as isJSONRPCRequest, Rt as brandedHasInstance, S as resolveInputRequiredDriverConfig, St as TRACESTATE_META_KEY, T as HEADER_MISMATCH_ERROR_CODE, Tt as withoutIssuer, U as DiscoverResultSchema, V as isTaskAugmentedRequestParams, W as JSONRPCMessageSchema, X as ResourceNotFoundError, Y as ProtocolError, Z as UnsupportedProtocolVersionError, _ as DEFAULT_REQUEST_TIMEOUT_MSEC, _t as RELATED_TASK_META_KEY, a as createFetchWithInit, at as CLIENT_CAPABILITIES_META_KEY, b as isSpecType, bt as SUPPORTED_PROTOCOL_VERSIONS, c as unfollowedRedirect, ct as INTERNAL_ERROR, d as deserializeMessage, dt as JSONRPC_VERSION, et as SUPPORTED_MODERN_PROTOCOL_VERSIONS, f as serializeMessage, ft as LATEST_PROTOCOL_VERSION, g as runInputRequiredFlow, gt as PROTOCOL_VERSION_META_KEY, h as mediaTypeEssence, ht as PARSE_ERROR, i as UriTemplate, it as BAGGAGE_META_KEY, j as assertCompleteRequestResourceTemplate, jt as OAuthTokensSchema, k as scanXMcpHeaderDeclarations, kt as OAuthMetadataSchema, l as ReadBuffer, lt as INVALID_PARAMS, m as isJsonContentType, mt as METHOD_NOT_FOUND, n as preloadSchemas, nt as legacyProtocolVersions, o as fetchLeavingRedirects, ot as CLIENT_INFO_META_KEY, p as getDisplayName, pt as LOG_LEVEL_META_KEY, q as codecForVersion, r as InMemoryTransport, rt as modernProtocolVersions, s as fetchWithinOrigin, st as DEFAULT_NEGOTIATED_PROTOCOL_VERSION, t as fromJsonSchema$1, tt as isModernProtocolVersion, u as STDIO_DEFAULT_MAX_BUFFER_SIZE, ut as INVALID_REQUEST, v as Protocol, vt as SERVER_INFO_META_KEY, w as parseSchema, wt as resourceUrlFromServerUrl, x as specTypeSchemas, xt as TRACEPARENT_META_KEY, y as mergeCapabilities, yt as SUBSCRIPTION_ID_META_KEY, z as isJSONRPCResponse, zt as stampErrorBrands } from "./src-WCy6ifGf.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));
@@ -974,12 +989,13 @@ async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn =
974
989
  * error object alone, so the swallow-and-fallthrough heuristic is preserved there.
975
990
  */
976
991
  async function fetchWithCorsRetry(url, headers, fetchFn = fetch) {
992
+ const withinOrigin = fetchWithinOrigin(fetchFn);
977
993
  try {
978
- return await fetchFn(url, { headers });
994
+ return await withinOrigin(url, { headers });
979
995
  } catch (error) {
980
996
  if (!(error instanceof TypeError) || !CORS_IS_POSSIBLE) throw error;
981
997
  if (headers) try {
982
- return await fetchFn(url, {});
998
+ return await withinOrigin(url, {});
983
999
  } catch (retryError) {
984
1000
  if (!(retryError instanceof TypeError)) throw retryError;
985
1001
  return;
@@ -1006,7 +1022,7 @@ async function tryMetadataDiscovery(url, protocolVersion, fetchFn = fetch) {
1006
1022
  function shouldAttemptFallback(response, pathname) {
1007
1023
  if (!response) return true;
1008
1024
  if (pathname === "/") return false;
1009
- return response.status >= 400 && response.status < 500 || response.status === 502;
1025
+ return !response.ok && response.status < 500 || response.status === 502;
1010
1026
  }
1011
1027
  /**
1012
1028
  * Generic function for discovering OAuth metadata with fallback support
@@ -1129,7 +1145,7 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fet
1129
1145
  continue;
1130
1146
  if (!response.ok) {
1131
1147
  await response.text?.().catch(() => {});
1132
- if (response.status >= 400 && response.status < 500 || response.status === 502) continue;
1148
+ if (response.status < 500 || response.status === 502) continue;
1133
1149
  throw new Error(`HTTP ${response.status} trying to load ${type === "oauth" ? "OAuth" : "OpenID provider"} metadata from ${endpointUrl}`);
1134
1150
  }
1135
1151
  const parsed = type === "oauth" ? OAuthMetadataSchema.parse(await response.json()) : OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
@@ -1248,7 +1264,7 @@ async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequ
1248
1264
  htm: "POST",
1249
1265
  htu: tokenUrl
1250
1266
  }));
1251
- return (fetchFn ?? fetch)(tokenUrl, {
1267
+ return fetchWithinOrigin(fetchFn ?? fetch)(tokenUrl, {
1252
1268
  method: "POST",
1253
1269
  headers: requestHeaders,
1254
1270
  body: tokenRequestParams
@@ -1265,7 +1281,7 @@ async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequ
1265
1281
  if (!response.ok) throw await parseErrorResponse(response);
1266
1282
  const json = await response.json();
1267
1283
  try {
1268
- return OAuthTokensSchema.parse(json);
1284
+ return OAuthTokensSchema.parse(withoutIssuer(json));
1269
1285
  } catch (parseError) {
1270
1286
  if (typeof json === "object" && json !== null && "error" in json) throw await parseErrorResponse(JSON.stringify(json));
1271
1287
  throw parseError;
@@ -1361,6 +1377,14 @@ async function fetchToken(provider, authorizationServerUrl, { metadata, resource
1361
1377
  expectedIssuer: metadata?.issuer,
1362
1378
  issParameterSupported: isIssParameterSupported(metadata)
1363
1379
  });
1380
+ const issuer = metadata?.issuer ?? String(authorizationServerUrl);
1381
+ const readClientInformation = async () => {
1382
+ const rawClientInfo = await provider.clientInformation({ issuer });
1383
+ const checked = discardIfIssuerMismatch(rawClientInfo, issuer, { canPersistStamp: false });
1384
+ if (rawClientInfo && checked === void 0) throw new AuthorizationServerMismatchError(String(rawClientInfo.issuer), issuer);
1385
+ return checked;
1386
+ };
1387
+ let clientInformation = await readClientInformation();
1364
1388
  const effectiveScope = scope ?? provider.clientMetadata.scope;
1365
1389
  let tokenRequestParams;
1366
1390
  if (provider.prepareTokenRequest) tokenRequestParams = await provider.prepareTokenRequest(effectiveScope);
@@ -1369,11 +1393,11 @@ async function fetchToken(provider, authorizationServerUrl, { metadata, resource
1369
1393
  if (!provider.redirectUrl) throw new Error("redirectUrl is required for authorization_code flow");
1370
1394
  tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, await provider.codeVerifier(), provider.redirectUrl);
1371
1395
  }
1372
- const clientInformation = await provider.clientInformation({ issuer: metadata?.issuer ?? String(authorizationServerUrl) });
1396
+ clientInformation ??= await readClientInformation();
1373
1397
  return executeTokenRequest(authorizationServerUrl, {
1374
1398
  metadata,
1375
1399
  tokenRequestParams,
1376
- clientInformation: clientInformation ?? void 0,
1400
+ clientInformation,
1377
1401
  addClientAuthentication: provider.addClientAuthentication,
1378
1402
  resource,
1379
1403
  dpop: await provider.dpop?.(),
@@ -1389,10 +1413,17 @@ async function fetchToken(provider, authorizationServerUrl, { metadata, resource
1389
1413
  * consistently across both DCR and the subsequent authorization request.
1390
1414
  *
1391
1415
  * @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.
1416
+ * 2026-07-28 in favor of Client ID Metadata Documents (SEP-991); the deprecation
1417
+ * landed via spec PR
1418
+ * {@link https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2858 | modelcontextprotocol#2858}
1419
+ * (SEP-2577 is the separate roots/sampling/logging deprecation). Remains
1420
+ * functional during the deprecation window — at least twelve months under the
1421
+ * feature lifecycle policy (SEP-2596), so 2027-07-28 is the earliest possible
1422
+ * removal date. Prefer a CIMD URL `client_id` when the authorization server
1423
+ * advertises `client_id_metadata_document_supported`: the built-in `auth()` flow
1424
+ * skips registration for you when that capability is advertised AND your
1425
+ * provider supplies `clientMetadataUrl`, but `registerClient` itself does not
1426
+ * gate — calling it directly always sends the registration request.
1396
1427
  */
1397
1428
  async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
1398
1429
  let registrationUrl;
@@ -1404,7 +1435,7 @@ async function registerClient(authorizationServerUrl, { metadata, clientMetadata
1404
1435
  ...clientMetadata,
1405
1436
  ...scope === void 0 ? {} : { scope }
1406
1437
  };
1407
- const response = await (fetchFn ?? fetch)(registrationUrl, {
1438
+ const response = await fetchWithinOrigin(fetchFn ?? fetch)(registrationUrl, {
1408
1439
  method: "POST",
1409
1440
  headers: { "Content-Type": "application/json" },
1410
1441
  body: JSON.stringify(submittedMetadata)
@@ -1414,7 +1445,7 @@ async function registerClient(authorizationServerUrl, { metadata, clientMetadata
1414
1445
  body: await response.text(),
1415
1446
  submittedMetadata
1416
1447
  });
1417
- return OAuthClientInformationFullSchema.parse(await response.json());
1448
+ return OAuthClientInformationFullSchema.parse(withoutIssuer(await response.json()));
1418
1449
  }
1419
1450
 
1420
1451
  //#endregion
@@ -1469,6 +1500,15 @@ function createPrivateKeyJwtAuth(options) {
1469
1500
  };
1470
1501
  }
1471
1502
  /**
1503
+ * The `issuer` stamp for constructor-supplied client information. Omitting `expectedIssuer` is
1504
+ * deprecated: nothing else says which authorization server such credentials belong to.
1505
+ */
1506
+ function checkedExpectedIssuer(expectedIssuer) {
1507
+ 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.");
1508
+ else if (typeof expectedIssuer !== "string" || !expectedIssuer) throw new Error("expectedIssuer must be the authorization server's issuer URL");
1509
+ return expectedIssuer;
1510
+ }
1511
+ /**
1472
1512
  * OAuth provider for `client_credentials` grant with `client_secret_basic` authentication.
1473
1513
  *
1474
1514
  * This provider is designed for machine-to-machine authentication where
@@ -1478,7 +1518,8 @@ function createPrivateKeyJwtAuth(options) {
1478
1518
  * ```ts source="./authExtensions.examples.ts#ClientCredentialsProvider_basicUsage"
1479
1519
  * const provider = new ClientCredentialsProvider({
1480
1520
  * clientId: 'my-client',
1481
- * clientSecret: 'my-secret'
1521
+ * clientSecret: 'my-secret',
1522
+ * expectedIssuer: 'https://auth.example.com'
1482
1523
  * });
1483
1524
  *
1484
1525
  * const transport = new StreamableHTTPClientTransport(serverUrl, {
@@ -1494,7 +1535,7 @@ var ClientCredentialsProvider = class {
1494
1535
  this._clientInfo = {
1495
1536
  client_id: options.clientId,
1496
1537
  client_secret: options.clientSecret,
1497
- issuer: options.expectedIssuer
1538
+ issuer: checkedExpectedIssuer(options.expectedIssuer)
1498
1539
  };
1499
1540
  this._clientMetadata = {
1500
1541
  client_name: options.clientName ?? "client-credentials-client",
@@ -1542,7 +1583,8 @@ var ClientCredentialsProvider = class {
1542
1583
  * const provider = new PrivateKeyJwtProvider({
1543
1584
  * clientId: 'my-client',
1544
1585
  * privateKey: pemEncodedPrivateKey,
1545
- * algorithm: 'RS256'
1586
+ * algorithm: 'RS256',
1587
+ * expectedIssuer: 'https://auth.example.com'
1546
1588
  * });
1547
1589
  *
1548
1590
  * const transport = new StreamableHTTPClientTransport(serverUrl, {
@@ -1558,7 +1600,7 @@ var PrivateKeyJwtProvider = class {
1558
1600
  constructor(options) {
1559
1601
  this._clientInfo = {
1560
1602
  client_id: options.clientId,
1561
- issuer: options.expectedIssuer
1603
+ issuer: checkedExpectedIssuer(options.expectedIssuer)
1562
1604
  };
1563
1605
  this._clientMetadata = {
1564
1606
  client_name: options.clientName ?? "private-key-jwt-client",
@@ -1617,7 +1659,7 @@ var StaticPrivateKeyJwtProvider = class {
1617
1659
  constructor(options) {
1618
1660
  this._clientInfo = {
1619
1661
  client_id: options.clientId,
1620
- issuer: options.expectedIssuer
1662
+ issuer: checkedExpectedIssuer(options.expectedIssuer)
1621
1663
  };
1622
1664
  this._clientMetadata = {
1623
1665
  client_name: options.clientName ?? "static-private-key-jwt-client",
@@ -1689,7 +1731,8 @@ var StaticPrivateKeyJwtProvider = class {
1689
1731
  * return result.jwtAuthGrant;
1690
1732
  * },
1691
1733
  * clientId: 'my-mcp-client',
1692
- * clientSecret: 'my-mcp-secret'
1734
+ * clientSecret: 'my-mcp-secret',
1735
+ * expectedIssuer: 'https://auth.example.com'
1693
1736
  * });
1694
1737
  *
1695
1738
  * const transport = new StreamableHTTPClientTransport(serverUrl, {
@@ -1710,7 +1753,7 @@ var CrossAppAccessProvider = class {
1710
1753
  this._clientInfo = {
1711
1754
  client_id: options.clientId,
1712
1755
  client_secret: options.clientSecret,
1713
- issuer: options.expectedIssuer
1756
+ issuer: checkedExpectedIssuer(options.expectedIssuer)
1714
1757
  };
1715
1758
  this._clientMetadata = {
1716
1759
  client_name: options.clientName ?? "cross-app-access-client",
@@ -2373,6 +2416,10 @@ function classifyProbeOutcome(outcome, context) {
2373
2416
  case "rpc-error": return classifyRpcError(outcome, context);
2374
2417
  case "http-error": return classifyHttpError(outcome, context);
2375
2418
  case "network-error": return classifyNetworkError(outcome.error, context);
2419
+ case "unusable-reply": return {
2420
+ kind: "error",
2421
+ error: new SdkError(SdkErrorCode.EraNegotiationFailed, `Version negotiation probe failed: the server answered with an unusable reply (${describeError(outcome.error)})`, { cause: outcome.error }, { cause: outcome.error })
2422
+ };
2376
2423
  case "auth-required": return {
2377
2424
  kind: "error",
2378
2425
  error: outcome.error
@@ -2710,6 +2757,11 @@ function buildProbeRequest(id, protocolVersion, clientInfo, capabilities) {
2710
2757
  }) }
2711
2758
  };
2712
2759
  }
2760
+ /** True for what the transport throws when the probe was answered 2xx without a usable reply. */
2761
+ function isUnusableReplyError(error) {
2762
+ if (error instanceof SdkError && error.code === SdkErrorCode.ClientHttpUnexpectedContent) return true;
2763
+ return error instanceof Error && error.name === "SyntaxError";
2764
+ }
2713
2765
  function normalizeReply(reply, timeoutMs) {
2714
2766
  switch (reply.kind) {
2715
2767
  case "response": return reply.error === void 0 ? {
@@ -2734,6 +2786,10 @@ function normalizeReply(reply, timeoutMs) {
2734
2786
  statusText: error.data.statusText
2735
2787
  };
2736
2788
  }
2789
+ if (isUnusableReplyError(error)) return {
2790
+ kind: "unusable-reply",
2791
+ error
2792
+ };
2737
2793
  return {
2738
2794
  kind: "network-error",
2739
2795
  error
@@ -3632,7 +3688,7 @@ var Client = class extends Protocol {
3632
3688
  }, options);
3633
3689
  const hit = await this._serveFromCache("prompts/list", void 0, options);
3634
3690
  if (hit !== void 0) return hit;
3635
- return this._listAllPages("prompts/list", params, options, (acc, page) => acc.prompts.push(...page.prompts));
3691
+ return this._listAllPages("prompts/list", params, options, (r) => r.prompts);
3636
3692
  }
3637
3693
  /**
3638
3694
  * Lists available resources.
@@ -3671,7 +3727,7 @@ var Client = class extends Protocol {
3671
3727
  }, options);
3672
3728
  const hit = await this._serveFromCache("resources/list", void 0, options);
3673
3729
  if (hit !== void 0) return hit;
3674
- return this._listAllPages("resources/list", params, options, (acc, page) => acc.resources.push(...page.resources));
3730
+ return this._listAllPages("resources/list", params, options, (r) => r.resources);
3675
3731
  }
3676
3732
  /**
3677
3733
  * Lists available resource URI templates for dynamic resources.
@@ -3696,7 +3752,7 @@ var Client = class extends Protocol {
3696
3752
  }, options);
3697
3753
  const hit = await this._serveFromCache("resources/templates/list", void 0, options);
3698
3754
  if (hit !== void 0) return hit;
3699
- return this._listAllPages("resources/templates/list", params, options, (acc, page) => acc.resourceTemplates.push(...page.resourceTemplates));
3755
+ return this._listAllPages("resources/templates/list", params, options, (r) => r.resourceTemplates);
3700
3756
  }
3701
3757
  /**
3702
3758
  * Walk every page of a paginated list verb, aggregate, and write ONE
@@ -3704,8 +3760,7 @@ var Client = class extends Protocol {
3704
3760
  * methods' no-`cursor` auto-aggregate path. Page 1's result object is
3705
3761
  * mutated in place (its items array is extended; `nextCursor` is
3706
3762
  * 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);
3763
+ * A page with the same items and `nextCursor` as the previous page ends the walk;
3709
3764
  * {@linkcode ClientOptions.listMaxPages} is a hard cap — hitting it
3710
3765
  * throws, so a partial aggregate is never cached. The
3711
3766
  * captured-generation guard skips the write when a `list_changed` landed
@@ -3720,7 +3775,7 @@ var Client = class extends Protocol {
3720
3775
  * trace context) supplied to the public `list*()` reaches every wire
3721
3776
  * request the walk issues.
3722
3777
  */
3723
- async _listAllPages(method, baseParams, options, append, finalize) {
3778
+ async _listAllPages(method, baseParams, options, items, finalize) {
3724
3779
  const bypass = options?.cacheMode === "bypass";
3725
3780
  const generation = this._cache.captureGeneration(method);
3726
3781
  const acc = await this.request({
@@ -3728,14 +3783,13 @@ var Client = class extends Protocol {
3728
3783
  ...baseParams && { params: { ...baseParams } }
3729
3784
  }, options);
3730
3785
  let cursor = acc.nextCursor;
3731
- const seen = /* @__PURE__ */ new Set();
3786
+ let previous = acc;
3732
3787
  let pages = 1;
3733
- while (cursor !== void 0 && !seen.has(cursor)) {
3788
+ while (cursor !== void 0) {
3734
3789
  if (this._listMaxPages !== 0 && pages >= this._listMaxPages) throw new SdkError(SdkErrorCode.ListPaginationExceeded, `${method}: exceeded listMaxPages (${this._listMaxPages}); server pagination did not terminate`, {
3735
3790
  method,
3736
3791
  listMaxPages: this._listMaxPages
3737
3792
  });
3738
- seen.add(cursor);
3739
3793
  const page = await this.request({
3740
3794
  method,
3741
3795
  params: {
@@ -3743,7 +3797,9 @@ var Client = class extends Protocol {
3743
3797
  cursor
3744
3798
  }
3745
3799
  }, options);
3746
- append(acc, page);
3800
+ if (page.nextCursor === cursor && JSON.stringify(items(page)) === JSON.stringify(items(previous))) break;
3801
+ items(acc).push(...items(page));
3802
+ previous = page;
3747
3803
  cursor = page.nextCursor;
3748
3804
  pages++;
3749
3805
  }
@@ -4004,19 +4060,22 @@ var Client = class extends Protocol {
4004
4060
  notifications: filter
4005
4061
  }
4006
4062
  };
4063
+ const routeSendFailure = (error) => {
4064
+ settle({
4065
+ cause: "remote",
4066
+ error: error instanceof Error ? error : new Error(String(error))
4067
+ });
4068
+ };
4007
4069
  try {
4008
- await this.transport.send(jsonrpcRequest, {
4070
+ this.transport.send(jsonrpcRequest, {
4009
4071
  requestSignal: requestAbort.signal,
4010
4072
  onRequestStreamEnd: () => settle({
4011
4073
  cause: "remote",
4012
4074
  error: /* @__PURE__ */ new Error("subscriptions/listen: stream ended")
4013
4075
  })
4014
- });
4076
+ }).catch(routeSendFailure);
4015
4077
  } catch (error) {
4016
- settle({
4017
- cause: "remote",
4018
- error: error instanceof Error ? error : new Error(String(error))
4019
- });
4078
+ routeSendFailure(error);
4020
4079
  }
4021
4080
  return {
4022
4081
  honoredFilter: await opening,
@@ -4268,7 +4327,7 @@ var Client = class extends Protocol {
4268
4327
  }
4269
4328
  const hit = await this._serveFromCache("tools/list", void 0, options);
4270
4329
  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));
4330
+ return this._listAllPages("tools/list", params, options, (r) => r.tools, (acc) => this._excludeInvalidXMcpHeaderTools(acc));
4272
4331
  }
4273
4332
  /**
4274
4333
  * SEP-2243 (protocol revision 2026-07-28): a Streamable HTTP client MUST
@@ -4381,7 +4440,7 @@ async function requestJwtAuthorizationGrant(options) {
4381
4440
  });
4382
4441
  if (clientSecret) params.set("client_secret", clientSecret);
4383
4442
  if (scope) params.set("scope", scope);
4384
- const response = await fetchFn(tokenUrl, {
4443
+ const response = await fetchWithinOrigin(fetchFn)(tokenUrl, {
4385
4444
  method: "POST",
4386
4445
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
4387
4446
  body: params.toString()
@@ -4474,7 +4533,7 @@ async function exchangeJwtAuthGrant(options) {
4474
4533
  client_id: clientId,
4475
4534
  client_secret: clientSecret
4476
4535
  }, headers, params);
4477
- const response = await fetchFn(tokenUrl, {
4536
+ const response = await fetchWithinOrigin(fetchFn)(tokenUrl, {
4478
4537
  method: "POST",
4479
4538
  headers,
4480
4539
  body: params.toString()
@@ -4489,7 +4548,7 @@ async function exchangeJwtAuthGrant(options) {
4489
4548
  throw new Error(`JWT grant exchange failed with status ${response.status}: ${JSON.stringify(errorBody)}`);
4490
4549
  }
4491
4550
  const responseBody = await response.json();
4492
- const parseResult = OAuthTokensSchema.safeParse(responseBody);
4551
+ const parseResult = OAuthTokensSchema.safeParse(withoutIssuer(responseBody));
4493
4552
  if (!parseResult.success) throw new Error(`Invalid token response: ${parseResult.error.message}`);
4494
4553
  return parseResult.data;
4495
4554
  }
@@ -4994,6 +5053,7 @@ var SSEClientTransport = class {
4994
5053
  _skipIssuerMetadataValidation;
4995
5054
  _fetch;
4996
5055
  _fetchWithInit;
5056
+ _redirectPolicy;
4997
5057
  _dpop;
4998
5058
  _protocolVersion;
4999
5059
  onclose;
@@ -5015,9 +5075,21 @@ var SSEClientTransport = class {
5015
5075
  this._fetch = this._dpop(opts.fetch ?? fetch);
5016
5076
  }
5017
5077
  } else this._authProvider = opts?.authProvider;
5078
+ this._redirectPolicy = opts?.redirectPolicy;
5018
5079
  this._fetchWithInit = createFetchWithInit(opts?.fetch, opts?.requestInit);
5080
+ if (this._redirectPolicy === "follow") this._fetchWithInit = fetchLeavingRedirects(this._fetchWithInit);
5019
5081
  }
5020
5082
  _last401Response;
5083
+ _connectAuthRetried = false;
5084
+ /** `baseFetch` with redirects handled as `redirectPolicy` says. */
5085
+ _redirects(baseFetch) {
5086
+ return this._redirectPolicy === "follow" ? baseFetch : fetchWithinOrigin(baseFetch);
5087
+ }
5088
+ /** Error text for a redirect `response` that was not followed, or `undefined` for any other response. */
5089
+ _unfollowedRedirect(url, response) {
5090
+ const text = this._redirectPolicy === "follow" ? void 0 : unfollowedRedirect(url, response);
5091
+ return text && `${text} (redirectPolicy: 'same-origin')`;
5092
+ }
5021
5093
  async _commonHeaders() {
5022
5094
  const headers = new Headers(this._requestInit?.headers || void 0);
5023
5095
  let token;
@@ -5032,7 +5104,8 @@ var SSEClientTransport = class {
5032
5104
  }
5033
5105
  _startOrAuth() {
5034
5106
  const eventSourceFetch = this._eventSourceInit?.fetch;
5035
- const fetchImpl = eventSourceFetch ? this._dpop?.(eventSourceFetch) ?? eventSourceFetch : this._fetch ?? fetch;
5107
+ const fetchImpl = this._redirects(eventSourceFetch ? this._dpop?.(eventSourceFetch) ?? eventSourceFetch : this._fetch ?? fetch);
5108
+ let redirect;
5036
5109
  return new Promise((resolve, reject) => {
5037
5110
  this._eventSource = new EventSource(this._url.href, {
5038
5111
  ...this._eventSourceInit,
@@ -5043,6 +5116,7 @@ var SSEClientTransport = class {
5043
5116
  ...init,
5044
5117
  headers
5045
5118
  });
5119
+ redirect = this._unfollowedRedirect(url, response);
5046
5120
  if (response.status === 401) {
5047
5121
  this._last401Response = response;
5048
5122
  if (response.headers.has("www-authenticate")) {
@@ -5057,31 +5131,42 @@ var SSEClientTransport = class {
5057
5131
  this._abortController = new AbortController();
5058
5132
  this._eventSource.onerror = (event) => {
5059
5133
  if (event.code === 401 && this._authProvider) {
5060
- if (this._authProvider.onUnauthorized && this._last401Response) {
5134
+ if (this._authProvider.onUnauthorized && this._last401Response && !this._connectAuthRetried) {
5061
5135
  const response = this._last401Response;
5062
5136
  this._last401Response = void 0;
5137
+ this._connectAuthRetried = true;
5063
5138
  this._eventSource?.close();
5064
5139
  this._authProvider.onUnauthorized({
5065
5140
  response,
5066
5141
  serverUrl: this._url,
5067
5142
  fetchFn: this._fetchWithInit
5068
5143
  }).then(() => this._startOrAuth().then(resolve, reject), (error$2) => {
5144
+ this._connectAuthRetried = false;
5069
5145
  markAuthSeamEscape(error$2);
5070
5146
  this.onerror?.(error$2);
5071
5147
  reject(error$2);
5072
5148
  });
5073
5149
  return;
5074
5150
  }
5075
- const error$1 = markAuthSeamEscape(new UnauthorizedError());
5151
+ const retried = this._connectAuthRetried;
5152
+ this._connectAuthRetried = false;
5153
+ const error$1 = markAuthSeamEscape(retried ? new SdkHttpError(SdkErrorCode.ClientHttpAuthentication, "Server returned 401 after re-authentication", {
5154
+ status: 401,
5155
+ statusText: this._last401Response?.statusText ?? ""
5156
+ }) : new UnauthorizedError());
5157
+ this._last401Response = void 0;
5076
5158
  reject(error$1);
5077
5159
  this.onerror?.(error$1);
5078
5160
  return;
5079
5161
  }
5080
- const error = new SseError(event.code, event.message, event);
5162
+ this._connectAuthRetried = false;
5163
+ const error = new SseError(event.code, redirect ?? event.message, event);
5081
5164
  reject(error);
5082
5165
  this.onerror?.(error);
5083
5166
  };
5084
- this._eventSource.onopen = () => {};
5167
+ this._eventSource.onopen = () => {
5168
+ this._connectAuthRetried = false;
5169
+ };
5085
5170
  this._eventSource.addEventListener("endpoint", (event) => {
5086
5171
  const messageEvent = event;
5087
5172
  try {
@@ -5148,7 +5233,7 @@ var SSEClientTransport = class {
5148
5233
  body: JSON.stringify(message),
5149
5234
  signal: this._abortController?.signal
5150
5235
  };
5151
- const response = await (this._fetch ?? fetch)(this._endpoint, init);
5236
+ const response = await this._redirects(this._fetch ?? fetch)(this._endpoint, init);
5152
5237
  if (!response.ok) {
5153
5238
  if (response.status === 401 && this._authProvider) {
5154
5239
  if (response.headers.has("www-authenticate")) {
@@ -5177,7 +5262,7 @@ var SSEClientTransport = class {
5177
5262
  throw markAuthSeamEscape(new UnauthorizedError());
5178
5263
  }
5179
5264
  const text = await response.text?.().catch(() => null);
5180
- throw new Error(`Error POSTing to endpoint (HTTP ${response.status}): ${text}`);
5265
+ throw new Error(`Error POSTing to endpoint (HTTP ${response.status}): ${this._unfollowedRedirect(this._endpoint, response) ?? text}`);
5181
5266
  }
5182
5267
  await response.text?.().catch(() => {});
5183
5268
  } catch (error) {
@@ -5262,6 +5347,7 @@ var StreamableHTTPClientTransport = class {
5262
5347
  _skipIssuerMetadataValidation;
5263
5348
  _fetch;
5264
5349
  _fetchWithInit;
5350
+ _redirectPolicy;
5265
5351
  _sessionId;
5266
5352
  _reconnectionOptions;
5267
5353
  _protocolVersion;
@@ -5292,7 +5378,9 @@ var StreamableHTTPClientTransport = class {
5292
5378
  this._authProvider = adaptOAuthProvider(opts.authProvider, { skipIssuerMetadataValidation: opts.skipIssuerMetadataValidation });
5293
5379
  if (opts.authProvider.dpop) this._fetch = withDpopFromProvider(opts.authProvider)(opts.fetch ?? fetch);
5294
5380
  } else this._authProvider = opts?.authProvider;
5381
+ this._redirectPolicy = opts?.redirectPolicy;
5295
5382
  this._fetchWithInit = createFetchWithInit(opts?.fetch, opts?.requestInit);
5383
+ if (this._redirectPolicy === "follow") this._fetchWithInit = fetchLeavingRedirects(this._fetchWithInit);
5296
5384
  this._sessionId = opts?.sessionId;
5297
5385
  this._protocolVersion = opts?.protocolVersion;
5298
5386
  this._reconnectionOptions = opts?.reconnectionOptions ?? DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS;
@@ -5344,6 +5432,15 @@ var StreamableHTTPClientTransport = class {
5344
5432
  skipIssuerMetadataValidation: this._skipIssuerMetadataValidation
5345
5433
  });
5346
5434
  }
5435
+ /** `baseFetch` with redirects handled as `redirectPolicy` says. */
5436
+ _redirects(baseFetch) {
5437
+ return this._redirectPolicy === "follow" ? baseFetch : fetchWithinOrigin(baseFetch);
5438
+ }
5439
+ /** Error text for a redirect `response` that was not followed, or `undefined` for any other response. */
5440
+ _unfollowedRedirect(url, response) {
5441
+ const text = this._redirectPolicy === "follow" ? void 0 : unfollowedRedirect(url, response);
5442
+ return text && `${text} (redirectPolicy: 'same-origin')`;
5443
+ }
5347
5444
  async _commonHeaders() {
5348
5445
  const headers = new Headers(this._requestInit?.headers || void 0);
5349
5446
  let token;
@@ -5395,7 +5492,7 @@ var StreamableHTTPClientTransport = class {
5395
5492
  if (resumptionToken) headers.set("last-event-id", resumptionToken);
5396
5493
  const transportSignal = this._abortController?.signal;
5397
5494
  const signal = requestSignal !== void 0 && transportSignal !== void 0 ? anySignal(transportSignal, requestSignal) : requestSignal ?? transportSignal;
5398
- const response = await (this._fetch ?? fetch)(this._url, {
5495
+ const response = await this._redirects(this._fetch ?? fetch)(this._url, {
5399
5496
  ...this._requestInit,
5400
5497
  method: "GET",
5401
5498
  headers,
@@ -5447,7 +5544,8 @@ var StreamableHTTPClientTransport = class {
5447
5544
  options.onRequestStreamEnd?.();
5448
5545
  return;
5449
5546
  }
5450
- throw new SdkHttpError(SdkErrorCode.ClientHttpFailedToOpenStream, `Failed to open SSE stream: ${response.statusText}`, {
5547
+ const reason = this._unfollowedRedirect(this._url, response) ?? response.statusText;
5548
+ throw new SdkHttpError(SdkErrorCode.ClientHttpFailedToOpenStream, `Failed to open SSE stream: ${reason}`, {
5451
5549
  status: response.status,
5452
5550
  statusText: response.statusText
5453
5551
  });
@@ -5636,7 +5734,7 @@ var StreamableHTTPClientTransport = class {
5636
5734
  body: JSON.stringify(message),
5637
5735
  signal
5638
5736
  };
5639
- const response = await (this._fetch ?? fetch)(this._url, init);
5737
+ const response = await this._redirects(this._fetch ?? fetch)(this._url, init);
5640
5738
  if (isHandshake && response.ok) this._sessionId = response.headers.get("mcp-session-id") || void 0;
5641
5739
  if (!response.ok) {
5642
5740
  if (response.status === 401 && this._authProvider) {
@@ -5687,7 +5785,8 @@ var StreamableHTTPClientTransport = class {
5687
5785
  return;
5688
5786
  }
5689
5787
  } catch {}
5690
- throw new SdkHttpError(SdkErrorCode.ClientHttpNotImplemented, `Error POSTing to endpoint: ${text}`, {
5788
+ const reason = this._unfollowedRedirect(this._url, response) ?? text;
5789
+ throw new SdkHttpError(SdkErrorCode.ClientHttpNotImplemented, `Error POSTing to endpoint: ${reason}`, {
5691
5790
  status: response.status,
5692
5791
  statusText: response.statusText,
5693
5792
  text
@@ -5744,9 +5843,9 @@ var StreamableHTTPClientTransport = class {
5744
5843
  headers,
5745
5844
  signal: this._abortController?.signal
5746
5845
  };
5747
- const response = await (this._fetch ?? fetch)(this._url, init);
5846
+ const response = await this._redirects(this._fetch ?? fetch)(this._url, init);
5748
5847
  await response.text?.().catch(() => {});
5749
- if (!response.ok && response.status !== 405) throw new SdkHttpError(SdkErrorCode.ClientHttpFailedToTerminateSession, `Failed to terminate session: ${response.statusText}`, {
5848
+ if (!response.ok && response.status !== 405) throw new SdkHttpError(SdkErrorCode.ClientHttpFailedToTerminateSession, `Failed to terminate session: ${this._unfollowedRedirect(this._url, response) ?? response.statusText}`, {
5750
5849
  status: response.status,
5751
5850
  statusText: response.statusText
5752
5851
  });