Skip to content

stdio MCP servers accumulate under a live app-server on 26.810.52044, after the #18881 / #19753 shutdown fix #38925

Description

@twkjtwkj

Filing separately from the closed #18881 because the shutdown path that PR #19753
fixed now works on this build, while accumulation during a live session does
not. Cross-referencing #12491 (open, GUI), #20349, #25015, #26984.

Environment

Codex (ChatGPT.app) 26.810.52044, bundle 6662
codex-cli 0.148.0-alpha.9
macOS 26.6.1 (25G76), arm64
Surface Codex desktop app, codex ... app-server

Two stdio MCP servers configured in ~/.codex/config.toml, both launched via a
wrapper script that execs (so the wrapper leaves no process of its own):

[mcp_servers.fin]
command = "/Users/<user>/.ai_ops/bin/mcp-launch.sh"
args = ["fin"]          # execs a python stdio server

[mcp_servers.email]
command = "/Users/<user>/.ai_ops/bin/mcp-launch.sh"
args = ["email"]        # execs `npx -y @codefuturist/email-mcp stdio`

What happens

A long-lived app-server spawns a fresh stdio MCP server roughly every three
minutes and never closes the previous one. The old servers stay parented to the
app-server with their stdio pipes still held open (lsof shows fds 0/1/2 as
PIPE), at 0.0% CPU and ~1s of accumulated CPU time. They are idle but retained.

This is the same shape as #18881, but that issue was closed by PR #19753
(merged 2026-04-28) and this build postdates it.

What PR #19753 did fix, verified here

Shutdown draining works. When the app-server exits, its MCP children go with it.
Observed directly: app-server PID 43065 was restarted, and all ~33 of its
accumulated MCP children terminated along with it, requiring no manual cleanup.

So this is not a regression of the shutdown path. It is the in-session path,
where servers are replaced but the superseded ones are never shut down.

Measurements

Two independent windows, one app-server each, machine otherwise idle:

Rate ~1 new stdio server per 3 minutes, sustained
Single app-server (PID 14353), 71 min uptime 24 fin_mcp children
Across both configured servers, ~1 hour after a manual clear from 11 processes 137 processes
RSS at that point ~5.4 GB
Free system memory at that point 141 MB
After killing the superseded children 4480 MB free

Reproduced twice, hours apart, across an app-server restart in between.

Reproduction

  1. Configure one or more stdio MCP servers in ~/.codex/config.toml.
  2. Start the Codex desktop app and leave a project session open.
  3. Watch the children of the app-server process:
APPSRV=$(pgrep -f "Resources/codex .*app-server" | head -1)
watch -n 30 "pgrep -P $APPSRV -f mcp | wc -l"

The count climbs monotonically and never decreases while the app-server lives.

Expected

When a stdio MCP server is replaced, the superseded one is shut down and its
process reaped, so the count tracks the number of configured servers rather than
session age.

Notes

Each server is cheap alone (~28 to 90 MB here) and the fault is only visible over
hours. With two servers configured it took roughly one hour to consume several GB
and drive the machine to 141 MB free. #12491 reports the same end state at much
larger scale (1319 processes, 37 GB), which suggests the ceiling is however long
the app stays open.

The three fix directions proposed in #12491 (process groups, startup reaping of
stale trees, heartbeat self-termination) would each cover this case too. The
narrowest fix specific to what is seen here is shutting down the superseded
server at the point of replacement, rather than only at session shutdown, which
is what #19753 addressed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appapp-serverIssues involving app server protocol or interfacesbugSomething isn't workingmcpIssues related to the use of model context protocol (MCP) serversperformance

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions