Skip to content

Local stdio MCP servers leak processes on disconnect / replace / rollback #26714

Closed as not planned

Description

@yangshuai0711

Description

When a local stdio MCP server is disconnected, replaced (via a second MCP.add() with the same name), or rolled back after tool discovery (defs()) failure, the spawned process tree is not terminated. Only client.close() is called, which stops the SDK transport but leaves the child process and its descendants running as orphans.

The existing cleanup code (added in #15516) only covers the instance disposal path, and even there it only kills descendant PIDs — not the transport's own root PID.

Over multiple sessions these orphaned processes accumulate, consuming memory and potentially holding ports.

OpenCode version

1.3.13 (dev branch, commit d112da0)

Steps to reproduce

  1. Configure a local stdio MCP server in opencode.json (e.g. "type": "local", "command": ["node", "server.js"])
  2. Disconnect the server via MCP.disconnect() — or trigger a replace by calling MCP.add() twice with the same name
  3. Check running processes: the MCP server process is still alive with PPID changed to 1

Operating System

macOS (Apple Silicon)

Terminal

Ghostty

Additional context

This is related to #15808 and #8257 but covers a distinct gap:

vs #15808 ("opencode run: MCP child processes not terminated on exit"): That issue is about the opencode run headless command not cleaning up MCP processes when the CLI exits. #15516 partially addressed it by adding descendant kill in the dispose handler. But the in-process teardown paths — disconnect(), add-replace, and defs-failure rollback — were never covered. This issue is specifically about those paths.

vs #8257 ("Memory leak: MCP clients not closed before reassignment"): That issue is about connections/sockets leaking when a client reference is overwritten without calling .close(). Our concern is broader: even when .close() is called (as in the current disconnect path), the process is not killed. Client close does not guarantee process termination.

No existing PR addresses this specific set of gaps. PR #15516 (merged) added descendant cleanup in the dispose path only. PR #21626 (open) is about SDK process groups, not MCP teardown. No one has submitted a fix covering the root PID kill or the disconnect/rollback paths.

Activity

  1. github-actions commented on May 10, 2026

    @github-actions
    Contributor

    This issue doesn't fully meet our contributing guidelines.

    What needs to be fixed:

    • No issue template was used. Please use the Bug Report template, which requires a description of the problem and reproduction steps.
    • Missing system information: please include your OpenCode version, OS, and any other relevant environment details.

    Please edit this issue to address the above within 2 hours, or it will be automatically closed.


    This issue might be a duplicate of existing issues. Please check:

    If you believe this was flagged incorrectly, please let a maintainer know.

  2. github-actions commented on May 10, 2026

    @github-actions
    Contributor

    Thanks for updating the issue! Everything looks good now — the bug report has a clear description, steps to reproduce, version info, and OS details. Appreciate the thorough write-up!

  3. github-actions commented on Jul 10, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions