MCP
view release on metacpan or search on metacpan
t/lite_app.t view on Meta::CPAN
use Mojo::Base -strict, -signatures;
use Test::More;
use Test::Mojo;
use Mojo::ByteStream qw(b);
use Mojo::File qw(curfile);
use Mojo::JSON qw(from_json true false);
use MCP::Client;
use MCP::Constants qw(PROTOCOL_VERSION);
use MCP::Server;
my $t = Test::Mojo->new(curfile->sibling('apps', 'lite_app.pl'));
subtest 'Normal HTTP endpoint' => sub {
$t->get_ok('/')->status_is(200)->content_like(qr/Hello MCP!/);
};
subtest 'List changed without streaming' => sub {
my $server = MCP::Server->new;
$server->to_action;
is $server->notify_list_changed('tools'), undef, 'no broadcast without streaming';
};
subtest 'MCP endpoint' => sub {
$t->get_ok('/mcp')->status_is(405)->content_like(qr/Method not allowed/);
$t->delete_ok('/mcp')->status_is(405)->content_like(qr/Method not allowed/);
my $client = MCP::Client->new(ua => $t->ua, url => $t->ua->server->url->path('/mcp'));
subtest 'Initialize session' => sub {
is $client->session_id, undef, 'no session id';
my $result = $client->initialize_session;
is $result->{protocolVersion}, PROTOCOL_VERSION, 'protocol version';
is $result->{serverInfo}{name}, 'PerlServer', 'server name';
is $result->{serverInfo}{version}, '1.0.0', 'server version';
ok $result->{capabilities}, 'has capabilities';
ok $result->{capabilities}{prompts}, 'has prompts capability';
ok $result->{capabilities}{resources}, 'has resources capability';
ok $result->{capabilities}{tools}, 'has tools capability';
ok !exists $result->{capabilities}{tools}{listChanged}, 'no listChanged for tools';
ok !exists $result->{capabilities}{prompts}{listChanged}, 'no listChanged for prompts';
ok !exists $result->{capabilities}{resources}{listChanged}, 'no listChanged for resources';
ok $client->session_id, 'session id set';
};
subtest 'Ping' => sub {
my $result = $client->ping;
is_deeply $result, {}, 'ping response';
};
subtest 'List tools' => sub {
my $result = $client->list_tools;
is $result->{tools}[0]{name}, 'echo', 'tool name';
is $result->{tools}[0]{description}, 'Echo the input text', 'tool description';
is_deeply $result->{tools}[0]{inputSchema},
{type => 'object', properties => {msg => {type => 'string'}}, required => ['msg']}, 'tool input schema';
ok !exists($result->{tools}[0]{outputSchema}), 'no output schema';
is_deeply $result->{tools}[0]{annotations}, {title => 'echo'}, 'corrent number of annotations';
is $result->{tools}[1]{name}, 'echo_async', 'tool name';
is $result->{tools}[1]{description}, 'Echo the input text asynchronously', 'tool description';
is_deeply $result->{tools}[1]{inputSchema},
{type => 'object', properties => {msg => {type => 'string'}}, required => ['msg']}, 'tool input schema';
ok !exists($result->{tools}[1]{outputSchema}), 'no output schema';
is keys %{$result->{tools}[1]{annotations}}, 0, 'empty annotations not serialized';
is $result->{tools}[2]{name}, 'echo_header', 'tool name';
is $result->{tools}[2]{description}, 'Echo the input text with a header', 'tool description';
is_deeply $result->{tools}[2]{inputSchema},
{type => 'object', properties => {msg => {type => 'string'}}, required => ['msg']}, 'tool input schema';
ok !exists($result->{tools}[2]{outputSchema}), 'no output schema';
is $result->{tools}[3]{name}, 'time', 'tool name';
is $result->{tools}[3]{description}, 'Get the current time in epoch format', 'tool description';
is_deeply $result->{tools}[3]{inputSchema}, {type => 'object'}, 'tool input schema';
ok !exists($result->{tools}[3]{outputSchema}), 'no output schema';
is $result->{tools}[4]{name}, 'generate_image', 'tool name';
is $result->{tools}[4]{description}, 'Generate a simple image from text', 'tool description';
is_deeply $result->{tools}[4]{inputSchema},
{type => 'object', properties => {text => {type => 'string'}}, required => ['text']}, 'tool input schema';
ok !exists($result->{tools}[4]{outputSchema}), 'no output schema';
is $result->{tools}[5]{name}, 'generate_audio', 'tool name';
is $result->{tools}[5]{description}, 'Generate audio from text', 'tool description';
is_deeply $result->{tools}[5]{inputSchema},
( run in 1.116 second using v1.01-cache-2.11-cpan-5735350b133 )