Skip to content

[Windows Desktop 26.810.41047] Local STDIO MCP process groups accumulate and consume ~7 GB RAM #38526

Open

Description

@ggoingDown

Title: [Windows Desktop 26.810.41047] Local STDIO MCP process groups accumulate and consume ~7 GB RAM

Environment:

  • Windows
  • ChatGPT/Codex desktop app 26.810.41047
  • Local STDIO MCP servers: Playwright, todo-query, node_repl

Actual behavior:
After starting/resuming multiple Codex threads, local MCP process groups accumulate and are not reclaimed when most threads become idle or unloaded.

Observed:

  • 26 identical MCP process groups
  • 183 processes total
  • Approximately 7 GB RAM and 1,200 threads
  • Each group contains:
    • 1 node_repl.exe
    • 2 Python processes for todo-query
    • 2 cmd.exe and 2 node.exe processes for Playwright MCP
  • The app listed only 1 active and approximately 4 idle threads at the time
  • System became noticeably unresponsive

Logs show each thread/start initializing a new MCP manager and launching the configured STDIO servers. Some temporary groups exit gracefully, but many remain attached to the main Codex process.

Expected behavior:
MCP processes belonging to closed, unloaded, or expired thread runtimes should be terminated or reused instead of accumulating.

Workaround:
Restarting the app or disabling local MCP servers releases/prevents the accumulated processes.

Activity

  1. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    windows-osIssues related to Codex on Windows systems
    mcpIssues related to the use of model context protocol (MCP) servers
    on Aug 14, 2026
  2. yzh522163-prog commented on Aug 16, 2026

    @yzh522163-prog

    Additional reproduction on a newer Windows Desktop build, with a full process-tree breakdown and before/after mitigation.

    Environment

    • Codex Desktop: 26.810.7004.0 x64
    • app-server: codex-cli 0.148.0-alpha.9
    • Windows 11
    • Global STDIO MCP servers enabled at the time:
      • bundled node_repl
      • unityMCP
      • comfyui
      • jcodemunch
    • A fifth optional MCP was configured but did not have a persistent process.
    • No project-scoped MCP override and no duplicate config merge were found.

    Observed process fan-out

    Although only two tasks were intentionally active, the app-server retained/restored approximately 29 execution contexts.

    Each retained context started this process set:

    Server Processes per context
    node_repl 1
    unityMCP 1 Node process
    comfyui 1 Node process
    jcodemunch 5-process chain (uvx -> uv -> python -> jcodemunch-mcp -> python)
    Total 8

    A process-tree snapshot showed:

    • 29 copies of each logical STDIO MCP group
    • 237 descendants of the single current codex.exe app-server
    • approximately 7.14 GB working set / 7.28 GB private memory
    • approximately 2,100 threads
    • approximately 42,848 handles

    At the system level this coincided with:

    • 639 processes
    • 12,331 threads
    • 276,432 handles
    • approximately 115,000 context switches/sec
    • severe system-wide lag

    The arithmetic was consistent with the tree: 29 retained contexts * 8 MCP processes = 232, plus a few app/tool helper processes.

    These were not leftovers from an older app-server instance. They were descendants of the current app-server and had been started after the current Desktop launch. Some MCP groups remained alive for roughly 68–97 minutes. Counts occasionally dropped as individual contexts were eventually cleaned up, which looks like delayed/partial cleanup rather than permanent OS orphans.

    Mitigation and confirming evidence

    I changed the four task-specific STDIO MCP servers to enabled = false, kept only the bundled node_repl enabled, and fully restarted Codex Desktop.

    After restart:

    • 16 Codex descendants total
    • 13 node_repl.exe processes, stable across repeated samples
    • 0 unityMCP processes
    • 0 comfyui processes
    • 0 jcodemunch / uv / uvx / Python processes
    • all node_repl instances together: about 133 MB working set / 44 MB private memory
    • system process count dropped from 639 to approximately 371

    This strongly suggests that per-context STDIO startup is multiplying the cost of every globally enabled server. Disabling the heavy servers removes the severe resource impact, but it does not eliminate the underlying retention: 13 node_repl workers still remained while only a small number of tasks were active.

    Expected behavior

    • STDIO MCP process trees should be terminated when their owning task/runtime becomes idle, unloaded, closed, or otherwise disposable.
    • Restored historical tasks should not eagerly start every globally enabled STDIO MCP unless the runtime is actually active.
    • Alternatively, eligible MCP servers should be pooled/shared or the number of retained tool runtimes should be bounded.
    • The UI-visible task count and the number of live tool/MCP runtimes should not diverge enough to create hundreds of background processes.

    The configuration-only workaround is effective but removes tools globally. I can provide sanitized PowerShell process-tree collection logic if useful.

  3. yzh522163-prog commented on Aug 16, 2026

    @yzh522163-prog

    I traced the current main lifecycle for the Windows process accumulation reported here.

    The remaining leak is at MCP runtime publication/shutdown boundaries:

    • McpRuntime::publish replaces the published McpConnectionSet, while bindings and prepared calls can still hold the previous set.
    • McpRuntime::shutdown only shut down the latest published set, so a superseded stdio generation could remain alive when an older binding was still in flight.
    • A lazy, dormant connection must not be shut down by awaiting its client: that would start the process during cleanup.

    I prepared a focused local patch that:

    1. Identifies connections removed by a refresh but not shared by the successor.
    2. Retires each old connection after its last Arc lease is released, preserving in-flight call semantics.
    3. Tracks retired generations weakly and force-shuts all live retired generations plus the current generation during final session shutdown; cleanup is kept alive if the initiating caller is cancelled.
    4. Cancels dormant lazy startup without polling/starting the child.
    5. Adds regressions for twenty repeated pending-server refreshes and for final session shutdown while an external in-flight call still holds the superseded stdio connection.

    This is ownership-based cleanup; it does not scan or kill processes by name/PID. Formatting and diff checks pass locally. Full Rust compilation is currently blocked on my Windows checkout because link.exe/MSVC Build Tools are not installed, so I am not claiming the test suite passed.

    The repository's contributing guide says external PRs require maintainer invitation. If this direction matches the intended fix, I can provide the focused branch/PR after an invitation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appbugSomething isn't workingmcpIssues related to the use of model context protocol (MCP) serversperformancewindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions