Skip to content

No MCP/plugin system — spec client to avoid upstream's SSE reconnect, stale-tool, and readiness bugs #4

Description

@grave0x

Problem

crates/plugin/src/lib.rs is a 1-line stub ("Plugin system — MCP, ACP integrations") — opencodeR has no MCP client/server implementation at all. Upstream just shipped four MCP/plugin fixes that should be baked into opencodeR's design from day one, not rediscovered later:

  1. SSE error reconnect loopsfix(opencode): stop MCP SSE error reconnect loops anomalyco/opencode#39697 (ports Fix: Handle error responses in Streamable HTTP SSE streams modelcontextprotocol/typescript-sdk#1390): JSON-RPC error responses over MCP Streamable HTTP SSE must be treated as completed requests; the transport must not resume an already-completed error stream (infinite reconnect loop).
  2. Legacy SDK compatibility breakage — #39373: a transport change silently broke older MCP SDK clients; opencodeR's own SDK must be pinned/tested against a compat matrix.
  3. Stale tool cache after server restart — #40062 (closes #40015): a restarted MCP server leaves the StreamableHTTP connection dead without firing onclose, so the cached tool set goes stale and the agent calls a dead server until process restart. Fix: reconnect hook triggered when a tool call fails, refreshing cached tool definitions.
  4. Cold-start catalog partial snapshots — #40070 (closes #36117): catalog reads returned success with a partial snapshot while catalog-producing plugins were still activating. Fix: one-shot initial-readiness barrier; provider.list/model.list await it and return 503 if readiness exceeds a bound (10s).

Impact

  • No MCP support is a hard blocker for parity with upstream (all plugin-based tools, model catalogs, integrations).
  • If implemented naively, all four upstream bugs get re-introduced in Rust.

Spec / Acceptance criteria

Design the MCP client (and minimal server) with:

  1. Transport: Streamable HTTP + SSE support (or start with stdio). On a JSON-RPC error response over SSE, treat the request as completed — never resume/retry the stream.
  2. Reconnect: when a tool call fails and the connection is dead, re-establish the session through the normal connect path and refresh cached tool definitions before retrying.
  3. Readiness: plugin loader exposes a one-shot initial-readiness barrier; catalog.list_providers/list_models/get_provider await it and return 503 ServiceUnavailable if it exceeds a bounded period (e.g. 10s) — no partial snapshots as authoritative state.
  4. Compat: pin the MCP protocol version; add a test matrix covering at least one legacy-version client against the opencodeR MCP server.
  5. Cache invalidation: tool definitions must be refreshed on reconnect; document staleness semantics for long-lived sessions.

Reference: upstream anomalyco/opencode#39697, #39373, #40062 (closes #40015), #40070 (closes #36117); our code: crates/plugin/src/lib.rs (stub), crates/core/src/lib.rs:34-38 (CatalogService).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions