Skip to content

MCP transport stays 'failed' after a transient connection close — plugin tools disappear for the rest of the session #38088

Closed as not planned

Description

@jaepo01

Describe the bug

When an MCP server's stdio transport drops a connection mid-session (the child process closes its stdout, the connection emits a close/error, or the transport's underlying pipe is recycled), opencode surfaces a MCP connection closed server=<name> WARN once and then leaves the transport in a permanently "failed" state. Tools registered by that MCP server stay unavailable for the rest of the session unless the user manually restartarts opencode — even when the MCP server is a self-healing daemon that would happily accept a fresh connection on the next call.

This is most visible with the lsp server from the oh-my-openagent plugin, which proxies tool calls to a per-user shared LSP daemon over a unix socket. The daemon kills its backing language server after a 5-minute idle timeout (intentional, to reclaim memory). The MCP stdio bridge between opencode and the daemon survives that, but when an in-flight tool call lands on the socket just as the daemon closes it, the resulting transport error is propagated to opencode as a fatal transport failure rather than as a recoverable per-call error.

Expected behavior

When an MCP transport reports a connection drop, opencode should at minimum:

  1. mark the transport as degraded (not failed),
  2. lazily attempt to re-establish the transport on the next tool call from the same MCP server,
  3. continue to accept other tool calls while the reconnect is in flight.

The MCP client SDK already exposes reconnect primitives; the gap is that opencode treats the first close as terminal for the lifetime of the session.

Actual behavior

  • MCP connection closed server=lsp WARN appears in ~/.local/share/opencode/log/opencode.log.
  • Subsequent tool calls against the same MCP server return "client not found" until opencode is restarted.
  • Plugin-registered tools effectively disappear for the rest of the session, forcing the AI to fall back to alternative tools (grep/read loops, etc.) — measurable as a behavior drift even though the daemon itself is healthy.

Measured baseline on this host: ~1.47 WARN events/day across 17 days (25 events between 2026-07-03 and 2026-07-19), with the daemon itself always recoverable on the next call.

Steps to reproduce

  1. Install opencode (1.18.x) with the oh-my-openagent plugin, which registers an lsp MCP server that proxies tool calls to a shared LSP daemon.
  2. Make a successful lsp_diagnostics tool call.
  3. Wait 5+ minutes (idle shutdown of the backing language server).
  4. Make another lsp_diagnostics call. The daemon closes the per-call socket mid-handshake.
  5. Observe the MCP connection closed server=lsp WARN.
  6. Make a third lsp_diagnostics call. It returns an error like "client not found" instead of lazily reconnecting.

Context

  • The plugin-side root cause (the daemon client treated requestWritten=true as terminal and never retried) is being fixed upstream at fix(lsp-daemon): retry mid-request socket close/error instead of bailing out code-yeongyu/oh-my-openagent#6256 — that PR makes the daemon client retry mid-request close, which independently recovers most occurrences.
  • This issue is about a separate gap on the opencode side: even after the plugin retries successfully, opencode's own MCP transport layer does not recover from a transient connection drop. If both sides recover, users never see the WARN; today only the plugin side is fixing itself.

Possible solution

Lazily re-run the transport's connect() on the next tool call after a close, instead of caching the failed state for the whole session. The existing managed reconnect work (#37570 / #37586) covers TUI↔server reconnection but does not appear to cover MCP plugin transports, which is the layer this issue lives in.

Logs

WARN MCP connection closed server=lsp

Host: opencode 1.18.x on Linux, oh-my-openagent 4.13.0 (observed) / 4.18+ (also affected before the plugin-side fix lands).

Activity

  1. github-actions commented on Jul 21, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

  2. jaepo01 commented on Jul 21, 2026

    @jaepo01
    Author

    Closing as duplicate of #25287 (canonical tracker, OPEN). Same root cause: MCP transport stays failed after a transient socket/connection close with no retry/reconnect logic in convertMcpTool.

    Our PR code-yeongyu/oh-my-openagent#6256 addresses the same symptom from the plugin side (oh-my-openagent LSP daemon-client: reset requestWritten=false on socket close/error so the next call retries) and is complementary to the opencode-core fix proposed in #25287 — they are different layers:

    Once #25287 lands at the core, the plugin-side retry becomes a defense-in-depth layer rather than the primary recovery path, but both are independently useful until the upstream fix ships.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions