openai / openai/codex

[Linux Desktop 0.147.0] Completed v2 subagents retain full stdio MCP runtimes

Open
#38,247 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app app-server bug mcp performance subagent
Dominant language
Rust
Stars
125k
Forks
19.5k
PR merge metrics
PR metrics pending

Description

Environment

  • Codex Desktop on Linux
  • Bundled / local CLI: codex-cli 0.147.0
  • Platform: Linux 6.8.0-137-generic x86_64 (Ubuntu 24.04)
  • Authentication: ChatGPT subscription
  • MCP configuration at the time of reproduction: 8 enabled stdio servers plus 4 Streamable HTTP servers
  • Long-lived Desktop app-server
  • Multi-agent v2 / spawn_agent workflows

What issue are you seeing?

Completed subagents can leave their entire stdio MCP runtime resident under the live Desktop app-server. The processes are not zombies and are not reparented to PID 1: every retained MCP launcher/server is still a direct descendant of the same healthy app-server.

On one real workload, after a subagent-heavy task:

  • 15 instances each of context7, github, gitee, playwright, and codex-security remained.
  • The 15 start clusters aligned across unrelated servers, so the growth unit was one complete MCP stack, not one crashing third-party server.
  • A sixth stdio MCP was unusually expensive because of its own development logging, amplifying the Codex lifecycle bug but not causing the stack duplication.
  • System used memory grew to about 29 GiB; the Desktop cgroup accounted for about 23.9 GiB RSS.
  • Sending SIGTERM only to the stale MCP descendants reduced system used memory to about 11 GiB and the Desktop cgroup to about 5.4 GiB. The live task then recreated one healthy current stack, demonstrating that the old stacks were not required for the current task.

Local logs correlate each new process batch with:

spawn_agent / followup_task
  -> thread_spawn
  -> session_init
  -> session_init.mcp_manager_init
  -> mcp.runtime.refresh
  -> start_server_task

This is related to #12491 and #17832, but the narrower failure mode here is completed v2 subagents retaining live runtimes while their logical agent identity remains resumable. It is not a request to mark the spawn edge closed, and it is not only the already-fixed manager-replacement leak from #18881.

Steps to reproduce

  1. Configure several global stdio MCP servers.
  2. Start Codex Desktop and keep the same app-server alive.
  3. Run a task that creates subagents with spawn_agent; let them finish normally.
  4. Repeat across several tasks and/or use follow-up/resume flows.
  5. After every child reports a terminal status, count the app-server descendants by MCP command.
  6. Observe complete, timestamp-aligned MCP stacks remaining after the child work has completed and memory increasing monotonically.

The problem becomes especially visible with a high-memory stdio server, but it also reproduces as equal instance counts across small, unrelated servers.

Current-main code observation

The current v2 residency path can unload Completed, Errored, or Interrupted threads, preserving their durable logical identity so they can be reloaded on later delivery. However, that unload path is currently driven by a later residency-slot reservation under capacity pressure. The completion watcher delivers the child result to the parent and returns without proactively releasing the now-idle resident thread/runtime.

This can leave completed children holding stdio MCP processes indefinitely when no later spawn forces eviction. Across multiple Desktop tasks, those resident stacks accumulate under the same long-lived app-server.

Recent lazy startup work reduces how many MCPs a child starts, but any MCP actually started by the child still needs an idle release path.

Expected behavior

After a v2 subagent reaches a terminal status, its result has been delivered, its active turn is cleared, and its mailbox is empty:

  1. Its resident execution runtime (including stdio MCP children) should be unloaded within a bounded period.
  2. Its logical agent id/path and open spawn edge should remain durable so followup_task / send_input can transparently reload it.
  3. Active turns and pending mailbox input must never be unloaded.
  4. Repeating completed subagent runs should return MCP process counts and RSS near the idle baseline instead of growing monotonically.

A regression test should use a PID-recording stdio MCP fixture, verify that the process exits after terminal idle, then send a follow-up and verify that the same logical agent reloads and can start/use MCP again.

Related issues / changes

  • #12491 — broad Desktop MCP child cleanup tracking; latest maintainer guidance asks distinct bugs to be filed separately
  • #17832 — Playwright stdio processes retained after subagents
  • #17574 — subagent MCP helper process trees
  • #30408 — closed/archived threads retaining MCP processes
  • #33700 — persisted subagent state / rehydration observations (logical edge lifetime is related but should not be conflated with runtime residency)
  • #18881 / #19753 — explicit manager/client shutdown fixes
  • #26632 and #26997 — durable v2 unload/reload behavior
  • #38217 — lazy startup of required cached MCP servers for subagents

I am preparing a minimal patch with tests. I understand external contributions are invitation-only; if maintainers agree that proactively releasing terminal-idle v2 runtimes is the right layer, please explicitly invite the PR and I will open it against main.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the v2 completion watcher, residency-slot unload/reload path, and the spawn_agent, followup_task, and send_input entry points described in the issue. Use a PID-recording stdio MCP fixture to verify terminal-idle runtimes exit, then confirm follow-up reloads the same logical agent and can use MCP again without unloading active turns or pending mailbox input.

Written by the indexing model from the issue text.

Assessment

Tech stack
linux, rust
Domain
backend, distributed-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.