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/server/src/server/streamableHttp.ts b/packages/server/src/server/streamableHttp.ts index 31053f35c..f77c71a89 100644 --- a/packages/server/src/server/streamableHttp.ts +++ b/packages/server/src/server/streamableHttp.ts @@ -230,6 +230,7 @@ export class WebStandardStreamableHTTPServerTransport implements Transport { private _requestResponseMap: Map = new Map(); private _initialized: boolean = false; private _enableJsonResponse: boolean = false; + private _closed: boolean = false; private _standaloneSseStreamId: string = '_GET_stream'; private _eventStore?: EventStore; private _onsessioninitialized?: (sessionId: string) => void | Promise; @@ -900,6 +901,9 @@ export class WebStandardStreamableHTTPServerTransport implements Transport { } async close(): Promise { + if (this._closed) return; + this._closed = true; + // Close all SSE connections for (const { cleanup } of this._streamMapping.values()) { cleanup();