Skip to content

JSON Parse error: Unrecognized token ' ' in MCP tool stdout parsing (Windows, v1.14.24+) #24414

@daveotero

Description

@daveotero

Description

After upgrading to v1.14.24/v1.14.25, MCP operations (connect, auth, clear auth) fail with a JSON parse error. The error originates from @modelcontextprotocol/sdk's deserializeMessage() (shared/stdio.ts:41) when it encounters non-JSON content (blank lines, startup output) on an MCP tool's stdout.

Environment

  • OpenCode version: v1.14.25 (was working on previous version)
  • Platform: Windows
  • Run as: opencode serve (managed by OpenChamber)

Expected behavior

MCP tools that write non-JSON content to stdout should either have it tolerated (skip non-JSON lines) or produce a clear, recoverable error without breaking the entire MCP subsystem.

Actual behavior

Server log during startup:

INFO  service=mcp key=perplexity-ask toolCount=1 create() successfully created client
INFO  service=mcp key=playwright toolCount=21 create() successfully created client
ERROR service=server-proxy name=SyntaxError message=JSON Parse error: Unrecognized token ' '
  stack=SyntaxError: JSON Parse error: Unrecognized token ' '
    at <parse> (:0)
    at parse (unknown)
    at ~effect/Effect/successCont (B:/~BUN/root/chunk-4crkreex.js:25:7738)
    at runLoop (B:/~BUN/root/chunk-4crkreex.js:25:2045)
    at evaluate (B:/~BUN/root/chunk-4crkreex.js:25:1435)

After this error, all MCP HTTP API calls (mcp.connect(), mcp.auth.start(), mcp.auth.remove()) fail. The error has no key= field (not tied to a specific MCP server), indicating the MCP subsystem enters a corrupted state.

The SSE event stream also shows "JSON Parse error: Unrecognized token '" after this point.

Root cause

@modelcontextprotocol/sdk/src/shared/stdio.ts:41deserializeMessage() calls JSON.parse(line) on every newline-delimited line from MCP tool stdout. If a tool outputs a blank line or non-JSON text to stdout (e.g., startup banner, logging), JSON.parse throws a SyntaxError. The StdioClientTransport.processReadBuffer() (line 133) catches this and fires onerror(), but subsequent MCP state becomes inconsistent.

MCP protocol requires strict JSON-RPC 2.0 over stdin/stdout — all non-JSON output must go to stderr. However, a blank line or log line on stdout should not permanently break the MCP subsystem. It should either be skipped gracefully or produce a scoped, recoverable error.

Suspect commit

011c23761bd7ebe9df0b772b409a353051d9489c — "feat(httpapi): bridge mcp status endpoint (#24100)" — refactored MCP Status from Zod to Effect Schema. This may have changed error propagation in the MCP HTTP API layer, causing previously-tolerated stdout noise to now corrupt the system.

Related issues

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions