Skip to content

Add owned stdio clients for local MCP servers - #16

Open
quinnj wants to merge 1 commit into
mainfrom
feat/stdio-client
Open

quinnj wants to merge 1 commit into
mainfrom
feat/stdio-client

Conversation

@quinnj

@quinnj quinnj commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

Local MCP servers using stdin/stdout cannot currently use this package's client: a manually constructed stdio descriptor fails during initialization with transport_unsupported. Add the qualified ModelContextProtocol.prepare_stdio_client(command) constructor, including a do-block form, and reuse the existing initialize, list/call, handler, and termination APIs.

The client owns one local child and its stdin/stdout pipes. It correlates concurrent requests, routes responses independently of user callbacks, keeps stderr separate, bounds frames/queues/request waits, and closes/reaps the child on EOF or failure. Condition notifications remove the polling floor in the new implementation; write-deadline races preserve failure, while complete replies received before EOF remain available. Shutdown can retry completed cleanup failures. Arbitrary blocked callbacks require cooperative release and produce a bounded close timeout.

Protocol selection is explicit: 2025-11-25 by default, or 2026-07-28 discovery and request metadata. Automatic version probing/restart/replay, modern subscriptions, Agentif catalog/schema import, and native subprocess compilation are outside this change. There are no new dependencies or exports. HTTP behavior and the old 16-, 18-, and 19-argument client constructors remain covered; MCPClient gains one optional field, which changes its exact field layout.

Validation on macOS arm64:

  • Full Julia 1.13 suite: 828 assertions, including 346 stdio assertions and all 7 existing strict static-server native controls.
  • Full Julia 1.10 suite: 822 assertions, including the same 346 stdio assertions and its expected native-unavailable check.
  • Strict documentation/doctests and the runnable local-child example pass. Local fixtures cover both protocol versions, concurrent/reentrant calls, exact ID types, cancellation/late replies, malformed/partial/oversized frames, blocked stdin/stderr/callbacks, EOF, termination escalation, and cleanup retry.
  • The actual subprocess entrypoint works under Julia, but strict native compilation reports 345 verifier errors and produces no executable. No verifier suppression is used.
  • Final warmed local echo medians are 148 µs on Julia 1.13 and 158 µs on Julia 1.10. The roughly 16× improvement is against the earlier polling prototype, not an existing-package capability. Warm HTTP allocations are unchanged; first HTTP call time increases by about 0.21 seconds in the final matched pair. Hosted CI passes all nine runtime/platform jobs and documentation at the published head, including Linux and Windows.

Co-authored by Codex

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.

1 participant