Codex desktop leaks orphaned MCP helper processes under launchd
Summary
Codex Desktop appears to repeatedly leak MCP helper processes. Over time, they become re-parented to launchd (PPID 1) and continue consuming CPU/RAM after the Codex session/tool invocation that created them is gone.
This has happened repeatedly on my machine. In the latest cleanup, I found and removed 501 stale MCP-related processes.
Environment
- App: Codex Desktop
- Codex app version:
26.429.30905(CFBundleVersion2345) - Bundle id:
com.openai.codex - macOS:
26.3.1 (a)build25D771280a - Architecture:
arm64
What I observed
A host-level process snapshot showed hundreds of stale MCP helpers with PPID 1, mostly:
php /Applications/Herd.app/Contents/Resources/herd-mcp.pharnode /private/tmp/bunx-501-@delorenj/mcp-server-trello@latest/node_modules/.bin/mcp-server-trello
Before cleanup:
target_count=501
total count=501 cpu=190.3 rss_mb=4013.5
php count=252 cpu=190.3 rss_mb=1660.3
node count=249 cpu=0.0 rss_mb=2353.2
After killing only MCP-related processes with PPID 1:
remaining_target_count=0
total count=0 cpu=0.0 rss_mb=0.0
There were also two STAT=Z defunct processes, but they were not the material resource problem because both had 0% CPU and 0 RSS.
Why this looks like a Codex leak
The live Codex app had active helpers under the current Codex process tree, which I left alone. The stale processes were specifically the MCP helpers re-parented to launchd with PPID 1, which suggests their original parent exited without terminating/reaping them.
This matches a recurring pattern I have seen where many Codex/MCP helper processes accumulate across sessions/tool invocations.
Expected behavior
When a Codex session, tool server, or MCP client process exits, Codex should terminate/reap any MCP helper process it spawned, or otherwise ensure those child processes do not become long-lived orphaned PPID 1 processes.
Actual behavior
MCP helper processes can accumulate under launchd and persist for hours/days, consuming significant CPU and RAM.
Detection command used
ps -axo pid,ppid,stat,%cpu,%mem,rss,etime,comm,args \
| awk 'NR>1 && $2==1 && /mcp-server-trello|herd-mcp\.phar|chrome-devtools-mcp|playwright-mcp|watchdog\/main\.js/'
Cleanup command used
ps -axo pid,ppid,stat,%cpu,%mem,rss,etime,comm,args > /tmp/codex_ps_before_cleanup.txt
awk 'NR>1 && $2==1 && /mcp-server-trello|herd-mcp\.phar|chrome-devtools-mcp|playwright-mcp|watchdog\/main\.js/ { print $1 }' /tmp/codex_ps_before_cleanup.txt > /tmp/codex_stale_mcp_pids.txt
xargs kill < /tmp/codex_stale_mcp_pids.txt
I intentionally scoped cleanup to MCP-related commands with PPID 1 so live Codex-attached helper processes were not killed.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗