Server::builder() configures a server; run() puts it on a transport and starts
answering. Every transport implements TransportInterface and is used the same way:
$server = Server::builder()
->setServerInfo('My Server', '1.0.0')
->setDiscovery(__DIR__, ['.'], excludeDirs: ['vendor'])
->build();
$transport = new SomeTransport();
$result = $server->run($transport); // Blocks for STDIO, returns a response for HTTPThe choice depends on the client you want to integrate with:
- The client runs locally and launches your server as a subprocess (Claude Desktop, most editors) → STDIO.
- The client is remote, or your server lives in a web application → HTTP, the Streamable HTTP transport.
The rest of this section:
- Server builder — every configuration knob: server info, discovery, dependency injection, logging, pagination.
- Framework integration — mounting the HTTP transport in a Symfony, Laravel, or Slim application, or running it standalone.
- Sessions — where per-client state lives, which matters as soon as you serve HTTP from more than one process.
- Serving both eras — the same endpoint also answers protocol
revision
2026-07-28, which has no handshake and no sessions; what a modern request carries, and how each one is routed. - Caching — the
ttlMs/cacheScopehints a modern-era result carries. - Subscriptions —
subscriptions/listenand the notification bus behind it. - Authorization — validating OAuth 2 access tokens in front of the HTTP transport.