AnyEvent-MCP

 view release on metacpan or  search on metacpan

t/03_simple.t  view on Meta::CPAN

print {$in} JSON::XS::encode_json ({
   jsonrpc => "2.0", id => 2, method => "tools/call", params => { name => "delayed" },
}), "\n";
close $in;
$output = <$out>;
$errors = <$err>;
waitpid $pid, 0;
ok !$? && $errors =~ /\bdelayed\b.*\nstopped\n\z/s,
   "mcp_stdio logs tool activity and returns after input EOF";
my @messages = map JSON::XS::decode_json ($_), split /\n/, $output;
ok @messages == 2 && $messages[1]{id} == 2
   && length $messages[1]{result}{content}[0]{text} == 200000,
   "EOF waits for an asynchronous reply and drains large output";

my ($started, $closed, $timer);
mcp_http auth => "none", port => 0, name => "local-instance",
   server_name => "advertised", server_version => 1.2,
   on_start => sub {
      $server = $_[0];
      $timer = AnyEvent->timer (after => 0.01, cb => sub { $server->close });
   };
ok $server->{server_info}{name} eq "advertised",
   "Simple server name is independent of instance name";
ok JSON::XS::encode_json ($server->{server_info}) =~ /"version":"1\.2"/,
   "flat Simple version is sent as a JSON string";
my $raw = { name => "raw", version => "7" };
mcp_http auth => "none", port => 0, name => "local-instance",
   server_info => $raw,
   on_start => sub {
      $server = $_[0];
      $timer = AnyEvent->timer (after => 0.01, cb => sub { $server->close });
   };
ok $server->{server_info} == $raw,
   "explicit raw server_info is passed through unchanged";
eval { mcp_http auth => "none", port => 0,
   server_name => "advertised", server_info => $raw };
ok $@ =~ /Cannot combine server_info with server_name/,
   "Simple rejects mixing raw and flat identity settings";

mcp_http auth => "none", port => 0, name => "another-instance",
   on_start => sub {
      $server = $_[0];
      $timer = AnyEvent->timer (after => 0.01, cb => sub { $server->close });
   };
ok $server->{server_info}{name} eq "AnyEvent::MCP",
   "Simple defaults to the library implementation name";
ok JSON::XS::encode_json ($server->{server_info}) =~ /"version":"\Q$AnyEvent::MCP::VERSION\E"/,
   "Simple defaults to the library version as a JSON string";

mcp_http auth => "none", port => 0, on_start => sub {
   my ($server) = @_;
   ++$started;
   $timer = AnyEvent->timer (after => 0.01, cb => sub { $server->close });
}, on_close => sub { ++$closed };
ok $started == 1 && $closed == 1, "mcp_http blocks through startup and returns on close";

eval { mcp_http auth => "none", port => 0, on_start => sub { die "startup failed\n" } };
ok $@ =~ /startup failed/, "startup hook exception closes the server and propagates";

{
   local @ARGV = ("--auto-deny=*,write", "--auto-allow=read_lines,read",
      "--auto-deny=*,*,*");
   my $options = mcp_getoptions ({ name => "auto-test" });
   ok JSON::XS::encode_json ($options->{auto_rules}) eq JSON::XS::encode_json ([
      ["deny", "*,write"], ["allow", "read_lines,read"], ["deny", "*,*,*"],
   ]), "CLI collects repeatable allow/deny rules in original order";

   my $perm = AnyEvent::MCP::Server::Permissions->new (
      rules => [{ decision => "deny", action => "^" }],
   );
   my $timer;
   mcp_http %$options, auth => "none", port => 0, permissions => $perm,
      on_start => sub {
         my ($server) = @_;
         $timer = AnyEvent->timer (after => 0.01, cb => sub { $server->close });
      };
   my $call = { action => "read", sandbox_grants => [], reason => "test" };
   ok $perm->check ($call, "read-lines")->{decision} eq "allow",
      "Simple starter installs ordered allow rule";
   ok $perm->check ({ %$call, action => "write" }, "read-lines")->{decision} eq "deny",
      "earlier auto-deny takes precedence over later allow";
   ok $perm->check ($call, "exec")->{decision} eq "deny",
      "later wildcard deny catches unmatched tools";

   my $created;
   mcp_http auth => "none", port => 0, auto_rules => [["deny", "*"]],
      on_start => sub {
         my ($server) = @_;
         $created = $server->{permissions};
         $timer = AnyEvent->timer (after => 0.01, cb => sub { $server->close });
      };
   ok $created && $created->check ($call, "anything")->{decision} eq "deny",
      "Simple starter creates a permission engine for automatic denial";
}



( run in 2.116 seconds using v1.01-cache-2.11-cpan-ac8be02dad9 )