Skip to content

MCP sub-agent processes are never terminated when codex sessions are stopped/suspended #16256

@AmirTlinov

Description

@AmirTlinov

What version of Codex CLI is running?

codex-cli 0.117.0

What subscription do you have?

ChatGPT Pro

Which model were you using?

gpt-5.4

What platform is your computer?

Linux 6.14.2-arch1-2 x86_64, GNOME 48, 16GB RAM + 8GB zram

What terminal emulator and version are you using (if applicable)?

GNOME Terminal (VTE-based), multiple pts sessions

What issue are you seeing?

When a Codex CLI session is stopped (Ctrl+Z) or suspended, the MCP server sub-processes it spawned (e.g. context7, claude-agent-mcp, infra, ai-dx-mcp, image-creator, ai3d, and others) are not terminated. Starting a new codex session on the same terminal (pts) layers a completely new set of MCP processes on top of the old ones.

Over a typical work session this leads to massive process accumulation:

  • 16 codex sessions found running simultaneously, many in Tl (stopped) state
    • The most active single session held 291 child processes, including dozens of duplicate MCP server instances
      • Multiple codex processes stacked on the same tty:
        • pts/1: 2 codex processes (one stopped, one active)
          • pts/2: 3 codex processes (two stopped, one active)
            • pts/3: 3 codex processes (two stopped, one active)
              • pts/4: 3 codex processes (two stopped, one active)
                • A headless Chromium instance spawned by a browser MCP server on 127.0.0.1:9222 had accumulated 571 chrome child processes, 1151 DevTools targets (994 of which were about:blank), and 566 renderer processes
                  • zram swap was completely saturated: 8/8 GiB

Root cause

Each codex CLI session spawns its own independent tree of MCP server processes. When the session is suspended (e.g. via Ctrl+Z or by starting a new session in the same terminal), the MCP child process tree is not cleaned up. The stopped parent codex process continues to hold references to all its children, but they remain alive and consuming memory.

There is no teardown/cleanup hook that fires when a codex CLI session transitions to a stopped state, and no mechanism to share or deduplicate MCP server instances across sessions.

Impact

  • Hundreds of duplicate node, npx, uvx processes consuming RAM
    • System becomes unusable as swap fills up
      • On a 16GB machine with 8GB zram, the system was brought to near-OOM by accumulated MCP processes alone

Related issues

What steps can reproduce the bug?

  1. Configure several MCP servers in ~/.codex/config.toml (e.g. context7, ai-dx-mcp, infra, image-creator, ai3d, or any stdio-based MCP servers)
    1. Open a terminal and run codex
    1. Wait for MCP servers to initialize (observe child processes via pstree -p $(pgrep -f codex))
    1. Suspend the session with Ctrl+Z
    1. Run codex again in the same terminal
    1. Repeat steps 4-5 several times
    1. Inspect the process tree:
# Count codex sessions
ps aux | grep '[c]odex' | wc -l

# Show process tree for each
for pid in $(pgrep -f 'codex'); do
  echo "=== PID $pid ==="
  pstree -p "$pid" | head -20
done

# Count total MCP-related processes
ps aux | grep -E 'context7|ai-dx-mcp|infra|image-creator|ai3d|claude-agent-mcp' | wc -l

Expected: Old MCP processes should be terminated when the codex session is stopped/suspended, or at least when a new session starts on the same tty.

Actual: Every suspended session retains its full MCP child tree. Process count grows linearly with each new session.

What is the expected behavior?

  1. When a codex CLI session is suspended (Ctrl+Z / SIGTSTP), all MCP child processes should be gracefully terminated (SIGTERM → SIGKILL after timeout).
    1. When a codex CLI session exits (normally or via signal), all MCP child processes must be reaped — no orphans should remain.
    1. Ideally, MCP server instances should be shared/pooled across sessions or at minimum deduplicated per-user, instead of each session spawning its own full copy of every configured MCP server.
    1. Headless browser instances spawned by MCP servers (e.g. Chromium on :9222) should have lifecycle management — idle tabs should be closed, and the browser should exit when its parent MCP server terminates.

Additional information

Suggested fix directions

  1. Register a SIGTSTP handler in the codex CLI process that sends SIGTERM to all MCP child processes before the parent is suspended.
    1. Use process groups (setpgid) so that the entire MCP subtree can be killed with a single kill(-pgid, SIGTERM).
    1. Add a cleanup-on-exit hook that walks the child process tree and ensures no orphans survive.
    1. Consider MCP server pooling — a single long-lived MCP server daemon per user that multiple codex sessions can connect to, instead of each session spawning its own.

Process audit data

A full process audit was captured at the time of observation and saved locally. Key numbers:

  • 16 concurrent codex sessions (most in stopped state)
    • ~1,500 total MCP-related child processes
      • 571 headless Chrome children from a single browser MCP
        • 8/8 GiB zram completely saturated on a 16 GiB machine

Cross-references

This is the Linux CLI manifestation of a broader cross-platform issue:

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmcpIssues related to the use of model context protocol (MCP) servers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions