Remote-installed plugin MCP prompts `codex mcp login`, but the command cannot resolve the server
What version of Codex CLI is running?
codex-cli 0.145.0 (latest stable at the time of filing)
What subscription/authentication do you have?
ChatGPT authentication
What platform is your computer?
Ubuntu 24.04.3 LTS under WSL2, x86_64
What issue are you seeing?
An account-synced remote plugin can contribute an OAuth MCP server to the running Codex session, and startup then prints an instruction that cannot be executed successfully:
The cloudflare-api MCP server is not logged in.
Run `codex mcp login cloudflare-api`.
MCP startup incomplete (failed: cloudflare-api)
Running the exact suggested command in another shell fails before OAuth starts:
$ codex mcp login cloudflare-api
Error: No MCP server named 'cloudflare-api' found.
The same registry mismatch is visible through the management commands:
$ codex mcp get cloudflare-api --json
Error: No MCP server named 'cloudflare-api' found.
$ codex mcp list --json
# Only locally configured MCP servers are returned.
The user-level ~/.codex/config.toml does not contain a cloudflare-api server or a local Cloudflare plugin entry. The Cloudflare plugin is account-synced and materialized under the remote plugin cache. Its bundled .mcp.json contains:
{
"mcpServers": {
"cloudflare-api": {
"type": "http",
"url": "https://mcp.cloudflare.com/mcp"
}
}
}
The local remote-install marker contains a backend plugin id, confirming that this is remote-installed plugin state rather than a hand-written MCP configuration.
Steps to reproduce
- Sign in to Codex with ChatGPT authentication.
- Install/enable the OpenAI-curated Cloudflare plugin on a surface that syncs remote plugin installation to the account.
- Start Codex CLI on another host or WSL environment using the same account.
- Observe that the runtime loads the Cloudflare plugin and reports that
cloudflare-apiis not logged in. - Run the suggested command:
``bash``
codex mcp login cloudflare-api
- Observe:
``text``
Error: No MCP server named 'cloudflare-api' found.
Expected behavior
The command printed by the startup warning should work.
More specifically, codex mcp login <name> should resolve the same effective MCP server registry used by the running session, including account-synced remote-installed plugins. If remote plugin MCP authentication must happen through another product surface, the warning should point to that supported flow instead of suggesting a command that cannot resolve the server.
Actual behavior
The running session can see and start the remote plugin MCP server, but a standalone codex mcp login process cannot see the same server name.
This repeats on every startup because the runtime continues to inject the remote plugin, while the suggested login command exits before OAuth.
Workaround
A process-local config override makes the management command resolve the same name and URL without permanently duplicating the MCP server in config.toml:
codex \
-c 'mcp_servers.cloudflare-api.url="https://mcp.cloudflare.com/mcp"' \
-c 'mcp_oauth_credentials_store="file"' \
mcp login cloudflare-api
This workaround was verified end to end on the environment above:
mcp getchanged fromNo MCP server namedto a validstreamable_httpserver record.- The OAuth flow completed with
Successfully logged in to MCP server 'cloudflare-api'. - Codex wrote one matching credential entry to
~/.codex/.credentials.jsonwith mode0600(token values were not printed). - Fresh management processes resolved the credential in both explicit
filemode and defaultautomode. - A fresh
codex execprocess exited successfully without a Cloudflare/MCP startup warning.
The file credential mode is used here because this WSL environment has no Linux Secret Service. It is not required to reproduce the server-registry problem. The important workaround is the one-shot mcp_servers.cloudflare-api.url injection.
This is only a workaround: it relies on duplicating runtime plugin metadata at command invocation. It should not be necessary, and permanently adding the same server to config.toml could create duplicate/conflicting registrations after the bug is fixed.
Source-level evidence
In the 0.145.0 source, run_login:
- loads ordinary configuration,
- creates a fresh
PluginsManager, - immediately calls
configured_servers, and - returns
No MCP server named...if the requested name is absent.
https://github.com/openai/codex/blob/rust-v0.145.0/codex-rs/cli/src/mcp_cmd.rs#L448-L464
A fresh PluginsManager initializes remote_installed_plugins_cache to None:
https://github.com/openai/codex/blob/rust-v0.145.0/codex-rs/core-plugins/src/manager.rs#L428-L469
When that cache is None, remote installed plugin configs resolve to an empty map:
https://github.com/openai/codex/blob/rust-v0.145.0/codex-rs/core-plugins/src/manager.rs#L749-L759
The long-running plugin/app-server path has separate background tasks that fetch remote installed plugins, populate that cache, and refresh the effective runtime:
https://github.com/openai/codex/blob/rust-v0.145.0/codex-rs/core-plugins/src/manager.rs#L945-L1076
So the startup warning and the standalone management command are resolving MCP servers from differently hydrated plugin state.
The same run_login flow is still present in rust-v0.146.0-alpha.4 and current main at the time of filing.
Related issues checked before filing
- #20970: plugin-provided Slack MCP is visible to
get, butremovecannot act on it. This is the closest registry-management mismatch, but hereget,list, andloginall miss an account-synced remote plugin that the runtime uses. - #26275: account-synced plugin capabilities appear in a remote CLI without local install/config. That establishes the adjacent remote-plugin visibility behavior, but it does not cover the broken login instruction.
- #30716: successful MCP login is not hot-reloaded into an already-running app. Here the login command cannot begin because it cannot resolve the server.
- #15122: OAuth login succeeds but does not persist across restarts. Here OAuth cannot start without the temporary registry override.
I could not find an existing issue covering the full combination: runtime-injected remote plugin MCP + startup-generated login instruction + standalone login unable to resolve that server.
4 Comments
Analysis (community)
Thanks for the clear repro and the one-shot
-c 'mcp_servers…'workaround — that was very helpful for narrowing this down. I traced the reported path on currentmain(same shape as onrust-v0.145.0/0.146.0-alpha.4at filing) and believe this is a registry split between the long-lived session/app-server plugin path and the short-lived MCP management CLI, not an OAuth bug.codex-cli0.145.0, Ubuntu 24.04 WSL2; ChatGPT auth + account-synced Cloudflare plugin; server namecloudflare-api.The cloudflare-api MCP server is not logged in. Run \codex mcp login cloudflare-api\.then
codex mcp login|list|get cloudflare-apifails withError: No MCP server named 'cloudflare-api' found.-cmakesmcp loginsucceed end-to-end — so OAuth itself is fine once the name is in the catalog.Root-cause hypothesis
Session / app-server hydrates account-synced remote-installed plugins into
PluginsManager.remote_installed_plugins_cache(background fetch + bundle materialization). Plugin.mcp.jsonservers (e.g.cloudflare-api) then enter the session MCP catalog, andconnection_managercan suggestcodex mcp login <name>when auth is required.codex mcp login|list|get|logoutbuild a freshPluginsManagerwith an empty remote cache and never hydrate it:cli/src/mcp_cmd.rs—run_login(~L448–L463; same pattern inrun_list/run_get/run_logout):Config::load_with_cli_overrides→PluginsManager::new→McpManager::configured_servers→bail!("No MCP server named '{name}' found.")when the name is absent.core/src/mcp.rs—McpManager::configured_servers(~L264–L267) →config.to_mcp_config(plugins_manager).core/src/config/mod.rs—to_mcp_config/to_mcp_config_with_plugin_registrations(~L1563–L1582) →plugins_manager.plugins_for_config.core-plugins/src/manager.rs:new_with_optionssetsremote_installed_plugins_cache: None(~L469).plugins_for_config*merges remote plugins only viaremote_installed_plugin_configs()(~L596 area).None,remote_installed_plugin_configsreturns{}(~L759–L768) — so plugin MCPs never appear, even if a bundle is already on disk.fetch_remote_installed_plugins+write_remote_installed_plugins_cache, loop ~L2410+).maybe_start_plugin_list_background_tasks_for_config/maybe_start_remote_installed_plugin_bundle_sync) are under app-server plugin list paths — not undermcp_cmd.codex-mcp/src/connection_manager.rs—mcp_init_error_display(~L809) hardcodes the login suggestion without checking whether the CLI management surface can resolve that name.So this is not a race inside OAuth: the management path never seeds
remote_installed_plugins_cache, so the name is missing before OAuth runs. Closest prior threads (#20970, #26275, #30716) touch related plugin-MCP visibility / reload edges but not this full combo (session suggests login → short-lived CLI cannot resolve remote-plugin MCP).High-level fix outline (not a PR)
Small, focused alignment: make MCP management CLI resolve the same effective MCP registry as the session for remote-installed plugins — without permanently dual-registering them into user
config.toml.PluginsManager(e.g.ensure_remote_installed_plugins_for_config(config, auth)) that, when plugins are enabled and ChatGPT auth is present, synchronouslyfetch_remote_installed_plugins+write_remote_installed_plugins_cache(and optionally wait/sync materialization for roots already tracked by remote bundle sync), then clear/reload the loaded-plugins cache beforeconfigured_servers.run_login/run_list/run_get/run_logout(any management entry that usesconfigured_servers).RemoteInstalledPluginentries when the API is unavailable — not a warning-text-only change.What not to change (unless product intent says otherwise): OAuth
perform_oauth_loginpath; credential store modes; permanentconfig.tomldual-registration;connection_managerauth detection (beyond maybe improving the message if hydrate fails).Risks / non-goals: CLI latency/network on every
mcp *; auth-required / offline partial state; accidentally exposing remote plugins when plugins are disabled; concurrent cache semantics are process-local so likely low risk.Test ideas
Failing-first, in the spirit of
docs/contributing.md:CODEX_HOMEwith a materialized remote plugin bundle whose.mcp.jsondefinesmcpServers.cloudflare-api(streamable HTTP URL) + remote-install metadata; plugins enabled; nocloudflare-apiin userconfig.toml.PluginsManager::newwithout writingremote_installed_plugins_cache→ login-styleconfigured_serverslookup misses the name (documents today’s bug).write_remote_installed_plugins_cache(orensure_remote_installed_…with mocked fetch returning that plugin) → same lookup finds the streamable HTTP server with the expected URL.mcp list --jsonincludes the plugin MCP;mcp getsucceeds;mcp loginreaches the OAuth entry (mocked transport/auth) rather than “No MCP server named…”.plugins_enabled=falsedoes not invent remote servers; missing ChatGPT auth fails soft (local servers still listed) rather than wiping unrelated config.Questions for maintainers
Happy to be corrected on any of this — especially product intent:
mcp loginalso trigger bundle materialization if the plugin is installed remotely but not yet cached locally (session may have materialized it first)?mcp loginon all platforms?codex mcp *verbs, or login-focused only?Happy to refine the analysis (or dig into any of the open questions) if useful. If the team later wants an invited PR along an approach you choose, I’d be glad to help — no pressure either way.
Building on the root-cause analysis above with the introducing-commit timeline (which I only described behaviorally as "same pattern in 0.145.0/0.146.0/main") and a verified test gap. Traced at
5dd992a(2026-07-24).Latent structure - PR #12864.
run_login's no-hydrate structure was introduced by PR #12864 (752402c4fe, merged 2026-03-01, "feat: load from plugins"), which touchescodex-rs/cli/src/mcp_cmd.rs+core/src/skills/manager.rs+thread_manager.rs. Atmcp_cmd.rsit callsmcp_manager.effective_servers(&config, None)(the historical API at the time; later renamed toconfigured_servers, e.g. by #21356) thenbail!("No MCP server named '{name}' found.")- the same no-hydrate pattern is inrun_logoutandrun_get. At that time remote-installed plugins did not exist, so the bug was latent.Went live - #20096 + #20268. The session-vs-CLI asymmetry was created by two PRs, neither of which touched
mcp_cmd.rs. #20096 (73cd831952, 2026-04-29) introducedremote_installed_plugins_cacheand the session/app-server refresh paths incodex-rs/core/src/plugins/manager.rs. #20268 (2686873e77, 2026-04-30, "Sync remote installed plugin bundles") added remote bundle sync on app-server startup andplugin/list(core-plugins/.../manager.rs+remote.rs+remote_installed_plugin_sync.rs+app-server/.../plugins.rs+app-server/tests/suite/v2/plugin_list.rs). Neither touchedmcp_cmd.rs, so CLI resolution stayed empty-cache while the session path populated the cache.Not fixed as of
5dd992a. Upstreammcp_cmd.rs's latest commit is265cd2e/ #34995 (2026-07-23, HTTP policy) - unrelated. PR #34877 "Wait for local plugin cache refreshes in plugin/list" (2026-07-23) touchescore-plugins/manager.rs+ the app-serverrequest_processors/plugins.rs+plugin_listtests + README, notmcp_cmd.rs- so the CLI hydrate gap remains open.Test gap. The CLI has
mcp list/getintegration coverage for user-config MCP (cli/tests/mcp_list.rs), but there are nomcp login/logouttests and no coverage of the remote-plugin resolution path withremote_installed_plugins_cache == None. Incore-plugins/src/manager_tests.rs, many tests pre-populate the cache viawrite_remote_installed_plugins_cache(...)then callplugins_for_config(e.g.remote_installed_cache_ignores_plugins_missing_local_cache); none exercise the CLIeffective_servers/run_loginpath, and none assert the bug's defining behavior:cache == None=> remote plugin MCP absent despite a materialized bundle on disk. A failing-first test would materialize a remote-plugin bundle, leaveremote_installed_plugins_cache == None(no hydrate), and assert the server name is missing from the CLIrun_login/effective_serverspath - documenting today's gap. To lock a fix, the same setup after a hydrate (write_remote_installed_plugins_cache(...)or fixed CLI wiring) must assert the server name resolves.Minor line-number drift vs my earlier 0.145.0 citations on
main(5dd992a).new_with_optionscache=Noneis now:519(I said ~L469);remote_installed_plugin_configsreturns{}at:809-819(I said ~L759-768);plugins_for_configmerges remote at:646/732/754(I said ~L596). Drift only; behavior identical.Additional reproduction from ChatGPT Pro Work on 2026-08-17:
cloudflare@openai-curated-remote, version 0.1.2, from the OpenAI-curated catalog.source_plugin_installed: trueandsource_plugin_user_enabled: true.cloudflare-apiMCP toolssearch()andexecute()are not exposed to the Work conversation.@Cloudflarein two consecutive turns does not mount either tool.Always ask; this did not change MCP tool availability.codexCLI, so the process-localcodex mcp loginworkaround documented in this issue cannot be tested here.This appears to extend the effective-registry mismatch to ChatGPT Work: the account-synced plugin bundle and skills are present, but its bundled OAuth MCP server is not available to the conversation’s tool registry.
Update: the Cloudflare remote-plugin/MCP integration issue is still reproducible on 2026-08-24.
Environment observed:
Current behavior:
cloudflare-apiMCP is not exposed to ChatGPT/Work sessions (search()/execute()unavailable).Try in chatopens Work, but Work reports that only the plugin skills are available and the official Cloudflare MCP is not available in the session.This matches the symptom reported in Cloudflare issue cloudflare/mcp-server-cloudflare#446 (“ChatGPT plugin only shows skills. No MCP access.”), which was closed on 2026-08-20 after a maintainer said latest ChatGPT upgrades should have fixed it and mentioned a prior
issauth breakage.So, at least for this Plus account, the problem persists after that date and across both ChatGPT Web and Android. The Cloudflare plugin appears to materialize skills but not the authenticated MCP app/tooling.