[BUG] HTTP MCP: OAuth succeeds, then initialize hangs until CONNECT_TIMEOUT (raising MCP_TIMEOUT doesn't help)

Status Open
Reported on v2.1.229
Maintainer reply None cached
Activity 2 comments · opened Aug 12, 2026

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 initialize after a successful OAuth should be reported distinctly from a network-level connect failure (e.g. "authenticated, but the server did not respond to initialize"), instead of the generic connection 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

  1. Add an HTTP MCP server that requires OAuth to ~/.claude.json:

``json
{ "mcpServers": { "meta-devtools": { "type": "http", "url": "https://mcp.facebook.com/devtools" } } }
``

  1. Run /mcp and complete the OAuth flow in the browser (it succeeds — the callback returns and the token is stored).
  2. Observe: Got new credentials, but reconnecting to meta-devtools failed: MCP server meta-devtools connection timed out after 30000ms.
  3. Add {"env": {"MCP_TIMEOUT": "60000"}} to ~/.claude/settings.json, restart, /mcp again.
  4. 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_PROXY unset)

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.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗