table of contents
| MCP::Server::Context(3) | User Contributed Perl Documentation | MCP::Server::Context(3) |
NAME¶
MCP::Server::Context - Request context container
SYNOPSIS¶
use MCP::Server::Context; my $context = MCP::Server::Context->new; $context->notify_progress(1, 2, 'halfway');
DESCRIPTION¶
MCP::Server::Context is a container for per-invocation request context.
EVENTS¶
MCP::Server::Context inherits all events from Mojo::EventEmitter and emits the following new ones.
cancelled¶
$context->on(cancelled => sub ($context) { ... });
Emitted once when the client abandons the current request, either by closing its response stream or by sending a "notifications/cancelled" notification. Long running operations should stop as soon as practical.
my $id = Mojo::IOLoop->recurring(1 => sub { ... });
$context->on(cancelled => sub ($context) { Mojo::IOLoop->remove($id) });
ATTRIBUTES¶
MCP::Server::Context implements the following attributes.
buffer¶
my $buffer = $context->buffer; $context = $context->buffer([]);
Notifications that have been queued up because no response "stream" was available yet, to be delivered by "flush".
client_capabilities¶
my $capabilities = $context->client_capabilities;
$context = $context->client_capabilities({elicitation => {}});
Capabilities declared by the client for the current request, from "_meta.io.modelcontextprotocol/clientCapabilities". Every request has to declare them, so this is only "undef" outside of request handling.
client_info¶
my $info = $context->client_info;
$context = $context->client_info({name => 'MyClient', version => '1.0.0'});
Name and version of the client making the current request, from "_meta.io.modelcontextprotocol/clientInfo", or "undef" if the client did not identify itself.
controller¶
my $c = $context->controller; $context = $context->controller(Mojolicious::Controller->new);
The Mojolicious::Controller serving the current request, when the HTTP transport is in use.
input_responses¶
my $responses = $context->input_responses;
$context = $context->input_responses({confirm => {action => 'accept', content => {ok => \1}}});
Responses to the input requests of an earlier "input_required" result, keyed by the same names, or "undef" if the current request is not a retry. See "input_required" in MCP::Primitive.
insufficient_scope¶
my $needed = $context->insufficient_scope; $context = $context->insufficient_scope(['mcp:write']);
Array reference of scopes a denied request was missing, set by the server so the HTTP transport can emit an "insufficient_scope" challenge. "undef" when no scope check failed.
legacy¶
my $version = $context->legacy;
$context = $context->legacy('2025-11-25');
The protocol revision a legacy request was made with, or "undef" for a current request, see MCP::Server::Legacy.
log_level¶
my $level = $context->log_level;
$context = $context->log_level('info');
The minimum severity of log messages the client wants for the current request, from "_meta.io.modelcontextprotocol/logLevel", or "undef" if the client asked for none.
principal¶
my $principal = $context->principal;
$context = $context->principal('user@example.com');
The authenticated caller the current request belongs to, populated from the "principal" key returned by the "auth" hook of the HTTP transport. Request state is bound to it, so state minted for one caller is never accepted from another. "undef" for unauthenticated requests.
progress_token¶
my $token = $context->progress_token;
$context = $context->progress_token('tok-1');
The progress token provided by the client in "_meta.progressToken", or "undef" if none was sent.
protocol_version¶
my $version = $context->protocol_version;
$context = $context->protocol_version('2026-07-28');
The protocol version the current request was made with, from "_meta.io.modelcontextprotocol/protocolVersion".
raw_request_state¶
my $state = $context->raw_request_state;
$context = $context->raw_request_state('eyJ...');
The "requestState" string the client sent back, exactly as received and not verified in any way. Use "request_state" instead, unless you want to protect the state yourself.
scopes¶
my $scopes = $context->scopes; $context = $context->scopes(['mcp:read', 'mcp:write']);
OAuth scopes granted to the current request, as an array reference, populated from the "auth" hook of the HTTP transport. "undef" (the default) imposes no scope restriction, so scopes are only enforced for authenticated requests that provide them.
state_binding¶
my $binding = $context->state_binding;
$context = $context->state_binding("tools/call\0deploy");
Identifies the request that request state may be used with, set by the server to the method name and the name or URI of the primitive being called. State sealed for one primitive is never accepted by another.
state_secret¶
my $secret = $context->state_secret; $context = $context->state_secret($bytes);
Key used to authenticate request state, copied from "state_secret" in MCP::Server.
state_timeout¶
my $seconds = $context->state_timeout; $context = $context->state_timeout(300);
How long request state sealed during this request stays valid, in seconds, copied from "state_timeout" in MCP::Server.
status¶
my $status = $context->status; $context = $context->status(404);
HTTP status the current request has to be answered with, set by the server for the protocol errors the specification maps to a specific status, such as 404 for an unknown method. "undef" (the default) means 200, and transports other than MCP::Server::Transport::HTTP ignore it.
stream¶
my $cb = $context->stream;
$context = $context->stream(sub ($notification) { ... });
Callback the transport installs once the response stream for the current request is open, to be called with every notification that belongs to it. Notifications sent before that are queued up in "buffer".
transport¶
my $transport = $context->transport; $context = $context->transport(MCP::Server::Transport::HTTP->new);
The transport handling the current request.
METHODS¶
MCP::Server::Context inherits all methods from Mojo::EventEmitter and implements the following new ones.
cancel¶
$context = $context->cancel;
Mark the current request as cancelled and emit the "cancelled" event, at most once.
flush¶
my $num = $context->flush;
Deliver all notifications queued up in "buffer" to "stream", and return the number of notifications delivered.
has_scope¶
my $bool = $context->has_scope('mcp:write');
my $bool = $context->has_scope('mcp:read', 'mcp:write');
Returns true if every given scope is present in "scopes", or if "scopes" is "undef" (no restriction).
is_cancelled¶
my $bool = $context->is_cancelled;
Returns true if the current request has been cancelled, for operations that cannot subscribe to the "cancelled" event and have to poll instead.
notify¶
my $bool = $context->notify($method);
my $bool = $context->notify($method, {foo => 'bar'});
Send a JSON-RPC notification on the response stream of the current request. Returns true on success, or "undef" if the request has been cancelled.
notify_log¶
my $bool = $context->notify_log('info', 'Something happened');
my $bool = $context->notify_log('error', {code => 23});
Send a "notifications/message" JSON-RPC notification with the given severity and payload. Returns "undef" unless the client requested logging with "_meta.io.modelcontextprotocol/logLevel" and the given severity is at or above the level it asked for.
notify_progress¶
my $bool = $context->notify_progress($progress); my $bool = $context->notify_progress($progress, $total); my $bool = $context->notify_progress($progress, $total, $message);
Send a "notifications/progress" JSON-RPC notification for the progress token associated with the current request. Returns true on success, or "undef" if no progress token was provided by the client.
request_state¶
my $state = $context->request_state;
Verify and decode the request state the client sent back, returning the data structure that was passed to "input_required" in MCP::Primitive. Returns "undef" if there was no state, or if it was tampered with, has expired, was sealed for a different primitive, or belongs to a different "principal", so a primitive that cannot tell those cases apart simply asks for input again.
Replay within "state_timeout" is not prevented; servers that need one-shot semantics have to enforce that themselves, for example by embedding a nonce and remembering it.
seal_state¶
my $sealed = $context->seal_state({step => 2});
Serialize a data structure into an opaque string, authenticated with "state_secret" and bound to "state_binding", "principal", and "state_timeout". Usually called through "input_required" in MCP::Primitive rather than directly.
SEE ALSO¶
MCP, <https://mojolicious.org>, <https://modelcontextprotocol.io>.
| 2026-07-31 | perl v5.44.0 |