The STDIO transport communicates via standard input/output streams, ideal for command-line tools and MCP client integrations.
use Mcp\Server\Transport\StdioTransport;
$transport = new StdioTransport(
input: STDIN, // Input stream (default: STDIN)
output: STDOUT, // Output stream (default: STDOUT)
logger: $logger // Optional PSR-3 logger
);input(optional): Input stream resource. Defaults toSTDIN.output(optional): Output stream resource. Defaults toSTDOUT.logger(optional):LoggerInterface- PSR-3 logger for debugging. Defaults toNullLogger.runnerControl(optional):RunnerControlInterface- controls the read loop. Defaults to aRunnerControl, which runs until the input stream closes.maxLineBytes(optional): Maximum accepted line length in bytes, including the newline. Defaults to 4 MiB (StdioTransport::DEFAULT_MAX_LINE_BYTES). The transport discards a longer line and logs a warning. It writes nothing back to the client. A value below1throwsInvalidArgumentException.
The STDIO transport serves both eras. The client's first request decides which one the connection uses, see Serving both eras.
!!! warning
When using STDIO transport, never write to STDOUT in your handlers as it's reserved for JSON-RPC communication.
Use STDERR for debugging instead.
<?php
require __DIR__.'/vendor/autoload.php';
use Mcp\Server\Server;
use Mcp\Server\Transport\StdioTransport;
$server = Server::builder()
->setServerInfo('STDIO Calculator', '1.0.0')
->addTool(function(int $a, int $b): int { return $a + $b; }, 'add_numbers')
->build();
$transport = new StdioTransport();
$status = $server->run($transport);
exit($status); // listen() returns 0 when the input stream closes
For MCP clients like Claude Desktop:
{
"mcpServers": {
"my-php-server": {
"command": "php",
"args": ["/absolute/path/to/server.php"]
}
}
}