Skip to content

ci: add stdio smoke test to verify LF-only wire format on all platforms#15

Merged
shigechika merged 3 commits intomainfrom
ci/stdio-smoke-test
May 1, 2026
Merged

ci: add stdio smoke test to verify LF-only wire format on all platforms#15
shigechika merged 3 commits intomainfrom
ci/stdio-smoke-test

Conversation

@shigechika
Copy link
Copy Markdown
Owner

Summary

  • Adds tests/test_stdio_smoke.py: spawns keycloak-mcp as a subprocess, sends a JSON-RPC initialize request, and asserts the response line is terminated with \n not \r\n.
  • No CI workflow changes required — the existing uv run pytest -v step picks up the new file automatically, so it runs on every matrix entry (ubuntu-latest × 3.10/3.12/3.13 + windows-latest × 3.12).
  • No Keycloak connection needed: initialize is handled entirely by the MCP framework before any tool dispatch.

What this guards against

modelcontextprotocol/python-sdk#2433stdio_server() on Windows emitted \r\n instead of \n, corrupting the NDJSON wire format. The previous Windows CI job only ran unit tests and would not have caught this regression.

Test plan

  • uv run pytest tests/test_stdio_smoke.py -v — passes locally (macOS)
  • CI green on ubuntu-latest × 3.10/3.12/3.13 + windows-latest × 3.12

Closes #3

🤖 Generated with Claude Code

shigechika and others added 3 commits May 2, 2026 00:52
The Windows CI job previously ran only pytest unit tests, which exercise
pure-Python logic and never spawn the MCP server.  This meant the CRLF
regression (modelcontextprotocol/python-sdk#2433) would not be caught.

Add tests/test_stdio_smoke.py: spawns keycloak-mcp as a subprocess,
sends a JSON-RPC initialize request, and asserts the response line is
terminated with LF (\n) not CRLF (\r\n).  Runs on every matrix entry
(ubuntu-latest × 3.10/3.12/3.13 + windows-latest × 3.12) via the
existing `uv run pytest -v` step — no CI workflow changes required.

Closes #3

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…tion

On Windows, sys.stdout defaults to text mode which translates \n to \r\n,
corrupting the NDJSON wire format (modelcontextprotocol/python-sdk#2433).
Use msvcrt.setmode to force binary mode on the underlying file descriptors
before mcp.run() so the MCP SDK's writes pass through unchanged.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
msvcrt.setmode() cannot prevent the \n -> \r\n translation because it
happens in Python's TextIOWrapper layer before reaching the OS fd level.

The MCP SDK creates TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
with the default newline=None, which on Windows translates \n to \r\n.
Work around this by rebuilding sys.stdout around a _CRStripper RawIOBase
that strips \r\n -> \n before each os.write(), so the SDK's subsequent
TextIOWrapper.write() calls are corrected at the raw I/O level.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@shigechika shigechika merged commit e220b7e into main May 1, 2026
5 checks passed
@shigechika shigechika deleted the ci/stdio-smoke-test branch May 1, 2026 16:11
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.

ci: Windows smoke test should exercise stdio_server, not just pytest

1 participant