Windows 26.715: duplicate MCP suites accumulate per session; termination misses cmd.exe/node.exe grandchildren (Job Object pattern exists in-repo but unused on MCP spawn path)
What version of the Codex App are you using (From "About Codex" dialog)?
26.715.61943 (Windows Store package OpenAI.Codex_26.715.8383.0). codex-cli 0.144.5 is also installed.
What subscription do you have?
Business
What platform is your computer?
Windows 11 Enterprise (build 26200), Intel Core Ultra 9 285H (16 cores), 64 GB RAM
What issue are you seeing?
After an ordinary workday with 2 active Codex Desktop conversations, the machine had 711 running processes and roughly 250 of them were leaked Codex children: 73 node.exe, 62 cmd.exe, and 72-80 git.exe at a single point in time. The machine was visibly sluggish. PPID forensics via Get-CimInstance Win32_Process show two distinct failure modes on the MCP spawn/teardown path.
This is the same family as #18881 (closed), #18333 (closed), #14950, #20867, #25744, and #28244, reproduced on a July Windows build, i.e. after the fixes for #18881 and #18333 landed.
Configured stdio MCP servers at the time: npx @playwright/mcp@latest, npx mcp-remote <remote-url> --transport http-only, npx -y @xdevplatform/xurl mcp <url>, one local Python stdio server, plus the bundled sites plugin design picker (node ./mcp/server.mjs) and node_repl.
Mode A: full MCP suite respawned per session "generation", old generations never terminated, parent still alive
The process table contained roughly 11 complete copies of the full MCP suite. The wrapper cmd.exe processes of every generation had PPID = the live codex.exe. Generation ages: 322, 245, 142, 141, 109, 94, 53, 46, 45, 38, 29, and 6 minutes. Each generation means every configured server spawned again, which matches the McpConnectionManager-replaced-without-shutdown pattern described in #18881. That issue is closed, but the path is evidently still reachable from the Desktop session flow in 26.715.
Because Windows MCP configs typically use command = "npx", each respawn also pays full npm package resolution (about 40% of a core per server for several seconds). On corporate endpoints this is further amplified by EDR software inspecting every process creation.
Mode B: Windows termination misses grandchildren in cmd.exe -> node.exe chains
On Windows the spawn chain is codex.exe -> cmd.exe /c npx.cmd ... -> cmd.exe /d /s /c ... -> node.exe. When codex does terminate a connection, only the direct child dies and the node.exe grandchild survives. Observed as node/npx processes whose PPID no longer exists.
The same hole affects git helpers: 72 git.exe processes (-c core.hooksPath=NUL -c core.fsmonitor=false rev-parse HEAD, remote -v, status --porcelain, config --null --get core.fsmonitor) were alive for 2-5 minutes with dead PPIDs and 0.02 s CPU each: blocked orphans. After clearing them, 21 more accumulated within about 15 minutes.
Respawn/retry storm
After externally killing leaked trees while the engine was running, the engine respawned aggressively: 51 new MCP-chain processes within 8 minutes, and the sites design picker respawned every 20-30 seconds (8 copies within 3 minutes). Only a full app restart stabilized it. Related mitigation gap: codex mcp remove and enabled = false edits to config.toml are not picked up by the running engine, so users cannot mitigate without a full restart.
Root-cause pointer
kill_on_drop(true) (for example in codex-rs/core/src/spawn.rs) maps to TerminateProcess on the direct child on Windows. It cannot reap the cmd.exe-wrapped grandchildren that npx-based Windows MCP configs always create. The repo already contains the correct mechanism: Job Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE in codex-rs/windows-sandbox-rs/src/bin/command_runner/win.rs, but it is not applied on the MCP server spawn path.
Suggested fix: assign stdio MCP server processes (and git helper spawns) to a Job Object with kill-on-close on Windows, and ensure a replaced connection manager explicitly shuts down its children (Mode A indicates the #18881 path is still reachable in 26.715).
What steps can reproduce the bug?
- Windows Codex Desktop 26.715 with 2 or more npx-based stdio MCP servers configured.
- Use 2 conversations normally for a few hours (new chats, session restores).
- Watch
Get-Process node,cmd,git | Group-Object Namegrow. Inspect PPIDs: full duplicate MCP suites parented by the livecodex.exe(Mode A), plus node/git processes with dead PPIDs (Mode B).
Happy to provide full raw process listings (name, PID, PPID, age, command line) from the incident if useful.
11 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Reviewed the suggested issues. #33946, #33531, and #34251 overlap with Mode A of this report (retained or duplicated MCP stacks per session or subagent; #34251 is the same build and identifies the thread/resume trigger). Not closing as duplicate because this report additionally documents Mode B, which none of them cover: on Windows, termination only reaches the direct cmd.exe child, so npx-launched node.exe grandchildren and git.exe helpers survive with dead PPIDs. It also includes a root-cause pointer and a suggested fix: apply the Job Object KILL_ON_JOB_CLOSE pattern that already exists in windows-sandbox-rs to the MCP and git spawn paths, and explicitly shut down replaced connection managers. If maintainers prefer to consolidate, the Mode B analysis can be folded into #33946 or #34251.
Confirmed source-level RED/GREEN for Windows Mode B (
root exited first)I ran a bounded source-only regression test against official Codex commit
61a44880a85d2fd0d8770908dea5733495e571c8on Windows 11 x64. The installed Codex app, Windows settings, services, and user configuration were not modified.STOCK RED
The test used the public
RmcpClientandLocalStdioServerLauncherpath. A PowerShell STDIO root process created a long-lived child, registered both PIDs, and then exited normally. The test held exact non-inheritable process handles, confirmed that the root had exited and the child was still alive, and then calledclient.shutdown().With the stock launcher, shutdown did not terminate the surviving child:
The local nextest profile automatically retried the single issued RED command, so the same failure ran twice. This is one reproducible product case, not two distinct occurrences. Both synthetic children were removed by the test guard.
Minimal candidate fix
On Windows only, wrap the existing Tokio command at the common STDIO launch point with the already-used
process-wrap 9.0.1primitives:process-wrap::JobObjectstarts the root suspended, assigns it to aKILL_ON_JOB_CLOSEJob Object, and resumes it only after assignment. This closes the spawn-to-assignment race without adding a second custom Win32 Job implementation.GREEN and compatibility evidence
1/1 PASS(1.138 s).codex-rmcp-clientproject suite:114/114 PASS; 5 platform/inapplicable cases skipped by the existing suite.cargo clippy --fix --tests -p codex-rmcp-client: completed.0.8/8 PASS, initialization +tools/list+ graceful shutdown:figma_framelink: 2 toolsfirecrawl: 26 toolsgithub: 43 toolsmorph: 2 toolsnode_repl: 3 toolsshadcn: 7 toolstavily: 2 toolsvalyu: 11 toolsScope and limitations
This confirms the Mode B containment defect and the candidate fix for the exact Windows source contour: a descendant that outlives the STDIO root is retained by stock shutdown and is terminated by Job Object containment.
It does not prove that Desktop releases thread/session ownership correctly, and it does not fix Mode A by itself (duplicate MCP suites retained because their owning managers/tasks remain alive). That remains a separate lifecycle layer, related to #33368 and #34658.
The canary covers the eight STDIO MCP server types configured in this environment, including wrapper-based and direct executables. It does not claim compatibility with every possible third-party server, explicit breakaway request, or out-of-job broker.
Per the repository contribution policy, I am sharing the RED/GREEN evidence and minimal design here rather than opening an unsolicited PR. If this approach aligns with the intended fix, I can provide the full regression test and focused patch if invited.
Post-reboot real Desktop route readback
I completed a full Windows reboot and a fresh Codex Desktop launch using the locally tested Job-at-create candidate build described above.
Verified on 2026-07-27 (Europe/Moscow):
26.721.4979.0; its bundled stock CLI SHA-256 remained39E9E041EA33AC34AAD9578ADFE660C5C7A6DC8F82620B77623960F9352A6EF3.587A638A481753FA87B2DAB774EF90D28D32B87EFA75A023ED1443160CA70C83, exactly matching the previously tested build.node server.jsparent was still alive.Current resource snapshot (scope warning): the Desktop app-server owned 58 direct child processes and about 1.6 GiB private memory. These children had a live owner at the snapshot, so this is not evidence that they are orphaned. It also does not show that Mode A/task-retention accumulation is fixed.
Conclusion: real Desktop launch, reboot persistence, image identity, and live STDIO-MCP compatibility are confirmed for the narrow Mode B Job Object candidate. This still does not prove
SYSTEM_FIXED, Desktop thread/session release correctness, or cleanup of every real MCP tree after a natural owner release. Those remain separate lifecycle evidence requirements.Independent Mode A reproduction on Codex Desktop 26.721.4979.0 (Windows)
I captured a real Desktop occurrence on 2026-07-29 (Europe/Riga). This is evidence for Mode A in this issue: repeated MCP workers remained direct children of a still-live Desktop-owned
codex.exe app-server. It is not a Mode B/dead-PPID case.Environment and version boundary
26200.8655.26.721.4979.0.0.144.6during the incident and has since been updated to0.146.0; the Desktop package remains26.721.4979.0. I am therefore not treating the standalone CLI update as proof that the Desktop runtime changed.Before restarting Codex Desktop
The live Desktop app-server subtree had accumulated:
The subtree included 61
nodeprocesses and 33node_replprocesses. Exact duplicate command-line groups were:node_repl.exeworkersnode ./mcp/server.cjs --stdioworkersnode ./mcp/server.mjs --stdioworkersThese workers were direct children of the still-running app-server, so descendant containment alone would not reclaim them while the owner continues retaining the connections/tasks.
Windows Error Reporting also recorded
RADAR_PRE_LEAK_64forcodex.exeat 17:55:33 local time.At the same time there was no hardware saturation that explained the severe interactive lag:
The whole system had reached 421 processes and 8,978 threads.
Restart A/B result
I restarted only Codex Desktop; Windows, hardware, configuration, and the working task data were not changed.
Immediately after the restart, the new app-server subtree was:
node_repl+ 2server.cjs+ 2server.mjsThe counts stayed stable during an 8-second verification sample. Whole-system counts dropped to 312 processes and 6,693 threads, with about 43.7 GiB RAM available. This strongly localizes the accumulated load to the Codex Desktop lifecycle rather than the GPU or storage.
Current follow-up and limits
After the standalone CLI update, a current readback still shows Desktop package
26.721.4979.0. The currently live app-server has 4 direct children in each of the three worker categories. I am not classifying that small current count as a leak because legitimate active ownership has not yet been excluded; a bounded task/create/resume/close test is still needed.The exact accumulation trigger is also not yet proven. During one observation window, ordinary research/tool calls did not continuously increase the post-restart baseline, which suggests task creation/resume/subagent or internal-task lifecycle may be involved, but that remains an inference.
Operator-reported historical context: the same progressive whole-PC lag happened before a GPU upgrade and was initially attributed to the older GPU. Upgrading to the RTX 5080 delayed the visible onset, but the same symptom eventually returned. There is no pre-upgrade process capture, so this is historical corroboration only, not instrumented proof.
Conclusion: this independently reproduces the live-owner/direct-child retention layer (Mode A) on Desktop
26.721.4979.0. It does not test or invalidate the Mode B Job Object work, and it does not yet prove that the MCP runtime-refresh changes in CLI0.146.0fix Desktop thread/session cleanup.Follow-up: bounded create / idle / archive lifecycle test on Desktop
26.721.11231.0Follow-up to my independent Mode A capture. This closes the specific gap noted there: “a bounded task/create/resume/close test is still needed.”
Environment and method
26.721.11231.0.0.146.0(not treated as proof of the Desktop runtime behavior).codex.exe app-serverthroughout the test.Baseline
The app-server tree initially had 13 processes and nine MCP workers:
node_repl.exenode ./mcp/server.cjs --stdionode ./mcp/server.mjs --stdioAggregate baseline was 710.1 MB working set, 503.8 MB private memory, 297 threads, and 3,175 handles.
Repeated lifecycle result
Test 1
node_replonce, completed successfully, and the task reachedidle; the MCP call and final response were both recorded as completed.Test 2
idle.Reactivation control
node_repl+server.cjs+server.mjssuite.The final app-server tree returned to 13 processes and the original nine MCP workers; no test PID remained.
Interpretation
This narrows Mode A on the current Desktop build:
idletask state is not a runtime-cleanup signal; the suite remained alive for the full bounded 60-second observation.A robust fix would likely need lazy per-server startup or a shared/ref-counted MCP runtime, plus deterministic release when the final owning thread/subagent/tool/background activity is gone. Exposing runtime-to-thread ownership in diagnostics would also make safe cleanup verifiable.
Limits
Current Windows Desktop reproduction: completed subagents retain live-owner
npxMCP trees on 26.803I reproduced the Mode A / subagent lifecycle gap on a newer Windows Desktop build than the current reports in this issue.
Environment
26.803.5235.00.147.0-alpha.6.5ChatGPT.exe -> codex.exe app-serverhierarchy throughout the observationcmd.exe /d /s /c "npx -y figma-console-mcp@latest"cmd.exe /d /s /c "npx -y figma-developer-mcp --stdio"Snapshot
node.exeprocesses used about 4.38 GB working set.cmd.exewrappers.``
text
``ChatGPT.exe
-> codex.exe app-server
-> cmd.exe
-> node.exe (npx)
-> cmd.exe
-> node.exe (actual MCP server)
Session/subagent correlation
I matched each direct MCP launcher creation time against local Codex session metadata:
task_complete.That leaves at least 18 logical MCP instances / 36 Node processes still alive after their owning session recorded completion, including 15 instances / 30 Node processes from completed subagents.
One representative subagent started both configured MCP servers at 11:26:53, recorded
task_completeat 12:40:10, and both complete process trees were still alive after 13:00. At the same time, the Desktop task list exposed only 9 loaded local tasks (6 idle, 3 active) while 35 logical Figma MCP instances were alive.Interpretation
This fills the subagent gap noted in the bounded idle/archive test above: on this build, completed native subagent sessions can retain their eager per-session MCP runtimes indefinitely under the live app-server. It is Mode A; this observation does not depend on, or demonstrate, the separate dead-PPID/grandchild Mode B.
Expected behavior is for subagent completion/unload to release its MCP manager and deterministically terminate the whole Windows wrapper tree, unless an explicit shared runtime still has an active reference. A runtime-to-thread/subagent ownership diagnostic would also make safe cleanup and regression testing much easier.
Follow-up with an all-local-STDIO validation on Codex Desktop 26.803.41515 (Windows), extending this beyond Node/npx:
Configured servers:
node_repl.exefastctx.exe servenpx -y figma-console-mcp@latestnpx -y figma-developer-mcp --stdioA completed subagent rollout started at 11:26:52.135 local time. One root for each configured server was created 875–960 ms later (node_repl, fastctx, figma-dev, figma-console); this was the only rollout start in a ±2 s window. The rollout's final
task_completewas 12:40:10.650. After a grace period, all four roots/trees were still alive. The figma-console tree later exited on its own, but node_repl, fastctx, and figma-dev were still alive at 13:44. A controlled FastCtx call changed I/O counters only on the current task's newer FastCtx instance; the older candidate instance showed no activity.A later process census under the same live Desktop app-server found 34 direct node_repl roots, 34 direct fastctx roots, 17 direct figma-console roots, and 25 direct figma-dev roots. These counts include active runtimes and are not themselves a stale-process count, but they confirm the duplication affects all four local STDIO MCP implementations, not only Node.
The missing observability/join key is important:
state_5.sqlitepersists thread metadata, but the completed candidate'sthread_spawn_edges.statuswas stillopen.logs_2.sqliterecords MCP tool calls withthread_idand the app-serverprocess_uuid, but MCP launcher/stderr records have no stable child PID ↔ thread/runtime mapping (oftenthread_id = NULL).Suggested lifecycle/diagnostic additions:
mcp_runtime_id, associated withthread_id(and optionally turn/agent ID).server_name, root child PID, app-server process UUID, launch time, shutdown request, EOF, and exit.tools/callstart/finish, and in-flight count. Idle time alone must not authorize killing; require an absent/terminal owner lease, zero in-flight requests, and a grace period.This would make stale-process classification deterministic instead of relying on start-time correlation.
Reproduced on Windows with ChatGPT/Codex Desktop 26.810.7004.0 the best flagship vibecoded application.
Task Manager showed 253 ChatGPT processes using 8.1 GB RAM. Shortly afterward, there were 139 node.exe processes using 12.5 GB, mostly repeated MCP servers such as GitLab, Jira, Confluence, and Chrome DevTools.
Reproduction on Codex Desktop 26.818: MCP process multiplication and cleanup failure
I can reproduce the same MCP process multiplication and cleanup failure on a
newer native Windows Codex Desktop build.
Environment at the time of the incident
OpenAI.Codex_26.818.8289.00.149.0-alpha.4.3codexonPATHis not the Desktop binary and should not beused as the Desktop version.
PlusConfigured stdio MCP servers
The affected setup contained five Node/npx-based MCP servers:
Some were configured directly and Playwright/Chrome DevTools were supplied by
plugins. The behavior therefore did not appear specific to one MCP package.
Observed behavior
Codex Desktop repeatedly launched complete or near-complete MCP suites during
ordinary task activity. The Windows process chain was:
The child processes appeared in distinct time batches: one around 13:56 and
several more around 15:56-15:59. A process-tree snapshot attributable to the
live Codex app-server contained approximately:
cmd.exeprocessesnode.exeprocessesThe same MCP server names occurred repeatedly across the batches. Closing or
completing the visible task did not reclaim the old process trees. The wrappers
also caused visible
cmd.execonsole flashes on Windows.Disabling MCP entries in
config.tomldid not terminate already-runningchildren. A full tray exit/restart was required before the reduced MCP config
took effect. After disabling the manual MCP entries, residual Context7
processes from the old app-server generation remained until that full exit.
Expected behavior
manager.
cmd.exe-wrapped Nodegrandchildren.
This looks consistent with both failure modes described in #34614: repeated
connection-manager generations and incomplete teardown of the Windows
cmd.exe -> node.exeprocess tree. It also appears related to the newerhigh-volume reproduction in #38825.
I can provide a sanitized PID/PPID/start-time snapshot if a fresh capture is
useful. I have not attached
config.tomlfor security reasons.Additional affected Windows user report — possibly the same process-lifecycle leak, although the exact child-process mix has not yet been captured.
Environment / workload
User-visible symptom
While Codex Desktop is open and has been working on web projects, the entire machine becomes noticeably sluggish: mouse movement/input stutters, and even basic browser page scrolling becomes choppy. The degradation persists while Codex remains open and system responsiveness returns when Codex is fully exited.
The user specifically suspects local/dev-server or helper processes are being left running instead of being torn down between work/session activity. This has not yet been confirmed by a process-tree capture, so I am adding it here as a matching field report rather than claiming the same root cause.
The hardware has ample CPU headroom, so the system-wide input/UI degradation is significant and reproducible enough to make normal desktop use difficult while Codex is open.
If useful, we can collect a sanitized
node.exe/cmd.exe/git.exeprocess count and PPID snapshot during the next affected state.