Skip to content

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

Closed as not planned

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:41 — deserializeMessage() 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

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Apr 26, 2026
  2. removed
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  3. github-actions commented on Jul 3, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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