MCP OAuth tokens not auto-refreshing despite valid refresh tokens
Description
MCP OAuth tokens for HTTP-based servers (Atlassian, Notion) are not being automatically refreshed when they expire, despite valid refresh tokens being stored in ~/.claude/.credentials.json.
Users are forced to manually run /mcp and re-authenticate through the browser OAuth flow every time tokens expire, which interrupts workflow.
Evidence
The credentials file (~/.claude/.credentials.json) under mcpOAuth stores all the necessary data for a token refresh:
{
"mcpOAuth": {
"atlassian|<hash>": {
"serverName": "atlassian",
"serverUrl": "https://mcp.atlassian.com/v1/mcp",
"clientId": "<client_id>",
"accessToken": "<expired_token>",
"expiresAt": 1771535707586,
"refreshToken": "<valid_refresh_token>",
"scope": ""
},
"notion|<hash>": {
"serverName": "notion",
"serverUrl": "https://mcp.notion.com/mcp",
"clientId": "<client_id>",
"accessToken": "<expired_token>",
"expiresAt": 1771872083256,
"refreshToken": "<valid_refresh_token>",
"scope": ""
}
}
}
Both tokens were expired (Atlassian ~5 days, Notion ~1 day) with valid refresh tokens present. Claude Code did not attempt to refresh them — tool calls simply failed until /mcp was run manually.
Expected Behavior
When an MCP OAuth access token expires (or is about to expire), Claude Code should automatically use the stored refreshToken to obtain a new accessToken via the standard OAuth2 refresh token grant, without requiring user interaction.
Ideally:
- On tool call failure due to auth, attempt a token refresh using the stored refresh token
- On session start, proactively check
expiresAtand refresh tokens that are expired or expiring soon - Only fall back to the interactive
/mcpbrowser OAuth flow if the refresh token itself is invalid/revoked
Current Workaround
Manually running /mcp to re-authenticate when tool calls start failing. A SessionStart hook can be used to check expiresAt and warn early, but cannot trigger the refresh itself.
Environment
- macOS (Darwin 25.3.0)
- Claude Code (latest stable)
- MCP servers: Atlassian (
https://mcp.atlassian.com/v1/mcp), Notion (https://mcp.notion.com/mcp) — both HTTP transport with OAuth
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗