Add a Windows implementation of StdioTransport - #280
Open
onetamer wants to merge 1 commit into
Open
Conversation
StdioTransport is gated on canImport(Darwin) || canImport(Glibc) || canImport(Musl) — it drives standard input/output through POSIX non-blocking file-descriptor I/O — so it compiles out on Windows and the SDK offers no stdio transport there. This adds an os(Windows) arm speaking the same wire contract (newline-delimited JSON-RPC frames on stdin/stdout) over Foundation's FileHandle, which Windows Foundation implements: - Reads run on a dedicated OS thread so a blocking stdin read never parks a cooperative-pool thread; lines are split on LF with a trailing CR stripped in case a Windows-side client writes CRLF. - Sends append the LF delimiter and write synchronously; write failures surface as MCPError.transportError. - EOF on stdin finishes the message stream, matching the POSIX implementation's behavior. The public surface matches the POSIX actor (connect/disconnect/ send/receive + logger), minus the FileDescriptor-typed initializer parameters, which have no Windows equivalent. Extracted from a production MCP server (CopyBucket) where this implementation runs the stdio loop under real agent clients on Windows 11.
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.
Problem
StdioTransportis gated oncanImport(Darwin) || canImport(Glibc) || canImport(Musl)— it drives stdin/stdout through POSIX non-blocking file-descriptor I/O (fcntl/O_NONBLOCK) — so it compiles out on Windows and the SDK offers no stdio transport there. Windows is where stdio matters most right now: Claude Desktop'sclaude_desktop_config.jsonvalidates stdio (command) entries only.Approach
An
#elseif os(Windows)arm of the same file provides apublic actor StdioTransport: Transportspeaking the same wire contract — newline-delimited JSON-RPC frames on standard input/output — over Foundation'sFileHandle, which Windows Foundation implements:Thread.detachNewThread), so a blocking stdin read never parks a cooperative-pool thread. Lines split on LF; a trailing CR is stripped in case a Windows-side client writes CRLF.MCPError.transportError.The public surface matches the POSIX actor (
connect/disconnect/send/receive+logger), minus theFileDescriptor-typed initializer parameters, which have no Windows equivalent — the Windows initializer takes only the optionalLogger.Verification
swift buildon macOS: green (the POSIX arm is untouched; the Windows arm is inactive).copybucket-mcp.exe, shipping since 2.0.2) where it runs the stdio loop under real agent clients — Claude Desktop and Codex CLI — includinginitialize,tools/list, and tool calls with multi-hundred-KB results.Notes
FileHandlewrite does not tear frames.