[BUG] HTTP MCP: OAuth succeeds, then initialize hangs until CONNECT_TIMEOUT (raising MCP_TIMEOUT doesn't help)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
An HTTP (streamable) MCP server completes the OAuth flow successfully — tokens are saved and the log reports Auth result: AUTHORIZED — but the MCP initialize handshake that follows never gets a response. Every connection attempt hangs until the connect timeout fires (CONNECT_TIMEOUT), including all 3 automatic retries, so the server is permanently shown as failed/offline.
The endpoint itself is healthy and fast: an unauthenticated POST from curl to the same URL returns HTTP 401 in ~0.3s. So this is not DNS, TLS, proxy or general reachability — only the authenticated connection started by Claude Code hangs.
Raising MCP_TIMEOUT does not help; it only makes the hang last longer (30s → 60s), which confirms the value is being honored and that the problem is a stalled handshake rather than a too-short deadline.
Possibly related but distinct: #20335 (that one is about the timeout setting being ignored; here it is clearly applied).
Server in question: https://mcp.facebook.com/devtools (Meta Developer Tools MCP). I can't rule out that the stall originates server-side, but Claude Code surfaces it only as an opaque "connection timed out", with no indication that the transport was opened and the handshake stalled — and the 3 silent retries make each /mcp attempt take ~2 minutes.
What Should Happen?
- A stalled
initializeafter a successful OAuth should be reported distinctly from a network-level connect failure (e.g. "authenticated, but the server did not respond toinitialize"), instead of the genericconnection timed out. - Ideally the client would surface the underlying HTTP status/response (if any) received on the post-auth request, so users can tell a server-side problem from a client one.
Error Messages/Logs
From ~/Library/Caches/claude-cli-nodejs/<project>/mcp-logs-meta-devtools/*.jsonl (deduplicated, values redacted):
22:02:11.879 | Auth result: AUTHORIZED
22:02:11.879 | Token length: 364
22:02:11.879 | Token expires_in: 5183999.97 (Has refresh token: false)
22:02:11.881 | Initializing HTTP transport to https://mcp.facebook.com/devtools
22:02:11.881 | Node version: v26.3.0, Platform: darwin
22:02:11.881 | Environment: {"NODE_OPTIONS":"not set","UV_THREADPOOL_SIZE":"default","HTTP_PROXY":"not set","HTTPS_PROXY":"not set","NO_PROXY":"not set"}
22:02:11.881 | HTTP transport options: {"url":"https://mcp.facebook.com/devtools","headers":{"User-Agent":"claude-code/2.1.229 (cli, agent-sdk/0.3.222)","Accept-Encoding":"identity"},"hasAuthProvider":true,"timeoutMs":60000}
22:02:11.881 | HTTP transport created successfully
22:02:11.882 | Client created, setting up request handler
22:02:11.882 | Starting connection with timeout of 30000ms
22:02:11.882 | Testing basic HTTP connectivity to https://mcp.facebook.com/devtools
22:02:41.883 | Connection timeout triggered after 30003ms (limit: 30000ms)
22:02:41.887 | HTTP Connection failed after 30007ms: MCP server "meta-devtools" connection timed out after 30000ms (code: CONNECT_TIMEOUT, errno: none)
22:02:41.889 | Transient CONNECT_TIMEOUT on initial connect — retry 1/3 in 1000ms
22:03:12.892 | Connection timeout triggered after 30002ms (limit: 30000ms)
22:03:12.893 | Transient CONNECT_TIMEOUT on initial connect — retry 2/3 in 2000ms
22:03:44.901 | Transient CONNECT_TIMEOUT on initial connect — retry 3/3 in 4000ms
22:04:18.914 | Connection timeout triggered after 30006ms (limit: 30000ms)
-- after setting MCP_TIMEOUT=60000 in ~/.claude/settings.json and restarting --
22:07:24.571 | Starting connection with timeout of 60000ms
22:08:24.571 | Connection timeout triggered after 60001ms (limit: 60000ms)
22:08:24.572 | HTTP Connection failed after 60002ms: MCP server "meta-devtools" connection timed out after 60000ms (code: CONNECT_TIMEOUT, errno: none)
Note the inconsistency in the first block: the transport is created with timeoutMs: 60000 while the connection gate immediately after logs Starting connection with timeout of 30000ms — two different deadlines in the same connect attempt (at that point no MCP_TIMEOUT was configured).
Reachability check against the same URL, unauthenticated:
$ curl -s -o /dev/null -w "connect=%{time_connect}s ttfb=%{time_starttransfer}s total=%{time_total}s http=%{http_code}\n" \
-X POST https://mcp.facebook.com/devtools \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'
connect=0.058741s ttfb=0.306056s total=0.306469s http=401
Steps to Reproduce
- Add an HTTP MCP server that requires OAuth to
~/.claude.json:
``json``
{ "mcpServers": { "meta-devtools": { "type": "http", "url": "https://mcp.facebook.com/devtools" } } }
- Run
/mcpand complete the OAuth flow in the browser (it succeeds — the callback returns and the token is stored). - Observe:
Got new credentials, but reconnecting to meta-devtools failed: MCP server meta-devtools connection timed out after 30000ms. - Add
{"env": {"MCP_TIMEOUT": "60000"}}to~/.claude/settings.json, restart,/mcpagain. - Observe the same failure, now after 60000ms — the setting is applied, the handshake still never completes.
Environment
- Claude Code: 2.1.229 (agent-sdk 0.3.222)
- Platform: macOS (darwin 25.5.0), Node v26.3.0
- Transport: HTTP (streamable), OAuth via DCR
- No proxy configured (
HTTP_PROXY/HTTPS_PROXY/NO_PROXYunset)
Additional Detail
During the OAuth step the log also reports a redirect-URI mismatch that forces re-registration on every run:
Cached client_id was registered for http://localhost:3118/callback; current redirectUri is http://127.0.0.1:3118/callback — forcing re-DCR
localhost vs 127.0.0.1 for the same port causes a fresh Dynamic Client Registration each time. It doesn't appear to cause the timeout (auth still completes), but it may be worth fixing separately.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗