[BUG] Notion MCP OAuth: complete_authentication fails when mcp.notion.com relay returns callback instead of localhost
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When authenticating the Notion MCP server (https://mcp.notion.com/mcp), the browser ends up at mcp.notion.com/callback instead of being forwarded to the local Claude Code callback server. Passing the mcp.notion.com/callback URL to mcp__notion__complete_authentication (the documented fallback) fails with a state mismatch error, making it impossible to complete authentication.
What Should Happen?
mcp__notion__complete_authentication should accept https://mcp.notion.com/callback?code=...&state=<base64-JSON> as a valid callback URL by decoding the state JSON and validating the inner state field against the stored value.
Error Messages/Logs
Authentication failed for notion: OAuth state mismatch - possible CSRF attack
Steps to Reproduce
- Call
mcp__notion__authenticate— receive an auth URL withredirect_uri=http://localhost:<port>/callback - Open the URL in browser →
mcp.notion.comredirects tohttps://www.notion.so/install-integration?...&redirect_uri=https://mcp.notion.com/callback&... - Authorize on the Notion page
- Browser lands on
https://mcp.notion.com/callback?code=...&state=<base64-JSON>— the relay does not forward to localhost - Paste that URL into
mcp__notion__complete_authentication - Error:
Authentication failed for notion: OAuth state mismatch - possible CSRF attack
Root cause: mcp.notion.com wraps the original state string inside a base64-encoded JSON object before sending the callback:
{
"state": "<original-raw-state>",
"redirectUri": "http://localhost:<port>/callback",
"codeChallenge": "...",
...
}
complete_authentication compares the raw state query parameter against the stored state, but it receives the base64 JSON wrapper instead of the raw state — so validation fails even though the original state is present inside the JSON.
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
N/A
Claude Code Version
2.1.119 (Claude Code)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
The mcp__notion__complete_authentication tool documentation states it handles the case where "the browser shows a connection error on the redirect page." However, when using Notion MCP, the browser never reaches localhost at all — it stays at mcp.notion.com/callback. The tool needs to handle this relay pattern.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗