Skip to content

Harden MCP transport and result handling - #113

Open
sambitcreate wants to merge 3 commits into
mainfrom
feature/harden-mcp-integration
Open

Harden MCP transport and result handling#113
sambitcreate wants to merge 3 commits into
mainfrom
feature/harden-mcp-integration

Conversation

@sambitcreate

Copy link
Copy Markdown
Owner

MCP HTTP/SSE connections previously allowed configured service headers to follow SDK OAuth discovery across origins, and ordinary tool results could materialize or silently discard large non-text payloads. This change gives all remote MCP transports one origin-scoped fetch policy, bounds OAuth requests and decoded responses, and preserves bounded structured evidence with explicit media/resource omission notices.

It also makes child workspace-read prompt claims follow the tools actually assembled for the child, and records the settlement requirements that must be met before background subagents are activated.

Validation:

  • npm run test:mcp — 53 passed
  • npm run test:config-recovery — 55 passed
  • focused supervisor/runtime/capability/timeline/Remote suites — 118 passed
  • npm run test:preflight — passed
  • npm run test:compaction — 301 passed
  • npm run type-check — passed
  • npm run lint — passed
  • npm run build — passed after review fixes
  • Android focused suites — 52 passed
  • physical iPhone focused suites — 198 passed, 3 skipped, 3 pre-existing fixture/client failures in unchanged native code

GPT-6 Astra medium reviewed the final implementation and independently reran all 53 MCP tests. Its initial findings around SSE classification, same-path OAuth deadlines, metadata protocol headers, and structured-key collisions are fixed; final review found no remaining actionable source issues.

The full implementation and verification record is in docs/testing/mcp-upgrade-acceptance-2026-09-12.md.

@pullfrog pullfrog 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.

Important

One reachable misclassification in the new fetch policy: the SSE transport's initialize POST is treated as an OAuth request and receives the 30-second authorization deadline — plus its misleading "authorization request timed out" error — instead of the SDK's own request deadline. The origin-scoping and result-bounding work reviewed cleanly.

Reviewed changes

  • Origin-scoped transport policy — new mcp-fetch-policy.ts / mcp-remote-transport.ts: configured service headers attach only to the exact service origin, SDK headers win case-insensitively, every request sets redirect: "error", and stale generations are rejected before dispatch and on every body chunk.
  • Bounded transport bodies — 8 MiB decoded-response cap for HTTP/SSE (per-frame for successful requested SSE streams) and maxBufferSize for stdio.
  • OAuth deadlines and lifecycle — 30s deadlines for discovery/registration/token/refresh, owner cancellation preserved, transport close aborts owned requests, and finishAuth restarts its exchange phase after the SDK closes the transport during redirection.
  • Bounded MCP result projection — 32,000-char aggregate cap, depth/node/field/string-limited structured projection, explicit omission notices for images/audio/resources, no automatic JSON-envelope stringify, and a bounded isError message.
  • Child prompt truthfulnessworkspaceRead prompt claims now follow the assembled tool set rather than the V2 grant, with a regression test that fails on the old derivation.
  • Docs, plan gates, and test registration — audit/acceptance records, orchestration settlement gates, and test:mcp wired into pretest / test:preflight.

ℹ️ Nitpicks

  • createNoRedirectFetch (main/services/mcp-presets.ts:104) no longer has a production caller now that the fetch policy forces redirect: "error" everywhere; only its own unit test references it.
  • The new test owner cancellation wins and transport close aborts in-flight OAuth requests only aborts the owner signal. The transport-close abort path in createMcpRemoteTransport runs via the first test's client.close(), but no assertion pins it.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Flash𝕏

Comment thread main/services/mcp-fetch-policy.ts Outdated

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes

Reviewed the delta since the prior pullfrog review: the SSE initialize classification fix, its two regressions, and the pretest ordering correction.

  • Made request classification JSON-RPC-awaremcp-fetch-policy.ts now treats a valid JSON-RPC envelope in a same-origin JSON POST body as MCP traffic, so the pinned SDK's SSE initialize POST keeps its SDK deadline before mcp-protocol-version exists, while OAuth registration JSON still receives the 30-second authorization deadline.
  • Added focused regressions — two tests pin both sides of that distinction; the initialize test fails against the pre-fix classifier, which I confirmed by running it against a reverted copy of the policy.
  • Moved test:mcp after the native remover buildpretest now runs the suite immediately after build:worktree-remover, and the acceptance record is updated to 55 tests.

The prior review's important finding is addressed. I verified against the pinned SDK that sse.js send() passes the body as a string through init and calls the injected fetch directly, so the new check covers the real transport path rather than only the synthetic test shape. npm run test:mcp 55/55, npm run type-check, and eslint on the changed files all pass.

Pullfrog  | View workflow run | Using DeepSeek Flash𝕏

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.

1 participant