jolicious> application. The tool name and
description are used for discovery, and the L<JSON schema|https://json-schema.org> is used to validate the input.
use Mojolicious::Lite -signatures;
use
type requests on the command line.
$ perl examples/echo_stdio.pl
{"jsonrpc":"2.0","id":"1","method":"tools/list"}
{"jsonrpc":"2.0","id":"2","method":"tools/call","params":{"name":"echo","argum
::Transport::Stdio;
use Mojo::Base 'MCP::Server::Transport', -signatures;
use Mojo::JSON qw(decode_json encode_json);
use Mojo::Log;
use Scalar::Util qw(blessed);
sub handle_requests ($self) {
my
TDOUT->autoflush(1);
while (my $input = <>) {
chomp $input;
my $request = eval { decode_json($input) };
next unless my $response = $server->handle($request, {});
if (blessed($respon
}
else { _print_response($response) }
}
}
sub _print_response ($response) { print encode_json($response) . "\n" }
1;
=encoding utf8
=head1 NAME
MCP::Server::Transport::Stdio - Stdio trans
atures;
use Carp qw(croak);
use MCP::Constants qw(PROTOCOL_VERSION);
use Mojo::JSON qw(from_json);
use Mojo::UserAgent;
use Scalar::Util qw(weaken);
has name => 'PerlClient';
has 'sess
+ 1 : 1;
return $request;
}
sub build_notification ($self, $method, $params = {}) {
return {jsonrpc => '2.0', method => $method, params => $params};
}
sub call_tool ($self, $name, $args = {}) {
d_request ($self, $request) {
my $headers = {Accept => 'application/json, text/event-stream', 'Content-Type' => 'application/json'};
if (my $session_id = $self->session_id) { $headers->{'Mcp-Sessi
package MCP::Server;
use Mojo::Base -base, -signatures;
use List::Util qw(first);
use Mojo::JSON qw(false true);
use MCP::Constants qw(INVALID_PARAMS INVALID_REQUEST METHOD_NOT_FOUND PARSE_ER
equest, $context) {
return _jsonrpc_error(PARSE_ERROR, 'Invalid JSON-RPC request') unless ref $request eq 'HASH';
return _jsonrpc_error(INVALID_REQUEST, 'Missing JSON-RPC method') unless my $metho
dle_initialize($request->{params} // {});
return _jsonrpc_response($result, $id);
}
elsif ($method eq 'ping') {
return _jsonrpc_response({}, $id);
}
elsif ($method eq 'prom
:Base 'MCP::Server::Transport', -signatures;
use Crypt::Misc qw(random_v4uuid);
use Mojo::JSON qw(to_json true);
use Mojo::Util qw(dumper);
use Scalar::Util qw(blessed);
use constant DEBUG => $
hod = $c->req->method;
return $self->_handle_post($c) if $method eq 'POST';
return $c->render(json => {error => 'Method not allowed'}, status => 405);
}
sub _extract_session_id ($self, $c) { retu
;
$c->render(json => $result, status => 200);
}
sub _handle_post ($self, $c) {
my $session_id = $self->_extract_session_id($c);
return $c->render(json => {error => 'Invalid JSON'}, status => 4
package MCP::Tool;
use Mojo::Base -base, -signatures;
use JSON::Validator;
use Mojo::JSON qw(false to_json true);
use Mojo::Util qw(b64_encode);
use Scalar::Util qw(blessed);
has code =>
};
}
sub structured_result ($self, $data, $is_error = 0) {
my $result = $self->text_result(to_json($data), $is_error);
$result->{structuredContent} = $data;
return $result;
}
sub text_result
e_input ($self, $args) {
unless ($self->{validator}) {
my $validator = $self->{validator} = JSON::Validator->new;
$validator->schema($self->input_schema);
}
my @errors = $self->{validat