Summary
The Notion MCP OAuth flow does not return a refresh_token, so when the access token expires (every few weeks in my case), users must manually re-run /mcp to re-authorize — there's no silent refresh.
This isn't a plugin-layer issue (the plugin only declares the MCP URL via .mcp.json), but the plugin team is the closest contact point to the Notion MCP server team.
Evidence
Stored credential at ~/.claude/.credentials.json after authorization (token redacted):
{
"mcpOAuth": {
"plugin:Notion:notion|<id>": {
"serverName": "plugin:Notion:notion",
"serverUrl": "https://mcp.notion.com/mcp",
"accessToken": "...",
"expiresAt": 0,
"discoveryState": {
"authorizationServerUrl": "https://mcp.notion.com",
"resourceMetadataUrl": "https://mcp.notion.com/.well-known/oauth-protected-resource/mcp",
"oauthMetadataFound": true
},
"clientId": "https://claude.ai/oauth/claude-code-client-metadata"
}
}
}
Two issues visible:
- No
refreshToken field — Notion's token endpoint did not return one, so Claude Code can't silently renew.
expiresAt: 0 — token endpoint did not include expires_in, so Claude Code has no expiry tracking.
Server metadata says it's supposed to work
GET https://mcp.notion.com/.well-known/oauth-authorization-server returns:
{
"authorization_endpoint": "https://mcp.notion.com/authorize",
"token_endpoint": "https://mcp.notion.com/token",
"grant_types_supported": ["authorization_code", "refresh_token"],
"scopes_supported": null
}
refresh_token is advertised as a supported grant type, but the actual /token response (during authorization_code exchange) doesn't include it.
Likely root cause
Notion MCP's token endpoint isn't returning refresh_token in the token exchange response. Possibly a Beta-phase gap (the resource metadata literally calls it "Notion MCP (Beta)"). The plugin layer can't fix this — needs to be addressed on Notion's MCP server.
Ask
Could you relay this to the Notion MCP team? Either:
- Have the token endpoint return
refresh_token + expires_in per RFC 6749, or
- Document that long-lived sessions aren't supported in Beta and users should expect periodic re-auth.
Environment:
- Claude Code: 2.1.131 (darwin-arm64)
- Plugin: notion-workspace-plugin@notion-plugin-marketplace 0.1.0
Summary
The Notion MCP OAuth flow does not return a
refresh_token, so when the access token expires (every few weeks in my case), users must manually re-run/mcpto re-authorize — there's no silent refresh.This isn't a plugin-layer issue (the plugin only declares the MCP URL via
.mcp.json), but the plugin team is the closest contact point to the Notion MCP server team.Evidence
Stored credential at
~/.claude/.credentials.jsonafter authorization (token redacted):{ "mcpOAuth": { "plugin:Notion:notion|<id>": { "serverName": "plugin:Notion:notion", "serverUrl": "https://mcp.notion.com/mcp", "accessToken": "...", "expiresAt": 0, "discoveryState": { "authorizationServerUrl": "https://mcp.notion.com", "resourceMetadataUrl": "https://mcp.notion.com/.well-known/oauth-protected-resource/mcp", "oauthMetadataFound": true }, "clientId": "https://claude.ai/oauth/claude-code-client-metadata" } } }Two issues visible:
refreshTokenfield — Notion's token endpoint did not return one, so Claude Code can't silently renew.expiresAt: 0— token endpoint did not includeexpires_in, so Claude Code has no expiry tracking.Server metadata says it's supposed to work
GET https://mcp.notion.com/.well-known/oauth-authorization-serverreturns:{ "authorization_endpoint": "https://mcp.notion.com/authorize", "token_endpoint": "https://mcp.notion.com/token", "grant_types_supported": ["authorization_code", "refresh_token"], "scopes_supported": null }refresh_tokenis advertised as a supported grant type, but the actual/tokenresponse (duringauthorization_codeexchange) doesn't include it.Likely root cause
Notion MCP's token endpoint isn't returning
refresh_tokenin the token exchange response. Possibly a Beta-phase gap (the resource metadata literally calls it "Notion MCP (Beta)"). The plugin layer can't fix this — needs to be addressed on Notion's MCP server.Ask
Could you relay this to the Notion MCP team? Either:
refresh_token+expires_inper RFC 6749, orEnvironment: