Codex Desktop MCP auto connection authorization bug
Open 💬 2 comments Opened May 21, 2026 by fhong-26
What version of the Codex App are you using (From “About Codex” dialog)?
26.513.31313 (2867)
What subscription do you have?
API
What platform is your computer?
Darwin 25.4.0 arm64 arm
What issue are you seeing?
When I am connecting to MCP servers (in my case Notion and Linear), either:
- I use
codex mcp login notion,codex mcp login linearfrom command line, it opens a browser page with the url it gives asking to trust the127.0.0.1, i approve, it shows approved in the browser, then I force quit the codex app, and reopen the runtime, it is connected (This one works) - If I directly tell Codex to look at a ticket in Linear (I had the MCP authenticated before but it does not stays authenticated forever), it launches automatically the webpage for authentication, I click, web page says it is authenticated, but
The XXX MCP is configured, but its refresh token is expired/invalid. I’m going to re-authenticate it now; the skill notes a restart may be needed after OAuth, but I’ll see if this live session can pick it up.and then does not continue with this MCP
What steps can reproduce the bug?
- Go into a session with the coding agent, when Linear/Notion is not yet authenticated/authenticated before but not now;
- Ask Codex to see Linear ticket xxx, It will pop the authenticate web page, you click authenticate
127.0.0.1, and it will say authenticated, but then Codex will say:The XXX MCP is configured, but its refresh token is expired/invalid. I’m going to re-authenticate it now; the skill notes a restart may be needed after OAuth, but I’ll see if this live session can pick it up.
What is the expected behavior?
After I approve the authentication and the page says authenticated, Codex can access the MCP
Additional information
_No response_
2 Comments
Solution: Codex Desktop MCP Auto-Connection Authorization Failure
Issue
openai/codex #23866 — Codex Desktop MCP auto connection authorization bug
Root Cause Analysis
The bug manifests as a token lifecycle management failure in the Desktop app's OAuth flow:
codex mcp login notion→ browser auth → token saved to disk → app restart picks up token → connectedThe root cause is a race condition / state synchronization gap between:
When the Desktop app initiates auth from a live session, the browser callback writes the token to the CLI's token location, but the Desktop app:
Solution A (Recommended): Optimistic Token Refresh with Polling
After the browser auth flow completes, poll for token availability and retry the MCP call:
Solution B: Unified Token Storage Path
Ensure CLI and Desktop app use the same token storage location:
Solution C: Desktop App Token Cache Invalidation
Add a file watcher to the Desktop app that invalidates the token cache when the CLI updates the token file:
Testing Strategy
Impact Assessment
| Metric | Value |
|--------|-------|
| Severity | High (MCP connectors unusable via Desktop auto-auth) |
| User Impact | All Desktop users with MCP connectors |
| Fix Complexity | Medium (token lifecycle management) |
| Workaround | Use CLI auth + app restart (documented in issue) |
Estimated Effort
Recommendation
Implement Solution A as the immediate fix (optimistic polling) and Solution B as the long-term fix (unified token storage). Both can be implemented in parallel. This is a zero-competition issue with a clear reproduction path.
A useful way to make this debuggable would be to expose the auth handoff as explicit states, not only as a final “expired/invalid” error.
For this flow there are at least four distinct points that can fail:
Right now the user sees the browser success page, then the agent still reports an invalid refresh token, so the observable state jumps from step 2 to failure without telling whether step 3 or step 4 broke.
A small diagnostic would help a lot here: after callback, log the token store/keychain location used by Desktop, whether a fresh token was observed, whether the token was accepted by the remote MCP server, and whether
tools/listwas retried. No raw token values needed. That would separate “token persisted to the wrong place” from “Desktop cache did not reload” from “connection was not rebuilt after reload.”