Skip to content

v1.18.8 remote MCP fails: server/discover probe rejected by server (-32700), no fallback to classic initialize #39354

Description

@genequ

Description

opencode 1.18.8 cannot connect to a spec-compliant Streamable HTTP MCP server whose protocol version predates the new server/discover discovery method. The connection fails during version negotiation and never falls back to the classic initialize handshake, ultimately timing out after 30000ms.

Root cause (confirmed via a transparent capture proxy):

opencode 1.18.8's remote transport opens the handshake with a server/discover probe using mcp-protocol-version: 2026-07-28:

POST /mcp
Accept: application/json, text/event-stream
Content-Type: application/json
mcp-method: server/discover
mcp-protocol-version: 2026-07-28

{"jsonrpc":"2.0","id":"server-discover-probe-1","method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"opencode","version":"1.18.8"},"io.modelcontextprotocol/clientCapabilities":{"roots":{}}}}}

The server does not implement server/discover and responds with a JSON-RPC error:

{"error":{"code":-32700,"message":"Parse Error"},"id":null,"jsonrpc":"2.0"}

opencode's strict message validator rejects this error response (it expects a result object and doesn't accept the error key in this position), so version negotiation fails:

■ Error: Version negotiation probe failed: [
    { "code": "unrecognized_keys", "keys": ["error"], ... },
    { "expected": "object", "code": "invalid_type", "path": ["result"], "received": "undefined" },
    ...
  ]

After the probe fails, the transport does not fall back to classic initialize. It opens a GET SSE stream and retries, never sending initialize, until it hits the 30s timeout:

● ✗ <server> failed
    Operation timed out after 30000ms
    http://127.0.0.1:63080/mcp

The server itself is healthy and spec-compliant. Verified directly (outside opencode), using the same Basic-auth header:

  • POST initialize200 in ~35ms with a valid result:
    {"id":1,"jsonrpc":"2.0","result":{"capabilities":{"prompts":{},"resources":{"listChanged":false},"tools":{"listChanged":true}},"protocolVersion":"2025-06-18","serverInfo":{"name":"<vendor server>","version":"<redacted>"}}}
  • GET /mcptext/event-stream with a welcome notification (long-lived stream):
    event: message
    data: {"jsonrpc":"2.0","method":"notifications/message","params":{"data":"...","level":"info"}}
    

So this is a client-side regression, not a server problem.

Workarounds attempted that did NOT help:

  • "oauth": false in the server config — this only disables the opencode mcp debug OAuth tool; the real connection still sends the server/discover probe (re-confirmed via capture).

Expected behavior:
When the server/discover probe fails or the server returns any JSON-RPC error (including -32700 / -32601), opencode should tolerate the error and fall back to the classic initialize handshake, which the server supports. A robust client should not hard-fail or stall just because a server doesn't yet implement the brand-new discovery method.

Secondary note (server-side, for awareness): returning -32700 Parse Error for a well-formed request carrying an unknown method is arguably non-spec; -32601 Method not found would be more correct. That said, a graceful client-side fallback should not depend on the exact error code.

Related 1.18.8 MCP-v2 regressions (same release, different code paths): #39343 (OAuth discoveryState), #39333 (strict AjvJsonSchemaValidator rejects draft-07 tool schemas), #39315 (local/stdio MCP timeout).

Plugins

mcp (remote)

OpenCode version

1.18.8

Steps to reproduce

  1. Run any Streamable HTTP MCP server that advertises protocolVersion 2025-06-18 (i.e., predates server/discover) and returns a JSON-RPC error for unknown methods. Listen on e.g. http://127.0.0.1:63080/mcp.
  2. Configure it as a remote server (Basic auth via headers):
    "mcp": {
      "demo": {
        "type": "remote",
        "url": "http://127.0.0.1:63080/mcp",
        "headers": { "Authorization": "Basic ***" }
      }
    }
  3. Run opencode mcp list (or opencode mcp debug demo).
  4. Observe: Operation timed out after 30000ms / Version negotiation probe failed.
  5. Confirm the server works via direct curl POST initialize (returns 200 + valid result) and curl GET (SSE stream).

Screenshot and/or share link

(capture-proxy transcripts available on request — the request/response bytes are quoted above)

Operating System

macOS (Apple Silicon), Darwin 26.x

Terminal

zsh

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