Sidecar that translates the stdio MCP transport to StreamableHTTP, exposing a JSON-RPC HTTP endpoint on port 3000. This lets Clerum route requests to MCP servers that only support stdin/stdout (e.g., PostgreSQL, Redis, GitHub, Brave Search) through the same HTTP-based infrastructure used for native HTTP MCP servers.
Use stdio-bridge for any MCP server image that communicates over stdin/stdout instead of HTTP. In a WorkflowRecipe, set transport.type: stdio on the workload -- the host-context-controller (HCC) automatically injects stdio-bridge as a sidecar container alongside the MCP server pod.
3000 (configurable via BRIDGE_PORT)
mcp-host / mcp-proxy
↓ POST /mcp (JSON-RPC)
stdio-bridge (:3000)
↓ stdin (JSON-RPC message)
MCP server process (e.g. @modelcontextprotocol/server-postgres)
↓ stdout (JSON-RPC response)
stdio-bridge
↓ HTTP 200 (JSON-RPC response)
caller
- Process spawn -- On startup,
StdioBridgespawns the target MCP server as a child process usingStdioClientTransportfrom@modelcontextprotocol/sdk. The command and args are configured via environment variables. - Request routing -- Incoming HTTP POST requests are parsed as JSON-RPC messages, sent to the child process over stdin, and the corresponding response (matched by
id) is returned as the HTTP response. - Health --
GET /healthreturns process status, command name, and restart count. - Auto-restart -- If the child process exits unexpectedly, stdio-bridge restarts it with exponential backoff (base delay x 3^n), up to a configurable maximum number of retries.
- Graceful shutdown -- On SIGTERM/SIGINT, pending requests are rejected, the HTTP server is closed, and the child process stdin is closed with a configurable timeout.
| Variable | Default | Description |
|---|---|---|
STDIO_COMMAND |
(required) | Command to spawn (e.g., node, npx) |
STDIO_ARGS |
[] |
JSON array of arguments (e.g., ["dist/index.js"]) |
BRIDGE_PORT |
3000 |
HTTP listen port |
BRIDGE_HEALTH_PATH |
/health |
Health endpoint path |
STDIO_RESTART_MAX |
3 |
Max auto-restart attempts |
STDIO_RESTART_DELAY |
5000 |
Base restart delay (ms) |
STDIO_INIT_TIMEOUT |
30000 |
Process init timeout (ms) |
STDIO_SHUTDOWN_TIMEOUT |
10000 |
Graceful shutdown timeout (ms) |
LOG_LEVEL |
info |
Log verbosity |
cd stdio-bridge
npm install
STDIO_COMMAND=node STDIO_ARGS='["../tests/e2e/fixtures/mock-stdio-mcp-server/dist/index.js"]' npm run devdocker build -t clerum/stdio-bridge:latest ./stdio-bridgestdio-bridge is not deployed as a standalone service. It runs as a sidecar container alongside MCP server pods in the mcp-server namespace. HCC injects it automatically when a WorkflowRecipe or McpServer CRD specifies transport.type: stdio:
- HCC adds stdio-bridge as a container in the pod spec
- An
emptyDirvolume is shared between the MCP server init container and stdio-bridge - MCP Proxy routes HTTP requests to
stdio-bridge:3000transparently
cd stdio-bridge
npm test # vitest — 1 test file (bridge.test.ts)
npm run test:watchTest files are in stdio-bridge/test/.
src/
├── main.ts # Entrypoint: load config, start bridge, graceful shutdown
├── bridge.ts # StdioBridge: process lifecycle, HTTP server, request/response routing
└── types.ts # BridgeConfig interface + env-based config loader