File Coverage

blib/lib/Net/Async/MCP/Transport/InProcess.pm
Criterion Covered Total %
statement 34 41 82.9
branch 9 16 56.2
condition 1 3 33.3
subroutine 9 12 75.0
pod 4 4 100.0
total 57 76 75.0


line stmt bran cond sub pod time code
1             package Net::Async::MCP::Transport::InProcess;
2             # ABSTRACT: In-process MCP transport via direct MCP::Server calls
3             our $VERSION = '0.002';
4 2     2   11749 use strict;
  2         5  
  2         98  
5 2     2   10 use warnings;
  2         4  
  2         159  
6              
7 2     2   14 use Future;
  2         4  
  2         80  
8 2     2   13 use Scalar::Util qw( blessed );
  2         4  
  2         142  
9 2     2   11 use Carp qw( croak );
  2         4  
  2         1971  
10              
11              
12             sub new {
13 1     1 1 5 my ( $class, %args ) = @_;
14 1 50       6 croak "server is required" unless $args{server};
15             return bless {
16             server => $args{server},
17 1         10 next_id => 0,
18             }, $class;
19             }
20              
21              
22             sub send_request {
23 8     8 1 16 my ( $self, $method, $params ) = @_;
24              
25 8         14 my $id = ++$self->{next_id};
26 8 100       32 my $request = {
27             jsonrpc => '2.0',
28             id => $id,
29             method => $method,
30             defined $params ? ( params => $params ) : (),
31             };
32              
33 8         35 my $response = $self->{server}->handle($request, {});
34              
35             # Handle Mojo::Promise from async MCP tools
36 8 50 33     2966 if (blessed($response) && $response->isa('Mojo::Promise')) {
37 0         0 my ( $resolved, $error );
38             $response->then(
39 0     0   0 sub { $resolved = $_[0] },
40 0     0   0 sub { $error = $_[0] },
41 0         0 )->wait;
42 0 0       0 return Future->fail("MCP async tool error: $error") if $error;
43 0         0 $response = $resolved;
44             }
45              
46 8         22 return $self->_process_response($response);
47             }
48              
49              
50             sub send_notification {
51 1     1 1 3 my ( $self, $method, $params ) = @_;
52              
53 1 50       6 my $request = {
54             jsonrpc => '2.0',
55             method => $method,
56             defined $params ? ( params => $params ) : (),
57             };
58              
59 1         7 $self->{server}->handle($request, {});
60 1         17 return Future->done;
61             }
62              
63              
64 0     0 1 0 sub close { Future->done }
65              
66              
67             sub _process_response {
68 8     8   13 my ( $self, $response ) = @_;
69              
70 8 50       27 return Future->fail("No response from MCP server") unless $response;
71 8 50       19 return Future->fail("Invalid response from MCP server")
72             unless ref $response eq 'HASH';
73              
74 8 100       20 if (my $err = $response->{error}) {
75 1         12 return Future->fail("MCP error $err->{code}: $err->{message}");
76             }
77              
78 7         31 return Future->done($response->{result});
79             }
80              
81              
82             1;
83              
84             __END__