File Coverage

blib/lib/MCP/Server/Context.pm
Criterion Covered Total %
statement 31 31 100.0
branch 9 12 75.0
condition n/a
subroutine 4 4 100.0
pod 3 3 100.0
total 47 50 94.0


line stmt bran cond sub pod time code
1             package MCP::Server::Context;
2 5     5   26 use Mojo::Base -base, -signatures;
  5         8  
  5         27  
3              
4             has [qw(controller insufficient_scope progress_token scopes session_id transport)];
5              
6 83     83 1 173 sub has_scope ($self, @needed) {
  83         85  
  83         108  
  83         107  
7 83 100       152 return 1 unless defined(my $scopes = $self->scopes);
8 26         111 my %granted = map { $_ => 1 } @$scopes;
  52         132  
9 26 100       46 for my $scope (@needed) { return 0 unless $granted{$scope} }
  26         74  
10 19         110 return 1;
11             }
12              
13 4     4 1 8 sub notify ($self, $method, $params = {}) {
  4         8  
  4         5  
  4         8  
  4         14  
14 4 50       12 return undef unless my $transport = $self->transport;
15 4         28 return $transport->notify($self->session_id, $method, $params);
16             }
17              
18 3     3 1 99564 sub notify_progress ($self, $progress, $total = undef, $message = undef) {
  3         13  
  3         5  
  3         5  
  3         6  
  3         6  
19 3 100       8 return undef unless defined(my $token = $self->progress_token);
20 2         22 my $params = {progressToken => $token, progress => $progress};
21 2 50       8 $params->{total} = $total if defined $total;
22 2 50       10 $params->{message} = $message if defined $message;
23 2         9 return $self->notify('notifications/progress', $params);
24             }
25              
26             1;
27              
28             =encoding utf8
29              
30             =head1 NAME
31              
32             MCP::Server::Context - Request context container
33              
34             =head1 SYNOPSIS
35              
36             use MCP::Server::Context;
37              
38             my $context = MCP::Server::Context->new;
39             $context->notify_progress(1, 2, 'halfway');
40              
41             =head1 DESCRIPTION
42              
43             L is a container for per-invocation request context.
44              
45             =head1 ATTRIBUTES
46              
47             L implements the following attributes.
48              
49             =head2 controller
50              
51             my $c = $context->controller;
52             $context = $context->controller(Mojolicious::Controller->new);
53              
54             The L serving the current request, when the HTTP transport is in use.
55              
56             =head2 insufficient_scope
57              
58             my $needed = $context->insufficient_scope;
59             $context = $context->insufficient_scope(['mcp:write']);
60              
61             Array reference of scopes a denied request was missing, set by the server so the HTTP transport can emit an
62             C challenge. C when no scope check failed.
63              
64             =head2 progress_token
65              
66             my $token = $context->progress_token;
67             $context = $context->progress_token('tok-1');
68              
69             The progress token provided by the client in C<_meta.progressToken>, or C if none was sent.
70              
71             =head2 session_id
72              
73             my $id = $context->session_id;
74             $context = $context->session_id('12345');
75              
76             Identifier of the session this request belongs to.
77              
78             =head2 scopes
79              
80             my $scopes = $context->scopes;
81             $context = $context->scopes(['mcp:read', 'mcp:write']);
82              
83             OAuth scopes granted to the current request, as an array reference, populated from the C hook of the HTTP
84             transport. C (the default) imposes no scope restriction, so scopes are only enforced for authenticated
85             requests that provide them.
86              
87             =head2 transport
88              
89             my $transport = $context->transport;
90             $context = $context->transport(MCP::Server::Transport::HTTP->new);
91              
92             The transport handling the current request.
93              
94             =head1 METHODS
95              
96             L inherits all methods from L and implements the following new ones.
97              
98             =head2 has_scope
99              
100             my $bool = $context->has_scope('mcp:write');
101             my $bool = $context->has_scope('mcp:read', 'mcp:write');
102              
103             Returns true if every given scope is present in L, or if L is C (no restriction).
104              
105             =head2 notify
106              
107             my $bool = $context->notify($method);
108             my $bool = $context->notify($method, {foo => 'bar'});
109              
110             Send a JSON-RPC notification to the client associated with the current request. Returns true on success, or
111             C if no notification could be delivered.
112              
113             =head2 notify_progress
114              
115             my $bool = $context->notify_progress($progress);
116             my $bool = $context->notify_progress($progress, $total);
117             my $bool = $context->notify_progress($progress, $total, $message);
118              
119             Send a C JSON-RPC notification for the progress token associated with the current request.
120             Returns true on success, or C if no progress token was provided by the client.
121              
122             =head1 SEE ALSO
123              
124             L, L, L.
125              
126             =cut