From fa780fa85be93718f16a5f710a64bfb2ce7ec89b Mon Sep 17 00:00:00 2001 From: lanxevo3 Date: Thu, 26 Mar 2026 16:55:19 -0500 Subject: [PATCH 1/2] fix(auth): enforce form-urlencoded Content-Type for token endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OAuth 2.1 §3.2 requires token endpoint requests to use application/x-www-form-urlencoded regardless of grant type. Add an explicit header.set() call immediately before the fetch in executeTokenRequest() to prevent any addClientAuthentication implementation from accidentally overriding the Content-Type. Fixes modelcontextprotocol/inspector#1160 --- packages/client/src/client/auth.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/client/src/client/auth.ts b/packages/client/src/client/auth.ts index 1a021be18..0391e35e9 100644 --- a/packages/client/src/client/auth.ts +++ b/packages/client/src/client/auth.ts @@ -1439,6 +1439,10 @@ export async function executeTokenRequest( applyClientAuthentication(authMethod, clientInformation as OAuthClientInformation, headers, tokenRequestParams); } + // Ensure Content-Type is always form-urlencoded for the token endpoint (OAuth 2.1 §3.2). + // Some addClientAuthentication implementations may have inadvertently set a different value. + headers.set('Content-Type', 'application/x-www-form-urlencoded'); + const response = await (fetchFn ?? fetch)(tokenUrl, { method: 'POST', headers, From 77273a0a211267a0c86eb7147e330ba0bdbd9f85 Mon Sep 17 00:00:00 2001 From: lanxevo3 Date: Sat, 28 Mar 2026 14:27:54 -0500 Subject: [PATCH 2/2] fix(client/streamableHttp): handle 404 by clearing session ID per MCP spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per MCP spec §Session Management (2025-03-26), when a client receives HTTP 404 in response to a request containing an Mcp-Session-Id, it MUST clear the session ID. Previously, both send() (POST) and _startOrAuthSse() (GET) would throw StreamableHTTPError without clearing _sessionId, permanently breaking the client with stale session IDs. This change: - Adds SdkErrorCode.ClientHttpNotFound - On 404, clears this._sessionId before throwing, so subsequent calls do not keep failing with the same stale session ID - Leaves full re-initialization to the caller (as InitializeRequest involves capability negotiation owned by the Client layer) Fixes #1708. --- packages/client/src/client/streamableHttp.ts | 11 +++++++++++ packages/core/src/errors/sdkErrors.ts | 1 + 2 files changed, 12 insertions(+) diff --git a/packages/client/src/client/streamableHttp.ts b/packages/client/src/client/streamableHttp.ts index 3d45b60e9..20f294a22 100644 --- a/packages/client/src/client/streamableHttp.ts +++ b/packages/client/src/client/streamableHttp.ts @@ -578,6 +578,17 @@ export class StreamableHTTPClientTransport implements Transport { } } + // Per MCP spec §Session Management: on 404 with an Mcp-Session-Id + // header, the client MUST clear the session ID and re-initialize. + // Clear the stale session so subsequent calls don't keep failing. + if (response.status === 404) { + this._sessionId = undefined; + throw new SdkError(SdkErrorCode.ClientHttpNotFound, `Session not found (HTTP 404). Clear and re-initialize. ${text}`.trim(), { + status: 404, + text + }); + } + throw new SdkError(SdkErrorCode.ClientHttpNotImplemented, `Error POSTing to endpoint: ${text}`, { status: response.status, text diff --git a/packages/core/src/errors/sdkErrors.ts b/packages/core/src/errors/sdkErrors.ts index f53c07ccf..44cb78235 100644 --- a/packages/core/src/errors/sdkErrors.ts +++ b/packages/core/src/errors/sdkErrors.ts @@ -31,6 +31,7 @@ export enum SdkErrorCode { ClientHttpNotImplemented = 'CLIENT_HTTP_NOT_IMPLEMENTED', ClientHttpAuthentication = 'CLIENT_HTTP_AUTHENTICATION', ClientHttpForbidden = 'CLIENT_HTTP_FORBIDDEN', + ClientHttpNotFound = 'CLIENT_HTTP_NOT_FOUND', ClientHttpUnexpectedContent = 'CLIENT_HTTP_UNEXPECTED_CONTENT', ClientHttpFailedToOpenStream = 'CLIENT_HTTP_FAILED_TO_OPEN_STREAM', ClientHttpFailedToTerminateSession = 'CLIENT_HTTP_FAILED_TO_TERMINATE_SESSION'