MCP OAuth token refresh not persisting for Notion MCP server
Description
The Notion MCP server (installed via the official marketplace plugin) requires re-authentication on nearly every session start, despite having a valid refresh token stored in ~/.claude/.credentials.json. The expected behavior is that Claude Code automatically uses the refresh token to obtain a new access token when the current one expires.
Steps to reproduce
- Install the Notion MCP plugin from the official marketplace
- Authenticate via OAuth (browser flow completes successfully)
- Use Notion MCP tools in a session — works fine
- Start a new session (or wait for the access token to expire, ~1 hour)
- Notion MCP shows
△ needs authenticationand requires manual re-auth via/mcp
Expected behavior
Claude Code should detect the expired access token, use the stored refresh token to obtain a new access token, update .credentials.json with the new tokens, and connect to the MCP server without user intervention.
Actual behavior
The MCP server shows needs authentication on every new session (or after token expiry within a session). The user must manually run /mcp to re-authenticate each time.
Environment
- OS: macOS (Darwin 25.3.0)
- Claude Code: latest stable channel
- MCP server: Notion (
https://mcp.notion.com/mcp) via official marketplace plugin - Credential storage:
~/.claude/.credentials.jsoncontains bothaccessTokenandrefreshTokenundermcpOAuth.notion|*
Additional context
- The access token appears to have a short TTL (~1 hour based on
expiresAttimestamps) - The refresh token IS present in the credentials file after each successful auth
- This may also affect other OAuth-based MCP servers (Atlassian appears to work more reliably, possibly due to longer token TTLs)
- Running multiple concurrent Claude Code sessions may exacerbate the issue if refresh token rotation causes one session to invalidate the other's stored token
This issue has 10 comments on GitHub. Read the full discussion on GitHub ↗