anomalyco / anomalyco/opencode

serve (1.18.25): MCP child processes accumulate on web-client reconnects until the server OOMs

Open
#46,035 6 comments 0 reactions 1 assignee View on GitHub

@neriousy is already working on this.

Since Aug 28, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Environment

  • opencode 1.18.25, opencode serve --hostname 0.0.0.0 --port 4040, headless under systemd (Linux, LXC, Debian 13)
  • 5 local MCP servers configured globally in opencode.json (two started via uv, three via npx), plus a few remote ones
  • clients: several browser tabs of the web UI, one opencode attach TUI

What happens

Each client connection, and each reconnect, initializes a full set of MCP server processes. When the connection dies, its processes are not reaped. An interrupted web session tab reconnects in a loop and leaks another full set on every cycle: about 5 processes, ~300 MB.

We watched the systemd unit grow ~20 GB in about 65 minutes (systemd recorded peaks of 20.4 GB and 20.1 GB on two runs), at which point the container hit its memory limit and the kernel OOM-killed the server. The kill interrupts every session, which interrupts more browser tabs, which reconnect and leak faster. After the first OOM, the second one arrived within the hour.

The server also re-spawns MCP sets at startup for projects nobody has open. Within a minute of a fresh start, with zero web clients connected, we counted 23 MCP processes, including 3 sets that only exist in a project-scoped config of a directory no session was using. This matches what #43845 describes for the V2 beta, but on stable.

Reproduction

  1. Run opencode serve with several local MCP servers in the global config.
  2. Open multiple sessions in web tabs.
  3. Restart the server (or break the connections any other way). Leave the tabs open.
  4. Watch ps under the server's cgroup.

Evidence

  • Census 22 minutes after one restart: ~100 MCP processes (34x lean-lsp, 22x gsd-mcp, 16x minimax, 16x playwright, 10x zai; each with an extra npm exec/uv wrapper, 70-100 MB RSS per process). RSS grew ~300 MB/min.
  • Killed the browser's TCP connections with ss -K: five fresh connections reappeared within 45 seconds, with another MCP set behind them.
  • With all web tabs closed, the counts freeze. A lone TUI attach does not leak.
  • MaxListenersExceededWarning: Possible EventTarget memory leak detected. 11 event listeners added (Effect emitter) appeared in the log minutes before the second OOM kill.
  • The server also holds about 15 loopback connections to itself (internal API calls) with similar lifetimes.

Expected

MCP processes die with the connection that spawned them. Process count should settle at one set per live client, and startup should not warm MCP sets for projects nobody opened.

Workaround (what we run with now)

Close interrupted web tabs, keep the global MCP list short, give the server memory headroom. Raising our container limit from 24 to 48 GB bought roughly a night, not a fix.

Related

  • #42270 (stale daemon + duplicated MCP servers after restart, V2)
  • #43845 (one MCP pair per cataloged project dir at startup, V2 beta)
  • #31554 (duplicate MCP processes at startup)
  • #41502 (RSS growth during active turns, OOM)
  • #36739 (serve leaks memory when an upstream SSE hangs)

Version note

We upgraded 1.18.23 to 1.18.25 the same evening this started, so we cannot say the upgrade introduced it. Heavy multi-tab web usage is the stronger correlate.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.