Repository navigation
Description
What version of the IDE extension are you using?
openai.chatgpt 26.803.41515 and 26.803.61601 (macOS x86_64 binary) — reproduced on both
What subscription do you have?
pro 20x
Which IDE are you using?
VS Code
What platform is your computer?
macOS (Darwin 25.5.0), x86_64
What issue are you seeing?
Each Codex session spawns a complete set of the configured MCP servers as children of the extension's codex app-server process. When a session ends (or a new one starts), the old set is never terminated. Sets accumulate for as long as the extension host lives — days — at roughly 80–160 MB RSS per process.
Setup: ~8 MCP servers configured (argent, @playwright/mcp, xcodebuildmcp, @upstash/context7-mcp, @lottiefiles/creator-mcp, plus 3 project-local stdio servers).
Measured occurrences (same machine, Aug 6–14, 2026)
- Aug 6: 14 leaked sets, 110 processes, ~8 GB resident; swap 8.2/9.2 GB
- Aug 9: ~20 sets, 243 processes, oldest 25+ h; swap 7.45/8.19 GB
- Aug 12 (worst): 71 sets, 490 processes, 26.5 GB resident; swap 25.4/26.6 GB — only 1.2 GB of swap left
- Aug 14 (twice): 19 sets / 169 processes, then 9 sets / 108 processes (~8 GB) after ~1 day of uptime — this time with swap healthy, so the leak shows up as general system jank well before memory pressure
Failure mode under pressure (Aug 12)
When memory is exhausted, MCP server startup fails, and the extension responds by respawning the entire set — we measured ~1.5 new sets per minute against only 9 actual session rollouts in ~/.codex/sessions in the same hour. That feedback loop is what users experience as "Codex could not start": the session journal shows the agent completing turns normally while the UI can't attach to MCP. The respawn storm stopped on its own the moment the leaked processes were killed.
What steps can reproduce the bug?
- Configure a set of MCP servers for the extension (~8 in our case: argent, @playwright/mcp, xcodebuildmcp, @upstash/context7-mcp, @lottiefiles/creator-mcp, plus 3 project-local stdio servers).
- Open VS Code with the extension and start a Codex session. A full set of MCP server processes is spawned as children of the extension's
codex app-serverprocess. - End that session and/or start a new one. A second full set is spawned; the first set is still running.
- Repeat over normal daily use and leave the extension host running for hours/days.
- Inspect the process tree (e.g.
ps -eo pid,ppid,rss,etime,command | grep -i mcp, orpstreefrom thecodex app-server/codexPID) and count the sets.
Observed: one full set of MCP server processes per session, none reaped. On this machine that reached 71 sets / 490 processes / 26.5 GB resident after several days of uptime (see the measurements above). Under memory pressure the extension additionally respawns sets at ~1.5/minute, far in excess of the actual session count in ~/.codex/sessions.
What is the expected behavior?
Old MCP server sets are terminated when their session ends, or at minimum reaped when a new set is spawned / on extension host shutdown.
Additional information
- Every leaked process (7 occasions, ~1,300 processes total) exited cleanly on plain
SIGTERM; none requiredSIGKILLand none orphaned to init. So this appears to be purely missing lifecycle cleanup, not hung children. - After an extension auto-update, the superseded version's extension host can linger with all its leaked children; nothing ever cleans those up either (observed Aug 12: old host holding 26 GB while the updated build failed to start).
- The parent process shape changes between builds (sometimes
codex app-serverowns the sets, sometimes the maincodexprocess does), but the leak reproduces in both.
Activity
github-actions commentedon Aug 14, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
xtyooo commentedon Sep 4, 2026
Windows Codex Desktop reproduction: per-session stdio MCP bundles still accumulate after the lifecycle fix in #19753
I can reproduce the same process-tree shape on Windows Codex Desktop. This expands the report beyond the macOS VS Code extension case and may help distinguish an app/extension session-ownership gap from the lower-level
McpConnectionManagershutdown bug fixed by #19753.Environment
10.0.1904526.707.31428codex-cli 0.144.0-alpha.4codex.exe ... app-serverprocess.vite/buildpayload against its preserved original ASAR backup and the core build files were byte-identical. The bundledcodex.exeis the binary reporting the version above.Observed failure
Before cleanup, one app-server process owned 414 descendants:
node.execmd.exepython.exeuv.exeuvx.exenode_repl.exemcp-server-fetch.exemcp-sequential-thinking.exeThe exact multiples are consistent with ten complete MCP startup cycles, not ten Codex app-server processes.
Clean-start timeline
After a full process-tree cleanup and restart:
There was no session/MCP shutdown event between
thread/startandthread/resume. Both bundles remained direct descendants of the same app-server process.This is especially easy to trigger in Desktop because startup opens/prewarms a new-thread route, then navigating to an existing conversation resumes a second session.
Why this appears to survive #19753
The local backend appears to contain the #19753 lifecycle code: its binary contains the added strings
MCP client is shut down,failed to initialize MCP client during shutdown, andShutting down Codex instance.PR #19753 added explicit MCP teardown for session shutdown, submission-channel closure, manager refresh/replacement, and temporary connector probing. Based on the absence of a shutdown event in this reproduction, the first session appears to remain owned/alive when the UI resumes another thread, so its manager is neither replaced nor shut down. The lower-level termination code cannot run if the app-server session never reaches a shutdown path.
This suggests a remaining lifecycle gap above
RmcpClient::shutdown()rather than the original absence of an MCP process terminator.Mitigation experiment
I reduced the enabled MCP configuration to four actually used servers (
fetch,github,playwright, and the Desktop-managednode_repl) and restarted cleanly:This bounds the impact but confirms the per-session accumulation still occurs and scales linearly with the number of retained bundles.
Suggested regression coverage / investigation
An app-server integration test could use a stub stdio MCP server that writes its PID, then reproduce the Desktop ownership sequence:
thread/startsession A and wait for MCP A's PID.The key question appears to be which layer should declare session A unreachable: the Desktop/extension client, app-server owner/subscription tracking, or a bounded idle-session eviction policy. Simply shutting down the previous session on every
thread/resumewould break legitimate parallel work, so cleanup likely needs to follow ownership plus active-turn state.I can provide additional sanitized process snapshots or run a targeted test build if maintainers identify the intended session-detach path.
vangj commentedon Sep 20, 2026
Linux reproduction on Codex CLI 0.154.0 with a project-local stdio Graphify MCP server:
This resembles the app-server ownership gap described above rather than the lower-level shutdown defect fixed by #19753: old per-session server trees remain live, while a direct non-MCP invocation still works. The large graph amplifies the memory impact of every retained MCP process, but it does not explain why obsolete per-session processes remain owned.
The corresponding downstream investigation was rocketvector/darkstar-bbn#940. We are closing it as an upstream lifecycle issue rather than convening a repository architecture council. No ambiguous processes were terminated during diagnosis.
chrisl10 commentedon Oct 15, 2026
Adding a data point that extends this beyond the VS Code extension: the same per-session spawn-without-reap happens under any long-lived
codex app-serverprocess driven programmatically (orchestrator creating threads over the MCP interface), codex-cli 0.162.1, macOS.Observed on one engine over a few hours of multi-thread work: 1 MCP child at engine start, +2 when a second thread came up, +11 spawned within 2 seconds during a thread-creation burst, total 14 live children (~65 MB RSS each, ~0.9 GB) with zero reaped, including the children from the first hour, after threads finished their work.
Two extra signals that may help triage:
codex app-server, create several threads programmatically, thenpgrep -f <your-mcp-server> | wc -lclimbs per thread and never decreases, even after those threads complete.This suggests the leak lives in the app-server/engine MCP lifecycle itself rather than the extension layer.