OpenCode marks an MCP server failed when it does not come up at startup or when a live connection drops, and never retries. A new managed plugin reconnects those servers with a per-server backoff (1s doubling to a 30s cap), wakes early on mcp.tools.changed, and stops on dispose. Only the failed state is retried; disabled and auth states stay untouched. The OPENCODE_CONFIG_CONTENT merge that agent-tool and system-prompt each carried is now one shared helper so the three managed plugins compose. Claude-Session: https://claude.ai/code/session_01VqV56Hez25hTxXH4ipJfzH
2.7 KiB
2.7 KiB
Managed MCP Reconnect
Purpose
OpenCode connects each configured MCP server once, when a project directory is
first used. A server that does not come up then is marked failed and never
retried; a server whose live connection later drops is marked failed too and
stays that way until OpenCode restarts. This module injects a small plugin into
the OpenCode process OpenChamber launches that reconnects those servers, so a
server that was slow to start or crashed mid-session comes back on its own.
Runtime flow
prepareManagedOpenCodeEnv(configContent)materializes the plugin under<openchamber-data-dir>/mcp-reconnect/and appends itsfile://URL toOPENCODE_CONFIG_CONTENTthrough the shared merge inpackages/web/server/lib/opencode/managed-plugin-config.js.- It is always on for managed OpenCode. There is no setting, because it only acts on servers OpenCode has already given up on.
- OpenCode loads the plugin once per project directory with an SDK client scoped to that directory, so each directory reconnects its own servers.
- The plugin reads MCP status one second after load, calls connect for every
server in the
failedstate, then re-reads status after a per-server delay that doubles from one second to a cap of thirty. A server seen in any other state resets its counter. While nothing is failed it checks every thirty seconds. - A dropped connection publishes
mcp.tools.changed, which the plugin uses to check right away instead of waiting out the idle interval. - OpenCode calls the plugin's
disposehook when it tears the directory down, which stops the loop.
Invariants
- Only
failedis retried.disabledis the user's choice, andneeds_authorneeds_client_registrationneed the user to act; retrying those would either re-enable a server the user turned off or loop on a login prompt. - The plugin logs nothing and swallows every error. OpenCode already logs each failed attempt, and a status call failing during an OpenCode restart is not news.
- One check runs at a time; a wake-up arriving during a check is honored once it finishes rather than starting a second loop.
What the UI sees
OpenCode publishes no event when a reconnect succeeds. The chat picks the
server up on the next prompt because tools are resolved from live state, but
the MCP page reads status on bootstrap and refresh, so it can show failed for
a while after the server is back.
Runtime parity
- Web and Desktop managed OpenCode: injected automatically.
- External OpenCode (
OPENCODE_HOSTor skip-start) and VS Code's separate OpenCode lifecycle: not injected, because OpenChamber does not control that process environment.