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, 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'