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::MCPand 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
instructionsin discovery whenauto_instructionsis 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 ameta-instructionstool's description and call result. Advertiseshort_instructionsinstead, 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-18and2025-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'sasksetting 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.$replyreceives 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.$replycan be called before this method returns, or later.peerin%contextis 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_versionsupplies the legacy HTTP protocol version.on_notifyis 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$jsonand 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.
$callbackcompletes$req. - on_tools_call => $callback->($server, $req, $args)
-
Replaces the default Toolset lookup and invocation.
$argsis also available as$req->{args}.$callbackcompletes$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.