ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MCP/lib/AnyEvent/MCP.pm
Revision: 1.2
Committed: Wed Oct 7 06:15:33 2026 UTC (5 weeks, 1 day ago) by root
Branch: MAIN
Changes since 1.1: +85 -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     mcp_stdio;
11    
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     The interfaces are still being designed; this documentation is intentionally
58     only an overview for now.
59    
60 root 1.2 =head1 GLOBAL CONFIGURATION
61    
62     The shared per-user configuration is C<$XDG_CONFIG_HOME/anyevent-mcp/global.ini>,
63     or C<$HOME/.config/anyevent-mcp/global.ini> when XDG_CONFIG_HOME is unset.
64     L<AnyEvent::MCP::Config> loads and holds it; loading this module does not access
65     configuration files.
66    
67     The file is UTF-8 and uses sections with single-line C<key = value> pairs.
68     Values are unquoted strings. Blank lines and whole-line comments beginning
69     with C<#> or C<;> are ignored; inline comment characters remain part of the
70     value. Later occurrences of a key replace earlier ones in the same section.
71    
72     [global]
73     secret = ...128 hexadecimal digits...
74    
75     [server example]
76     url = https://example.net:31740/mcp/{cookie}/
77    
78     [mcp-fs]
79     utility = /path/to/utility
80    
81     Section names are unrestricted. Application-specific sections, including
82     exports, utility paths and user settings, are documented by their applications.
83    
84     C<[global]> holds C<secret>, a 64-byte master key encoded as 128 hexadecimal
85     digits. The file must be owned by the current user, with no group or other
86     permissions. A missing secret is generated automatically on first configuration
87     access and saved when possible. Existing secrets are never replaced implicitly.
88     An invalid secret is an error.
89    
90     If saving fails, Config warns and retains the secret in memory. Credentials
91     then remain stable only for that process; other processes cannot derive the
92     same credentials. If randomness is unavailable, supply a securely generated
93     secret in the file.
94    
95     C<[server NAME]> holds named-server settings. Its C<url> is a complete template;
96     C<{cookie}> is replaced with the cookie derived for that server and optional
97     username. Scheme, host, port and cookie placement are explicit in the template.
98     These settings do not yet configure HTTP authentication automatically.
99    
100     =head1 FUNCTIONS
101    
102     =head2 $bytes = AnyEvent::MCP::random_bytes $length
103    
104     Returns exactly C<$length> random bytes. Tries C</dev/urandom>, then an external
105     C<openssl rand> command. No additional random-number module is required.
106     Dies if neither source supplies the requested bytes successfully.
107     C<$length> must be a nonnegative integer; zero returns an empty string.
108    
109 root 1.1 =cut
110    
111     package AnyEvent::MCP;
112    
113     use common::sense;
114     use Digest::SHA ();
115    
116     our $VERSION = '0.0';
117    
118 root 1.2 sub random_bytes($) {
119     my ($length) = @_;
120    
121     die "Invalid random byte count\n"
122     unless defined $length && $length =~ /\A[0-9]+\z/;
123     return "" unless $length;
124    
125     my $bytes = "";
126    
127     if (open my $fh, "<", "/dev/urandom") {
128     binmode $fh;
129     while (length $bytes < $length) {
130     read ($fh, $bytes, $length - length ($bytes), length $bytes)
131     or last;
132     }
133     close $fh;
134    
135     return $bytes if length $bytes == $length;
136     }
137    
138     if (open my $fh, "-|", "openssl", "rand", $length) {
139     binmode $fh;
140     local $/;
141     $bytes = <$fh>;
142     my $success = close $fh;
143    
144     return $bytes
145     if $success && defined $bytes && length $bytes == $length;
146     }
147    
148     die "Cannot obtain $length random bytes from /dev/urandom or openssl rand\n";
149     }
150    
151 root 1.1 sub hkdf_sha512_expand($$$) {
152     my ($prk, $info, $l) = @_;
153    
154 root 1.2 64 == length $prk
155     or die "hkdf_sha512_expand: prk length mist be 64 octets";
156    
157 root 1.1 my $t = "";
158     my $okm = "";
159     my $i = 0;
160    
161     do {
162     $t = Digest::SHA::hmac_sha512 $t . $info . chr ++$i, $prk;
163     $okm .= $t;
164     } while $l > length $okm;
165    
166     substr $okm, 0, $l
167     }
168    
169     sub _clean_text($) {
170     my ($text) = @_;
171    
172     my ($prefix) = (join "\n", grep /\S/, split /\n/, $text)
173     =~ /\A([ \t]*)[^\n]*(?:\n\1[^\n]*)*\z/;
174    
175     $text =~ s/^\Q$prefix\E//mg;
176     $text =~ s/\A\s+//;
177     $text =~ s/\s+\z//;
178     $text
179     }
180    
181     package AnyEvent::MCP::Base;
182    
183     sub new {
184     my ($class, %kv) = @_;
185     bless \%kv, $class
186     }
187    
188     sub event {
189     my ($self, $event, @args) = @_;
190     ($self->{"on_$event"} or return)->($self, @args)
191     }
192    
193     =head1 SEE ALSO
194    
195     L<AnyEvent>, L<https://modelcontextprotocol.io/>
196    
197     =head1 AUTHOR
198    
199     The main author of this module is OpenAI ChatGPT.
200    
201     Additional guidance received by:
202    
203     Marc Lehmann <schmorp@schmorp.de>
204     http://home.schmorp.de/
205    
206     =cut
207    
208     1
209