StdioServerTransport
Server-side MCP transport that exchanges JSON-RPC messages over arbitrary byte streams.
Reads framed messages from the supplied Source and writes framed messages to the supplied Sink. Three internal coroutines drive the pipeline:
reader — pulls bytes from the input source into the parsing buffer; runs on Builder.ioDispatcher.
processor — parses messages out of the buffer and invokes the registered message handler; runs on Builder.handlerDispatcher (defaults to Dispatchers.Default) so blocking handler code does not starve the I/O pool.
writer — serialises outbound messages and flushes them to the output sink; runs on Builder.ioDispatcher.
Both internal channels are bounded, so a slow handler or slow output naturally back-pressures the upstream producer — send suspends when the outbound channel is full.
Both explicit close and a natural EOF from the input perform a graceful drain: in-flight outbound messages are flushed before onClose fires, and the input source and output sink are released.
Example:
val transport = StdioServerTransport(
input = System.`in`.asSource().buffered(),
output = System.out.asSink().buffered(),
) {
scope = myScope
}
transport.start()Constructors
Creates a StdioServerTransport reading from input and writing to output, with optional configuration applied through a Builder block.
Creates a StdioServerTransport from the given input source and output sink with default configuration. Retained for binary compatibility; prefer the Builder-based constructor.
Types
Configuration builder for StdioServerTransport. Used via the StdioServerTransport(input, output) { ... } factory; the I/O endpoints are supplied positionally, while scope, handlerDispatcher, and ioDispatcher are configurable inside the block.
Functions
Closes the transport. When called after start, waits for in-flight outbound messages to be flushed, releases the input source and output sink, cancels the internal scope when the transport owns it, and invokes onClose. When called before start, transitions directly to the closed state without releasing the input/output or invoking onClose — the caller remains responsible for resources that were never handed off to a running transport. Safe to call multiple times and safe to race with start.
Queues message for the writer coroutine. Suspends when the outbound channel is full, applying back-pressure to the caller. Throws McpException with RPCError.ErrorCode.CONNECTION_CLOSED if the transport has not been started or has already closed.