Repository navigation
service: v2 service spawns one local MCP server pair per cataloged project directory at startup #43845
Description
Summary
On startup, the opencode V2 background service (opencode2 serve --service) spawns one full set of local stdio MCP server processes per project directory discovered by its project catalog, instead of one set total. With ~53 directories in the catalog and 2 local MCP servers configured, this produced 51 duplicate MCP process pairs (~153 processes including grandchildren) in a ~70-second burst. The extra processes are never cleaned up and keep running until the service is manually restarted.
Environment
- opencode version: opencode2 v0.0.0-beta-17793 (
@opencode-ai/cli, npm) - OS: macOS 26.x / Darwin Kernel Version 27.0.0, arm64 (Apple Silicon M1)
- Terminal: Ghostty (xterm-256color, truecolor)
- Shell: fish
- Install/channel: beta (npm global)
- Active plugins: none found in config
Reproduction
- Configure two local stdio MCP servers in
~/.config/opencode/opencode.jsonc(oneuv run ...Python server, one native binary):{ "$schema": "https://opencode.ai/config.json", "mcp": { "servers": { "telegram": { "type": "local", "command": ["uv", "--directory", "/path/to/telegram-mcp", "run", "--locked", "python", "main.py"] }, "cua-driver": { "type": "local", "command": ["cua-driver", "mcp"] } } } } - Have many directories under
$HOMEso the project catalog discovers dozens of projects (in this setup the catalog was rooted at/). - Start or restart the service (
opencode2 service restart, or a fresh boot/login that starts it). - Watch the process table:
ps -eo pid,ppid,lstart,command | grep -E 'telegram-mcp|cua-driver'
Expected Behavior
One process tree per configured local MCP server, created lazily and reused across projects/sessions; unused trees terminated when no longer needed.
Actual Behavior
Immediately after service start, one (uv telegram-mcp + cua-driver) pair was spawned roughly every 1–2 seconds for ~70 seconds, then spawning stopped — but all spawned pairs stayed alive indefinitely, all as direct children of the service PID:
51 × uv --directory .../telegram-mcp run --locked python main.py
51 × cua-driver mcp
51 × .venv/bin/python3 main.py (grandchildren)
Counts verified stable 15+ minutes later; only restarting the service removes them (same leak observed on 2026-08-18 with 43 pairs / 116 connects in 20s on an earlier beta).
Correlation evidence from ~/.local/share/opencode/log/opencode.log: right after service start it emitted 3,061 catalog.updated events covering exactly ~53 unique directories (/, /Users, /Users/kote, /Users/kote/Notes, home subdirectories...), matching the ~51 leaked pairs almost 1:1. No MCP errors are logged during the burst. A remote MCP server configured alongside these (Composio) is unaffected, consistent with only stdio servers being spawned.
Additional Context
- Impact: dozens of idle processes per service start (RAM, plus side effects — each duplicate telegram-mcp opens a Telegram MTProto session, each cua-driver connects to its daemon).
- Recurs on every service start; not tied to opening sessions.
- Workaround: restart the service after login, or keep the number of discoverable project directories small.
- Possibly related open issues: MCP servers spawn 2-4 duplicate processes per server on startup, causing TasksMax exhaustion and EAGAIN errors #31554, Bug: MCP servers spawn duplicate processes per session — 1 project = 8+ instances, 2+ projects = crash #29939, MCP servers spawned 8-10x per instance on Windows, consuming ~3.5 GB RAM on startup #26336, Local stdio MCP servers leak processes on disconnect / replace / rollback #26714, MCP server processes not cleaned up on exit (orphan processes) + eagerly starts all servers #30123, local MCP server child processes become orphaned on restart #30073, service: restart leaves stale daemon and duplicated MCP servers running #42270 — those describe per-session/per-restart duplication and orphaned children; this report pins a specific trigger on V2: one spawn set per catalog-discovered directory.
Activity
github-actions commentedon Aug 21, 2026
This issue might be a duplicate of existing issues. Please check:
You already noted these as "possibly related" — they may in fact be the same underlying bug or closely related root causes worth consolidating.
firefoxmmx2 commentedon Sep 12, 2026
Same symptom reproduced on the v2.0.2 stable line — one full local MCP set per directory, and the #46828 browse fix is not present in 2.0.x
Environment
@opencode/cli, pnpm global), runningopencode serve --service6.18.49-2-ltsx86_64mysql+postgresvia@bytebase/dbhub,jetbrainsviasupergateway) plus 1 remote (context7)Deterministic reproduction (one request)
Reading any directory through the location-scoped fs endpoint used by the picker materializes a full Location runtime and starts a complete set of local MCP servers for that directory.
GET /api/fs/list?location[directory]=/tmp/opencodeThat is roughly 1 GB RSS added per directory visited. Browsing a directory tree with N children starts N of these sets. All spawned processes are direct children of the service PID and are not cleaned up.
The fix for #46826 is not in v2.0.2
#46828 (which closed #46826 and #46679) added
GET /api/browse/listso the workspace picker and/cdnavigate without resolving a Location. On v2.0.2:GET /api/browse/listreturns 404browseroute at all (onlyapi/fs/list,api/fs/find,api/fs/read/)/openapi.json(122 routes) has nobrowseentrySo on 2.0.x, directory browsing still goes through
fs/list->LocationMiddleware, the exact mechanism described in #46826 and #37844.Ask
Was #46828 intended to land in the 2.0.x stable line? If yes, could it be picked/re-landed? If 2.0.x deliberately uses a different navigation path, what is the expected behavior when a browsed directory inherits user-scope local MCP servers?
Related: #46826, #46828, #46679, #37844
yudaiyan commentedon Sep 22, 2026
Same symptom on v2.0.12 (Linux/WSL2): one local MCP set per touched directory, kept alive while idle
Environment:
@opencode-ai/cli)npx-based:tavily-mcp@latest,@playwright/mcp@latest,@fangjunjie/ssh-mcp-serverSetup: one background service (
opencode serve --service) and TUIs opened across a few project directories.The service spawned 5 full MCP sets, one per cwd, including directories with no active session:
npm execparentsEach set is
npm exec <pkg>(~105–111 MB) →sh -c→ the actual node server (67–105 MB). Just the 15npm execparents accounted for 1.6 GB RSS; the full MCP tree was ≈ 2.8 GB while all sessions were idle. The service itself was 519 MB.Sample from one set:
Nothing is torn down when a Location goes idle — the processes only go away after a service restart.
/root(the service's own cwd) had no active session at all but still held a full set.Looks like the same root cause as #37844 (cached locations multiply MCP subprocesses). The multiplication is especially expensive with npm-based servers, where each copy costs ~190 MB including the
npm execwrapper. Idle-Location teardown, or one shared set per resolved config, would help a lot.