Skip to content

fix(client): decompress gzip token response bodies in oauth flows#2436

Open
KlyneChrysler wants to merge 1 commit into
modelcontextprotocol:mainfrom
KlyneChrysler:fix/2408-gzip-token-response
Open

fix(client): decompress gzip token response bodies in oauth flows#2436
KlyneChrysler wants to merge 1 commit into
modelcontextprotocol:mainfrom
KlyneChrysler:fix/2408-gzip-token-response

Conversation

@KlyneChrysler

Copy link
Copy Markdown

fixes #2408

why the maintainer repro failed

undici (and every spec-compliant fetch) auto-decompresses only when the response carries a usable Content-Encoding header, which is why a mock server returning proper gzip headers could not reproduce the crash. the failing environments get raw gzip bytes past fetch in two ways:

  1. a proxy (common in corporate windows setups like the reporter's) strips or mangles the Content-Encoding header while leaving the body compressed, so fetch never decompresses
  2. a custom fetchFn built on something that does not decompress (e.g. a raw undici.request wrapper) surfaces the compressed body as-is

either way response.json() in executeTokenRequest throws SyntaxError: Unexpected token '\x1f' — the gzip magic byte, matching the reported stack trace.

fix

  • token response and OAuth error response bodies are read as bytes, sniffed for the gzip magic bytes (1f 8b, RFC 1952), and transparently decompressed via the web-standard DecompressionStream before JSON parsing — runtime neutral (node 18+, browsers, workers), no node builtins
  • minimal Response-like objects without arrayBuffer (custom fetchFn implementations, test mocks) fall back to json() / text() unchanged
  • gzip magic bytes cannot begin valid JSON, so the sniff cannot misfire on plain responses

tests

four new tests: gzip body without Content-Encoding (stripped-header case), gzip body with Content-Encoding (non-decompressing fetchFn case), gzip-compressed OAuth error response, and a plain-JSON real Response control. all written first and failing with the exact SyntaxError from the issue before the fix.

client package tests (702), typecheck, and lint all pass. changeset included.

Fixes modelcontextprotocol#2408. Fetch implementations only auto-decompress when the response
carries a usable Content-Encoding header. A proxy that strips the header,
or a custom fetchFn that surfaces raw bytes, hands the SDK gzip bytes that
crash response.json() during token exchange. Token and OAuth error response
bodies are now sniffed for the gzip magic bytes and decompressed via the
web-standard DecompressionStream before JSON parsing, with a json()/text()
fallback for minimal Response-like objects.
Copilot AI review requested due to automatic review settings July 5, 2026 23:02
@KlyneChrysler KlyneChrysler requested a review from a team as a code owner July 5, 2026 23:02
@changeset-bot

changeset-bot Bot commented Jul 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8840fa9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@modelcontextprotocol/client Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@pkg-pr-new

pkg-pr-new Bot commented Jul 5, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2436

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@2436

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@2436

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2436

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@2436

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2436

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2436

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2436

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2436

commit: 8840fa9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OAuth token exchange crashes on gzip-compressed token response (JSON.parse on undecompressed bytes)

2 participants