ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MCP/lib/AnyEvent/MCP.pm
Revision: 1.4
Committed: Wed Oct 7 11:17:27 2026 UTC (3 weeks, 4 days ago) by root
Branch: MAIN
Changes since 1.3: +6 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     AnyEvent::MCP - Model Context Protocol client/server support
4    
5     =head1 SYNOPSIS
6    
7     use AnyEvent::MCP::Server::Simple;
8    
9     mcp_tool ...
10 root 1.3 mcp_start;
11 root 1.1
12     or use the object interface directly:
13    
14     use AnyEvent::MCP::Server;
15    
16     my $server = AnyEvent::MCP::Server->new (...);
17    
18     =head1 DESCRIPTION
19    
20     AnyEvent::MCP provides event-driven Model Context Protocol client and server
21     support.
22    
23     The usual way to implement a small MCP server is
24     L<AnyEvent::MCP::Server::Simple>, which provides a function-based interface and
25     creates the underlying server objects when a transport such as stdio or HTTP is
26     started.
27    
28     The lower-level object interfaces are intended for applications that need to
29     manage MCP connections, servers or reusable tool registries directly.
30    
31     =head2 MODULES
32    
33     =over 4
34    
35     =item L<AnyEvent::MCP::Server::Simple>
36    
37     Function-based interface for implementing ordinary MCP servers.
38    
39     =item L<AnyEvent::MCP::Server>
40    
41     Object-oriented MCP server interface.
42    
43     =item L<AnyEvent::MCP::Client>
44    
45     Object-oriented MCP client interface.
46    
47     =item L<AnyEvent::MCP::Server::Toolset>
48    
49     Reusable registry of MCP tool declarations.
50    
51     =item L<AnyEvent::MCP::Server::Permissions>
52    
53     Permission and capability handling for MCP servers.
54    
55     =back
56    
57 root 1.4 C<mcp-multibroker> combines downstream HTTP and stdio servers under tool-name
58     prefixes. It uses the same client, server and permission helper facilities,
59     including modern input forwarding and local permission prompts for legacy
60     callers. Run C<mcp-multibroker --help> for command-line syntax; its manual
61     describes authentication and configuration.
62    
63 root 1.1 The interfaces are still being designed; this documentation is intentionally
64     only an overview for now.
65    
66 root 1.2 =head1 GLOBAL CONFIGURATION
67    
68     The shared per-user configuration is C<$XDG_CONFIG_HOME/anyevent-mcp/global.ini>,
69     or C<$HOME/.config/anyevent-mcp/global.ini> when XDG_CONFIG_HOME is unset.
70     L<AnyEvent::MCP::Config> loads and holds it; loading this module does not access
71     configuration files.
72    
73     The file is UTF-8 and uses sections with single-line C<key = value> pairs.
74     Values are unquoted strings. Blank lines and whole-line comments beginning
75     with C<#> or C<;> are ignored; inline comment characters remain part of the
76     value. Later occurrences of a key replace earlier ones in the same section.
77    
78     [global]
79     secret = ...128 hexadecimal digits...
80    
81     [server example]
82 root 1.3 port = 31740
83     url = https://example.net:31740/{cookie}/
84 root 1.2
85     [mcp-fs]
86     utility = /path/to/utility
87    
88     Section names are unrestricted. Application-specific sections, including
89     exports, utility paths and user settings, are documented by their applications.
90    
91     C<[global]> holds C<secret>, a 64-byte master key encoded as 128 hexadecimal
92     digits. The file must be owned by the current user, with no group or other
93     permissions. A missing secret is generated automatically on first configuration
94     access and saved when possible. Existing secrets are never replaced implicitly.
95     An invalid secret is an error.
96    
97     If saving fails, Config warns and retains the secret in memory. Credentials
98     then remain stable only for that process; other processes cannot derive the
99     same credentials. If randomness is unavailable, supply a securely generated
100     secret in the file.
101    
102     C<[server NAME]> holds named-server settings. Its C<url> is a complete template;
103     C<{cookie}> is replaced with the cookie derived for that server and optional
104     username. Scheme, host, port and cookie placement are explicit in the template.
105 root 1.3 HTTP servers with an explicit C<name> load C<host>, C<port>, C<path>,
106     C<url_host>, C<url_scheme>, C<cookie>, C<bearer> and C<users> from this section
107     as defaults. C<users> is a comma-separated allowlist whose Basic passwords
108     are derived for the named server. An explicit password hash can instead be
109     passed to the constructor. C<url> is a template for the utility program; it
110     does not set the listener's address.
111    
112     C<mcp_start> chooses an application name and supplies cookie/bearer
113     authentication by default. Explicit authentication settings replace this
114     default. Stdio startup does not access global configuration.
115    
116     C<[client NAME]> supplies HTTP client defaults: C<url>, C<bearer>, C<username>,
117     C<password> and C<timeout>. Clients consult it only when explicitly given a
118     C<name>. An unnamed client or HTTP server does not read global configuration.
119     Explicit constructor arguments take precedence over named defaults.
120    
121     =head1 ENVIRONMENT
122    
123     Project-specific environment variables use the C<PERL_ANYEVENT_MCP_> prefix.
124     C<PERL_ANYEVENT_MCP_MULTIBROKER_PROTOCOL=stdio> selects stdio in Simple.
125     C<PERL_ANYEVENT_MCP_MULTIBROKER_ALIAS> supplies the default application name.
126     C<PERL_ANYEVENT_MCP_PERMISSION_HELPER> selects the external asking executable.
127     Standard C<HOME> and C<XDG_CONFIG_HOME> keep their standard names.
128 root 1.2
129     =head1 FUNCTIONS
130    
131     =head2 $bytes = AnyEvent::MCP::random_bytes $length
132    
133     Returns exactly C<$length> random bytes. Tries C</dev/urandom>, then an external
134     C<openssl rand> command. No additional random-number module is required.
135     Dies if neither source supplies the requested bytes successfully.
136     C<$length> must be a nonnegative integer; zero returns an empty string.
137    
138 root 1.1 =cut
139    
140     package AnyEvent::MCP;
141    
142     use common::sense;
143     use Digest::SHA ();
144    
145     our $VERSION = '0.0';
146    
147 root 1.2 sub random_bytes($) {
148     my ($length) = @_;
149    
150     die "Invalid random byte count\n"
151     unless defined $length && $length =~ /\A[0-9]+\z/;
152     return "" unless $length;
153    
154     my $bytes = "";
155    
156     if (open my $fh, "<", "/dev/urandom") {
157     binmode $fh;
158     while (length $bytes < $length) {
159     read ($fh, $bytes, $length - length ($bytes), length $bytes)
160     or last;
161     }
162     close $fh;
163    
164     return $bytes if length $bytes == $length;
165     }
166    
167     if (open my $fh, "-|", "openssl", "rand", $length) {
168     binmode $fh;
169     local $/;
170     $bytes = <$fh>;
171     my $success = close $fh;
172    
173     return $bytes
174     if $success && defined $bytes && length $bytes == $length;
175     }
176    
177     die "Cannot obtain $length random bytes from /dev/urandom or openssl rand\n";
178     }
179    
180 root 1.1 sub hkdf_sha512_expand($$$) {
181     my ($prk, $info, $l) = @_;
182    
183 root 1.2 64 == length $prk
184     or die "hkdf_sha512_expand: prk length mist be 64 octets";
185    
186 root 1.1 my $t = "";
187     my $okm = "";
188     my $i = 0;
189    
190     do {
191     $t = Digest::SHA::hmac_sha512 $t . $info . chr ++$i, $prk;
192     $okm .= $t;
193     } while $l > length $okm;
194    
195     substr $okm, 0, $l
196     }
197    
198     sub _clean_text($) {
199     my ($text) = @_;
200    
201     my ($prefix) = (join "\n", grep /\S/, split /\n/, $text)
202     =~ /\A([ \t]*)[^\n]*(?:\n\1[^\n]*)*\z/;
203    
204     $text =~ s/^\Q$prefix\E//mg;
205     $text =~ s/\A\s+//;
206     $text =~ s/\s+\z//;
207     $text
208     }
209    
210     package AnyEvent::MCP::Base;
211    
212     sub new {
213     my ($class, %kv) = @_;
214     bless \%kv, $class
215     }
216    
217     sub event {
218     my ($self, $event, @args) = @_;
219     ($self->{"on_$event"} or return)->($self, @args)
220     }
221    
222     =head1 SEE ALSO
223    
224     L<AnyEvent>, L<https://modelcontextprotocol.io/>
225    
226     =head1 AUTHOR
227    
228     The main author of this module is OpenAI ChatGPT.
229    
230     Additional guidance received by:
231    
232     Marc Lehmann <schmorp@schmorp.de>
233     http://home.schmorp.de/
234    
235     =cut
236    
237     1
238