[BUG] Hosted MCP OAuth initiation ignores NODE_EXTRA_CA_CERTS on corporate MITM networks (v2.1.113+)

Status Fixed / completed
Maintainer reply ✓ Yes — claude[bot]
Activity 4 comments · opened May 3, 2026 · closed May 8, 2026
💡 Likely answer: A maintainer (claude[bot], contributor) responded on this thread — see the highlighted reply below.

Bug description

On corporate networks that intercept TLS with a custom root CA (Zscaler, Netskope, device-level CA, etc.), triggering OAuth for hosted MCP servers (gmail, gcal at *.mcp.claude.com) via /mcp or mcp__<server>__authenticate fails with:

SDK auth failed: self signed certificate in certificate chain

Environment

  • Claude Code v2.1.121 (native/Bun binary)
  • macOS 15
  • Corporate MITM proxy injects its root CA into the TLS chain
  • NODE_EXTRA_CA_CERTS set to a PEM that includes the corporate root
  • NODE_OPTIONS=--use-system-ca set; corporate roots also present in macOS System keychain
  • Users cannot disable the VPN/proxy by policy

What works (important for diagnosis)

  • claude mcp list succeeds against the same *.mcp.claude.com hosts — proving NODE_EXTRA_CA_CERTS is being honored by the main MCP HTTP transport.
  • Token refresh (401/403 re-auth) for MCP servers that were authenticated previously (from a non-MITM network) also succeeds — proving the refresh path is CA-aware.

What fails

Only first-time OAuth initiation for hosted MCP servers. Discovery, dynamic client registration, and the initial token exchange all fail TLS validation.

Likely root cause

Since v2.1.113 Claude Code ships as a Bun-compiled native binary. Bun's global fetch uses BoringSSL and does not honor NODE_EXTRA_CA_CERTS — extra CAs must be passed per-call via init.tls.ca.

Almost everywhere in the binary, HTTPS calls are wrapped with a CA-aware helper that reads NODE_EXTRA_CA_CERTS and threads it into init.tls.ca. StreamableHTTPClientTransport builds its internal fetch this way, and — crucially — passes that same CA-aware fetch into the MCP SDK's auth() helper when handling 401/403 re-auth. That is why refreshes work.

The OAuth initiation path appears to invoke the MCP SDK's auth() without a custom fetchFn, so the SDK falls back to the global Bun.fetch with no tls.ca override, and TLS validation fails against the corporate chain.

Proposed fix

In the OAuth initiation code path for hosted MCP servers, pass a CA-aware fetchFn (the same one used by the transport's internal fetch wrapper, or a freshly-built one using the existing CA-loading helper) into the MCP SDK's auth() call. Symmetric with how the transport's own 401/403 re-auth path already works.

Workaround for users

For first-time bootstrap only:

NODE_TLS_REJECT_UNAUTHORIZED=0 claude
# inside the session:
/mcp authenticate <server>

Quit and relaunch normally afterward — the stored tokens keep working through the CA-aware refresh path. NODE_TLS_REJECT_UNAUTHORIZED=0 disables TLS verification for every Bun.fetch call in that session, so it should be used only for the bootstrap and never exported to a shell.

Related issues

  • #44754 — per-server TLS config feature request; overlapping root cause
  • #4053 — WebFetch exhibits the same "some paths honor the CA, some don't" pattern
  • #50115 — docs still describe a Node.js runtime post-v2.1.113 Bun switch

View original on GitHub ↗

4 Comments

github-actions[bot] · 5 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/20194
  2. https://github.com/anthropics/claude-code/issues/43967
  3. https://github.com/anthropics/claude-code/issues/4053

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

tomra-hub · 5 months ago

Confirming repro on Claude Code 2.1.129, macOS 15, monday.com corp network (MITM via internal device CA).

Not a duplicate of the bot-flagged candidates:

  • #20194 is the broader "Bun doesn't honor NODE_EXTRA_CA_CERTS" parent — covers mcp install, auto-update, API calls. Fixing it would likely fix this one, but this issue is narrower and more actionable: the hosted-MCP OAuth initiation path specifically doesn't pass a CA-aware fetchFn into the MCP SDK's auth(), while the 401/403 refresh path does. That asymmetry is the root cause and the proposed fix is symmetric with existing code in the repo.
  • #43967 is Windows + a different endpoint (api.z.ai), not hosted MCP OAuth.
  • #4053 is WebFetch, and the reporter explicitly notes MCP worked in their env — opposite symptom.

Organizational impact: this blocks Gmail/Gcal MCP for our entire R&D org on corp network (monday.com, several hundred engineers). The NODE_TLS_REJECT_UNAUTHORIZED=0 workaround does work for first-time bootstrap — tokens do persist through the CA-aware refresh path afterward, so the diagnosis is sound — but disabling TLS validation on a MITM'd network, even for one command, isn't something we can ship in onboarding docs at scale.

Related follow-up filed: #56641 — after applying this workaround, the next blocker is that gmail.mcp.claude.com and gcal.mcp.claude.com currently return HTTP 404 from Google Frontend for every path (base, OAuth discovery, /register). That's a separate service-side problem; the two issues compound but are independent.

Adding this comment to keep the issue open against the auto-closure bot. Happy to +1 or consolidate with whichever issue ends up owning the fix.

claude[bot] contributor · 5 months ago

This issue was fixed as of version 2.1.133.

github-actions[bot] · 3 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.