deadbyte-mcp 0.15.48 → 0.15.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MANIFEST.SHA256 +121 -91
- package/PROVENANCE.json +11 -22
- package/README.txt +18 -18
- package/RELEASE.json +368 -378
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +2 -2
- package/bench/r121-epoch-readhead.mjs +54 -0
- package/bench/r124-epoch-predecessor.mjs +53 -0
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/HARNESS2-ADAPTATION-20261020.md +24 -0
- package/docs/R128-RELEASE-CANDIDATE.md +26 -0
- package/docs/R130-SDK-SECURITY-PATCH.md +34 -0
- package/node_modules/@modelcontextprotocol/client/README.md +1 -7
- package/node_modules/@modelcontextprotocol/client/dist/{index-BCtJi0p5.d.mts → index-B-4n9P0J.d.mts} +5 -1
- package/node_modules/@modelcontextprotocol/client/dist/index-B-4n9P0J.d.mts.map +1 -0
- package/node_modules/@modelcontextprotocol/client/dist/{index-CEk3qkZM.d.cts → index-J2FaQ-KY.d.cts} +5 -1
- package/node_modules/@modelcontextprotocol/client/dist/index-J2FaQ-KY.d.cts.map +1 -0
- package/node_modules/@modelcontextprotocol/client/dist/index.cjs +175 -76
- package/node_modules/@modelcontextprotocol/client/dist/index.cjs.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/index.d.cts +214 -35
- package/node_modules/@modelcontextprotocol/client/dist/index.d.cts.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/index.d.mts +214 -35
- package/node_modules/@modelcontextprotocol/client/dist/index.d.mts.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/index.mjs +175 -76
- package/node_modules/@modelcontextprotocol/client/dist/index.mjs.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/shimsWorkerd.cjs +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/shimsWorkerd.mjs +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/{src-D0qEN74R.cjs → src-DpAS0jfg.cjs} +125 -11
- package/node_modules/@modelcontextprotocol/client/dist/src-DpAS0jfg.cjs.map +1 -0
- package/node_modules/@modelcontextprotocol/client/dist/{src-DDAAhLnO.mjs → src-WCy6ifGf.mjs} +102 -12
- package/node_modules/@modelcontextprotocol/client/dist/src-WCy6ifGf.mjs.map +1 -0
- package/node_modules/@modelcontextprotocol/client/dist/stdio.cjs +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/stdio.d.cts +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/stdio.d.mts +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/stdio.mjs +1 -1
- package/node_modules/@modelcontextprotocol/client/package.json +5 -5
- package/node_modules/@modelcontextprotocol/core/dist/{auth--n_Yzytt.d.cts → auth-Anm-lwWi.d.mts} +9 -8
- package/node_modules/@modelcontextprotocol/core/dist/{auth--n_Yzytt.d.cts.map → auth-Anm-lwWi.d.mts.map} +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/{auth-CGP0BDVq.mjs → auth-BNDyLTqp.mjs} +5 -3
- package/node_modules/@modelcontextprotocol/core/dist/{auth-CGP0BDVq.mjs.map → auth-BNDyLTqp.mjs.map} +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/{auth-4-zilcqg.cjs → auth-D1CeV_Jr.cjs} +5 -3
- package/node_modules/@modelcontextprotocol/core/dist/{auth-4-zilcqg.cjs.map → auth-D1CeV_Jr.cjs.map} +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/{auth-YUQV3RRv.d.mts → auth-V9XJSCfa.d.cts} +9 -8
- package/node_modules/@modelcontextprotocol/core/dist/{auth-YUQV3RRv.d.mts.map → auth-V9XJSCfa.d.cts.map} +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/index.cjs +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/index.d.cts +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/index.d.mts +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/index.mjs +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/internal.cjs +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/internal.d.cts +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/internal.d.mts +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/internal.mjs +1 -1
- package/node_modules/@modelcontextprotocol/core/package.json +2 -2
- package/node_modules/@modelcontextprotocol/server/README.md +1 -7
- package/node_modules/@modelcontextprotocol/server/dist/{createMcpHandler-Bt6U_Fqb.d.mts → createMcpHandler-D4NN8WsG.d.mts} +35 -13
- package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-D4NN8WsG.d.mts.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/{createMcpHandler-BLVe3qmU.d.cts → createMcpHandler-DZmmlN8e.d.cts} +35 -13
- package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-DZmmlN8e.d.cts.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/index.cjs +32 -5
- package/node_modules/@modelcontextprotocol/server/dist/index.cjs.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/index.d.cts +41 -5
- package/node_modules/@modelcontextprotocol/server/dist/index.d.cts.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/index.d.mts +41 -5
- package/node_modules/@modelcontextprotocol/server/dist/index.d.mts.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/index.mjs +32 -5
- package/node_modules/@modelcontextprotocol/server/dist/index.mjs.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/{mcp-DUcCQSTW.cjs → mcp-BumlNux0.cjs} +73 -23
- package/node_modules/@modelcontextprotocol/server/dist/mcp-BumlNux0.cjs.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/{mcp-Dw2OlZ1f.mjs → mcp-DIH4cS6P.mjs} +73 -23
- package/node_modules/@modelcontextprotocol/server/dist/mcp-DIH4cS6P.mjs.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/shimsWorkerd.cjs +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/shimsWorkerd.mjs +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/{src-CgFsfg3E.cjs → src-BhnGYybN.cjs} +29 -11
- package/node_modules/@modelcontextprotocol/server/dist/src-BhnGYybN.cjs.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/{src-D-y6h4N7.mjs → src-Cqbh3MYc.mjs} +29 -11
- package/node_modules/@modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/stdio.cjs +2 -2
- package/node_modules/@modelcontextprotocol/server/dist/stdio.d.cts +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/stdio.d.mts +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/stdio.mjs +2 -2
- package/node_modules/@modelcontextprotocol/server/package.json +4 -4
- package/node_modules/which/CHANGELOG.md +166 -0
- package/package.json +3 -3
- package/scripts/npm-release-r48.mjs +0 -4
- package/scripts/verify-authority-epoch-history.mjs +38 -0
- package/src/activation-continuity-engine-r65.mjs +9 -15
- package/src/agent-eval-r42.mjs +30 -0
- package/src/authority-continuity-r65.mjs +182 -13
- package/src/autonomous-local-supervisor.mjs +77 -47
- package/src/deadbyte-cli.mjs +18 -28
- package/src/remote-live-log.mjs +15 -8
- package/src/remote-log-decode-r60.mjs +65 -0
- package/src/remote-session-guardian.mjs +4 -5
- package/src/version.mjs +1 -1
- package/test/autonomous-local-supervisor.test.mjs +1 -1
- package/test/harness2-eval-context-isolation.test.mjs +90 -0
- package/test/r108-remote-powershell-path.test.mjs +59 -0
- package/test/r110-supervisor-powershell-path.test.mjs +28 -0
- package/test/r111-supervisor-marker-cas.test.mjs +116 -0
- package/test/r112-supervisor-claim-cas.test.mjs +63 -0
- package/test/r113-supervisor-cleanup-terminality.test.mjs +100 -0
- package/test/r114-supervisor-absence-proof.test.mjs +45 -0
- package/test/r115-posix-continuity-entrypoint.test.mjs +17 -0
- package/test/r116-authority-crash-matrix.test.mjs +83 -0
- package/test/r117-concurrent-orphan-recovery.test.mjs +54 -0
- package/test/r118-cross-process-orphan-recovery.test.mjs +99 -0
- package/test/r119-recovery-crash-after-commit.test.mjs +91 -0
- package/test/r120-authority-history-audit.test.mjs +103 -0
- package/test/r121-signed-transition-invariant.test.mjs +132 -0
- package/test/r122-epoch-bounded-read.test.mjs +58 -0
- package/test/r123-recovery-bounded-read.test.mjs +64 -0
- package/test/r124-live-log-integrity.test.mjs +66 -0
- package/test/r124-live-log-tail-boundaries.test.mjs +57 -0
- package/test/r124-signed-predecessor-shape.test.mjs +66 -0
- package/test/r125-restore-binding-types.test.mjs +63 -0
- package/test/r126-restore-policy-envelope.test.mjs +89 -0
- package/test/r127-restore-append-policy-boundary.test.mjs +25 -0
- package/test/r129-sdk-security-baseline.test.mjs +38 -0
- package/test/r130-release-security-contract.test.mjs +28 -0
- package/test/r59-tool-surface-compat.test.mjs +1 -1
- package/test/r65-authority-epoch-store.test.mjs +9 -6
- package/test/r74-prepublish-contract.test.mjs +3 -1
- package/node_modules/@modelcontextprotocol/client/dist/index-BCtJi0p5.d.mts.map +0 -1
- package/node_modules/@modelcontextprotocol/client/dist/index-CEk3qkZM.d.cts.map +0 -1
- package/node_modules/@modelcontextprotocol/client/dist/src-D0qEN74R.cjs.map +0 -1
- package/node_modules/@modelcontextprotocol/client/dist/src-DDAAhLnO.mjs.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-BLVe3qmU.d.cts.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-Bt6U_Fqb.d.mts.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/mcp-DUcCQSTW.cjs.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/mcp-Dw2OlZ1f.mjs.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/src-CgFsfg3E.cjs.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/src-D-y6h4N7.mjs.map +0 -1
- package/scripts/npm-release-readiness-r108.mjs +0 -134
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
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
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
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()`
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
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
|
|
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
|
|
211
|
-
if (stored.issuer
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
527
|
-
*
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
1396
|
+
clientInformation ??= await readClientInformation();
|
|
1373
1397
|
return executeTokenRequest(authorizationServerUrl, {
|
|
1374
1398
|
metadata,
|
|
1375
1399
|
tokenRequestParams,
|
|
1376
|
-
clientInformation
|
|
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
|
|
1393
|
-
*
|
|
1394
|
-
*
|
|
1395
|
-
*
|
|
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, (
|
|
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, (
|
|
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, (
|
|
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`
|
|
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,
|
|
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
|
-
|
|
3786
|
+
let previous = acc;
|
|
3732
3787
|
let pages = 1;
|
|
3733
|
-
while (cursor !== void 0
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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, (
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|