claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[BUG] OAuth Authentication Succeeds but MCP Reconnection Fails - Requires Restart

Open jhinrichsen opened this issue 6 months ago • 8 comments

Bug Report: OAuth Authentication Succeeds but MCP Reconnection Fails - Requires Claude Code Restart

Summary

After successful OAuth authentication with an MCP server using streamable-http transport, Claude Code displays "Authentication successful, but server reconnection failed. You may need to manually restart Claude Code for the changes to take effect." The OAuth tokens are correctly stored, but MCP tools remain unavailable until Claude Code is restarted.

Environment

  • Claude Code Version: 2.0.26
  • OS: Linux (Fedora 42, kernel 6.16.12)
  • MCP Server: Custom Quarkus-based MCP server
  • Transport: streamable-http
  • Auth Method: OAuth 2.0 with Dynamic Client Registration (RFC 7591)
  • OAuth Provider: Keycloak 24.0.3

Steps to Reproduce

  1. Configure an MCP server with OAuth using streamable-http transport:

    claude mcp add --transport http myserver http://localhost:8080/mcp
    
  2. Start MCP server with OAuth/OIDC enabled:

    • Server implements Dynamic Client Registration (DCR)
    • Server provides protected resource metadata at /.well-known/oauth-protected-resource
    • Token lifetime: 24 hours
    • Redirect URIs: localhost only (as per MCP spec)
  3. Run /mcp command in Claude Code

  4. Complete OAuth flow in browser (login with test user)

  5. Observe authentication completion in browser

Expected Behavior

Based on Claude Code MCP documentation:

"Authentication tokens are stored securely and refreshed automatically."

Expected: After OAuth completes, Claude Code should:

  1. Store the OAuth tokens ✅ (works)
  2. Automatically reconnect to the MCP server using stored tokens ❌ (fails)
  3. Load authenticated MCP tools immediately ❌ (fails)
  4. No restart required ❌ (restart IS required)

Actual Behavior

  1. OAuth authentication completes successfully in browser
  2. Tokens are correctly stored in ~/.claude/.credentials.json:
    {
      "mcpOAuth": {
        "myserver|<hash>": {
          "serverName": "myserver",
          "serverUrl": "http://localhost:8080/mcp",
          "clientId": "<dynamically-registered-client-id>",
          "accessToken": "[valid 24h JWT token]",
          "expiresAt": 1761406726618,
          "refreshToken": "[valid refresh token]",
          "scope": "email profile"
        }
      }
    }
    
  3. Claude Code displays error: "Authentication successful, but server reconnection failed. You may need to manually restart Claude Code for the changes to take effect."
  4. MCP tools are NOT available in the current session
  5. Running claude mcp list shows: ✗ Failed to connect
  6. After restarting Claude Code:
    • Connection succeeds automatically using stored tokens
    • All authenticated MCP tools are available
    • No re-authentication needed

Technical Details

Token Validity

The stored access token is valid and working:

  • Decoded JWT shows: exp: 1761406726 (24 hours from issuance)
  • Token contains correct user identity
  • Token includes proper scopes (email profile)
  • Token can successfully call authenticated API endpoints when tested directly with curl

Server Configuration

  • MCP server is running (verified with curl http://localhost:8080/mcp → HTTP 405 as expected)
  • Server properly implements:
    • Dynamic Client Registration endpoint
    • OAuth 2.0 protected resource metadata (RFC 9728)
    • PKCE flow support
    • Token validation

Transport Details

  • NOT using deprecated SSE (this is different from issue #9127)
  • Using modern streamable-http transport
  • Server is properly configured for streamable-http

Workaround

Restart Claude Code after OAuth authentication completes. The stored tokens are preserved and work correctly after restart.

Impact

  • Poor user experience: requires manual restart after every OAuth authentication
  • Contradicts documentation which states tokens work automatically
  • Makes iterative development/testing of OAuth-enabled MCP servers cumbersome
  • First-time users may think authentication failed when it actually succeeded

Related Issues

  • #9127 - Different issue (SSE-specific servers like Jira)
  • #956 - Auto-refresh OAuth (marked as fixed May 2025)
  • #1845 - Auth lost on config update
  • #7290 - HTTP/SSE transport ignores auth headers

This issue is distinct from #9127 as it affects streamable-http (modern protocol), not deprecated SSE.

Additional Notes

  • The OAuth flow itself works perfectly (DCR succeeds, tokens are valid)
  • The token storage works correctly
  • The issue is specifically in the reconnection logic after initial authentication
  • Subsequent Claude Code sessions work fine (tokens persist across restarts)
  • The problem only occurs during the initial authentication session

Proposed Fix

After successful OAuth token storage, Claude Code should:

  1. Use the newly stored tokens to establish an MCP connection
  2. Load the MCP tools into the current session
  3. Avoid requiring a restart for a session state that should be hot-reloadable

Questions for Maintainers

  1. Is the "reconnection failed" + restart requirement intentional behavior?
  2. If so, why does the documentation not mention this?
  3. Is there a technical limitation preventing hot-reconnection after OAuth completes?
  4. Should the error message be clearer about whether restart is always required vs. optional?

Would you like me to test any additional scenarios or provide more debug information?

jhinrichsen avatar Oct 24 '25 15:10 jhinrichsen

Found 1 possible duplicate issue:

  1. https://github.com/anthropics/claude-code/issues/9127

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

github-actions[bot] avatar Oct 24 '25 16:10 github-actions[bot]

#9127 is all about SSE, which is deprecated. The problem can be reproduced using streamable HTTP.

jhinrichsen avatar Oct 24 '25 16:10 jhinrichsen

same issue with newrelic mcp

$ claude --version
2.0.31 (Claude Code)
  • Set up New Relic MCP | New Relic Documentation https://docs.newrelic.com/jp/docs/agentic-ai/mcp/setup/
claude mcp add newrelic --transport http https://mcp.newrelic.com/mcp/
Image

naofumi-fujii avatar Nov 01 '25 15:11 naofumi-fujii

Same here with supabase mcp

pedromarcos11 avatar Nov 19 '25 19:11 pedromarcos11

I have a custom MCP that uses Microsoft OAuth. Microsoft access tokens are valid for 60-75 minutes, so the MCP regularly enters an unauthenticated state. Refresh tokens are issued, but currently not used by Claude Code to automatically re-authenticate

mauricekleine avatar Dec 16 '25 15:12 mauricekleine

I think I'm experiencing the same issue with the Notion mcp plugin. I've done additional investigation that suggests this is a Claude Code client-side issue, not a server-side problem.

Environment

  • Claude Code version: 2.0.75
  • OS: macOS Darwin 25.1.0 (arm64)
  • Node version: v25.2.1
  • Plugin: Notion@claude-plugins-official v0.1.0

Proof: The same OAuth tokens work perfectly via curl

After Claude Code's OAuth flow completed (and failed with 401)

Debug Log Evidence

From ~/.claude/debug/latest:

[DEBUG] MCP server "plugin:Notion:notion": Initializing HTTP transport to https://mcp.notion.com/mcp [DEBUG] MCP server "plugin:Notion:notion": HTTP transport options: {"url":"https://mcp.notion.com/mcp","headers":{"User-Agent":"claude-code/2.0.75"},"hasAuthProvider":true,"timeoutMs":60000}

Tokens are successfully retrieved

[DEBUG] MCP server "plugin:Notion:notion": Returning tokens [DEBUG] MCP server "plugin:Notion:notion": Token length: 86 [DEBUG] MCP server "plugin:Notion:notion": Has refresh token: true [DEBUG] MCP server "plugin:Notion:notion": Expires in: 3594s

Tokens are saved

[DEBUG] MCP server "plugin:Notion:notion": Saving tokens [DEBUG] MCP server "plugin:Notion:notion": Token expires in: 3600 [DEBUG] MCP server "plugin:Notion:notion": Has refresh token: true

Then it fails

[DEBUG] MCP server "plugin:Notion:notion": HTTP Connection failed after 1085ms: Streamable HTTP error: Server returned 401 after successful authentication [ERROR] MCP server "plugin:Notion:notion" Error: Streamable HTTP error: Server returned 401 after successful authentication [ERROR] MCP server "plugin:Notion:notion" Connection failed: Streamable HTTP error: Server returned 401 after successful authentication

I extracted the tokens and tested manually:

Initialize MCP session - works!

curl -X POST https://mcp.notion.com/mcp
-H "Authorization: Bearer $ACCESS_TOKEN"
-H "Accept: application/json, text/event-stream"
-d '{"jsonrpc":"2.0","id":1,"method":"initialize",...}' Returns: {"result":{"protocolVersion":"2024-11-05","serverInfo":{"name":"Notion MCP"}}}

Call tools - works!

curl -X POST https://mcp.notion.com/mcp
-H "Authorization: Bearer $ACCESS_TOKEN"
-H "Mcp-Session-Id: $SESSION_ID"
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"notion-search",...}}' Returns search results successfully

This proves:

  • The OAuth tokens are valid
  • The Notion MCP server accepts them
  • Claude Code's MCP client fails to use them correctly after OAuth

The bug looks to be specifically in how Claude Code reconnects to the MCP server after storing the OAuth tokens, not in the OAuth flow itself or the server.

canarybrad avatar Dec 21 '25 16:12 canarybrad