Disabled plugin's cached MCP server still starts and hangs TUI startup indefinitely (openai-developers / openai-api-key-local-confirmation, no MCP startup timeout)
Summary
A fresh Codex TUI session (v0.144.6, macOS) stalled indefinitely (observed 14+ minutes, no timeout, Escape did not skip) at:
Starting MCP servers (17/18): openai-api-key-local-confirmation
That MCP server is not defined in ~/.codex/config.toml — it ships inside the openai-developers plugin (.mcp.json declares openai-api-key-local-confirmation → node ./mcp/server.mjs, cwd: "."). The plugin was disabled ([plugins."openai-developers@openai-curated"] enabled = false, and codex plugin list agreed: "installed, disabled"), yet Codex started the plugin's MCP server anyway.
Root cause chain (as diagnosed locally)
- Disabled flag and load path referenced different copies. Two cached copies of the plugin existed under different marketplace identities:
~/.codex/plugins/cache/openai-curated/openai-developers/<hash 11c74d6b>and~/.codex/plugins/cache/openai-curated-remote/openai-developers/1.2.3. Theenabled = falsekey (@openai-curated) did not cover theopenai-curated-remotecopy, whose.mcp.jsonwas still loaded at session start. - Registry pointed at a temp staging path.
codex plugin listshowed the install path as~/.codex/.tmp/plugins/plugins/openai-developers— a half-finished remote install (the.tmp/pluginstree contained a full ~180-plugin marketplace mirror, 77 MB, plus a.codex-remote-plugin-install.jsonmarker and a stray.tmpwIcWm7file). This left the remote-cache copy loadable outside the enable/disable bookkeeping. - Why it hangs rather than errors:
server.mjsis a normal stdio JSON-RPC server and answersinitializefine when actually running. But the plugin's.mcp.jsonusescwd: "."with a relative script path (node ./mcp/server.mjs). Launched via the stale cache identity, the relative path apparently resolves against the wrong cwd → node exits immediately (module not found) → Codex waits forever for aninitializeresponse. There is evidently no per-server MCP startup timeout and no detection of a dead child process at this stage, and no way to skip from the TUI.
Bugs to fix
- A disabled plugin's cached
.mcp.jsonservers should never start — plugin enable/disable should be enforced across all marketplace identities / cache copies, and a registry entry pointing into.tmpstaging should be treated as invalid. - MCP startup needs a per-server timeout (and/or child-exit detection) with a visible skip path; a single unresponsive server currently blocks the whole session and queued input indefinitely.
- Interrupted plugin installs should clean up
~/.codex/.tmp/pluginsstaging rather than leaving a loadable orphan that the registry points at.
Workarounds that worked
- Explicit by-name gate in
config.toml:
``toml`
[mcp_servers.openai-api-key-local-confirmation]
command = "node"
args = ["./mcp/server.mjs"]
enabled = false
codex exec` clean.
→ sessions start in seconds, headless
- Permanent fix:
codex plugin remove openai-developers@openai-curated+ purging the orphaned.tmp/pluginsstaging tree and theopenai-curated-remotecache copy. After that the gate is unnecessary.
Environment
- Codex CLI v0.144.6, macOS (arm64, macOS 27.0 beta)
- Plugin: openai-developers 1.2.3 (openai-curated / openai-curated-remote)
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗