CLI 0.147.0 reports “MCP startup interrupted” even though all servers initialize successfully
What version of Codex CLI is running?
codex-cli 0.147.0
What subscription do you have?
paid company account
Which model were you using?
gpt-5.6-sol
What platform is your computer?
Darwin 25.5.0 arm64 arm
What terminal emulator and version are you using (if applicable)?
iTerm2 3.7.0beta9, without a terminal multiplexer.
Codex doctor report
{
"schemaVersion": 1,
"generatedAt": "<REDACT>",
"overallStatus": "ok",
"codexVersion": "0.147.0",
"checks": {
"app_server.status": {
"id": "app_server.status",
"category": "app-server",
"status": "ok",
"summary": "background server is not running",
"details": {
"control socket": "/Users/<REDACT>/.codex/app-server-control/app-server-control.sock",
"daemon state dir": "/Users/<REDACT>/.codex/app-server-daemon",
"mode": "ephemeral",
"pid file": "/Users/<REDACT>/.codex/app-server-daemon/app-server.pid (missing)",
"settings": "/Users/<REDACT>/.codex/app-server-daemon/settings.json (missing)",
"status": "not running",
"update-loop pid file": "/Users/<REDACT>/.codex/app-server-daemon/app-server-updater.pid (missing)"
},
"remediation": null,
"durationMs": 0
},
"auth.credentials": {
"id": "auth.credentials",
"category": "auth",
"status": "ok",
"summary": "auth is configured",
"details": {
"auth file": "/Users/<REDACT>/.codex/auth.json",
"auth storage mode": "File",
"stored API key": "false",
"stored ChatGPT tokens": "true",
"stored agent identity": "false",
"stored auth mode": "chatgpt"
},
"remediation": null,
"durationMs": 0
},
"config.load": {
"id": "config.load",
"category": "config",
"status": "ok",
"summary": "config loaded",
"details": {
"CODEX_HOME": "/Users/<REDACT>/.codex",
"config.toml": "/Users/<REDACT>/.codex/config.toml",
"config.toml parse": "ok",
"cwd": "<REDACT>",
"enabled feature flags": "shell_tool, view_image, unified_exec, shell_snapshot, code_mode_host, terminal_resize_reflow, sqlite, hooks, enable_request_compression, multi_agent, apps, tool_search_always_defer_mcp_tools, tool_suggest, plugins, in_app_browser, in_app_updates, browser_use, browser_use_full_cdp_access, browser_use_external, computer_use, remote_plugin, plugin_sharing, image_generation, resize_all_images, item_ids, skill_mcp_dependency_install, skill_search, mentions_v2, steer, guardian_approval, goals, collaboration_modes, tool_call_mcp_elicitation, auth_elicitation, personality, fast_mode, tui_app_server, remote_compaction_v2, workspace_dependencies",
"feature flag overrides": "none",
"feature flags enabled": "39",
"log dir": "/Users/<REDACT>/.codex/log",
"mcp servers": "5",
"model": "gpt-5.6-sol",
"model provider": "openai",
"sqlite home": "/Users/<REDACT>/.codex"
},
"remediation": null,
"durationMs": 0
},
"git.environment": {
"id": "git.environment",
"category": "git",
"status": "ok",
"summary": "git version 2.55.0",
"details": {
".git entry": "directory",
"PATH git #1": "/opt/homebrew/bin/git",
"PATH git #2": "/usr/bin/git",
"PATH git entries": "2",
"git branch": "<REDACT>",
"git build options": "git version 2.55.0; cpu: arm64; no commit associated with this build; sizeof-long: 8; sizeof-size_t: 8; shell-path: /bin/sh; rust: disabled; feature: fsmonitor--daemon; gettext: enabled; libcurl: 8.7.1; zlib: 1.2.12; SHA-1: SHA1_DC; SHA-256: SHA256_BLK; default-ref-format: files; default-hash: sha1",
"git exec path": "/opt/homebrew/opt/git/libexec/git-core",
"git version": "git version 2.55.0",
"repo detected": "true",
"repo root": "<REDACT>",
"selected git": "/opt/homebrew/bin/git"
},
"remediation": null,
"durationMs": 95
},
"installation": {
"id": "installation",
"category": "install",
"status": "ok",
"summary": "installation looks consistent",
"details": {
"PATH codex #1": "/opt/homebrew/bin/codex",
"current executable": "/opt/homebrew/bin/codex",
"install context": "brew (package /opt/homebrew/Caskroom/codex/0.147.0, bin /opt/homebrew/Caskroom/codex/0.147.0/bin, resources /opt/homebrew/Caskroom/codex/0.147.0/codex-resources, path /opt/homebrew/Caskroom/codex/0.147.0/codex-path)",
"managed by bun": "false",
"managed by npm": "false",
"managed by pnpm": "false",
"managed package root": "not set"
},
"remediation": null,
"durationMs": 2
},
"mcp.config": {
"id": "mcp.config",
"category": "mcp",
"status": "ok",
"summary": "MCP configuration is locally consistent",
"details": {
"configured servers": "5",
"disabled servers": "1",
"stdio servers": "3",
"streamable_http servers": "2"
},
"remediation": null,
"durationMs": 1176
},
"network.env": {
"id": "network.env",
"category": "network",
"status": "ok",
"summary": "network-related environment looks readable",
"details": {
"proxy env vars": "none"
},
"remediation": null,
"durationMs": 0
},
"network.provider_reachability": {
"id": "network.provider_reachability",
"category": "reachability",
"status": "ok",
"summary": "active provider endpoints are reachable over HTTP",
"details": {
"ChatGPT base URL": "https://chatgpt.com/backend-api/ reachable (HTTP 404)",
"reachability mode": "ChatGPT auth"
},
"remediation": null,
"durationMs": 216
},
"network.websocket_reachability": {
"id": "network.websocket_reachability",
"category": "websocket",
"status": "ok",
"summary": "Responses WebSocket handshake succeeded",
"details": {
"DNS": "2 IPv4, 0 IPv6, first IPv4",
"auth mode": "chatgpt",
"connect timeout": "15000 ms",
"endpoint": "wss://chatgpt.com/backend-api/<redacted>",
"handshake result": "HTTP 101 Switching Protocols",
"model provider": "openai",
"models etag present": "true",
"provider name": "OpenAI",
"proxy env vars": "none",
"reasoning header": "false",
"server model present": "false",
"supports websockets": "true",
"wire API": "responses"
},
"remediation": null,
"durationMs": 628
},
"runtime.provenance": {
"id": "runtime.provenance",
"category": "runtime",
"status": "ok",
"summary": "running brew on macos-aarch64",
"details": {
"commit": "unknown",
"current executable": "/opt/homebrew/bin/codex",
"install method": "brew (package /opt/homebrew/Caskroom/codex/0.147.0, bin /opt/homebrew/Caskroom/codex/0.147.0/bin, resources /opt/homebrew/Caskroom/codex/0.147.0/codex-resources, path /opt/homebrew/Caskroom/codex/0.147.0/codex-path)",
"platform": "macos-aarch64",
"version": "0.147.0"
},
"remediation": null,
"durationMs": 0
},
"runtime.search": {
"id": "runtime.search",
"category": "search",
"status": "ok",
"summary": "search is OK (bundled)",
"details": {
"search command": "/opt/homebrew/Caskroom/codex/0.147.0/codex-path/rg",
"search command readiness": "file exists",
"search provider": "bundled"
},
"remediation": null,
"durationMs": 0
},
"sandbox.helpers": {
"id": "sandbox.helpers",
"category": "sandbox",
"status": "ok",
"summary": "sandbox configuration is readable",
"details": {
"approval policy": "OnRequest",
"codex-linux-sandbox helper": "none",
"execve wrapper helper": "/Users/<REDACT>/.codex/tmp/arg0/<REDACT>/codex-execve-wrapper",
"filesystem sandbox": "restricted",
"network sandbox": "restricted"
},
"remediation": null,
"durationMs": 0
},
"state.paths": {
"id": "state.paths",
"category": "state",
"status": "ok",
"summary": "state paths and databases are inspectable",
"details": {
"CODEX_HOME": "/Users/<REDACT>/.codex (dir)",
"active rollout files": "467 files, 317879022 total bytes, 680683 average bytes",
"archived rollout files": "0 files, 0 total bytes, 0 average bytes",
"goals DB": "/Users/<REDACT>/.codex/goals_1.sqlite (file)",
"goals DB integrity": "ok",
"log DB": "/Users/<REDACT>/.codex/logs_2.sqlite (file)",
"log DB integrity": "ok",
"log dir": "/Users/<REDACT>/.codex/log (dir)",
"memories DB": "/Users/<REDACT>/.codex/memories_1.sqlite (file)",
"memories DB integrity": "ok",
"queue DB": "/Users/<REDACT>/.codex/queue_1.sqlite (file)",
"queue DB integrity": "ok",
"sqlite home": "/Users/<REDACT>/.codex (dir)",
"state DB": "/Users/<REDACT>/.codex/state_5.sqlite (file)",
"state DB integrity": "ok",
"thread history DB": "/Users/<REDACT>/.codex/thread_history_1.sqlite (file)",
"thread history DB integrity": "ok"
},
"remediation": null,
"durationMs": 313
},
"state.rollout_db_parity": {
"id": "state.rollout_db_parity",
"category": "threads",
"status": "ok",
"summary": "rollout files and state DB thread inventory agree",
"details": {
"default model provider": "openai",
"rollout DB active files": "467",
"rollout DB active rows": "467",
"rollout DB archive mismatches": "0",
"rollout DB archived files": "0",
"rollout DB archived rows": "0",
"rollout DB duplicate DB paths": "0",
"rollout DB duplicate rollout thread ids": "0",
"rollout DB malformed file names": "0",
"rollout DB missing active rows": "0",
"rollout DB missing archived rows": "0",
"rollout DB model providers": "openai=467",
"rollout DB rows": "467",
"rollout DB scan cap reached": "false",
"rollout DB scan errors": "0",
"rollout DB sources": "cli=429, subagent:other=27, subagent:thread_spawn=8, vscode=3",
"rollout DB stale rows": "0"
},
"remediation": null,
"durationMs": 165
},
"system.environment": {
"id": "system.environment",
"category": "system",
"status": "ok",
"summary": "OS language en-US",
"details": {
"EDITOR": "set",
"GH_PAGER": "set",
"GIT_PAGER": "set",
"LANG": "en_US.UTF-8",
"LC_ALL": "C.UTF-8",
"LC_CTYPE": "C.UTF-8",
"LESS": "set",
"PAGER": "set",
"VISUAL": "set",
"os": "Mac OS 26.5.2 [64-bit]",
"os language": "en-US",
"os type": "Mac OS",
"os version": "26.5.2"
},
"remediation": null,
"durationMs": 4
},
"terminal.env": {
"id": "terminal.env",
"category": "terminal",
"status": "ok",
"summary": "terminal metadata was detected",
"details": {
"COLORFGBG": "15;0",
"COLORTERM": "truecolor",
"NO_COLOR": "1",
"TERMINFO_DIRS entry": [
"/Applications/iTerm.app/Contents/Resources/terminfo (dir)",
"/usr/share/terminfo (dir)"
],
"TERM_PROGRAM": "iTerm.app",
"color output": "disabled (NO_COLOR)",
"effective locale": "C.UTF-8",
"stderr is terminal": "false",
"stdin is terminal": "false",
"stdout is terminal": "false",
"terminal": "iTerm2",
"terminal size": "80x24",
"terminal version": "3.7.0beta9"
},
"remediation": null,
"durationMs": 6
},
"terminal.title": {
"id": "terminal.title",
"category": "title",
"status": "ok",
"summary": "terminal title default",
"details": {
"terminal title activity": "true",
"terminal title items": "activity, project-name",
"terminal title project source": "git repo root",
"terminal title project value": "<REDACT>",
"terminal title source": "default"
},
"remediation": null,
"durationMs": 0
},
"updates.status": {
"id": "updates.status",
"category": "updates",
"status": "ok",
"summary": "update configuration is locally consistent",
"details": {
"cached latest version": "0.147.0",
"check for update on startup": "true",
"last checked at": "<REDACT>",
"latest version": "0.147.0",
"latest version status": "current version is not older",
"update action": "brew upgrade --cask codex",
"version cache": "/Users/<REDACT>/.codex/version.json"
},
"remediation": null,
"durationMs": 73
}
}
}
What issue are you seeing?
After upgrading from Codex CLI 0.146.x to 0.147.0, the TUI displays this message during startup:
MCP startup interrupted. The following servers were not initialized: appsignal, codex_apps, linear, node_repl, <REDACT>_readonly
This status appears to be incorrect or stale. Codex’s logs show that each named MCP server subsequently initializes successfully, without an authentication failure, timeout, or transport error.
The affected servers include:
- Two streamable HTTP servers
- The built-in
codex_appsserver - A local Node REPL stdio server
- A project-scoped PostgreSQL toolbox stdio server whose identifying name has been redacted
After startup, /mcp and the available tool catalog show tools from all five servers. codex doctor --json also reports overallStatus: "ok" and an internally consistent MCP configuration.
This is therefore primarily a status-reporting problem: the message says the servers “were not initialized,” even though initialization continues in the background and completes successfully.
What steps can reproduce the bug?
- Configure multiple optional MCP servers, including at least one stdio server that takes several seconds to initialize.
- Upgrade Codex CLI through Homebrew:
``sh``
brew upgrade --cask codex
codex --version
- Confirm the installed version is
codex-cli 0.147.0. - Start the interactive TUI:
``sh``
codex
- Begin interacting with or typing into the TUI while MCP startup is still in progress.
- Observe the following status message:
``text``
MCP startup interrupted. The following servers were not initialized: ...
- Wait several seconds and inspect
/mcpor the available MCP tool catalog. - Observe that the servers listed as “not initialized” have actually initialized and their tools are available.
- Run:
``sh``
codex doctor --summary
- Observe that the installation, network, WebSocket, authentication, and MCP configuration checks all pass.
On this machine, repeated startup logs showed initialization completing approximately as follows:
node_repl: initialized
codex_apps: initialized
linear: initialized
appsignal: initialized
<REDACT>_readonly: initialized
The slowest project-scoped stdio server completed within approximately 5–13 seconds and has a configured 60-second startup timeout. The Node REPL has a configured 120-second startup timeout. No timeout was reached.
No thread ID is included because the warning occurs during TUI startup, before a task-specific thread is needed.
What is the expected behavior?
If optional MCP initialization continues in the background, the TUI should not report those servers as definitively “not initialized.”
A more accurate status would be something like:
MCP startup is continuing in the background: ...
The status should then update or disappear when those servers initialize.
If startup is interrupted only at the UI/waiting layer, the message should distinguish that from an actual MCP initialization failure. Only servers that genuinely fail, time out, or are cancelled should be reported as not initialized.
Additional information
- This started immediately after upgrading to CLI 0.147.0.
- It was not observed with the previous 0.146.x installation.
- The 0.147.0 changelog mentions non-blocking optional MCP startup and changes to terminal input handling while MCP servers initialize, so this may be related to the new startup lifecycle.
- The experimental
mcp_2026_07_28feature is not enabled. - All five named servers are usable in the same session where the warning was reported.
- Relevant logs, with paths and identifying information removed, contain successful
Service initializedevents for every named server and do not contain a corresponding startup timeout or fatal connection failure.
8 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
This matches earlier-reported issues — same underlying mechanism, now directly reproduced (see the update below):
mcpServer/startupStatus/updatednotifications, including spuriouscancelledevents, for servers started exactly onceTwo additional data points:
~/.codex/logs_2.sqlite, desktop 26.803.41515 / bundled 0.147.0-alpha.6.5) also containstart_server_task{server_name=…}:initialize:serve_inner: task cancelledevents duringthread/startandthread/resume, for servers such ascodex_appsandnode_repl— the same signature noted in #36486/#36682.Per #36486,
[features] plugins = falseconsistently removed the warning (reported workaround, not a fix).Update — deterministic direct repro + code path (0.147.0-alpha.6.5, isolated CODEX_HOME, synthetic stdio MCP servers whose
initializeresponses are delayed):codex— wait for the "Starting MCP servers (0/N) … esc to interrupt" headerCode path (current main): ESC with no active turn →
Session::interrupt_task→cancel_mcp_startup()(codex-rs/core/src/session/mod.rs:4074) → pending startup tasks emitMcpStartupStatus::Cancelled(codex-rs/codex-mcp/src/connection_manager.rs:451–545) → forwarded asmcpServer/startupStatus/updated { status: Cancelled }(codex-rs/app-server/src/bespoke_event_handling.rs:217) → TUI renders the warning for every Cancelled server (codex-rs/tui/src/chatwidget/mcp_startup.rs:186).So a user-cancelled eager startup is reported with the same wording as an initialization failure, while the servers simply start on next use — matching the report's observation that everything works afterwards. The
thread/start/thread/resumevariant of the spurioustask cancelledtraces is the same Cancelled mechanism reached via runtime replacement rather than ESC.Suggested direction: treat user-cancelled startup separately from failures — a neutral message ("startup skipped; servers start on first use") or no warning at all, since nothing actually failed.
Independent Linux reproduction on Codex CLI 0.147.0 with two local stdio MCP servers: Flameox 0.1.12 and Jacobian 0.9.0.
The TUI reported:
Both server commands were then verified with the exact
initializerequest used by Codex (protocolVersion: "2025-06-18"): each returned a valid MCP initialize result and exited cleanly when stdin closed; neither wrote stderr.The local Codex log also shows the startup timeline:
For Flameox, the successful initialization was recorded about four seconds after it was omitted as pending. This confirms the problem is not limited to the built-in or HTTP MCPs: it also affects independently maintained Python stdio servers on Linux, and the warning does not establish an MCP-side failure.
Corroborated on Windows 11 with
codex-cli 0.147.0and the same all-server false negative pattern.The TUI reported these four servers as not initialized:
codex_appsdos(stdio)fak(stdio)openaiDeveloperDocs(streamable HTTP)The authoritative local
logs_2.sqlitestartup process (pid:50440:e865d723-a011-4f93-ac63-5a851a430040) records successfulrmcp::service ... Service initialized as clientevents for all four:codex_appsandopenaiDeveloperDocsat 14:59:22, thenfakanddosat 14:59:25. That process has zero MCP WARN/ERROR rows. Immediately afterward,/mcp/tool availability was healthy; the fak-side independent probes also passed (fak doctor mcp --jsonvalid initialize, andfak dev codex-mcp-health --jsonreturnedRECONNECT_OK).This rules out a fak startup failure in this occurrence and matches the 0.147.0 UI/wait-layer regression described here. It also differs from the real plugin-refresh cancellation/process leak in #37025: no failed server and no stray
fak serve --stdiochild remained.Another reproduction on Linux/WSL2 where the affected server is streamable HTTP, not stdio.
Environment:
codex-cli 0.147.0streamable_httpserver athttps://mcp.context7.com/mcpThe first turn did not receive the Context7 tools and Context7 was reported/unavailable as though startup had failed. The SQLite log shows a startup/refresh race rather than an MCP-side failure:
There was no Context7 HTTP authentication error, transport error, protocol error, or startup timeout.
codex mcp get context7continued to show the server as enabled withtransport: streamable_httpand a masked configured header.The logs also contain warnings that
org.freedesktop.secretsis unavailable while Codex attempts to load OAuth tokens. Those warnings occur for multiple HTTP MCP servers and appear non-causal here: Context7 accepted the configured static header and returned a valid initialize response.This corroborates the runtime-replacement/cancellation path described above. One additional user-visible consequence in this reproduction is that, although Context7 successfully initialized, its tools were absent from the first turn's tool snapshot. The snapshot had already omitted the server as pending and was not rebuilt for that turn after initialization completed.
Independent reproduction on macOS 15.7.8 (24G824), x86_64, with Codex CLI 0.147.0 (observed 2026-08-19 KST).
This reproduces in the interactive TUI with no keyboard input during startup. Context7 is a local stdio server launched as
npx -y @upstash/context7-mcp(Context7 4.0.2).codex doctor --summary --asciireports 17 OK, 0 warnings, and 0 failures; the MCP configuration is locally consistent.A representative no-input TUI launch showed the interruption banner even though the backend log recorded every configured server as initialized first:
The TUI then reported all four servers as not initialized. In ordinary launches the banner often names only Context7, which is the slowest of the four.
Context7 itself is healthy:
npxsucceeds in 1.61 s, well below the documented 10 s default startup timeout.codex exec --ephemeralsession successfully called Context7'sresolve-library-idtool and returned/reactjs/react.dev.startup_timeout_sectherefore does not match the observed cancellation timing or failure mode.I also ran a non-persistent control launch:
In that run there were zero remote installed-plugin sync events, all four MCP servers initialized (Context7 in about 1.4 s), and no interruption banner appeared during a 15-second observation window. The actual config file was not modified.
This seems to corroborate the plugin-sync/runtime-reconciliation path in #37025 together with the duplicate/stale startup-status behavior in #36682, rather than an MCP transport, Context7, authentication, or timeout failure. It may also be relevant that #36895 is already included in 0.147.0, yet this no-input reproduction remains.
Adding a second source of
Cancelledfound in source — the ESC path from my earlier comment is not the only one, which may account for reproductions with no keypress.Every startup task also waits on a publication gate before reporting its outcome; if the gate's sender is dropped without publishing (the MCP runtime being replaced/discarded), the task returns
StartupOutcomeError::Cancelledwith no user action:McpPublicationGate::wait()returns false when the watch sender is dropped (codex-rs/codex-mcp/src/runtime.rs:128–159)codex-rs/codex-mcp/src/connection_manager.rs:446, 467, 562, 681all returnErr(StartupOutcomeError::Cancelled)This is the same
Cancelledstatus the TUI renders as "MCP startup interrupted / not initialized", so anything that swaps the runtime while servers are still starting (session start/resume replacing the MCP runtime) surfaces the identical misleading banner — and matches the spurioustask cancelledstartup traces observed during desktopthread/start/thread/resume. It also lines up with @ragtimelab's observation that the banner disappears withfeatures.plugins=false: plugin-sync churn (e.g. the unscopedcodex_appsstartup task being cancelled) is exactly the kind of startup replacement that reaches this path without any keypress.This reinforces the earlier suggested direction: the user-visible status should distinguish real failures from lifecycle cancellation — or suppress the warning for
Cancelledentirely, since the servers start on next use. (Verified on main @67ed4e7.)Still reproduces on 0.148.0 (release binary, macOS 26.5.2 arm64) — same shape as the ESC-triggered repro in my original comment.
Repro on 0.148.0 (isolated, no auth; temp
CODEX_HOMEwith three synthetic stdio MCP servers whoseinitializeresponses are delayed 1 s / 8 s / 8 s, ESC injected at t=2 s while the two slow servers are still Starting):The 1 s server (Ready before ESC) is again excluded — the list is a snapshot of what was still Starting at cancel time, not a set of failures.
Code state (current main). The ESC chain is unchanged: ESC with no active turn →
interrupt_task→cancel_mcp_startup()(codex-rs/core/src/session/mod.rs:4091–4098), per-serverCancelledstatus (codex-rs/codex-mcp/src/connection_manager.rs), forwarded atcodex-rs/app-server/src/bespoke_event_handling.rs:219, and the TUI renders the same "interrupted / not initialized" warning atcodex-rs/tui/src/chatwidget/mcp_startup.rs:185–191. With the second, keypress-free source ofCancelled(publication gate) described in my follow-up also still present, 0.148.0 covers neither trigger.The earlier suggestion therefore stands: cancelled-but-healthy startup should be reported distinctly from failures (or not at all), since the servers simply start on next use and nothing actually failed.