Acme-MCP
view release on metacpan or search on metacpan
lib/Acme/MCP.pm view on Meta::CPAN
use v5.42;
use feature 'class';
no warnings 'experimental::class';
#
class Acme::MCP v1.0.1 {
use JSON::PP;
use Carp qw[carp croak];
#
field $name : param : reader : writer = 'Generic MCP Server';
field $version : param : reader : writer = '1.0.0';
field %tools : reader;
field $json = JSON::PP->new->utf8(1);
#
method add_tool (%params) {
my $name = $params{name} or croak 'Tool name required';
my $code = $params{code} or croak 'Tool code (sub) required';
$tools{$name}
= { description => $params{description} // '', inputSchema => $params{schema} // { type => 'object', properties => {} }, code => $code };
}
method run () {
$| = 1; # Autoflush for stdio communication
carp "$name started, listening on STDIN";
while ( my $line = <STDIN> ) {
chomp $line;
my $request;
try { $request = $json->decode($line) }
catch ($e) {
$self->_send_error( undef, -32700, 'Parse error' );
next;
}
$self->_handle_request($request);
}
}
method _handle_request ($req) {
my $id = $req->{id};
my $method = $req->{method} // '';
if ( $method eq 'initialize' ) {
$self->_send_response(
$id,
{ protocolVersion => '2024-11-05',
capabilities => { tools => { listChanged => JSON::PP::true }, },
serverInfo => { name => $name, version => $version }
}
);
}
elsif ( $method eq 'tools/list' ) {
my @tool_list;
for my $t_name ( sort keys %tools ) {
push @tool_list, { name => $t_name, description => $tools{$t_name}{description}, inputSchema => $tools{$t_name}{inputSchema} };
}
$self->_send_response( $id, { tools => \@tool_list } );
}
elsif ( $method eq 'tools/call' ) {
$self->_handle_tool_call( $id, $req->{params} );
}
else {
$self->_send_error( $id, -32601, 'Method not found: ' . $method );
}
}
method _handle_tool_call ( $id, $params ) {
my $t_name = $params->{name};
my $args = $params->{arguments} // {};
if ( my $tool = $tools{$t_name} ) {
try {
my $result = $tool->{code}->($args);
$self->_send_tool_result( $id, $result );
}
catch ($e) {
$self->_send_tool_result( $id, { error => $e }, 1 );
( run in 1.027 second using v1.01-cache-2.11-cpan-e93a5daba3e )