mcp: keep the stdio session alive on a malformed JSON frame - #1210
Open
blackwell-systems wants to merge 1 commit into
Open
mcp: keep the stdio session alive on a malformed JSON frame#1210blackwell-systems wants to merge 1 commit into
blackwell-systems wants to merge 1 commit into
Conversation
The stdio transport feeds os.Stdin into a single streaming json.Decoder. A syntactically malformed frame makes Decode return a *json.SyntaxError, and the read goroutine returned on that error, so one bad frame terminated the whole session. A streaming decoder also cannot resynchronize on its own: a syntax error poisons its buffered stream state. Per JSON-RPC 2.0, a parse error should be answered with a -32700 response and the session should continue. That is what mark3labs/mcp-go does (it reads newline-delimited frames and unmarshals each independently), and it is the same recoverable-decode direction taken for empty-method requests in modelcontextprotocol#1000. The stdio read loop now: - replies with a -32700 parse-error response (id: null) for a malformed frame, - resynchronizes to the next newline-delimited frame and keeps reading, - terminates only on a genuine EOF or I/O error, as before. An EOF immediately after a malformed frame (with or without a trailing newline) still ends the session cleanly. Only *json.SyntaxError is recovered; the existing "invalid trailing data" handling is unchanged. Tests cover a malformed frame followed by a valid request (the request is still delivered and a -32700 is written), consecutive malformed frames, and malformed frames at end-of-stream. Verified with -race. Surfaced by an MCP conformance study run against a downstream server (blackwell-systems/agent-lsp#14). The behavior is a property of this transport, shared by every server built on the SDK's stdio transport. Fixes modelcontextprotocol#1209
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The stdio transport feeds os.Stdin into a single streaming json.Decoder. A
syntactically malformed frame makes Decode return a *json.SyntaxError, and the
read goroutine returned on that error, so one bad frame terminated the whole
session. A streaming decoder also cannot resynchronize on its own: a syntax
error poisons its buffered stream state.
Per JSON-RPC 2.0, a parse error should be answered with a -32700 response and
the session should continue. That is what mark3labs/mcp-go does (it reads
newline-delimited frames and unmarshals each independently), and it is the same
recoverable-decode direction taken for empty-method requests in #1000.
The stdio read loop now:
An EOF immediately after a malformed frame (with or without a trailing newline)
still ends the session cleanly. Only *json.SyntaxError is recovered; the
existing "invalid trailing data" handling is unchanged.
Tests cover a malformed frame followed by a valid request (the request is still
delivered and a -32700 is written), consecutive malformed frames, and malformed
frames at end-of-stream. Verified with -race.
Surfaced by an MCP conformance study run against a downstream server
(blackwell-systems/agent-lsp#14). The behavior is a property of this transport,
shared by every server built on the SDK's stdio transport.
Fixes #1209