Transport-level routing for MCP/ACP protocols
We appreciate your patience. The service is temporarily operating in an external runtime environment.
Transport-level routing for MCP/ACP protocols
We appreciate your patience. The service is temporarily operating in an external runtime environment.
This section describes the internal architecture of the stdio Bus reference implementation. The content is informative (non-normative) and intended to help developers understand the runtime behavior and debug issues.
Non-Normative Content
This page describes the reference implementation architecture. Alternative implementations may use different internal structures while still conforming to the normative specification. For normative requirements, see the Protocol Specification.
stdio Bus operates as a transport layer between external clients and worker processes. The daemon consists of four main components: the event loop, transport layer, router, and process manager.
Loading diagram...
Event Loop
Single-threaded I/O multiplexing using platform-specific APIs (epoll on Linux, kqueue on macOS). Processes all I/O events, signal handling, and timeout checks in a non-blocking manner.
Transport Layer
Handles NDJSON framing for all connections. Manages input buffering, message extraction, output queuing, and partial write tracking. Implements backpressure when output queues exceed configured limits.
Router
Maintains session and request tables for message routing. Routes client messages to workers based on session affinity, and routes worker responses back to the originating client based on request ID correlation.
Process Manager
Spawns and monitors worker processes according to pool definitions. Handles worker lifecycle including startup, health monitoring, restart with backoff, and graceful shutdown.
The stdio Bus runtime follows a deterministic startup sequence and maintains clear ownership of all file descriptors throughout its lifecycle.
Workers are spawned using the standard Unix fork/exec pattern with pipe-based communication:
stdin_pipe[2] and stdout_pipe[2]dup2() pipes to stdin/stdout, then execvp() the configured command| Owner | File Descriptors |
|---|---|
| stdio Bus Runtime | Listening socket (if any), client connection FDs, worker pipe FDs (write-end of stdin, read-end of stdout) |
| Worker Processes | Their stdin/stdout (which are the other ends of stdio Bus's pipes) |
stdio Bus uses platform-specific I/O multiplexing APIs wrapped in a unified abstraction layer. This allows the same application logic to run on both Linux (using epoll) and macOS (using kqueue).
Loading diagram...
| Function | Description |
|---|---|
stdio_bus_event_loop_create() | Create a new event loop instance |
stdio_bus_event_loop_add() | Register a file descriptor with a callback handler |
stdio_bus_event_loop_modify() | Change event interest (read/write) for a registered FD |
stdio_bus_event_loop_remove() | Unregister a file descriptor from the event loop |
stdio_bus_event_loop_run_once() | Process pending events with optional timeout |
stdio_bus_event_loop_destroy() | Clean up event loop resources |
The main loop runs with a 1-second timeout, checking for:
The transport layer handles NDJSON (Newline-Delimited JSON) framing for all client and worker connections. Each message is a single JSON object followed by a newline character.
Loading diagram...
max_input_buffer limitsent offset in each chunkThe router maintains two tables for message routing: a session table that maps session IDs to worker assignments, and a request table that tracks pending requests for response correlation.
Loading diagram...
id, sessionId, and method from the JSON message (minimal parsing)sessionId exists in session table → route to the assigned workersessionId is new → assign worker via round-robin, create session entrysessionId → route via round-robin (no session affinity)id (request) → record in pending request tableid, sessionId, and result/error from JSONresult or error present (response) → look up id in pending requests → route to originating clientsessionId present (notification) → look up session → route to session owner| Table | Key | Value | Purpose |
|---|---|---|---|
| Session Table | sessionId | Worker assignment + client FD | Maintain session affinity for related messages |
| Request Table | Request id | Originating client FD | Correlate responses with requesting clients |
Backpressure prevents memory exhaustion when a slow consumer cannot keep up with message production. stdio Bus implements flow control by pausing reads from the corresponding input source when output queues exceed configured limits.
Loading diagram...
max_output_queue bytesread_paused flag, record timestamp)backpressure_timeout_sec| Limit | Default Value | Description |
|---|---|---|
max_input_buffer | 1 MB (1,048,576 bytes) | Maximum bytes buffered per input FD |
max_output_queue | 4 MB (4,194,304 bytes) | Maximum bytes queued per output FD |
max_restarts | 5 | Maximum worker restarts within time window |
restart_window_sec | 60 seconds | Time window for counting restarts |
drain_timeout_sec | 30 seconds | Graceful shutdown drain timeout |
backpressure_timeout_sec | 60 seconds | Close connection if queue full this long |
Configuration Override
All resource limits can be overridden in the configuration file under the limits object. See the Getting Started guide for configuration examples.