Search by

superconductor / stdio-transport

projectsaturnstudios

The stdio transport for Superconductor MCP.

Package info

github.com/superconductor-mcp/stdio

pkg:composer/superconductor/stdio-transport

Statistics

Installs: 162

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

20241105.5.0 2025-09-04 19:37 UTC

This package is auto-updated.

Last update: 2026-10-29 13:50:41 UTC


README

superconductor/stdio

The stdio transport for Superconductor MCP: serve over your own pipes, consume over theirs

CI Packagist PHP MCP License OKF

MCP's stdio transport is the simplest one there is: the client starts the server as a child process, writes JSON-RPC lines to its stdin and reads them from its stdout. Every harness supports it, every SDK ships it, and a server that speaks it needs no port, no TLS and no network.

superconductor/core speaks the protocol but knows no transport by name. The only problem? Someone has to own the pipes.

superconductor/stdio owns both ends. On the server side it is a sketch, rocket mcp:cli <server>, that puts stdin and stdout on the application's event loop and runs the lifecycle around superconductor/core's procedures. On the client side it is a StdioConnection that spawns the server named in mcp_servers, joins its pipes to the same loop, and hands every decoded line straight to its MCPClient.

Basic usage

Most ways you will interface with superconductor/stdio are in two parts -

Serving a server defined with superconductor/core:

php rocket mcp:cli concept

That is the command a harness runs. In Claude Desktop, Cursor or Claude Code:

{
  "mcpServers": {
    "concept": { "command": "php", "args": ["/path/to/app/rocket", "mcp:cli", "concept"] }
  }
}

Consuming another stdio server. The entry in config/mcp.php has the same keys; type defaults to stdio when a command is present.

'mcp_servers' => [
    'neo4j' => ['command' => 'neo4j-mcp', 'env' => ['NEO4J_URI' => env('NEO4J_URI'), 'NEO4J_PASSWORD' => env('NEO4J_PASSWORD')]],
],
$neo4j = app(ClientManager::class)->client('neo4j');
$neo4j->ready()->wait();
$neo4j->callTool('get-schema')->wait()->content;

Requirements

PHP 8.4.27 or newer in 8.4, or 8.5.12 or newer, with proc_open available.
VenusianPHP A 0.11 application with venusian-voyager/io-pools and sketches.
superconductor/core 0.11. This package adds the transport only.
Platform macOS and Linux. On macOS the server sketch needs a pipe or a terminal on stdin; kqueue refuses /dev/null.

Installation

composer require superconductor/core superconductor/stdio

The provider is discovered. It merges config/stdio.php, adds mcp:cli to the application's sketches and registers the stdio client creator on mcp.clients. Publish the config to change any of it:

php computer vendor:publish --tag=stdio-config

Verify with a one-line handshake:

$ printf '%s\n' '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"me","version":"1"}}}' '[{"jsonrpc":"2.0","method":"notifications/initialized"},{"jsonrpc":"2.0","id":1,"method":"ping"}]' | php rocket mcp:cli concept
{"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2025-03-26","capabilities":{…},"serverInfo":{…}}}
{"jsonrpc":"2.0","id":1,"result":{}}

Configuration

config/stdio.php:

Key Default What it does
handshake.stop_waiting.enabled / .ttl true / 60 A client that sends initialize but never notifications/initialized is dropped after this many seconds.
ping_time.enabled / .ttl / .max_misses true / 10 / 3 The server pings its client every ttl seconds in every state but Idle; this many unanswered in a row stops the server.
notifications initialized, cancelled Method to Action class (Fabricate\Mechanism\Session\Actions). A notification not listed is logged and ignored.
client.shutdown_grace 2 Seconds a closing connection waits for the server to exit after closing its stdin, and again after SIGTERM, before escalating.

The server's response latency is one sketch frame, set by SKETCH_REFRESH_RATE in the application's .env (60 Hz is 16.7 ms). A server that needs less puts a higher rate in its entry's env.

The server side

STDIOServerSketch runs the lifecycle:

State Accepts Leaves on
Idle initialize only the initialize response
Handshake initialize, ping, logging/setLevel notifications/initialized, or stop_waiting running out
Available everything but initialize the pipe closing, or max_misses unanswered pings

A line may be a JSON-RPC batch when the session negotiated 2025-03-26 or earlier; each message in it is handled in order and each request answered on its own line. A 2025-06-18 session's batch is refused whole with one InvalidRequest. A server request the client answers (an elicitation) comes back on stdin like any other line. A request the state refuses gets InvalidRequest "Method [x] is not allowed." with its id. The sketch stops when the pipe closes, the handshake times out, or the client stops answering pings. PHP warnings go to stderr so stdout carries frames only.

The client side

StdioConnection is a loop WakeSource around the child's three pipes. It reads stdout on wakes, keeps the last 2 KiB of stderr so a server that dies on start can say why, writes stdin with a Writable wake only while bytes are waiting, and listens for the process exiting where the loop supports it. Decoded lines go straight to the connection's own client, never to loop mail, so two servers can both answer id 1 without crossing.

Closing follows the spec's order on loop timers, so several connections close side by side and the loop keeps turning: stdin closed, shutdown_grace to exit, SIGTERM, the same grace again, SIGKILL. A server that exits on its own, or a command that is not there, turns its client into Error with the reason, exit code and stderr tail.

Packages you might use with this one

Package Gives
superconductor/core The protocol: servers, clients, messages, procedures. Required.

AI-assisted development

This codebase was built with LLM assistance under human direction. Prompts, reviews, and architectural decisions were owned by a professional software engineer — the model accelerates drafting and exploration; it does not replace judgment on APIs, dependency direction, or what ships.

Agentic Documentation

This repository carries an Open Knowledge Format bundle at .okf/: Markdown with YAML frontmatter, readable by you and loadable by a coding agent. It records what the README doesn't: how the sketch, the pipe and the start node share a frame, what each lifecycle state refuses and why, how the server's pings and the client's answers avoid colliding ids, how the client connection reads, writes and closes without ever blocking the loop, and a log of every change that altered behaviour.

Start at .okf/index.md. AGENTS.md is the short rule sheet an agent reads before touching the pipe, the sketch, the connection or the lifecycle; each rule points into the bundle for the reason behind it.

Point your agent at the repo and it has the same context the maintainer has. Point yourself at it when the README's answer is "it does X" and you want "because".

Resources

Running the test suite

The suite is Pest v4. The connection tests run real children: a fixture server in tests/Fixtures/echo-server.php under the PHP that runs the tests, and sleep for the server that ignores a closed stdin. The start node runs on socket pairs. No test needs a terminal or a network. The tests read superconductor/core's config/mcp.php from vendor/superconductor/core, so core must be installed; venusian/framework is in require-dev because the code calls config() and app().

git clone https://github.com/superconductor-mcp/stdio.git
cd stdio
composer install
vendor/bin/pest
Tests:    14 passed (53 assertions)

Contributing

Open an issue first for anything beyond a typo. Pull requests come with a Pest test for the behaviour and keep CI green. A protocol change goes to superconductor/core first; this package moves lines. Read AGENTS.md for the rules the code follows.

Security

The server end reads and writes the streams it was started with and nothing else; the client end spawns the command its config names and kills it on close if it will not leave. See SECURITY.md for the model and how to report a vulnerability.

License

MIT. See LICENSE.