Skip to content

fix(server): return stdio parse errors#2766

Open
he-yufeng wants to merge 1 commit into
modelcontextprotocol:mainfrom
he-yufeng:fix/stdio-deep-request-parse-error
Open

fix(server): return stdio parse errors#2766
he-yufeng wants to merge 1 commit into
modelcontextprotocol:mainfrom
he-yufeng:fix/stdio-deep-request-parse-error

Conversation

@he-yufeng
Copy link
Copy Markdown

Summary

  • make the stdio server return JSON-RPC error frames when incoming lines fail JSON-RPC parsing/validation
  • recover a simple request id from the raw line when possible so id-bearing malformed requests do not stay pending
  • keep later valid stdio messages flowing after an invalid line

Fixes #2751.

To verify

  • uv run pytest tests/server/test_stdio.py -q
  • uv run ruff check src/mcp/server/stdio.py tests/server/test_stdio.py
  • uv run pyright src/mcp/server/stdio.py tests/server/test_stdio.py
  • git diff --check

@he-yufeng he-yufeng force-pushed the fix/stdio-deep-request-parse-error branch from f6b844e to c0ce601 Compare June 2, 2026 22:23
@he-yufeng
Copy link
Copy Markdown
Author

Updated the coverage for the parse-error path after the first CI run showed the full test suite passing but coverage dropping below 100%.

Local checks on the updated branch:

  • uv run pytest tests/server/test_stdio.py -q (5 passed)
  • uv run ruff check src/mcp/server/stdio.py tests/server/test_stdio.py
  • uv run pyright src/mcp/server/stdio.py tests/server/test_stdio.py
  • python -m py_compile src\mcp\server\stdio.py tests\server\test_stdio.py
  • git diff --check

I also attempted the full coverage command locally on Windows/Python 3.13, but it fails in existing integration transport tests before coverage reporting (HTTPStatusError 502 / websocket closed-before-status-line cases). Those failures are outside this stdio parse-error change; the targeted stdio coverage has been expanded and pushed.

@he-yufeng he-yufeng force-pushed the fix/stdio-deep-request-parse-error branch from c0ce601 to f76a0b3 Compare June 2, 2026 22:38
@he-yufeng
Copy link
Copy Markdown
Author

Follow-up pushed in f76a0b3 after the remote coverage failure on stdio.py line 51.

I added the missing malformed-JSON numeric-id regression case so the fallback int(raw_request_id) branch is covered.

Local validation:

  • uv run pytest tests/server/test_stdio.py -q: 5 passed
  • uv run ruff check src/mcp/server/stdio.py tests/server/test_stdio.py: passed
  • uv run pyright src/mcp/server/stdio.py tests/server/test_stdio.py: 0 errors
  • python -m py_compile src\mcp\server\stdio.py tests\server\test_stdio.py: passed
  • git diff --check: passed

@he-yufeng he-yufeng force-pushed the fix/stdio-deep-request-parse-error branch from f76a0b3 to b63f5f8 Compare June 2, 2026 22:44
@he-yufeng
Copy link
Copy Markdown
Author

Follow-up pushed in b63f5f8 after the Python 3.14 lowest-direct job exposed an unrelated stderr exact-match fragility in the stdio interaction test.

The test still verifies that the subprocess clean-exit marker is passed through stderr, but now checks the marker as a suffix so dependency warnings emitted by the child interpreter do not fail the test before the server's own line.

Local validation:

  • uv run pytest tests/server/test_stdio.py tests/interaction/transports/test_stdio.py -q: 7 passed
  • uv run ruff check src/mcp/server/stdio.py tests/server/test_stdio.py tests/interaction/transports/test_stdio.py: passed
  • uv run pyright src/mcp/server/stdio.py tests/server/test_stdio.py tests/interaction/transports/test_stdio.py: 0 errors
  • python -m py_compile src\mcp\server\stdio.py tests\server\test_stdio.py tests\interaction\transports\test_stdio.py: passed
  • git diff --check: passed

Copy link
Copy Markdown

@StantonMatt StantonMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked head b63f5f8 with the stdio paths this changes.

Local validation passed:

  • uv run --frozen pytest tests/server/test_stdio.py tests/interaction/transports/test_stdio.py -q -> 7 passed
  • uv run --frozen ruff check src/mcp/server/stdio.py tests/server/test_stdio.py tests/interaction/transports/test_stdio.py
  • uv run --frozen pyright src/mcp/server/stdio.py tests/server/test_stdio.py tests/interaction/transports/test_stdio.py

I also ran a small stdin/stdout probe with a malformed id-bearing line followed by a valid ping: the malformed line produced a JSON-RPC parse error with id "bad-1", and the later valid request still arrived on the read stream. That covers the main regression boundary from #2751 for me.

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.

Deep JSON-RPC request over stdio logs a validation error and leaves the original request pending

2 participants