anomalyco / anomalyco/opencode

[FEATURE] Official MCP warm-up / pre-spawn mechanism (+ reconnect path) — all local MCPs marked failed at session start when many cold-start concurrently

Open
#48,743 4 comments 1 reaction 1 assignee View on GitHub

@kitlangton is already working on this.

Since Sep 13, 2026.

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

Description

Summary

On the Windows desktop app, when many local stdio MCP servers are configured (we run 14+), every one of them gets marked server unavailable ... status=failed at session start, and the user must manually restart each server in the UI. The servers themselves are healthy — they simply lose a startup race: the sidecar spawns all local MCP processes concurrently (uv venvs, npx, python shims — all cold-start), and once its initialization window is exhausted, the remaining servers are marked failed in the same second, never retried.

Feature request: an official, opt-in MCP warm-up / pre-spawn mechanism (plus a reconnect path), so session-start MCP spawn succeeds without manual restarts. Once official support lands, users can delete their homemade workarounds (ours: a PowerShell warm-up script + Startup-folder .vbs).

Environment

  • OpenCode Desktop 1.18.30 (Electron 42.3.3), Windows 11 x64
  • Install path: C:\Users\<user>\AppData\Local\Programs\@opencode-aidesktop
  • Sidecar mode (desktop spawns the opencode server)
  • 19 MCP servers configured in opencode.json: 13 local stdio (uv tool venv exes for CAD/CADQuery/FreeCAD/OpenSCAD, npx -y packages, npm .cmd shims) + 6 remote URLs
  • One plugin (oh-my-openagent) which dynamically injects additional local MCPs (e.g. lsp, codegraph)

Observed behavior (log evidence, ~/.local/share/opencode/log/opencode.log)

At session start (2026-09-13T01:33–01:35Z), all local servers failed:

01:33:26 server unavailable key=playwright          type=local status=failed
01:33:33 server unavailable key=postgres            type=local status=failed
01:33:39 server unavailable key=lsp                 type=local status=failed
01:34:14 server unavailable key=sci-forge           type=local status=failed  \
01:34:14 server unavailable key=mysql               type=local status=failed   \
01:34:14 server unavailable key=sqlite              type=local status=failed    \
01:34:14 server unavailable key=sequential-thinking type=local status=failed     >  12 servers,
01:34:14 server unavailable key=fetch               type=local status=failed    /  same second
01:34:14 server unavailable key=build123d-mcp       type=local status=failed   /
01:34:14 server unavailable key=cadquery-mcp        type=local status=failed  /
01:34:14 server unavailable key=freecad-mcp         type=local status=failed
01:34:14 server unavailable key=openscad-mcp        type=local status=failed
01:34:14 server unavailable key=tradingview-mcp     type=local status=failed
01:34:14 server unavailable key=financial-hub-mcp   type=local status=failed

Key observations:

  1. Servers with short per-server timeouts fail first (playwright had timeout: 1200, fails at +0s; postgres had 12000, fails at +7s), then the remaining 12 fail in the same second (+48s) — that looks like a shared sidecar initialization budget being exhausted, after which everything still pending is marked failed at once.
  2. No retry/reconnect happens afterwards. Manually restarting each server in the UI then succeeds immediately — because by then the interpreter processes and OS file caches are warm. This confirms the servers/config are fine; the failure is purely the cold-start race.
  3. Every subsequent session repeats this: all local MCPs need manual restart on every app launch.

Root cause

Session start spawns all local MCP stdio processes concurrently. Each local server pays a cold-start cost (uv venv interpreter boot, npx resolution, Python import cadquery ≈ 12 s warm / 95 s cold with OCCT/VTK). With 14+ racing at once, disk I/O contention pushes total init past the sidecar's window, and the one-shot snapshot marks everything failed — matching #44291's finding that "MCP connection state is a one-shot startup snapshot with no reconnect path."

Feature request

  1. Official warm-up / pre-spawn — an opt-in config knob, e.g.:
    {
      "mcp": {
        "warmup": true           // pre-spawn/warm local MCP interpreters before the session's init window
      }
    }
    
    Implementation could be as simple as: at app/session start, before opening MCP clients, briefly spawn each configured local interpreter (command[0] -c pass style) or touch its entry-point binary to warm OS file caches — the same trick users currently hand-roll.
  2. Reconnect path — a failed server should retry (with backoff) instead of staying a one-shot failed snapshot (this is the reconnect half of #44291).
  3. Per-server or global init budget surfaced in the UI — when a server is marked failed, show whether it was a timeout vs. spawn failure, so users stop debugging healthy configs.

Current workaround (would happily delete once official support lands)

  • C:\Users\<user>\.opencode\mcp-warmup.ps1: warms every uv-tool venv interpreter, heavy imports, and npx resolution cache at logon
  • Startup\mcp-warmup.vbs: silent logon trigger
  • Plus config-side fixes that each removed one failure mode: raised a 1200 ms timeout to 120000, removed a duplicate MCP

Related

  • #44291 — MCP servers fail to connect when a session starts during self-upgrade (same one-shot-snapshot, no-reconnect behavior)

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.