NAME

AnyEvent::MCP::Server - MCP request dispatch and JSON-RPC framing

DESCRIPTION

An MCP server needs to understand requests, but it does not necessarily need to own a listening socket. This class handles the protocol: it accepts decoded JSON-RPC objects (or UTF-8 JSON), dispatches requests and delivers responses through callbacks. Its subclasses AnyEvent::MCP::Server::JSONL and AnyEvent::MCP::Server::HTTP handle the actual connections. If you are writing a standalone server, AnyEvent::MCP::Server::Simple is usually the easier starting point.

The server implements discovery, initialization, ping and tool listing/calls. The 2025 compatibility path supports ordinary requests and responses, but not server-initiated requests. Permission asking supports modern input challenges as well as local helpers. SSE, subscriptions and schema validation are not implemented yet.

The usual object-level assembly is a AnyEvent::MCP::Server::Toolset holding tool callbacks, a Server handling protocol messages, and a transport accepting connections. Use "FIRST USE" in AnyEvent::MCP::Server::HTTP for an executable HTTP assembly or "EXAMPLE" in AnyEvent::MCP::Server::JSONL for stdio. The corresponding client entry point is AnyEvent::MCP::Client.

Only embedders that already own their transport need rpc or json_rpc directly; these methods do not create connections or run the event loop.

METHODS

$server = AnyEvent::MCP::Server->new (%config)

Creates the protocol object without opening a listener or starting an event loop. Options are:

toolsets => [$toolset...]

AnyEvent::MCP::Server::Toolset objects searched in order, defaulting to an empty array. The first Toolset containing a called tool handles it.

server_info => { name => $name, version => $version }

Advertised server identity, defaulting to AnyEvent::MCP and this distribution's version.

instructions => $text

Optional human-readable guidance. Surrounding whitespace and common indentation are stripped. Empty instructions are omitted from discovery and initialization results.

short_instructions => $text

Optional condensed guidance for deciding when to discover this server's tools. Used instead of instructions in discovery when auto_instructions is true. Without either short or custom instructions, the full instructions remain advertised.

custom_instructions => $text

Instance-specific purpose, prepended to the advertised instructions.

auto_instructions => $boolean

When true, expose full instructions, prefixed by any custom instance purpose, in a meta-instructions tool's description and call result. Advertise short_instructions instead, when provided, preceded by any custom purpose. Append a pointer to the generated tool's description when short or custom instructions exist. With neither, advertise the original full instructions without a redundant pointer. Defaults to false; a conflicting tool name is an error.

capabilities => { %capabilities }

Advertised server capabilities, defaulting to { tools => {} }. Declaring a capability does not implement it.

versions => [$version...]

Supported revisions in preference order. Defaults to 2026-07-28, 2025-11-25, 2025-06-18 and 2025-03-26. The 2026 protocol uses discovery and per-request metadata; the 2025 protocol uses initialization.

permissions => $permissions

AnyEvent::MCP::Server::Permissions object used by $req->require_permission. The server handles permission-needed exceptions. The permission object's ask setting chooses between modern input challenges and local prompts; local asking retries the handler internally. Checks must precede side effects.

Event callbacks are also constructor options; see "EVENTS".

$req = $server->rpc ($message, $reply->($message), %context)

Accepts the decoded JSON-RPC hash reference $message. $reply receives the decoded response, or undef when a notification is accepted or a request is cancelled. Undef completes transport bookkeeping without a JSON-RPC response. Returns the Request object for a request, or undef for notifications and rejected messages. $reply can be called before this method returns, or later.

peer in %context is a hash reference shared by messages on one connection. It holds legacy initialization state and weak references to outstanding requests for cancellation. Embedders supply a different peer for each independent connection. Modern request metadata takes precedence over legacy peer state.

protocol_version supplies the legacy HTTP protocol version. on_notify is an optional $callback-($req, $message)> receiving decoded outgoing notifications. Without it, notifications are dropped.

$req = $server->json_rpc ($json, $reply->($json), %context)

Like rpc, but $json and the response are UTF-8 encoded JSON strings. The notification callback still receives decoded objects. Parse errors are returned as JSON-RPC errors.

$server->dispatch ($req)

Dispatches an already constructed Request. Normally called by rpc. Subclasses can override this method while retaining JSON-RPC handling.

EVENTS

on_request => $callback->($server, $req)

Called before each dispatch attempt, including permission retries. This synchronous hook can inspect the request or refresh application state. It does not replace dispatch; avoid side effects that must happen only once.

on_tools_list => $callback->($server, $req)

Replaces the default Toolset listing. $callback completes $req.

on_tools_call => $callback->($server, $req, $args)

Replaces the default Toolset lookup and invocation. $args is also available as $req->{args}. $callback completes $req.

on_error => $callback->($server, $req, $error)

Reports an exception caught during synchronous dispatch. A tool exception becomes a text tool-error result; other exceptions become internal JSON-RPC errors. Exceptions after a reply are propagated, as are exceptions from asynchronous application callbacks.