Skip to content

Reject GET on /mcp instead of holding an unused SSE stream open - #180

Merged
brianglass merged 1 commit into
mainfrom
mcp-reject-get-stream
Aug 16, 2026
Merged

Reject GET on /mcp instead of holding an unused SSE stream open#180
brianglass merged 1 commit into
mainfrom
mcp-reject-get-stream

Conversation

@brianglass

Copy link
Copy Markdown
Owner

Summary

  • Investigated an unexpectedly large Cloud Run bill by pulling request logs/metrics for the orthocal service. /mcp traffic jumped ~50x starting Aug 11 (from a few hundred/day to 4,300-4,700/day), driven entirely by GET requests from claude-code/2.1.224 (cli) and python-httpx clients across hundreds of distinct Google-owned IPs.
  • Every GET to /mcp opens the streamable-http transport's optional SSE channel and holds it open indefinitely waiting for a server-push message. Neither of orthocal's tools (get_day, search_saints) ever sends one, so the stream just sits there until Cloud Run kills it at the 20s request timeout — confirmed via logs: GET latency was pinned at ~21.0s (avg=median=max), vs ~8ms for POST (the actual tool calls). That's the single largest cost driver on this service right now.
  • Fix: reject GET on /mcp* at the ASGI dispatch level in orthocal/asgi.py, before it ever reaches the MCP app. POST (and DELETE) pass through unchanged.

Test plan

  • docker compose run --rm tests — 152 tests pass
  • Manually verified locally: GET /mcp405 in ~6ms (was previously a held-open 21s stream); POST /mcp initialize and a tools/call (search_saints) both still return 200 and correct results, unaffected

🤖 Generated with Claude Code

https://claude.ai/code/session_01Hf6j2xXQXywHVh3HAVRxB3

Neither MCP tool (get_day, search_saints) ever pushes unsolicited
messages to a client, so the streamable-http transport's optional
GET/SSE channel serves no purpose here. The SDK holds that stream open
indefinitely waiting for a server-initiated message that never comes,
and Cloud Run only closes it at the 20s request timeout -- request
logs showed a sustained flood of GET /mcp requests (up ~50x since
Aug 11, steady ~190/hour) each billed for a full 20s of held-open
compute, the largest driver behind this month's Cloud Run bill.
Rejecting GET before it reaches the MCP app costs single-digit
milliseconds instead; POST (actual tool calls) is unaffected.
@brianglass
brianglass merged commit f11775e into main Aug 16, 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