Skip to content

Server API

The Server class runs against a TransportInterface. It blocks the caller until the transport closes. Build one with the fluent ServerBuilder, then run it against any transport implementation.

use Nexus\Mcp\Server\ServerBuilder;
use Nexus\Mcp\Server\Transport\StdioServerTransport;

$server = (new ServerBuilder())
    ->setServerInfo(name: 'my-server', version: '1.0.0')
    // ... register features ...
    ->build()
;

$server->run(new StdioServerTransport());

Server::run() returns when the transport closes. For the stdio transport, that is EOF on stdin. A request-scoped transport such as Streamable HTTP uses Server::listen() instead. That method attaches the dispatcher and returns, so the HTTP host keeps driving the loop.

Guide

  • Server configuration: server info and its disclosure, instructions, the logger, and the in-flight dispatch cap.
  • Tools: registering tools, structured content, and schema validation.
  • Prompts: registering prompt renderers.
  • Resources: static and templated resources, and the cache hints every read and list result carries.
  • Completions: serving completion/complete from a completion store.
  • Stores and pagination: page size, custom store implementations, and runtime mutation.
  • Custom handlers: vendor-extension methods and spec-method overrides.
  • Extensions: enabling SEP-2133 extensions and the declared-capability gate on their methods.
  • Tasks: the SEP-2663 tasks extension. It brokers tool calls into polled long-running tasks.
  • Apps: the SEP-1865 MCP Apps extension. It declares ui:// view resources and links tools to them.
  • Capability advertisement: how ServerCapabilities is derived from what you registered.
  • Subscriptions: serving subscriptions/listen streams and the list-changed notifications.
  • ServerContext: what every handler receives.
  • Asking the client for input: the InputRequiredResult flow and elicitation.

You can also declare tools, prompts, resources, completions, and the server identity with attributes. Mark a plain object with #[AsTool], #[AsPrompt], #[AsResource], #[AsResourceTemplate], #[AsCompletion], or #[AsServer], then register it in one call with ServerBuilder::register(). See Attribute discovery for the full reference.

Lifecycle

Build

build() validates the configuration and returns a Server instance. For example, the server info must be set.

Run

run($transport) registers the listener chain on the transport and starts it. The call blocks until the transport closes.

Dispatch

While the server runs, the dispatcher classifies each inbound envelope and routes it to its handler. The protocol is stateless, so every request dispatches immediately. The dispatcher reads the client's identity and capabilities from the request's _meta.

A request for an unregistered method gets a MethodNotFound error. A malformed envelope gets an InvalidRequest or a ParseError error.

Shutdown

The transport signals shutdown when it closes. For stdio, that is EOF on stdin. The dispatcher drains the in-flight coroutines before the transport's close listeners fire, so responses already in flight are flushed before the process exits. On an event-loop HTTP host, call close() on the transport before stopping the HTTP server: closing ends every open subscriptions/listen stream, and the HTTP server's own stop waits for those responses to finish, so the reverse order deadlocks with a stream open.

See also