Skip to content

fix(identity): /mcp defensive route backstop — worker-first, never the SPA shell (#196) - #237

Merged
unforced merged 2 commits into
ParachuteComputer:mainfrom
unforcedagi:fix/mcp-route-prefixes
Aug 11, 2026
Merged

fix(identity): /mcp defensive route backstop — worker-first, never the SPA shell (#196)#237
unforced merged 2 commits into
ParachuteComputer:mainfrom
unforcedagi:fix/mcp-route-prefixes

Conversation

@unforcedagi

@unforcedagi unforcedagi commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Cloud-side half of #196 (the parachute-app service-worker denylist entry is the separate follow-up the issue scopes out).

What

If the Cloudflare zone route dispatching my.parachute.computer/mcp* to the vault worker ever vanishes, the identity worker now answers a loud 503 mcp_route_missing instead of silently serving the SPA shell to an MCP client:

  • /mcp + /mcp/* added to DEFENSIVE_PREFIXES (route-manifest) with a dedicated 503 handler
  • run_worker_first entries in both prod and staging configs (parity pinned by the existing config tests)
  • Cannot shadow the healthy path: zone routes beat Custom Domains on the same hostname, and this PR adds no routes — only the assets-vs-script decision inside identity (verified against both TOMLs by the topology test)

Tests (HEAD d285268)

identity 1096 pass / 0 fail (typecheck clean), vault 409 pass / 1 todo against the pinned core, control plane 177 pass. 503 coverage includes /mcp, /mcp/anything, POST /mcp, /mcp/ (trailing slash), and /mcp?foo=bar, all asserting error_type: mcp_route_missing. scripts/verify-spa-routing.ts gains a live-edge /mcp probe, closing the gap where a TOML typo would leave /mcp asset-first with every unit test still green.

Caveat until the app half lands

On my. with the PWA installed, a browser navigation to /mcp is still answered from the service worker's cached shell — MCP clients are unaffected. The manifest parity test records /mcp as manifest-only until the app-side denylist entry ships.

🤖 Generated with Claude Code

Adds /mcp to DEFENSIVE_PREFIXES alongside /vault: a Cloudflare zone route
(my.parachute.computer/mcp*, already declared in workers/vault/wrangler.toml)
is meant to intercept the canonical root MCP connector endpoint before it
reaches this worker. If that route ever goes missing or is misconfigured,
the identity worker now answers a loud 503 route_missing/mcp_route_missing
instead of letting the SPA shell masquerade as a working MCP endpoint.

- route-manifest.ts: /mcp added to DEFENSIVE_PREFIXES, third documented
  parity difference against the parachute-app SW denylist (the SW-side
  /^\/mcp(\/|$)/ entry is a separate follow-up in that repo).
- index.ts: mcpRouteMissing handler mirrors vaultRouteMissing exactly
  (same response shape, same 503, live on every serving host from deploy).
- wrangler.toml: "/mcp", "/mcp/*" added to run_worker_first in both the
  production and [env.staging] asset blocks.
- Tests pinned: route-manifest.test.ts's drift-catcher + P0.3 parity suite,
  and a new "/mcp defensive backstop" describe block in
  static-assets-routing.test.ts (GET /mcp, GET /mcp/anything, POST /mcp).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@unforcedagi
unforcedagi force-pushed the fix/mcp-route-prefixes branch from 6ae8b7e to 8062d1b Compare August 11, 2026 19:42
…ash/query probes; verify-spa-routing checks the live backstop (cloud#196 review)

Nits from review: static-assets-routing.test.ts's /mcp/anything case checked
status + content-type but never error_type (the sibling /mcp case already
does); add it, plus two cases for the spellings a hand-typed connector URL
most plausibly takes (/mcp/, /mcp?foo=bar). verify-spa-routing.ts never
probed any DEFENSIVE_PREFIXES path, so nothing proved run_worker_first
actually claims /mcp at the live edge — add the /mcp probe, following the
existing probe pattern.
@unforced
unforced merged commit b7fb3d1 into ParachuteComputer:main Aug 11, 2026
3 checks passed
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.

2 participants