Scroll to navigation

MCP::Server(3) User Contributed Perl Documentation MCP::Server(3)

NAME

MCP::Server - MCP server implementation

SYNOPSIS

  use MCP::Server;
  my $server = MCP::Server->new(name => 'MyServer');
  $server->tool(
    name         => 'echo',
    description  => 'Echo the input text',
    input_schema => {type => 'object', properties => {msg => {type => 'string'}}, required => ['msg']},
    code         => sub ($tool, $args) {
      return "Echo: $args->{msg}";
    }
  );
  $server->prompt(
    name        => 'echo',
    description => 'A prompt to demonstrate the echo tool',
    code        => sub ($prompt, $args) {
      return 'Use the echo tool with the message "Hello, World!"';
    }
  );
  $server->resource(
    uri         => 'file:///example.txt',
    name        => 'example',
    description => 'A simple text resource',
    mime_type   => 'text/plain',
    code        => sub ($resource) {
      return 'This is an example resource content.';
    }
  );
  $server->to_stdio;

DESCRIPTION

MCP::Server is an MCP (Model Context Protocol) server.

EVENTS

MCP::Server inherits all events from Mojo::EventEmitter and emits the following new ones.

prompts

  $server->on(prompts => sub ($server, $prompts, $context) { ... });

Emitted whenever the list of prompts is accessed.

resources

  $server->on(resources => sub ($server, $resources, $context) { ... });

Emitted whenever the list of resources is accessed.

tools

  $server->on(tools => sub ($server, $tools, $context) { ... });

Emitted whenever the list of tools is accessed.

ATTRIBUTES

MCP::Server implements the following attributes.

cache_scope

  my $scope = $server->cache_scope;
  $server   = $server->cache_scope('private');

Cache scope advertised for "server/discover" results, either "public" or "private". Defaults to "public". Cache hints for the other cacheable results are declared per primitive with "cache_scope" in MCP::Primitive.

cache_ttl

  my $ttl = $server->cache_ttl;
  $server = $server->cache_ttl(3_600_000);

How long "server/discover" results may be cached, in milliseconds. Defaults to 0, which means the document must be revalidated on every request.

instructions

  my $instructions = $server->instructions;
  $server          = $server->instructions('Use the echo tool to repeat text.');

Free-form guidance for the model on how to use this server, returned by "server/discover". Omitted from the document when "undef", which is the default.

log

  my $log = $server->log;
  $server = $server->log(Mojo::Log->new);

Where exceptions thrown by prompts, resources, and tools are reported, defaults to a Mojo::Log object writing to "STDERR", which is where an MCP host collects the output of a stdio server.

A server mounted in a Mojolicious application with "to_action" adopts the log of that application on its first request, so exceptions end up wherever the rest of the application logs, with the same level and format. Set this attribute yourself to opt out of that.

The caller never sees the exception itself, only an "InternalError", since it can easily contain file system paths or connection strings.

name

  my $name = $server->name;
  $server  = $server->name('MyServer');

The name of the server, used for identification.

prompts

  my $prompts = $server->prompts;
  $server    = $server->prompts([MCP::Prompt->new]);

An array reference containing registered prompts.

resources

  my $resources = $server->resources;
  $server      = $server->resources([MCP::Resource->new]);

An array reference containing registered resources.

state_secret

  my $secret = $server->state_secret;
  $server    = $server->state_secret($ENV{MY_MCP_SECRET});

Key used to authenticate the request state of "input_required" results, which travels through the client and has to be tamper proof. Defaults to 32 random bytes generated once per process.

That default is only correct for a single process. Under a pre-forking web server or behind a load balancer every worker mints state the others reject, so retries loop instead of completing, and you have to configure the same secret everywhere. Use at least 32 bytes from a cryptographically secure source, and keep it out of your code.

state_timeout

  my $seconds = $server->state_timeout;
  $server     = $server->state_timeout(60);

How long the request state of an "input_required" result stays valid, in seconds. Defaults to 300, and should be no longer than a client plausibly needs to gather the requested input.

tools

  my $tools = $server->tools;
  $server   = $server->tools([MCP::Tool->new]);

An array reference containing registered tools.

transport

  my $transport = $server->transport;
  $server       = $server->transport(MCP::Server::Transport::HTTP->new);

The transport layer used by the server, such as MCP::Server::Transport::HTTP or MCP::Server::Transport::Stdio.

version

  my $version = $server->version;
  $server     = $server->version('1.0.0');

The version of the server.

METHODS

MCP::Server inherits all methods from Mojo::EventEmitter and implements the following new ones.

handle

  my $response = $server->handle($request, $context);

Handle a JSON-RPC request and return a response, which may also be a Mojo::Promise. A "subscriptions/listen" request yields an MCP::Server::Subscription object instead, which the transport turns into a notification stream. Notifications yield "undef".

notify_list_changed

  my $bool = $server->notify_list_changed('tools');

Broadcast a "notifications/$kind/list_changed" JSON-RPC notification to all connected clients. Returns true on success, or "undef" if no notification could be delivered.

oauth_metadata

  my $metadata = $server->oauth_metadata(
    resource              => 'https://example.com/mcp',
    authorization_servers => ['https://auth.example.com']
  );

Build an OAuth 2.0 Protected Resource Metadata document from the given fields, to be served from "/.well-known/oauth-protected-resource". Unless "scopes_supported" is provided, it is filled in with the sorted union of all scopes declared by registered tools, prompts, and resources.

prompt

  my $prompt = $server->prompt(
    name        => 'my_prompt',
    description => 'A sample prompt',
    arguments   => [{name => 'foo', description => 'Whatever', required => 1}],
    code        => sub ($prompt, $args) { ... }
  );

Register a new prompt with the server.

resource

  my $resource = $server->resource(
    uri         => 'file://my_resource',
    name        => 'sample_resource',
    description => 'A sample resource',
    mime_type   => 'text/plain',
    code        => sub ($resource) { ... }
  );

Register a new resource with the server.

to_action

  my $action = $server->to_action;
  my $action = $server->to_action({streaming => 1});

Convert the server to a Mojolicious action. Any options are passed through to the constructor of MCP::Server::Transport::HTTP; in particular, "streaming => 1" opts in to "subscriptions/listen", the long-lived notification stream.

to_stdio

  $server->to_stdio;

Handles JSON-RPC requests over standard input/output.

tool

  my $tool = $server->tool(
    name         => 'my_tool',
    description  => 'A sample tool',
    input_schema => {type => 'object', properties => {foo => {type => 'string'}}},
    code         => sub ($tool, $args) { ... }
  );

Register a new tool with the server.

SEE ALSO

MCP, <https://mojolicious.org>, <https://modelcontextprotocol.io>.

2026-07-31 perl v5.44.0