anomalyco / anomalyco/opencode
serve (1.18.25): MCP child processes accumulate on web-client reconnects until the server OOMs
@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 viauv, three vianpx), plus a few remote ones - clients: several browser tabs of the web UI, one
opencode attachTUI
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
- Run
opencode servewith several local MCP servers in the global config. - Open multiple sessions in web tabs.
- Restart the server (or break the connections any other way). Leave the tabs open.
- Watch
psunder 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/uvwrapper, 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
attachdoes 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.