[BUG] OAuth Authentication Succeeds but MCP Reconnection Fails - Requires Restart
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
-
Configure an MCP server with OAuth using streamable-http transport:
claude mcp add --transport http myserver http://localhost:8080/mcp -
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)
-
Run
/mcpcommand in Claude Code -
Complete OAuth flow in browser (login with test user)
-
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:
- Store the OAuth tokens ✅ (works)
- Automatically reconnect to the MCP server using stored tokens ❌ (fails)
- Load authenticated MCP tools immediately ❌ (fails)
- No restart required ❌ (restart IS required)
Actual Behavior
- OAuth authentication completes successfully in browser
- 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" } } } - Claude Code displays error: "Authentication successful, but server reconnection failed. You may need to manually restart Claude Code for the changes to take effect."
- MCP tools are NOT available in the current session
- Running
claude mcp listshows:✗ Failed to connect -
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-httptransport - 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:
- Use the newly stored tokens to establish an MCP connection
- Load the MCP tools into the current session
- Avoid requiring a restart for a session state that should be hot-reloadable
Questions for Maintainers
- Is the "reconnection failed" + restart requirement intentional behavior?
- If so, why does the documentation not mention this?
- Is there a technical limitation preventing hot-reconnection after OAuth completes?
- 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?
Found 1 possible duplicate issue:
- 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
#9127 is all about SSE, which is deprecated. The problem can be reproduced using streamable HTTP.
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/
Same here with supabase mcp
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
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.