Skip to content

fix(mcp): disable deprecated SSE transport — GHB-189#97

Merged
Gastonfoncea merged 1 commit into
mainfrom
gastonfoncea09/ghb-189-bug-mcp-sse-handshake-timeout-en-produccion
May 17, 2026
Merged

fix(mcp): disable deprecated SSE transport — GHB-189#97
Gastonfoncea merged 1 commit into
mainfrom
gastonfoncea09/ghb-189-bug-mcp-sse-handshake-timeout-en-produccion

Conversation

@Gastonfoncea
Copy link
Copy Markdown
Collaborator

Closes GHB-189.

Root cause (found via systematic debugging)

mcp-handler@1.1.0 line 381 — the /sse GET handler unconditionally calls initializeRedis(redisUrl) before flushing any HTTP headers. redisUrl defaults to process.env.REDIS_URL || process.env.KV_URL. If neither is set, initializeRedis throws synchronously with "redisUrl is required", the Vercel function crashes, and the client sees a 0-byte hang until it times out (the symptom reported).

Our Vercel project has Upstash provisioned via Marketplace, but the Marketplace integration only auto-injects the REST-API env vars (KV_REST_API_URL, KV_REST_API_TOKEN) used by our rate-limiter at lib/rate-limit/upstash.ts. The classic TCP Redis URL (KV_URL / REDIS_URL) required by mcp-handler is not injected, and was never added manually.

The mcp-handler README says "Redis (optional, for SSE)" but the source has Redis as mandatory for SSE. The disableSse config flag exists precisely for this case.

Fix

disableSse: true in the createMcpHandler config. Per the library's own type docs, SSE was removed from the MCP spec on 2025-03-26:

If true, disables the SSE endpoint. As of 2025-03-26, SSE is not supported by the MCP spec.

Streamable HTTP (/api/mcp/mcp) remains the canonical transport. Claude Code, Cursor, Codex CLI, and modern MCP SDKs already speak Streamable HTTP.

Verified locally

/api/health      → 200 OK
/api/mcp/sse     → 404 "Not found"   (was: timeout, 0 bytes)
/api/mcp/mcp     → 200 OK with MCP initialize response (protocolVersion 2025-03-26)

Test plan

  • pnpm typecheck (workspace-wide) passes
  • pnpm test (workspace-wide) passes
  • Local: /sse returns clean 404
  • Local: /mcp still returns valid MCP initialize handshake
  • Post-deploy: curl -i https://mcp.ghbounty.com/api/mcp/sse returns 404 in <1s (not timeout)
  • Post-deploy: a real MCP client (e.g. Claude Code with the mcp.ghbounty.com URL configured) still connects via Streamable HTTP

Out of scope

  • Setting up KV_URL (TCP Redis) to actually wire SSE — explicitly rejected because SSE is deprecated upstream and we have no clients that depend on it.
  • README update — already says "Streamable HTTP" as the transport; the deprecation note now lives in the code comment.

🤖 Generated with Claude Code

`/api/mcp/sse` was timing out in prod with 0 bytes received (no
HTTP headers). Root cause: mcp-handler 1.1.0's SSE handler hard-
requires a TCP Redis URL via REDIS_URL/KV_URL env vars. Our Vercel
project has Upstash via Marketplace but only the REST-API env vars
(KV_REST_API_URL/_TOKEN) are auto-injected — the TCP URL is not.
Without it, initializeRedis() throws synchronously before flushing
any response, so the Vercel runtime kills the function and the
client sees a 0-byte hang.

The README "Redis (optional, for SSE)" is misleading; in the code
Redis is mandatory for SSE.

Fix: set `disableSse: true` in createMcpHandler config. Per mcp-
handler's own type docs, SSE was removed from the MCP spec on
2025-03-26, so `/sse` now returns a clean 404 instead of hanging.
Streamable HTTP (`/api/mcp/mcp`) remains the canonical transport
and continues to work for all current MCP clients (Claude Code,
Cursor, Codex, custom SDKs aligned with the latest spec).

Verified locally:
- /api/mcp/sse → 404 "Not found"
- /api/mcp/mcp → 200 with valid MCP initialize handshake

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Gastonfoncea Gastonfoncea requested a review from tomazzi14 as a code owner May 17, 2026 20:58
@vercel
Copy link
Copy Markdown

vercel Bot commented May 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gh-bounty-frontend Ready Ready Preview, Comment May 17, 2026 9:00pm
ghbounty-mcp Ready Ready Preview, Comment May 17, 2026 9:00pm

@Gastonfoncea Gastonfoncea merged commit 218f708 into main May 17, 2026
5 checks passed
@Gastonfoncea Gastonfoncea deleted the gastonfoncea09/ghb-189-bug-mcp-sse-handshake-timeout-en-produccion branch May 17, 2026 21:13
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