From 8743a46a6cbb4e8b4d9aa5a0eb20dd6cca05fe88 Mon Sep 17 00:00:00 2001 From: Peter Siska <63866+peschee@users.noreply.github.com> Date: Thu, 26 Feb 2026 20:56:26 +0100 Subject: [PATCH] fix: prevent dual Content-Type header in OAuth token requests for direct connections The custom fetch wrappers for direct SSE and Streamable HTTP transports were overwriting or conflicting with headers set by the SDK's OAuth token requests. This caused authorization servers (e.g. Keycloak) to reject token exchanges with "Failed to parse media type application/json, application/x-www-form-urlencoded". Move default accept/content-type headers out of the fetch wrapper and into requestInit.headers with lowercase keys, and simplify the custom fetch to a pass-through. The SDK's createFetchWithInit merges defaults with per-request headers (per-request wins), so OAuth token requests now correctly use application/x-www-form-urlencoded. --- client/src/lib/hooks/useConnection.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index e14d1037f..5ffa24a11 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -581,7 +581,7 @@ export function useConnection({ } switch (transportType) { case "sse": - requestHeaders["Accept"] = "text/event-stream"; + requestHeaders["accept"] = "text/event-stream"; requestHeaders["content-type"] = "application/json"; transportOptions = { authProvider: serverAuthProvider, @@ -589,10 +589,7 @@ export function useConnection({ url: string | URL | globalThis.Request, init?: RequestInit, ) => { - const response = await fetch(url, { - ...init, - headers: requestHeaders, - }); + const response = await fetch(url, init); // Capture protocol-related headers from response captureResponseHeaders(response); @@ -605,19 +602,15 @@ export function useConnection({ break; case "streamable-http": + requestHeaders["accept"] = "text/event-stream, application/json"; + requestHeaders["content-type"] = "application/json"; transportOptions = { authProvider: serverAuthProvider, fetch: async ( url: string | URL | globalThis.Request, init?: RequestInit, ) => { - requestHeaders["Accept"] = - "text/event-stream, application/json"; - requestHeaders["Content-Type"] = "application/json"; - const response = await fetch(url, { - headers: requestHeaders, - ...init, - }); + const response = await fetch(url, init); // Capture protocol-related headers from response captureResponseHeaders(response);