Reject GET on /mcp instead of holding an unused SSE stream open - #180
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
orthocalservice./mcptraffic jumped ~50x starting Aug 11 (from a few hundred/day to 4,300-4,700/day), driven entirely by GET requests fromclaude-code/2.1.224 (cli)andpython-httpxclients across hundreds of distinct Google-owned IPs./mcpopens 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./mcp*at the ASGI dispatch level inorthocal/asgi.py, before it ever reaches the MCP app. POST (and DELETE) pass through unchanged.Test plan
docker compose run --rm tests— 152 tests passGET /mcp→405in ~6ms (was previously a held-open 21s stream);POST /mcpinitializeand atools/call(search_saints) both still return200and correct results, unaffected🤖 Generated with Claude Code
https://claude.ai/code/session_01Hf6j2xXQXywHVh3HAVRxB3