Description
When opencode batches multiple MCP tool calls in a single message and the MCP server uses SSE transport (port 4201), the second+ tool calls fail with "JSON Parse error: Unexpected EOF". The first call succeeds, but subsequent calls receive corrupted parameters.
Reproduction
- Configure an MCP server with SSE transport (not stdio)
- Have the LLM produce a response with 2+ tool_use blocks targeting that server
- Opencode dispatches the tool calls
- First call succeeds, second call fails with corrupted parameters
Error Pattern
Invalid input for tool register_update: JSON parsing failed:
Text: {"entry_id": {"tool": "register_update", "error": "Invalid input
for tool register_update: JSON parsing failed: Text: {"entry_id": .
Error message: JSON Parse error: Unexpected EOF
The error shows the first tool call's error response text concatenated into the second tool call's parameters string. The parameters should be a JSON object but arrive as a corrupted string containing both valid JSON and error text from a previous call.
Root Cause Analysis
The streaming parser (Vercel AI SDK Anthropic provider) correctly separates input_json_delta buffers per content block index — there is no cross-block buffer leak at the streaming level.
The corruption happens in the MCP SSE transport layer during concurrent tool call dispatch:
- Opencode sends tool call N as an HTTP POST to the SSE-transport MCP server
- The server returns an error response (e.g., validation failure)
- The error response text is somehow fed back into the shared parameter buffer for the next tool call
- Tool call N+1 is sent with parameters =
valid_json + error_text_from_N
- The server receives corrupted JSON and rejects it
This is a client-side routing/buffering issue — the MCP client does not properly isolate request construction from response handling when dispatching concurrent tool calls over SSE transport.
Affected Transport
- SSE transport (port 4201): Bug present
- stdio transport: Not affected (serialized connection)
- Streamable HTTP (port 4200): Possibly affected (same HTTP POST mechanism)
Environment
- opencode: v1.18.15 (Bun-compiled TypeScript)
- MCP server: Python MCP SDK (mcp package)
- Transport: SSE via Starlette
- OS: macOS arm64
Suggested Fix
Ensure each tools/call JSON-RPC request has its own isolated parameter buffer. Error responses from one call must not be concatenated into parameter buffers for subsequent calls. Consider:
- Using separate HTTP connections for concurrent tool calls to the same SSE server
- Implementing strict request/response correlation with unique JSON-RPC IDs
- Ensuring parameter buffers are constructed fresh for each call, not shared
Workaround
Our MCP server now has a server-side sanitizer that detects and repairs corrupted parameters by extracting valid JSON from the corruption. This is a safety net, not a proper fix — the fix needs to be in the opencode client.
Description
When opencode batches multiple MCP tool calls in a single message and the MCP server uses SSE transport (port 4201), the second+ tool calls fail with "JSON Parse error: Unexpected EOF". The first call succeeds, but subsequent calls receive corrupted parameters.
Reproduction
Error Pattern
The error shows the first tool call's error response text concatenated into the second tool call's parameters string. The parameters should be a JSON object but arrive as a corrupted string containing both valid JSON and error text from a previous call.
Root Cause Analysis
The streaming parser (Vercel AI SDK Anthropic provider) correctly separates
input_json_deltabuffers per content block index — there is no cross-block buffer leak at the streaming level.The corruption happens in the MCP SSE transport layer during concurrent tool call dispatch:
valid_json + error_text_from_NThis is a client-side routing/buffering issue — the MCP client does not properly isolate request construction from response handling when dispatching concurrent tool calls over SSE transport.
Affected Transport
Environment
Suggested Fix
Ensure each
tools/callJSON-RPC request has its own isolated parameter buffer. Error responses from one call must not be concatenated into parameter buffers for subsequent calls. Consider:Workaround
Our MCP server now has a server-side sanitizer that detects and repairs corrupted parameters by extracting valid JSON from the corruption. This is a safety net, not a proper fix — the fix needs to be in the opencode client.