Skip to content

Fix production 421 "Invalid Host header" on /mcp - #160

Merged
brianglass merged 1 commit into
mainfrom
fix-mcp-transport-security-421
Aug 4, 2026
Merged

Fix production 421 "Invalid Host header" on /mcp#160
brianglass merged 1 commit into
mainfrom
fix-mcp-transport-security-421

Conversation

@brianglass

Copy link
Copy Markdown
Owner

Summary

  • /mcp returned 421 "Invalid Host header" for every real request in production, confirmed via Cloud Run logs (Invalid Host header: orthocal-6czswbhara-uc.a.run.app on every request since PR Add an MCP server exposing calendar and saint-search tools #158 merged).
  • Root cause: orthocal/asgi.py called mcp.streamable_http_app() with no arguments. The SDK defaults host='127.0.0.1' in that case, which auto-enables DNS-rebinding protection restricted to localhost/127.0.0.1/::1 — fine in local dev (where the Host header naturally is localhost), but it rejects every real production request, since Cloud Run's own hostname (forwarded as the Host header by the Firebase Hosting proxy in front of it) isn't on that allowlist.
  • Fix: explicitly pass transport_security=TransportSecuritySettings(enable_dns_rebinding_protection=False). DNS-rebinding protection defends a server bound to localhost against a malicious webpage's JS reaching it through the browser — it doesn't apply to a public HTTPS API with no localhost-only trust boundary, so disabling it here is the correct fix, not a workaround.

Test plan

  • docker compose run --rm tests — 135/135 passing
  • Verified locally by replaying the exact Host header from the production error logs (Host: orthocal-6czswbhara-uc.a.run.app) against the dev server — confirmed 200 OK after the fix, reproduced the 421 before it

🤖 Generated with Claude Code

https://claude.ai/code/session_01Hf6j2xXQXywHVh3HAVRxB3

orthocal/asgi.py called mcp.streamable_http_app() with no arguments,
so the SDK defaulted host='127.0.0.1' and auto-enabled DNS-rebinding
protection restricted to localhost -- fine in dev, but it rejected
every real request in production, since Cloud Run's own hostname
(forwarded as the Host header by the Firebase Hosting proxy in front
of it) isn't on that allowlist. Confirmed via Cloud Run logs showing
"Invalid Host header: orthocal-6czswbhara-uc.a.run.app" on every /mcp
request since the merge.

DNS-rebinding protection defends a server bound to localhost against
a malicious webpage's JS reaching it through the browser; it doesn't
apply to a public HTTPS API with no localhost-only trust boundary, so
disabling it explicitly is the correct fix. Verified locally by
replaying the exact Host header from the production error logs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hf6j2xXQXywHVh3HAVRxB3
@brianglass
brianglass merged commit e345831 into main Aug 4, 2026
4 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.

1 participant