Skip to content

Preserve binary request bodies in the MCP fetch gateway - #702

Merged
kody-bot merged 2 commits into
mainfrom
cursor/fetch-gateway-binary-bodies-e399
Jul 10, 2026
Merged

kody-bot merged 2 commits into
mainfrom
cursor/fetch-gateway-binary-bodies-e399

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 10, 2026 •

Copy link
Copy Markdown
Owner

Summary

The MCP fetch gateway read every outbound request body with request.text() before secret-placeholder expansion. Binary bodies (for example multipart uploads with file bytes, such as Discord attachment uploads from package code) were lossily decoded to a string and re-encoded, corrupting the bytes on the wire.

This PR makes the gateway binary-safe:

  • readRequestBody now reads the body as an ArrayBuffer and attempts strict UTF-8 decoding (fatal: true). Valid UTF-8 bodies keep the existing text path; anything else is passed through as raw bytes.
  • Request bodies are modeled as a discriminated union ({ kind: 'text' } | { kind: 'binary' }). Secret placeholder scanning, expansion, and Basic-auth placeholder collection only run on text bodies; binary bodies are forwarded byte-for-byte.
  • Header placeholder resolution, host approval checks, and the x-kody-secret-resolution: off opt-out all behave the same for binary bodies as before.

Secret placeholders were never a supported feature inside binary payloads, so skipping expansion there is a behavior clarification, not a regression: placeholder text embedded in binary content is now guaranteed to leave the gateway unresolved.

Testing

  • New unit tests: binary bodies preserved byte-for-byte (with header secrets still resolved), placeholder-looking bytes inside binary bodies never resolved, and opt-out passthrough for binary bodies.
  • npm run validate green locally.
System recap — extends existing primitives (medium risk)

Mode: recap · Base: main @ e5a88469 · Head: 54e7770a

Classification: extends — changes the fetch gateway's request-body handling contract inside the capabilities execute runtime; no new primitives.

Primitives touched

Primitive Group Impact
capabilities-execute runtime extends — gateway body pipeline becomes a text/binary discriminated union
secrets runtime composes — placeholder expansion unchanged for text; explicitly skipped for binary bodies

System map

Package and execute fetch calls flow through the gateway, which now branches on body kind before secret placeholder expansion.

Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged, included only when an edge crosses it).

flowchart LR
	capabilitiesExecute["capabilities-execute<br/>Capabilities execute runtime"]:::extended
	secrets["secrets<br/>Secret references"]:::touched
	upstream["Upstream host (e.g. discord.com)"]:::untouched
	capabilitiesExecute -->|"text body: expand {{secret:...}}"| secrets
	capabilitiesExecute -->|"binary body: byte-for-byte passthrough"| upstream
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Before / after

Body content Before After
Valid UTF-8 text request.text(), placeholders resolved Unchanged
Binary (invalid UTF-8) Corrupted via lossy decode/encode Passed through byte-for-byte, placeholders ignored
Header placeholders Resolved Unchanged (both body kinds)
Open in Web Open in Cursor 

Summary by CodeRabbit

  • Bug Fixes
    • Preserved binary request bodies byte-for-byte when forwarding through the gateway.
    • Secret placeholder processing now applies only to text-based payloads, preventing corruption of binary data.
    • Ensures placeholder resolution honors the secret-resolution opt-out, leaving binary requests unchanged.
    • Continued resolving secret placeholders in supported text payloads.
  • Tests
    • Added coverage for binary/multipart payloads, BOM/byte-encoding edge cases, and opt-out behavior.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5e504f63-575f-4974-b83a-d02580b38d64

📥 Commits

Reviewing files that changed from the base of the PR and between 54e7770 and d3e7a4f.

📒 Files selected for processing (2)
  • packages/worker/src/mcp/fetch-gateway.node.test.ts
  • packages/worker/src/mcp/fetch-gateway.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/worker/src/mcp/fetch-gateway.node.test.ts
  • packages/worker/src/mcp/fetch-gateway.ts

📝 Walkthrough

Walkthrough

The gateway classifies request bodies as UTF-8 text or binary bytes. Placeholder expansion and reference collection apply only to text bodies, while binary payloads are preserved during normal and opt-out forwarding.

Changes

Binary body preservation

Layer / File(s) Summary
Classify and reconstruct request bodies
packages/worker/src/mcp/fetch-gateway.ts
readRequestBody distinguishes decoded text from raw bytes, and requestBodyInit reconstructs the corresponding outbound body, including the opt-out path.
Apply selective placeholder expansion
packages/worker/src/mcp/fetch-gateway.ts, packages/worker/src/mcp/fetch-gateway.node.test.ts
Binary bodies bypass placeholder replacement and reference collection; tests cover multipart bytes, BOM preservation, embedded placeholder-like bytes, and opt-out forwarding.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant IncomingRequest
  participant expandSecretPlaceholders
  participant resolveSecret
  participant OutgoingRequest
  IncomingRequest->>expandSecretPlaceholders: provide request body and headers
  expandSecretPlaceholders->>resolveSecret: resolve text-body and header placeholders
  resolveSecret-->>expandSecretPlaceholders: resolved secrets
  expandSecretPlaceholders->>OutgoingRequest: forward text or unchanged binary body
Loading

Possibly related PRs

  • kentcdodds/kody#676: Updates the same secret-resolution opt-out flow and related gateway tests.
  • kentcdodds/kody#452: Adds placeholder expansion and body/header parsing in the same gateway code paths.
  • kentcdodds/kody#605: Changes secret resolution within the same expandSecretPlaceholders flow.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: preserving binary request bodies in the MCP fetch gateway.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/fetch-gateway-binary-bodies-e399

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kody-bot
kody-bot marked this pull request as ready for review July 10, 2026 06:40
@github-actions

github-actions Bot commented Jul 10, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-702.kody-a99.workers.dev

Worker: kody-pr-702
D1: kody-pr-702-db
KV: kody-pr-702-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/worker/src/mcp/fetch-gateway.ts`:
- Around line 487-498: Update the TextDecoder construction in readRequestBody to
set ignoreBOM: true alongside fatal: true, preserving a leading UTF-8 BOM when
decoding text request bodies so they round-trip byte-for-byte.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 166650e2-3dea-4be7-a14f-8aff4aa6323f

📥 Commits

Reviewing files that changed from the base of the PR and between e5a8846 and 54e7770.

📒 Files selected for processing (2)
  • packages/worker/src/mcp/fetch-gateway.node.test.ts
  • packages/worker/src/mcp/fetch-gateway.ts

Comment thread packages/worker/src/mcp/fetch-gateway.ts
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kody-bot
kody-bot merged commit df547fe into main Jul 10, 2026
5 checks passed
@kody-bot
kody-bot deleted the cursor/fetch-gateway-binary-bodies-e399 branch July 10, 2026 07:15
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.

3 participants