The codex vscode plugin fails to start ace-tool mcp, causing an process/thread storm and eventually causing the physical machine to freeze
What version of the IDE extension are you using?
0.4.69
What subscription do you have?
api key
Which IDE are you using?
VS Code
What platform is your computer?
Windows connect to remote ssh docker container Linux 5.15.0-60-generic x86_64 x86_64
What issue are you seeing?
When I configure ace-tool or ace-tool-rs or auggie mcp in codex, when I open the vscode codex plugin, it gets stuck, and then I see that the number of process threads in the physical machine is growing wildly, and I know that the physical machine is stuck. Looking at the process, I found that there are many npx ace-tool processes
cat /sys/fs/cgroup/pids.current shows
<img width="119" height="696" alt="Image" src="https://github.com/user-attachments/assets/8d0af8c3-e510-48ea-922e-11b5535c0933" />
<img width="141" height="465" alt="Image" src="https://github.com/user-attachments/assets/6bfbcc85-8234-4dec-be24-54f2b5a0390d" />
What steps can reproduce the bug?
- Configure ace-tool or ace-tool-rs or auggie mcp in codex
- Open the vscode codex plugin
What is the expected behavior?
Hopefully MCP works fine and doesn't cause a process/thread storm
Additional information
some log
2026-01-30T02:03:44.211037Z INFO codex_core::codex::handlers: Shutting down Codex instance
2026-01-30T02:03:44.223477Z INFO codex_core::shell_snapshot: Shell snapshot successfully created: /root/.codex/shell_snapshots/019bff50-ba39-7191-a81e-6f7b45ab289b.sh
2026-01-30T02:05:57.936375Z INFO codex_core::stream_events_utils: ToolCall: write_stdin {"session_id":17607,"chars":"\^C","yield_time_ms":1000,"max_output_tokens":2000}
2026-01-30T02:06:07.445399Z INFO codex_core::stream_events_utils: ToolCall: exec_command {"cmd":"cd vlfm && echo 'time:' && date && echo 'loadavg:' && cat /proc/loadavg && echo 'cgroup pids.current/max:' && cat /sys/fs/cgroup/pids.current 2>/dev/null && cat /sys/fs/cgroup/pids.max 2>/dev/null && echo 'npx count:' && (pgrep -x npx | wc -l) && echo 'ace-tool-rs count:' && (pgrep -f 'ace-tool-rs' | wc -l) && echo 'process count:' && (ps -e --no-headers | wc -l) && echo 'top 10 by threads (process-level):' && ps -eo pid,nlwp,comm --sort=-nlwp | head -n 11","yield_time_ms":100000,"max_output_tokens":4000}
2026-01-30T02:06:45.618165Z INFO codex_core::stream_events_utils: ToolCall: exec_command {"cmd":"cd vlfm && echo 'sample npx:' && ps -C npx -o pid,ppid,stat,etime,args --no-headers | head -n 30 | sed -E 's/(--token) [^ ]+/\\1 <REDACTED>/g'","yield_time_ms":100000,"max_output_tokens":4000}
2026-01-30T02:07:17.562698Z INFO codex_core::stream_events_utils: ToolCall: exec_command {"cmd":"cd vlfm && p=943; echo \"pid=$p\"; ps -p $p -o pid,ppid,stat,etime,cmd --no-headers | sed -E 's/(--token) [^ ]+/\\1 <REDACTED>/g'; pp=$(ps -p $p -o ppid= | tr -d ' '); echo \"ppid=$pp\"; ps -p $pp -o pid,ppid,stat,etime,cmd --no-headers 2>/dev/null || echo 'ppid not found';","yield_time_ms":100000,"max_output_tokens":2000}
2026-01-30T02:07:40.392375Z WARN codex_core::codex: stream disconnected - retrying sampling request (1/5 in 203ms)...
2026-01-30T02:07:56.065453Z INFO codex_core::stream_events_utils: ToolCall: exec_command {"cmd":"cd vlfm && echo 'top npx PPIDs:' && ps -C npx -o ppid= --no-headers | sort | uniq -c | sort -nr | head -n 20","yield_time_ms":100000,"max_output_tokens":2000}
2026-01-30T02:08:25.418404Z INFO codex_core::stream_events_utils: ToolCall: exec_command {"cmd":"cd vlfm && set -euo pipefail\n\nredact(){ sed -E 's/(--token) [^ ]+/\\1 <REDACTED>/g'; }\n\nsnapshot(){\n echo '---'\n date\n echo -n 'pids.current/max: '\n cat /sys/fs/cgroup/pids.current 2>/dev/null || true\n echo -n '/ '\n cat /sys/fs/cgroup/pids.max 2>/dev/null || true\n echo -n 'npx total: ' && (pgrep -x npx | wc -l || true)\n echo -n 'npx ace-tool: ' && (pgrep -af 'npx ace-tool' | redact | wc -l || true)\n echo -n 'ace-tool-rs: ' && (pgrep -af 'ace-tool-rs' | redact | wc -l || true)\n}\n\necho '[before]'\nsnapshot\n\necho '\\n[kill TERM: only ace-tool-related]'\n# 仅杀 ace-tool 相关,避免误伤其他 npx\npkill -TERM -f 'npx ace-tool' || true\npkill -TERM -f 'ace-tool-rs' || true\nsleep 3\n\necho '\\n[mid]'\nsnapshot\n\necho '\\n[kill KILL: leftovers]'\nif pgrep -f 'npx ace-tool' >/dev/null 2>&1 || pgrep -f 'ace-tool-rs' >/dev/null 2>&1; then\n pkill -KILL -f 'npx ace-tool' || true\n pkill -KILL -f 'ace-tool-rs' || true\nfi\nsleep 2\n\necho '\\n[after]'\nsnapshot\n","yield_time_ms":100000,"max_output_tokens":4000}
2026-01-30T02:09:42.297560Z INFO codex_core::stream_events_utils: ToolCall: write_stdin {"session_id":55350,"yield_time_ms":100000,"max_output_tokens":4000}
14 Comments
the issue in ace-tool was https://github.com/eastxiaodong/ace-tool/issues/9
If you (or other Codex community members who see this bug report) are so inclined, you might try reproducing this with the Codex CLI. The extension is built on the CLI, and the CLI code is open-sourced, so you (with the help of Codex) can debug and analyze the problem to see if it's in Codex or the MCP server.
This should be a problem with the vscode plugin, I use the cli and I can start and use this mcp normally
The VS Code Extension uses the CLI under the covers, so you should see the same behavior in both cases. One potential difference is in the environment variables that are set when the CLI is launched by the VS Code Extension versus when you launch it yourself from the terminal. Sometimes env variables will change the behavior of MCP servers.
Hey, I've put up a fix for this. It looks like mcp-client wasn't cleaning up the entire process group on Unix when the transport dropped. I've added a ProcessGroupGuard to ensure we send a SIGKILL to the whole group. That should stop the zombie processes.
Has the modification been merged? I really need it
@NormanMises Not yet, the fix is implemented but still pending merge. I'll update here once it's in.
@Ashutosh0x, in case you didn't see, we've announced that we are not accepting unsolicited code contributions from the community. If you'd like to help us improve Codex, we welcome contributions in the form of bug reports, repro steps, and root cause analyses.
@etraut-openai Got it, thanks for the update! Totally understand and I’m happy to help with bug reports, repro steps, and root cause analysis instead.
Analysis of Issue #10581: MCP Process Storm
Bug Description
The Codex VS Code plugin fails to start
ace-toolMCP correctly, leading to a process/thread storm that eventually freezes the physical machine. Logs indicate a proliferation ofnpx ace-toolprocesses.Reproduction Steps
ace-tool,ace-tool-rs, orauggieMCP in Codex.Root Cause Analysis
The issue stems from incomplete process cleanup in the
codex-rmcp-client.npx ace-tool) usingtokio::process::Command.tokio::process::Command(withkill_on_drop(true)) is to send a termination signal to the direct child process.npxspawn subprocesses. When the parentnpxprocess is killed, its children (the actual tool logic) are not automatically killed. They become orphaned and continue running, leading to the observed "storm" as Codex retries connection and spawns new instances.Proposed Resolution
To ensure complete cleanup, the client must manage the process group:
setpgidor equivalent Unix mechanisms).SIGKILLto the entire process group (negative PID) rather than just the single process ID.Implementation Details
The fix involves introducing a
ProcessGroupGuardinrmcp-clientthat:Dropto calllibc::kill(-pgid, libc::SIGKILL)on Unix systems.process_group(0)during spawn.This logic ensures that even if
npxacts as a wrapper, the underlying tool processes are terminated along with the wrapper.Thanks @Ashutosh0x, I agree with your analysis.
Thank you all very much
Root-Cause Analysis: MCP Process Storm (Issue #10581)
Problem
When using certain MCP servers (notably those invoked via wrappers like
npx, e.g.,npx ace-tool), the Codex client can trigger a "process storm." This occurs when the client attempts to reconnect or reload, leading to dozens of orphaned subprocesses that eventually consume all system resources and freeze the host machine.Technical Root Cause
The issue lies in how subprocess termination is handled in the
codex-rmcp-client.npxor shell scripts create a process tree where the direct child of the Codex client is the wrapper (e.g., node/npx), which then spawns the actual tool logic as a grandchild.tokio::process::Commandwithkill_on_drop(true)) sends a termination signal only to the direct child PID.As Codex retries the connection, it spawns new wrappers which in turn spawn new tool processes, leading to the process storm.
Proposed Resolution
To ensure reliable cleanup of the entire subprocess tree, the client should manage the Process Group:
setpgid(0, 0)on Unix).ProcessGroupGuard) that, uponDrop, sends a signal (e.g.,SIGKILL) to the entire process group (using the negative PID/PGID) rather than just the individual process.Implementation Strategy
codex-rs/rmcp-client/src/rmcp_client.rs: Introduce aProcessGroupGuardand updateRmcpClient::new_stdio_clientto utilizecommand.process_group(0)on supported platforms.npxchild-parent signaling defaults, the guard provides a structural way to ensure cleanup across the session lifecycle.Verification
npxwrapper and the underlying tool process (e.g.,ace-tool).rmcp_clientconfirm that transport drops now leave zero lingering subprocesses in the process table.It appears this bug still exists. Specifically, the mcp configured with npx works fine in the CLI, but fails to launch in VS Code Codex.
My environment is Ubuntu 2004, and I installed Node.js and CodeX using Volta.
Even though I enabled network permissions in the sandbox and started maximum privilege mode...