[Linux CLI 0.147.0] Completed subagents retain bundled plugin MCP processes
Summary
The interactive Codex CLI starts a separate pair of bundled plugin helper processes for every subagent. When the subagent reports completion, those helper processes remain alive under the main Codex process.
For someone unfamiliar with these terms:
- A subagent is a parallel worker that Codex starts to handle part of a task.
- An MCP server is a local helper process that exposes plugin tools to Codex.
- In this reproduction, every subagent started two Node.js MCP servers: one for the OpenAI Developers plugin and one for the Data Analytics plugin.
- Three completed subagents therefore left six extra Node.js processes running.
- These were not independent user programs. Their parent was the main native Codex CLI process, and their start times matched the three subagent starts.
This is a plain interactive CLI reproduction. There was no Codex IDE integration or codex app-server in the affected process tree.
Environment
- Codex:
codex-cli 0.147.0 - Surface: interactive terminal CLI
- OS: Rocky Linux 8.10
- Kernel:
4.18.0-553.126.1.el8_10.x86_64 - Architecture:
x86_64 - Runtime: Slurm interactive allocation on a multi-user HPC cluster
- Multi-agent support: enabled
- Bundled plugin MCP servers involved:
openai-developers 1.2.3:node ./mcp/server.mjsdata-analytics 0.2.8-13ceeea1f599:node ./mcp/server.cjs --stdio- The only user-configured top-level MCP server was remote HTTP; the leaking processes were bundled plugin MCP servers.
What happened
The main Codex session started at 18:07:19 UTC. Its normal baseline included one OpenAI Developers MCP process and one Data Analytics MCP process.
Three subagents started within ten seconds:
|Subagent start|OpenAI Developers MCP|Data Analytics MCP|
|-|-|-|
|18:26:25 UTC|PID 4017219|PID 4017220|
|18:26:30 UTC|PID 4017259|PID 4017258|
|18:26:35 UTC|PID 4017405|PID 4017406|
The subagents returned completed results between 18:28:52 and 18:33:35 UTC. Codex's agent list showed all three as completed.
At 18:56:24 UTC, roughly 23 to 28 minutes after their last completed results, all six MCP processes were still alive:
PID PPID START ELAPSED STATE COMMAND
4017219 4007696 18:26:25 30:00 Sl node ./mcp/server.mjs
4017220 4007696 18:26:25 30:00 Sl node ./mcp/server.cjs --stdio
4017258 4007696 18:26:30 29:55 Sl node ./mcp/server.cjs --stdio
4017259 4007696 18:26:30 29:55 Sl node ./mcp/server.mjs
4017405 4007696 18:26:35 29:50 Sl node ./mcp/server.mjs
4017406 4007696 18:26:35 29:50 Sl node ./mcp/server.cjs --stdio
All six were direct children of the same live native Codex process, PID 4007696. Each helper also had its own process group.
The main session's expected baseline pair was separate:
4007811 4007696 node ./mcp/server.mjs
4007812 4007696 node ./mcp/server.cjs --stdio
Working directories confirmed the identity of every process:
server.mjs -> $CODEX_HOME/plugins/cache/openai-curated-remote/openai-developers/1.2.3
server.cjs -> $CODEX_HOME/plugins/cache/openai-curated-remote/data-analytics/0.2.8-13ceeea1f599
Two completed subagents were given a later follow-up turn. They reused their existing helper pair rather than starting another pair. After the follow-up completed, the pair still remained alive. The third subagent received no follow-up and its pair also remained alive.
The CLI surface in this session exposed spawn, follow-up, interrupt, list, and wait controls, but no close/dispose control for completed subagent threads.
Controlled cleanup
I sent SIGTERM only to the six processes associated with the three completed subagents:
kill -TERM 4017219 4017220 4017258 4017259 4017405 4017406
All six exited immediately. No SIGKILL was required.
A process-tree check seven seconds later showed:
- the main Codex CLI was still running;
- the main session's original two plugin MCP servers were still running;
- all six completed-subagent MCP servers were gone;
- the interactive session continued to work;
- the three agents still appeared as
completedin the agent list.
This isolates the extra six processes from the main session's required helper processes.
Reproduction steps
- Start
codexin an interactive Linux terminal with multi-agent support and bundled plugin MCP tools available. - Record the native Codex PID and its baseline children:
``bash``
ps -u "$USER" -o pid,ppid,lstart,etime,stat,args --forest
- Ask Codex to spawn three parallel subagents for bounded tasks.
- Wait until all three subagents return their final result and appear as
completed. - Wait several minutes.
- Record the same process tree again.
- Resolve each
node ./mcp/server.mjsandnode ./mcp/server.cjs --stdioprocess's working directory through/proc/<pid>/cwd. - Observe one OpenAI Developers and one Data Analytics MCP process for each completed subagent, in addition to the main session's baseline pair.
Expected behavior
When a subagent finishes, Codex should do one of the following:
- terminate and reap that subagent's MCP child processes;
- share a bounded MCP process pool with the parent session; or
- stop the helpers after completion and restart them only if the subagent is resumed.
A completed subagent should not permanently add plugin processes to a long-running CLI session.
If retaining resources until explicit thread disposal is intentional, the CLI and agent API need an available close/dispose operation, and completed agents should not be presented as fully finished while their process resources remain allocated.
Actual behavior
Every subagent adds two plugin MCP processes. The processes remain alive after the subagent is marked completed, so process count grows linearly with the number of subagents used during a long CLI session.
These processes are not Unix orphans because the main Codex process remains their parent. That also means the operating system will not independently reap them while Codex stays open.
Impact
This is particularly harmful on multi-user Linux and HPC systems:
- long-running Codex sessions accumulate idle processes;
- repeated parallel-agent work can exhaust per-user process limits;
- leaked processes consume cluster resources after their work is finished;
- when Codex is run directly on a shared login node, the accumulation can degrade that shared node;
- users currently have to identify and kill only the stale plugin children or restart Codex.
Suggested fix
Tie each plugin MCP client to the owning subagent lifecycle and await complete child-process termination when the subagent completes or is disposed.
A bounded shared MCP pool would also solve the multiplication. If completed subagent threads must remain resumable, release their MCP processes while idle and initialize them again on resume.
It would also help if Codex diagnostics reported:
- owning parent thread/subagent for each MCP process;
- whether that owner is active, completed, or closed;
- MCP PID and uptime;
- an explicit command to dispose completed agent resources.
Related issues
- #25015 reports the same general leak on Linux, but through the IDE/app-server path and Codex 0.128.0.
- #34658 reports completed subagents leaking plugin MCP Node.js processes on Windows.
- #30408 reports per-thread MCP processes accumulating under app-server on macOS.
- #20883 proposes a shared project-scoped MCP process pool.
This report is separate because it confirms the defect in the plain interactive Linux CLI on current 0.147.0, with bundled plugin MCPs, exact one-pair-per-subagent timing, and a controlled cleanup that left the parent CLI operational.
2 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Mechanism from the multi-agent v2 runtime: each subagent is a full thread with its own connection set, so it spawns its own copies of every bundled plugin MCP server. On completion the thread is deliberately kept loaded —
followup_taskmust be able to resume it — and the only path that actually tears one down is LRU eviction under capacity pressure:V2Residency::try_unload_one_residentcallsshutdown_and_wait(which kills the MCP children) only when a new spawn needs a slot and the thread passesis_unloadable(https://github.com/openai/codex/blob/1f41cc5d92/codex-rs/core/src/agent/control/residency.rs#L117-L151). With three subagents and default capacity, no pressure ever builds, so the six Node processes idle until the parent exits.That makes this the "quiet session" complement of two known families: the per-thread MCP process accumulation in #30408/#26984 (whose fd accounting — 3 pipes + 1 pidfd per child — is measured in #37971), and the capacity livelock in #37748 where the same residency logic can't unload anything.
Fix shape: decouple process lifetime from thread residency — when a subagent reaches Completed/Errored, shut down its MCP connection set after a short idle grace period and respawn lazily if a
followup_taskarrives (startup cost is the price of an explicit resume, which is rare; six idle Node processes per burst of subagents is paid always). On HPC/multi-user hosts like yours the per-process memory also counts against allocations, which makes the lazy-respawn tradeoff clearly right.