Skip to content

Commit 064808d

Browse files
committed
fix(auth): add Accept: application/json header to OAuth token requests
Some OAuth providers (e.g., GitHub) return form-encoded responses by default unless the client explicitly requests JSON via the Accept header. This causes token exchange to fail with a parse error since the SDK expects JSON responses. Add 'Accept: application/json' to all token endpoint requests: - Authorization code token exchange (oauth2.py) - Token refresh (oauth2.py) - Client credentials grant (client_credentials.py) - Private key JWT grant (client_credentials.py) - Signed JWT assertion grant (client_credentials.py) This aligns with RFC 6749 Section 5.1 which specifies that token responses use JSON, and ensures interoperability with providers that require explicit content negotiation. Fixes #1523 Signed-off-by: Gaurav Kumar Sinha <gaurav@substrai.dev>
1 parent e8e6484 commit 064808d

2 files changed

Lines changed: 8 additions & 5 deletions

File tree

src/mcp/client/auth/extensions/client_credentials.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ async def _exchange_token_client_credentials(self) -> httpx.Request:
9292
"grant_type": "client_credentials",
9393
}
9494

95-
headers: dict[str, str] = {"Content-Type": "application/x-www-form-urlencoded"}
95+
headers: dict[str, str] = {"Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json"}
9696

9797
# Use standard auth methods (client_secret_basic, client_secret_post, none)
9898
token_data, headers = self.context.prepare_token_auth(token_data, headers)
@@ -320,7 +320,7 @@ async def _exchange_token_client_credentials(self) -> httpx.Request:
320320
"grant_type": "client_credentials",
321321
}
322322

323-
headers: dict[str, str] = {"Content-Type": "application/x-www-form-urlencoded"}
323+
headers: dict[str, str] = {"Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json"}
324324

325325
# Add JWT client authentication (RFC 7523 Section 2.2)
326326
await self._add_client_authentication_jwt(token_data=token_data)
@@ -481,5 +481,8 @@ async def _exchange_token_jwt_bearer(self) -> httpx.Request:
481481

482482
token_url = self._get_token_endpoint()
483483
return httpx.Request(
484-
"POST", token_url, data=token_data, headers={"Content-Type": "application/x-www-form-urlencoded"}
484+
"POST",
485+
token_url,
486+
data=token_data,
487+
headers={"Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json"},
485488
)

src/mcp/client/auth/oauth2.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ async def _exchange_token_authorization_code(
402402
token_data["resource"] = self.context.get_resource_url() # RFC 8707
403403

404404
# Prepare authentication based on preferred method
405-
headers = {"Content-Type": "application/x-www-form-urlencoded"}
405+
headers = {"Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json"}
406406
token_data, headers = self.context.prepare_token_auth(token_data, headers)
407407

408408
return httpx.Request("POST", token_url, data=token_data, headers=headers)
@@ -447,7 +447,7 @@ async def _refresh_token(self) -> httpx.Request:
447447
refresh_data["resource"] = self.context.get_resource_url() # RFC 8707
448448

449449
# Prepare authentication based on preferred method
450-
headers = {"Content-Type": "application/x-www-form-urlencoded"}
450+
headers = {"Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json"}
451451
refresh_data, headers = self.context.prepare_token_auth(refresh_data, headers)
452452

453453
return httpx.Request("POST", token_url, data=refresh_data, headers=headers)

0 commit comments

Comments
 (0)