Skip to content

fix: bound stdio JSON-RPC message size#985

Open
he-yufeng wants to merge 1 commit into
modelcontextprotocol:mainfrom
he-yufeng:fix/stdio-max-message-bytes
Open

fix: bound stdio JSON-RPC message size#985
he-yufeng wants to merge 1 commit into
modelcontextprotocol:mainfrom
he-yufeng:fix/stdio-max-message-bytes

Conversation

@he-yufeng

Copy link
Copy Markdown
Contributor

Fixes #984.

Summary

Adds an optional MaxMessageBytes limit for newline-delimited JSON-RPC transports:

  • CommandTransport.MaxMessageBytes bounds frames read from child process stdout.
  • StdioTransport.MaxMessageBytes and IOTransport.MaxMessageBytes expose the same behavior for server-side stdio and custom IO transports.
  • The IO reader now frames input by NDJSON line, preserves the existing trailing-data rejection, and rejects oversized frames before JSON-RPC decoding.

Validation

  • go test ./mcp -run "TestIOConnRead|TestIOConnReadMaxMessageBytes|TestBatchFraming"
  • go test ./mcp -run TestCommandTransportTerminateDuration
  • go test ./...
  • go vet ./...
  • gofmt -l .
  • go run honnef.co/go/tools/cmd/staticcheck@v0.6.1 ./...
  • git diff --check -- mcp\transport.go mcp\cmd.go mcp\transport_test.go

@he-yufeng

Copy link
Copy Markdown
Contributor Author

Rebased on current origin/main and reran validation locally.

Validated:

gofmt -w mcp\cmd.go mcp\transport.go mcp\transport_test.go
go test ./mcp
go test -race ./mcp
go test ./...
git diff --check origin/main...HEAD

All passed after the rebase.

@he-yufeng he-yufeng force-pushed the fix/stdio-max-message-bytes branch from 37c0444 to 00c9bfb Compare June 2, 2026 19:28
@he-yufeng

Copy link
Copy Markdown
Contributor Author

Fresh local re-validation on the current checkout:

  • go test ./mcp -> passed
  • gofmt -l mcp/cmd.go mcp/transport.go mcp/transport_test.go -> no output
  • git diff --check origin/main...HEAD -> passed

The GitHub checks are also green as of the latest run.

@he-yufeng he-yufeng force-pushed the fix/stdio-max-message-bytes branch from 00c9bfb to b70eb70 Compare June 6, 2026 19:16
@he-yufeng

Copy link
Copy Markdown
Contributor Author

Rebased this branch onto the latest upstream main and force-pushed the cleaned head.

Validated locally:

  • gofmt -l mcp/cmd.go mcp/transport.go mcp/transport_test.go (no output)
  • go test ./mcp
  • go test -race ./mcp
  • go test ./...
  • git diff --check origin/main..HEAD

@piyushbag

Copy link
Copy Markdown

Nice refactor in the stdio framing path. A few notes from reading the diff:

  1. Pre-decode bound — Checking len(frame)+len(part) against MaxMessageBytes before validateJSONFrame avoids allocating/decoding oversized payloads. That composes well with other stdio hardening work on malformed envelopes.

  2. ReadSlice + ErrBufferFull — The continue loop on bufio.ErrBufferFull is correct for long lines, but it does grow frame without an early cap when maxMessageBytes == 0. Worth confirming that is intentional (unbounded mode preserves prior behavior) and that the capped path rejects before unbounded growth when maxMessageBytes > 0.

  3. Limit semanticsTestIOConnReadMaxMessageBytes uses int64(len(input)) without the trailing newline, which matches rejecting only the JSON payload bytes. A one-line doc comment on whether the limit includes \n/\r\n would help server authors pick values.

  4. Surface area — Exposing the knob on CommandTransport, StdioTransport, and IOTransport covers the main server entry points I have been exercising in go-sdk transport tests.

I ran a quick read-only review against current main; I have not tested this branch locally. Looks like a solid fix for #984.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose max JSON-RPC frame/message size for stdio transports

2 participants