| 1 |
root |
1.1 |
=head1 NAME |
| 2 |
|
|
|
| 3 |
root |
1.5 |
AnyEvent::MCP::Intro - using MCP servers, clients and permissions |
| 4 |
root |
1.1 |
|
| 5 |
|
|
=head1 DESCRIPTION |
| 6 |
|
|
|
| 7 |
root |
1.5 |
You can use the servers in this distribution without writing any Perl. |
| 8 |
|
|
This walkthrough starts with one filesystem server, connects it to an MCP |
| 9 |
|
|
client, and makes a useful request. Once that works, it explains persistent |
| 10 |
|
|
configuration, permissions and combining several servers. |
| 11 |
root |
1.1 |
|
| 12 |
root |
1.5 |
If you want to write a small server yourself, continue with |
| 13 |
|
|
L<AnyEvent::MCP::Server::Simple/TUTORIAL>. Applications needing their own |
| 14 |
|
|
connection management or dispatch can use the modules described in |
| 15 |
|
|
L<AnyEvent::MCP/MODULES>. |
| 16 |
root |
1.1 |
|
| 17 |
root |
1.5 |
The examples use C</home/alice/src/project> as an existing project directory. |
| 18 |
|
|
Replace it with your own absolute path. Commands shown here are commands |
| 19 |
|
|
for you to run; requests addressed to the LLM are shown separately. |
| 20 |
|
|
|
| 21 |
|
|
=head1 INSTALLATION |
| 22 |
|
|
|
| 23 |
|
|
Install the Perl distribution and the external programs used by the |
| 24 |
|
|
servers. Installing one does not install the other. |
| 25 |
|
|
|
| 26 |
|
|
For mcp-fs, install Linux bubblewrap and the filesystem utilities. On |
| 27 |
|
|
Debian or Ubuntu, for example: |
| 28 |
|
|
|
| 29 |
|
|
sudo apt install bubblewrap findutils grep patch sed perl yad |
| 30 |
|
|
|
| 31 |
|
|
C<yad> is optional: it supplies graphical permission dialogs. |
| 32 |
|
|
Without a usable YAD dialog, the helper tries C</dev/tty>; if neither is |
| 33 |
|
|
available, it denies the request. Bubblewrap's executable is C<bwrap>. |
| 34 |
|
|
The machine must allow the unprivileged user namespaces it needs. |
| 35 |
|
|
|
| 36 |
|
|
mcp-fs detects its utilities at startup and omits tools whose utilities |
| 37 |
|
|
are unavailable or unsuitable. It requires bubblewrap by default. |
| 38 |
|
|
See L<mcp-fs/TRUSTED CONFIGURATION> for explicit utility paths and |
| 39 |
|
|
L<mcp-fs/LIMITATIONS> for the sandbox's limits. |
| 40 |
|
|
|
| 41 |
|
|
If you have an unpacked distribution or source checkout, run these commands |
| 42 |
|
|
in its top-level directory: |
| 43 |
|
|
|
| 44 |
|
|
perl Makefile.PL |
| 45 |
|
|
make |
| 46 |
|
|
make test |
| 47 |
|
|
make install |
| 48 |
|
|
|
| 49 |
|
|
C<perl Makefile.PL> reports missing Perl dependencies. Install those with |
| 50 |
|
|
your usual package manager or CPAN client before continuing. For example, |
| 51 |
|
|
the main non-core dependencies can be installed with: |
| 52 |
|
|
|
| 53 |
|
|
cpan AnyEvent AnyEvent::HTTP common::sense JSON::XS |
| 54 |
|
|
|
| 55 |
|
|
Use the same Perl installation for dependency installation, building and |
| 56 |
|
|
running the servers. A module installed for the system Perl might not be |
| 57 |
|
|
available to a Perl installed under C</opt>. C<make install> needs write |
| 58 |
|
|
access to the selected Perl's installation directories; use an appropriate |
| 59 |
|
|
local Perl installation or run that final step with the required privileges. |
| 60 |
|
|
|
| 61 |
root |
1.15 |
Installation puts C<mcp-fs>, C<mcp-multibroker>, C<mcp-vim>, C<mcp-webbrowser>, |
| 62 |
root |
1.5 |
C<mcp-ask-user>, C<anyevent-mcp> and C<anyevent-mcp-askpermission> in the |
| 63 |
|
|
selected executable directory. Make that directory available in the |
| 64 |
|
|
environment of your MCP client, or configure absolute executable paths. |
| 65 |
|
|
A desktop application need not have the same C<PATH> as your shell. |
| 66 |
|
|
|
| 67 |
|
|
To try an uninstalled source tree after installing its dependencies, you |
| 68 |
|
|
can run a program with the source library path: |
| 69 |
|
|
|
| 70 |
|
|
perl -Ilib bin/mcp-fs --stdio --name code /home/alice/src/project |
| 71 |
|
|
|
| 72 |
|
|
Do this from the distribution directory. When configuring a client to |
| 73 |
|
|
start such a command, account for the client's working directory or use |
| 74 |
|
|
absolute paths to Perl, C<lib> and the script. An installed executable |
| 75 |
|
|
avoids that extra setup. |
| 76 |
|
|
|
| 77 |
root |
1.15 |
=head1 CONNECTED BROWSER PAGES |
| 78 |
|
|
|
| 79 |
|
|
C<mcp-webbrowser> is the browser-page counterpart to C<mcp-vim>. Its own |
| 80 |
|
|
HTTP/WebSocket listener remains active when MCP uses stdio or C<--connect>: |
| 81 |
|
|
|
| 82 |
|
|
mcp-webbrowser --stdio |
| 83 |
|
|
mcp-webbrowser --print-url |
| 84 |
|
|
|
| 85 |
root |
1.16 |
Install the companion userscript from |
| 86 |
|
|
C<webbrowser/mcp-webbrowser.user.js> in the source distribution or from |
| 87 |
|
|
L<https://dist.schmorp.de/mcp-webbrowser/1/mcp-webbrowser.user.js>. |
| 88 |
|
|
Chromium with ScriptCat has been tested. The browser's userscript menu lets |
| 89 |
|
|
you explicitly allow or disconnect individual tabs; only allowed tabs can |
| 90 |
|
|
be discovered and controlled by an MCP client. The broker supplies C<pages>, |
| 91 |
|
|
C<execute> and C<add_element> tools, permission prompts, cancellation and |
| 92 |
|
|
execution timeouts. See L<mcp-webbrowser/USERSCRIPT INSTALLATION AND USE> |
| 93 |
|
|
for setup, compatibility and the current ScriptCat discard limitation. |
| 94 |
|
|
|
| 95 |
|
|
To keep a lazily spawned multibroker child available for browser connections |
| 96 |
|
|
from startup, use C<--eager>: |
| 97 |
root |
1.15 |
|
| 98 |
|
|
mcp-multibroker browser --- mcp-webbrowser --- --eager |
| 99 |
|
|
|
| 100 |
root |
1.5 |
=head1 YOUR FIRST FILESYSTEM SERVER |
| 101 |
|
|
|
| 102 |
|
|
Start with one project and one connection. You do not need a multibroker, |
| 103 |
|
|
a hand-written configuration file or saved permission rules yet. |
| 104 |
|
|
|
| 105 |
|
|
=head2 Choose stdio or HTTP |
| 106 |
|
|
|
| 107 |
|
|
Use B<stdio> when your MCP client runs on the same machine and can launch |
| 108 |
|
|
a server process. Configure the client to start the following command: |
| 109 |
|
|
|
| 110 |
|
|
mcp-fs --stdio --name code /home/alice/src/project |
| 111 |
|
|
|
| 112 |
|
|
The client starts this process and uses its stdin/stdout for MCP. |
| 113 |
|
|
You do not start a second copy in a terminal, and there is no listener |
| 114 |
|
|
URL or HTTP token to configure. Diagnostics go to stderr. |
| 115 |
|
|
|
| 116 |
|
|
Clients that take a command and an argument array need these values: |
| 117 |
|
|
|
| 118 |
|
|
command: mcp-fs |
| 119 |
|
|
arguments: --stdio, --name, code, /home/alice/src/project |
| 120 |
|
|
|
| 121 |
|
|
These describe separate arguments, not one shell command string. |
| 122 |
|
|
Use an absolute executable path if the client cannot find C<mcp-fs>. |
| 123 |
|
|
See L</CLIENT EXAMPLES> for examples of particular clients. |
| 124 |
|
|
|
| 125 |
|
|
Use B<HTTP> when the client connects to an already-running server, or when |
| 126 |
|
|
it cannot launch a local process. Start this in a terminal on the server |
| 127 |
|
|
machine and leave it running: |
| 128 |
|
|
|
| 129 |
|
|
mcp-fs --name code --bind :31741 /home/alice/src/project |
| 130 |
|
|
|
| 131 |
|
|
In another terminal, obtain the matching connection URL: |
| 132 |
|
|
|
| 133 |
|
|
mcp-fs --name code --bind :31741 --print-url |
| 134 |
|
|
|
| 135 |
|
|
The second command prints a credential-bearing URL and exits without |
| 136 |
|
|
opening a listener. Configure that URL in the client. The default address |
| 137 |
|
|
is IPv4 loopback, so this example is reachable from the same machine only. |
| 138 |
|
|
A hosted client needs a suitable tunnel or reachable endpoint; its own |
| 139 |
|
|
C<localhost> is not your computer. |
| 140 |
|
|
|
| 141 |
|
|
Repeat the same name and listener overrides when printing the URL. |
| 142 |
|
|
Both commands must use the same user and configuration directory. |
| 143 |
|
|
Port zero chooses an ephemeral port, which C<--print-url> cannot predict; |
| 144 |
|
|
use an explicit port for this walkthrough. |
| 145 |
|
|
|
| 146 |
|
|
The HTTP server generates and saves its private master secret when needed. |
| 147 |
|
|
You can initialize it explicitly with C<anyevent-mcp init>, but that |
| 148 |
|
|
command is unnecessary when configuration already exists and will refuse |
| 149 |
|
|
to replace it. Keep the printed URL private: possession of its token |
| 150 |
|
|
authenticates a client. |
| 151 |
|
|
|
| 152 |
|
|
=head2 Make a useful request |
| 153 |
|
|
|
| 154 |
|
|
Once your client reports that the server is connected, ask the LLM: |
| 155 |
|
|
|
| 156 |
|
|
Show me the configured workdirs. List the top-level files in the |
| 157 |
|
|
project, then read its README. Do not modify files or run commands. |
| 158 |
|
|
|
| 159 |
|
|
C<workdirs> returns the configured paths, sandbox grants, trusted mounts |
| 160 |
|
|
and runtime paths. Listing names requests C<inspect> permission; reading |
| 161 |
|
|
contents requests C<read> permission. Expect a permission prompt when |
| 162 |
|
|
there is no saved rule allowing the operation. |
| 163 |
|
|
|
| 164 |
|
|
Choose C<Allow once> for the first operation. The worker then runs with |
| 165 |
|
|
the requested sandbox grants. A denial is a tool failure that the LLM |
| 166 |
|
|
should report, rather than an empty file or a disconnected server. |
| 167 |
|
|
|
| 168 |
|
|
For a slightly larger task, ask: |
| 169 |
|
|
|
| 170 |
|
|
Find TODO comments in this project and explain the three that look |
| 171 |
|
|
most useful to address next. Do not modify files or run commands. |
| 172 |
|
|
|
| 173 |
|
|
This can use C<find>, C<grep> and C<read-lines>. You need not write MCP |
| 174 |
|
|
requests yourself. If a client offers its own tool-approval prompt, that |
| 175 |
|
|
is an additional client policy; it does not replace mcp-fs's permissions. |
| 176 |
|
|
|
| 177 |
|
|
=head2 Understand the workdir |
| 178 |
|
|
|
| 179 |
|
|
The directory passed at startup tells mcp-fs which workdir to expose. |
| 180 |
|
|
It does not grant permission for every operation in that directory. |
| 181 |
|
|
Each operation still requests its action and sandbox grants. |
| 182 |
|
|
|
| 183 |
|
|
With one workdir, tools can omit the C<workdir> argument. With several: |
| 184 |
|
|
|
| 185 |
|
|
mcp-fs --stdio --name code /home/alice/src/project /home/alice/notes |
| 186 |
|
|
|
| 187 |
root |
1.14 |
tools select one using a persistent positive integer ID, a numeric string |
| 188 |
|
|
or an exact configured/resolved path returned by C<workdirs>. The |
| 189 |
|
|
C<workdirs> and C<resolved_workdirs> objects use these IDs as keys. |
| 190 |
|
|
Relative tool paths are relative to that selection. Permission rules |
| 191 |
|
|
continue to use the configured path, not its numeric ID. |
| 192 |
|
|
|
| 193 |
|
|
IDs are shared across filesystem servers in |
| 194 |
|
|
C<$XDG_CONFIG_HOME/anyevent-mcp/fs-workdir-ids.json>, or under |
| 195 |
|
|
C<$HOME/.config> by default. They identify resolved absolute paths and |
| 196 |
root |
1.15 |
survive restarts and argument reordering. Startup resolves IDs once and |
| 197 |
|
|
reserves new allocations under the lock. A timer runs immediately and every |
| 198 |
|
|
5.25 days to reread the registry and refresh the server's fixed assignments. |
| 199 |
|
|
Other entries expire after seven days and their IDs may be reused. Restart |
| 200 |
|
|
servers after manually changing the registry. |
| 201 |
root |
1.5 |
|
| 202 |
|
|
C<workdir-read> exposes the selected workdir read-only. |
| 203 |
|
|
C<workdir-write> makes it writable and implies read access. |
| 204 |
|
|
A path in another configured workdir requires all-workdirs authority; |
| 205 |
|
|
a path elsewhere requires suitable home/world or shared-tmp authority. |
| 206 |
|
|
A symlink cannot make an unmounted target appear inside the sandbox. |
| 207 |
|
|
|
| 208 |
|
|
Prefer separate, non-overlapping workdirs. Overlapping mounts have |
| 209 |
|
|
unspecified access effects. See L<mcp-fs/SANDBOX GRANTS> before granting |
| 210 |
|
|
access beyond the selected workdir. |
| 211 |
|
|
|
| 212 |
root |
1.6 |
=head2 Inspect version-control changes |
| 213 |
|
|
|
| 214 |
|
|
For a Git, SVN, CVS or Mercurial working copy, ask the LLM to use |
| 215 |
|
|
C<vcs-diff> and C<vcs-status>, with C<backend> set to C<git>, C<svn>, C<cvs> |
| 216 |
|
|
or C<hg>. C<workdirs> reports the available clients. These tools accept |
| 217 |
|
|
filenames and construct the command themselves; no shell pipeline or arbitrary |
| 218 |
|
|
VCS options need to be approved. |
| 219 |
|
|
|
| 220 |
|
|
For example: |
| 221 |
|
|
|
| 222 |
|
|
Show the CVS diff for this project, limited to 200 lines. |
| 223 |
|
|
Then show its status, keeping stdout lines matching "File:|Status:". |
| 224 |
|
|
|
| 225 |
|
|
These operations have their own permission actions. They request read access |
| 226 |
|
|
to the selected workdir and home configuration; CVS also requests network |
| 227 |
|
|
access automatically. Read permission for ordinary file tools does not |
| 228 |
|
|
automatically authorize a VCS operation. |
| 229 |
|
|
|
| 230 |
|
|
For arbitrary C<exec> commands, the same output options are available: |
| 231 |
|
|
C<grep> filters stdout using PCRE, C<max_lines> limits matching stdout lines, |
| 232 |
|
|
and C<max_bytes> bounds returned bytes per stream. Prefer these options to a |
| 233 |
|
|
shell wrapper that mixes execution and output processing. Stderr is unfiltered, |
| 234 |
|
|
and exit status still describes the original command. |
| 235 |
|
|
|
| 236 |
|
|
Defaults return at most 2000 stdout lines and 64 KiB per stream. Raw capture |
| 237 |
|
|
has a separate 1 MiB limit per stream. A true C<capture_truncated> means |
| 238 |
|
|
output was omitted before filtering or collection ended on timeout, so absent |
| 239 |
|
|
matches do not prove the omitted output had none. See L<mcp-fs/Command output> |
| 240 |
|
|
for all result flags and limits. |
| 241 |
|
|
|
| 242 |
root |
1.5 |
=head1 CONFIGURING YOUR SETUP |
| 243 |
|
|
|
| 244 |
|
|
There are three different things to configure: how the client connects, |
| 245 |
|
|
how the server runs, and which operations the user allows. Changing one |
| 246 |
|
|
does not necessarily change the other two. |
| 247 |
|
|
|
| 248 |
|
|
=head2 Where each setting belongs |
| 249 |
root |
1.1 |
|
| 250 |
|
|
=over |
| 251 |
|
|
|
| 252 |
root |
1.5 |
=item Directories to expose |
| 253 |
|
|
|
| 254 |
|
|
Pass workdirs on the mcp-fs startup command. For a stdio server, that |
| 255 |
|
|
command belongs in the client's server configuration. For an HTTP server, |
| 256 |
|
|
it belongs in the command used to run the service. |
| 257 |
root |
1.1 |
|
| 258 |
root |
1.5 |
=item Connection transport |
| 259 |
root |
1.1 |
|
| 260 |
root |
1.5 |
The client launches a command for stdio or connects to a URL for HTTP. |
| 261 |
|
|
C<--stdio> selects the former for mcp-fs and the multibroker. |
| 262 |
root |
1.1 |
|
| 263 |
root |
1.5 |
=item Listener address, port and tokens |
| 264 |
root |
1.1 |
|
| 265 |
root |
1.5 |
Use C<[instance NAME]> in the global configuration or command-line |
| 266 |
|
|
C<--bind> and C<--token> overrides. |
| 267 |
root |
1.1 |
|
| 268 |
root |
1.5 |
=item Trusted mounts and utility paths |
| 269 |
|
|
|
| 270 |
|
|
For mcp-fs, use C<[program NAME]> defaults and C<[instance NAME]> |
| 271 |
|
|
overrides in the global configuration. |
| 272 |
|
|
|
| 273 |
|
|
=item Allowed operations and sandbox grants |
| 274 |
|
|
|
| 275 |
|
|
Use the permission rules file, normally created through approval dialogs. |
| 276 |
|
|
This file is separate from the global configuration. |
| 277 |
|
|
|
| 278 |
|
|
=item Location of permission prompts |
| 279 |
|
|
|
| 280 |
root |
1.12 |
Use C<--ask helper>, C<--ask tty>, C<--ask yad>, C<--ask auto> or C<--ask mcp>, or set |
| 281 |
root |
1.5 |
C<PERL_ANYEVENT_MCP_PERMISSION_ASK> in the server's environment. |
| 282 |
|
|
|
| 283 |
|
|
=item Combined server connections |
| 284 |
|
|
|
| 285 |
|
|
Put prefix/server pairs on the multibroker startup command. HTTP child |
| 286 |
|
|
credentials can also use C<[client PREFIX]> in the global configuration. |
| 287 |
root |
1.1 |
|
| 288 |
|
|
=back |
| 289 |
|
|
|
| 290 |
root |
1.5 |
=head2 One complete named configuration |
| 291 |
|
|
|
| 292 |
|
|
The global file is C<$XDG_CONFIG_HOME/anyevent-mcp/global.ini>, falling |
| 293 |
|
|
back to C<$HOME/.config/anyevent-mcp/global.ini>. Settings are UTF-8 |
| 294 |
|
|
C<key = value> lines; values are unquoted. Whole-line C<#> and C<;> |
| 295 |
|
|
comments are allowed. See L<AnyEvent::MCP/GLOBAL CONFIGURATION> for the |
| 296 |
|
|
complete format. |
| 297 |
|
|
|
| 298 |
|
|
Start with the existing file, preserving its C<[global]> secret. |
| 299 |
|
|
If you have no file yet, C<anyevent-mcp init> creates it privately. |
| 300 |
|
|
Add the following sections: |
| 301 |
|
|
|
| 302 |
|
|
[program mcp-fs] |
| 303 |
|
|
mount.opt = ro:/opt |
| 304 |
|
|
|
| 305 |
|
|
[instance code] |
| 306 |
|
|
bind = 127.0.0.1:31741 |
| 307 |
|
|
|
| 308 |
|
|
The optional C<mount.opt> line assumes C</opt> exists and contains tools |
| 309 |
|
|
or libraries your workers need. Omit it if you do not need that access. |
| 310 |
|
|
The ordinary sandbox runtime includes C</usr>, C</bin> and system |
| 311 |
|
|
libraries, but not C</opt>. If your worker Perl is C</opt/bin/perl>, you |
| 312 |
|
|
can additionally put C<executable.perl = /opt/bin/perl> in that program |
| 313 |
|
|
section. Supply the actual executable path; selecting it does not itself |
| 314 |
|
|
mount its files or libraries. |
| 315 |
|
|
|
| 316 |
|
|
Now start: |
| 317 |
|
|
|
| 318 |
|
|
mcp-fs --name code /home/alice/src/project |
| 319 |
|
|
|
| 320 |
|
|
and retrieve its URL with: |
| 321 |
|
|
|
| 322 |
|
|
mcp-fs --name code --print-url |
| 323 |
|
|
|
| 324 |
|
|
Both use C<[instance code]>. No explicit token is needed: the server |
| 325 |
|
|
derives one from its name and the existing master secret. |
| 326 |
|
|
|
| 327 |
|
|
For this setup: |
| 328 |
|
|
|
| 329 |
|
|
program defaults: [program mcp-fs] |
| 330 |
|
|
instance settings: [instance code] |
| 331 |
|
|
selected workdir: /home/alice/src/project |
| 332 |
root |
1.8 |
permission file: ~/.config/anyevent-mcp/rules/fs-code.ini |
| 333 |
root |
1.5 |
rule-manager profile: fs-code |
| 334 |
|
|
|
| 335 |
|
|
The permission pathname above assumes the default configuration directory. |
| 336 |
|
|
C<anyevent-mcp manage-rules fs-code> opens the graphical rule manager; |
| 337 |
|
|
C<anyevent-mcp edit-rules fs-code> opens the file in your editor. |
| 338 |
|
|
|
| 339 |
|
|
Keep global configuration and rule files owned by the server user and |
| 340 |
|
|
private, normally mode 0600. C<--config FILE> on C<anyevent-mcp init> |
| 341 |
|
|
selects that command's output file; it does not make the servers use an |
| 342 |
|
|
arbitrary alternate file. Use the same C<HOME>/C<XDG_CONFIG_HOME> |
| 343 |
|
|
environment when running the server and its management commands. |
| 344 |
|
|
|
| 345 |
|
|
=head2 Names, prefixes and profiles |
| 346 |
|
|
|
| 347 |
|
|
C<--name code> selects instance settings, derived HTTP credentials and |
| 348 |
root |
1.8 |
mcp-fs's C<rules/fs-code.ini>. Without C<--name>, mcp-fs uses C<default>, |
| 349 |
|
|
giving profile C<fs-default>. Two processes with the same program, name and |
| 350 |
root |
1.5 |
configuration share credentials and rules, even if their workdirs differ. |
| 351 |
|
|
|
| 352 |
|
|
A multibroker prefix, such as C<files>, only routes tools: C<grep> becomes |
| 353 |
|
|
C<files.grep>. It does not rename the child server or select its rules. |
| 354 |
|
|
For example: |
| 355 |
|
|
|
| 356 |
|
|
mcp-multibroker files \ |
| 357 |
|
|
'stdio:mcp-fs --name code /home/alice/src/project' |
| 358 |
|
|
|
| 359 |
|
|
The tools are C<files.*>, but the child still uses instance C<code> |
| 360 |
|
|
and rule-manager profile C<fs-code>. The multibroker's own C<--name> |
| 361 |
|
|
selects its upstream listener settings. |
| 362 |
root |
1.1 |
|
| 363 |
root |
1.5 |
=head2 Configuration changes and restarts |
| 364 |
root |
1.1 |
|
| 365 |
root |
1.5 |
Command-line listener options override the named global settings. |
| 366 |
|
|
For mcp-fs trusted settings, an instance entry overrides the corresponding |
| 367 |
|
|
program entry; an empty instance mount value suppresses the inherited mount. |
| 368 |
root |
1.1 |
|
| 369 |
root |
1.5 |
Workdirs, mounts, utility paths, listener settings and tokens are read at |
| 370 |
|
|
startup. Change the file or startup command, then restart the affected |
| 371 |
|
|
server. The multibroker also needs restarting to change its prefix/server |
| 372 |
|
|
pairs; refreshing discovery does not change those pairs. |
| 373 |
|
|
|
| 374 |
|
|
Permission rules are reread on permission checks, so editing them does |
| 375 |
|
|
not require a restart. A client's displayed tool list can still be cached. |
| 376 |
|
|
After restarting a child, refresh tool discovery or reconnect the client |
| 377 |
|
|
as described in L</COMBINING SERVERS>. |
| 378 |
|
|
|
| 379 |
|
|
=head1 PERMISSIONS IN PRACTICE |
| 380 |
|
|
|
| 381 |
|
|
HTTP authentication establishes that the client may connect. |
| 382 |
|
|
Permission checks decide whether a tool may perform an operation. |
| 383 |
|
|
A correct token therefore does not prevent permission prompts. |
| 384 |
|
|
|
| 385 |
|
|
=head2 What the prompt means |
| 386 |
|
|
|
| 387 |
|
|
The prompt describes an action, paths or command, a reason and sandbox |
| 388 |
|
|
grants. For filesystem tools, the actions are: |
| 389 |
|
|
|
| 390 |
root |
1.6 |
inspect stat, list, find |
| 391 |
|
|
read file-read, read-lines, grep |
| 392 |
|
|
write file-write, file-patch |
| 393 |
|
|
manage path-op |
| 394 |
|
|
exec arbitrary command execution |
| 395 |
|
|
vcs-diff working-copy differences |
| 396 |
|
|
vcs-status working-copy status |
| 397 |
root |
1.5 |
|
| 398 |
|
|
The action and grants are independent. Allowing C<read> does not allow |
| 399 |
|
|
C<write>, even if a worker grant permits both kinds of filesystem access. |
| 400 |
|
|
C<exec> runs arbitrary commands; it is not a classification of supposedly |
| 401 |
|
|
safe command prefixes. |
| 402 |
|
|
|
| 403 |
|
|
Choose allow/deny once, or always. Closing the dialog denies once. |
| 404 |
|
|
An optional denial reason is returned with the error; it is not added to |
| 405 |
root |
1.13 |
successful tool results. An always choice opens a rule editor. Choose an |
| 406 |
|
|
indefinite lifetime (the default), 900 seconds or 16 hours. Finite lifetimes |
| 407 |
|
|
are stored as C<expires> Unix timestamps. Expired rules disappear on every |
| 408 |
|
|
read; the next ordinary save removes them from disk. Expiry affects future |
| 409 |
|
|
permission checks, not operations already authorized. |
| 410 |
root |
1.5 |
Filesystem allow rules can select grants and the selected workdir when |
| 411 |
|
|
the authority depends on it. Deny rules can also select an exact affected |
| 412 |
|
|
path. Exec offers persistent command/argv subjects. |
| 413 |
|
|
|
| 414 |
|
|
For exec, C<View stdin...> lets you inspect supplied input without closing |
| 415 |
root |
1.9 |
the approval dialog. Filesystem and Vim patch tools similarly offer |
| 416 |
|
|
C<View patch...>, including the target file or editor and buffer. Longer |
| 417 |
|
|
text is shown as an explicitly incomplete preview. These are YAD button |
| 418 |
|
|
labels; other interfaces can show the details inline. |
| 419 |
|
|
That input is display-only: an exec allow rule does |
| 420 |
root |
1.5 |
not constrain future stdin. Allowing an interpreter command can therefore |
| 421 |
|
|
allow a different script on its next invocation. |
| 422 |
|
|
|
| 423 |
|
|
A worker accessing several paths requests their combined sandbox authority |
| 424 |
|
|
once. If the chosen grants are insufficient, it fails before starting. |
| 425 |
|
|
|
| 426 |
|
|
=head2 Save a useful read-only policy |
| 427 |
|
|
|
| 428 |
|
|
After trying individual operations, you might want the LLM to inspect and |
| 429 |
|
|
read the project without asking each time, while keeping changes subject |
| 430 |
root |
1.8 |
to approval. Put these rules in C<rules/fs-code.ini>, or create equivalent |
| 431 |
root |
1.5 |
allow rules through the prompt: |
| 432 |
|
|
|
| 433 |
|
|
[rule] |
| 434 |
|
|
decision=allow |
| 435 |
|
|
action=inspect |
| 436 |
|
|
workdir=/home/alice/src/project |
| 437 |
|
|
sandbox-grants=workdir-read |
| 438 |
|
|
|
| 439 |
|
|
[rule] |
| 440 |
|
|
decision=allow |
| 441 |
|
|
action=read |
| 442 |
|
|
workdir=/home/alice/src/project |
| 443 |
|
|
sandbox-grants=workdir-read |
| 444 |
|
|
|
| 445 |
|
|
[rule] |
| 446 |
|
|
decision=deny |
| 447 |
|
|
action=exec |
| 448 |
root |
1.1 |
|
| 449 |
root |
1.5 |
Use the exact workdir spelling passed at server startup. Absolute startup |
| 450 |
|
|
paths make this easier. If creating the rules file manually, ensure it |
| 451 |
|
|
belongs to the server user and is private before making another request. |
| 452 |
|
|
For the default configuration directory: |
| 453 |
root |
1.1 |
|
| 454 |
root |
1.8 |
chmod 600 ~/.config/anyevent-mcp/rules/fs-code.ini |
| 455 |
root |
1.1 |
|
| 456 |
root |
1.5 |
Use the corresponding XDG path when configured. Without matching rules, write and manage operations |
| 457 |
|
|
still ask. The final rule denies command execution outright; omit it if you |
| 458 |
|
|
want execution to ask instead. |
| 459 |
root |
1.1 |
|
| 460 |
root |
1.5 |
Rules run in order, stopping at the first match. An allow rule matches only |
| 461 |
|
|
when its grants cover the request, including implications. |
| 462 |
|
|
C<workdir-write> implies C<workdir-read>; C<network> remains independent. |
| 463 |
|
|
Action and subject match exactly unless beginning with C<^>, which selects |
| 464 |
|
|
a Perl regular expression. Workdir matching is always exact. |
| 465 |
|
|
An explicit C<ask> rule can override later allow rules. |
| 466 |
|
|
|
| 467 |
|
|
These allow rules authorize sandbox access to the selected workdir. |
| 468 |
|
|
They cannot confine authority to one file or a subtree inside it. |
| 469 |
|
|
Filesystem operations do not offer persistent path subjects. |
| 470 |
|
|
An exact C<path> matcher is available for deny rules only. |
| 471 |
|
|
Trusted runtime and configured mounts remain baseline access independently |
| 472 |
|
|
of these grants. See L<mcp-fs/TRUSTED CONFIGURATION>. |
| 473 |
|
|
|
| 474 |
|
|
=head2 Change or remove saved rules |
| 475 |
|
|
|
| 476 |
|
|
Use: |
| 477 |
|
|
|
| 478 |
|
|
anyevent-mcp manage-rules fs-code |
| 479 |
|
|
anyevent-mcp edit-rules fs-code |
| 480 |
|
|
|
| 481 |
|
|
The first command lets you delete and reorder rules in YAD. |
| 482 |
|
|
The second uses C<$VISUAL>, C<$EDITOR>, C<sensible-editor> or C<vi>. |
| 483 |
|
|
An earlier deny or ask rule can explain why adding a later allow rule |
| 484 |
|
|
does not change the result. |
| 485 |
|
|
|
| 486 |
|
|
For a custom application with another rule pathname, use: |
| 487 |
|
|
|
| 488 |
|
|
anyevent-mcp manage-rules-file /path/to/rules.ini |
| 489 |
|
|
anyevent-mcp edit-rules-file /path/to/rules.ini |
| 490 |
|
|
|
| 491 |
|
|
A failed attempt to save a permanent rule is an error, not a successful |
| 492 |
|
|
permanent approval. The file must remain private and owned by the server |
| 493 |
|
|
user. For full syntax and programming interfaces, see |
| 494 |
|
|
L<AnyEvent::MCP::Server::Permissions>. |
| 495 |
|
|
|
| 496 |
|
|
=head2 Choose where to ask |
| 497 |
|
|
|
| 498 |
|
|
The default C<helper> mode runs C<anyevent-mcp-askpermission> on the server |
| 499 |
|
|
machine. It tries YAD, then C</dev/tty>, then denies if neither can be used. |
| 500 |
|
|
The helper inherits the server's display environment. |
| 501 |
root |
1.12 |
C<--ask tty> and C<--ask yad> instead force the built-in terminal or YAD |
| 502 |
|
|
interface. They ignore custom helper settings and never try another |
| 503 |
|
|
interface. These modes work for permission prompts and ordinary forms, |
| 504 |
|
|
including forms handled by a multibroker. |
| 505 |
root |
1.5 |
C<PERL_ANYEVENT_MCP_PERMISSION_HELPER> selects a different executable. |
| 506 |
|
|
|
| 507 |
|
|
For a modern client supporting MCP form elicitation, you can instead use: |
| 508 |
|
|
|
| 509 |
|
|
mcp-fs --stdio --name code --ask auto /home/alice/src/project |
| 510 |
|
|
|
| 511 |
|
|
C<auto> uses the client's form support when advertised for that request, |
| 512 |
|
|
otherwise the local helper. C<mcp> requires that support and fails when |
| 513 |
|
|
unavailable. It does not silently fall back. Use client-side permission |
| 514 |
|
|
approval only when that client is a trusted authority to grant access. |
| 515 |
|
|
|
| 516 |
|
|
To set the default for servers using the shared permission engine: |
| 517 |
|
|
|
| 518 |
|
|
PERL_ANYEVENT_MCP_PERMISSION_ASK=auto \ |
| 519 |
|
|
mcp-fs --stdio --name code /home/alice/src/project |
| 520 |
|
|
|
| 521 |
|
|
An explicit application C<ask> setting or C<--ask> overrides the environment. |
| 522 |
|
|
For spawned stdio children, C<mcp-multibroker --ask auto> passes this |
| 523 |
|
|
default to them. It cannot change the environment of an independently |
| 524 |
|
|
running HTTP server. |
| 525 |
|
|
|
| 526 |
root |
1.7 |
The multibroker can handle form elicitation locally for both stdio and HTTP |
| 527 |
|
|
children. C<--ask helper> selects local dialogs even if the upstream client |
| 528 |
|
|
advertises native forms; C<--ask mcp> forwards forms upstream, and C<auto> |
| 529 |
|
|
uses native forms when advertised. If a client claims support but silently |
| 530 |
|
|
declines questions, use C<helper>. A decline never causes a fallback prompt. |
| 531 |
|
|
|
| 532 |
|
|
Standalone C<mcp-ask-user> also supports these modes and defaults to the |
| 533 |
|
|
local helper. A question is different from an approval: answering it does |
| 534 |
|
|
not grant a filesystem worker any authority. |
| 535 |
root |
1.5 |
|
| 536 |
|
|
=head1 COMBINING SERVERS |
| 537 |
|
|
|
| 538 |
|
|
Once the first connection works, use the multibroker to give a client |
| 539 |
|
|
one connection for several servers: |
| 540 |
|
|
|
| 541 |
|
|
mcp-multibroker --name tools --bind :31740 \ |
| 542 |
|
|
code 'stdio:mcp-fs --name code /home/alice/src/project' \ |
| 543 |
|
|
notes 'stdio:mcp-fs --name notes /home/alice/notes' |
| 544 |
|
|
|
| 545 |
|
|
Quote each C<stdio:> shell command as one argument. |
| 546 |
|
|
The broker supplies the child's stdio environment and starts ordinary |
| 547 |
|
|
children lazily, on first use. The explicit child names give them separate |
| 548 |
|
|
permission profiles C<fs-code> and C<fs-notes>. |
| 549 |
|
|
|
| 550 |
|
|
Obtain the upstream HTTP URL with: |
| 551 |
|
|
|
| 552 |
|
|
mcp-multibroker --name tools --bind :31740 --print-url |
| 553 |
|
|
|
| 554 |
|
|
Configure this URL in place of the client's old direct connection. |
| 555 |
|
|
The client can now see C<code.grep>, C<code.read-lines>, C<notes.find> |
| 556 |
|
|
and other prefixed tools. It does not need a separate connection to each |
| 557 |
|
|
child. |
| 558 |
|
|
|
| 559 |
|
|
For a client launching the multibroker locally, configure: |
| 560 |
|
|
|
| 561 |
|
|
mcp-multibroker --stdio --name tools \ |
| 562 |
|
|
code 'stdio:mcp-fs --name code /home/alice/src/project' \ |
| 563 |
|
|
notes 'stdio:mcp-fs --name notes /home/alice/notes' |
| 564 |
|
|
|
| 565 |
|
|
C<--stdio> selects the upstream connection. The child commands still use |
| 566 |
|
|
C<stdio:>; that selects each downstream connection independently. |
| 567 |
|
|
No upstream HTTP URL is needed in this case. |
| 568 |
|
|
|
| 569 |
|
|
=head2 Discover and refresh tools |
| 570 |
|
|
|
| 571 |
|
|
Ask the LLM: |
| 572 |
|
|
|
| 573 |
|
|
Call discover-brokers and list-tools, then show me which servers |
| 574 |
|
|
are available and what each is for. |
| 575 |
|
|
|
| 576 |
|
|
C<discover-brokers> returns instructions, no instructions, or an error for |
| 577 |
|
|
each configured server. C<list-tools> requests current tool definitions; |
| 578 |
|
|
unreachable servers are omitted. A reachable server can still fail later. |
| 579 |
|
|
|
| 580 |
|
|
If the client still has an old direct tool list, C<call-tool> can invoke |
| 581 |
|
|
an exact prefixed name found by C<list-tools>. Refresh the client's MCP |
| 582 |
|
|
connection if it continues to hide newly available tools. |
| 583 |
|
|
|
| 584 |
root |
1.15 |
Discovery queries configured servers and currently registered reverse |
| 585 |
|
|
connections. Changing the static downstream command still requires a restart. |
| 586 |
|
|
|
| 587 |
|
|
=head2 Let a server connect to the multibroker |
| 588 |
|
|
|
| 589 |
|
|
To add independently started servers without editing the multibroker command, |
| 590 |
|
|
keep its HTTP/extension listener active alongside stdio: |
| 591 |
|
|
|
| 592 |
|
|
mcp-multibroker --stdio --listen --bind 127.0.0.1:31740 |
| 593 |
|
|
mcp-multibroker --bind 127.0.0.1:31740 --print-url |
| 594 |
|
|
|
| 595 |
|
|
Append an alias to the returned credential-bearing URL: |
| 596 |
|
|
|
| 597 |
|
|
mcp-fs --connect http://127.0.0.1:31740/TOKEN/files /home/alice/project |
| 598 |
|
|
|
| 599 |
|
|
The filesystem server initiates the TCP connection but remains the MCP server. |
| 600 |
|
|
The multibroker authenticates the same token used for HTTP, registers the |
| 601 |
|
|
alias and discovers the tools. A configured or connected alias cannot be |
| 602 |
|
|
replaced. After disconnecting, the server retries once per second for sixty |
| 603 |
|
|
attempts. Pending calls fail and are never replayed. Remote registration does |
| 604 |
|
|
not grant the multibroker spawned-child shutdown authority. |
| 605 |
|
|
|
| 606 |
|
|
The hello is a raw JSON line, followed by ordinary MCP JSONL on the same socket; |
| 607 |
|
|
the HTTP-shaped URL is an address and credential, not an HTTP request. |
| 608 |
|
|
The bundled connector supports plain C<http://> endpoints. An HTTP listener is |
| 609 |
|
|
already active by default when the upstream connection is HTTP. |
| 610 |
root |
1.5 |
|
| 611 |
|
|
=head2 Add an HTTP child |
| 612 |
|
|
|
| 613 |
|
|
A broker can mix spawned stdio servers and existing HTTP endpoints: |
| 614 |
|
|
|
| 615 |
|
|
mcp-multibroker --stdio \ |
| 616 |
|
|
code 'stdio:mcp-fs --name code /home/alice/src/project' \ |
| 617 |
|
|
remote https://example.org/mcp/ --bearer TOKEN |
| 618 |
|
|
|
| 619 |
|
|
C<--bearer> immediately after the HTTP pair belongs to that child. |
| 620 |
|
|
C<--token> before all pairs configures the multibroker's own HTTP listener. |
| 621 |
|
|
They authenticate different connections. |
| 622 |
|
|
|
| 623 |
|
|
To avoid putting a child's bearer token in the startup command, add: |
| 624 |
|
|
|
| 625 |
|
|
[client remote] |
| 626 |
|
|
bearer = TOKEN |
| 627 |
|
|
timeout = 300 |
| 628 |
|
|
|
| 629 |
|
|
to the private global configuration, and omit C<--bearer> from the command. |
| 630 |
|
|
The prefix C<remote> selects these client defaults. The command-line URL |
| 631 |
|
|
still chooses the endpoint. Use the actual credential accepted by that |
| 632 |
|
|
server, not the literal placeholder C<TOKEN>. |
| 633 |
|
|
|
| 634 |
|
|
A token already present in a child's URL needs no separate bearer option. |
| 635 |
|
|
The bundled servers use static URL-safe tokens; they do not validate |
| 636 |
|
|
OAuth access tokens or implement HTTP Basic authentication. |
| 637 |
|
|
Use TLS or an appropriate tunnel when credentials cross untrusted networks. |
| 638 |
|
|
|
| 639 |
|
|
The multibroker does not put every child inside the mcp-fs sandbox. |
| 640 |
|
|
Each process or remote service has its own authority and enforcement. |
| 641 |
|
|
|
| 642 |
|
|
=head2 Add a live Vim editor |
| 643 |
|
|
|
| 644 |
|
|
Install the Vim plugin using L<mcp-vim/VIM PLUGIN INSTALLATION>. It is |
| 645 |
|
|
included in the source distribution but is not installed by Perl's |
| 646 |
|
|
C<make install>. |
| 647 |
|
|
|
| 648 |
|
|
A spawned mcp-vim child also listens for editor connections. Start it |
| 649 |
|
|
eagerly so Vim can connect before the first MCP tool call: |
| 650 |
|
|
|
| 651 |
|
|
mcp-multibroker --stdio \ |
| 652 |
|
|
code 'stdio:mcp-fs --name code /home/alice/src/project' \ |
| 653 |
|
|
vim 'stdio:mcp-vim --name editor' --eager |
| 654 |
|
|
|
| 655 |
|
|
In another terminal, obtain the editor child's URL prefix: |
| 656 |
|
|
|
| 657 |
|
|
mcp-vim --name editor --print-url |
| 658 |
|
|
|
| 659 |
|
|
Append the desired target name in Vim: |
| 660 |
|
|
|
| 661 |
|
|
:Mcp http://HOST:PORT/TOKEN/my-editor |
| 662 |
|
|
|
| 663 |
|
|
Use the actual printed prefix in place of C<http://HOST:PORT/TOKEN/>. |
| 664 |
|
|
Ask the LLM to call C<vim.targets>, then C<vim.state> before reading or |
| 665 |
|
|
editing buffers. These tools see live, possibly unsaved buffers. |
| 666 |
|
|
Edits require a current changedtick and do not save files to disk. |
| 667 |
|
|
|
| 668 |
root |
1.13 |
To pass arguments directly, use C<PREFIX --- PROGRAM ARG... --->: |
| 669 |
|
|
|
| 670 |
|
|
mcp-multibroker --stdio \ |
| 671 |
|
|
vim --- mcp-vim --name editor --bind :: --- --eager \ |
| 672 |
|
|
code --- mcp-fs --name code '/home/alice/project with spaces' --- |
| 673 |
|
|
|
| 674 |
|
|
Only the invoking shell processes quoting. The broker passes all arguments |
| 675 |
|
|
between the delimiters unchanged, including empty arguments and child options. |
| 676 |
|
|
Use C<stdio:COMMAND> for shell syntax or a literal C<---> child argument. |
| 677 |
|
|
An empty command or missing closing delimiter is an error. |
| 678 |
|
|
|
| 679 |
|
|
C<--eager> belongs immediately after its stdio URL or closing C<--->. |
| 680 |
root |
1.5 |
An eager connection failure is logged; the broker does not continuously |
| 681 |
|
|
restart the child. Later tool use can try connecting again. |
| 682 |
|
|
|
| 683 |
|
|
=head2 Ask the client's human a question |
| 684 |
|
|
|
| 685 |
root |
1.7 |
To let the assistant ask you questions, add a question server: |
| 686 |
root |
1.5 |
|
| 687 |
|
|
mcp-multibroker --stdio \ |
| 688 |
|
|
code 'stdio:mcp-fs --name code /home/alice/src/project' \ |
| 689 |
|
|
questions 'stdio:mcp-ask-user' |
| 690 |
|
|
|
| 691 |
|
|
The LLM can call C<questions.ask-user> with a question, up to three |
| 692 |
|
|
suggested answers and room for free text. For example, tell it to use |
| 693 |
|
|
that tool if choosing among several possible tasks needs your input. |
| 694 |
root |
1.10 |
For several fields or other value types, C<questions.ask-form> accepts |
| 695 |
|
|
C<message> and C<requestedSchema> directly and returns the standard |
| 696 |
|
|
elicitation response. Both tools use the same configured presentation mode. |
| 697 |
root |
1.5 |
Decline and cancel are distinct results; neither supplies an answer. |
| 698 |
|
|
|
| 699 |
root |
1.7 |
By default the multibroker displays questions locally, using YAD or a terminal. |
| 700 |
|
|
Add C<--ask mcp> before the broker entries to use the client's native forms, |
| 701 |
|
|
or C<--ask auto> to select by advertised capability. This also works with |
| 702 |
|
|
C<mcp-ask-user> started separately: give that server C<--ask mcp> so it |
| 703 |
|
|
delegates presentation to its connecting multibroker. |
| 704 |
|
|
|
| 705 |
|
|
C<anyevent-mcp-form-elicitation> is the standalone form renderer. It reads standard MCP |
| 706 |
|
|
form parameters as UTF-8 JSON on stdin and writes an accept/decline/cancel |
| 707 |
|
|
response as JSON on stdout. C<PERL_ANYEVENT_MCP_ELICITATION_HELPER> selects |
| 708 |
|
|
a replacement executable. See L<anyevent-mcp-form-elicitation> for supported fields |
| 709 |
|
|
and L<mcp-ask-user> for question arguments and result fields. |
| 710 |
root |
1.5 |
|
| 711 |
|
|
=head1 HTTP TOKENS AND SERVER IDENTITY |
| 712 |
|
|
|
| 713 |
|
|
For the ordinary bundled HTTP endpoints, a client can present an accepted |
| 714 |
|
|
token in either of these ways: |
| 715 |
|
|
|
| 716 |
|
|
POST /TOKEN/ |
| 717 |
|
|
POST / Authorization: Bearer TOKEN |
| 718 |
|
|
|
| 719 |
|
|
URL tokens are path components, not browser cookies. |
| 720 |
|
|
For another configured endpoint, C</TOKEN> prefixes that endpoint path. |
| 721 |
|
|
All accepted tokens authenticate the same operations; they are not separate |
| 722 |
|
|
users or permission levels. Permissions still govern the tool operation. |
| 723 |
|
|
|
| 724 |
|
|
By default, the master secret and server name determine one stable token |
| 725 |
|
|
and a port in 16384..32767. Changing a server's name changes its derived |
| 726 |
|
|
credentials and default port. Changing or losing the master secret changes |
| 727 |
|
|
all derived credentials. Keep an existing C<[global]> secret when editing |
| 728 |
|
|
other configuration. |
| 729 |
|
|
|
| 730 |
|
|
To configure explicit tokens: |
| 731 |
|
|
|
| 732 |
|
|
[instance code] |
| 733 |
|
|
tokens = first-secret,second-secret |
| 734 |
root |
1.1 |
|
| 735 |
root |
1.5 |
Replace those placeholders with actual unguessable URL-safe tokens. |
| 736 |
|
|
Repeated C<--token> options replace the whole configured list and the |
| 737 |
|
|
derived default. The first token appears in C<--print-url>; all are accepted. |
| 738 |
|
|
mcp-vim also accepts its token set for Vim and browser WebSocket connections. |
| 739 |
|
|
|
| 740 |
|
|
If C<--print-url> disagrees with the client's URL, compare the name, |
| 741 |
|
|
command-line overrides, user and configuration environment with the running |
| 742 |
|
|
process. The command resolves configuration; it does not ask the running |
| 743 |
|
|
server which URL it uses. A changed file needs a server restart. |
| 744 |
|
|
|
| 745 |
|
|
An Origin allowlist restricts browser origins; it does not authenticate |
| 746 |
|
|
clients. A CORS preflight can succeed without a token, while the MCP POST |
| 747 |
|
|
still requires one. See L<AnyEvent::MCP::Server::HTTP/AUTHENTICATION> for |
| 748 |
|
|
the low-level server interface. |
| 749 |
|
|
|
| 750 |
|
|
=head1 CLIENT EXAMPLES |
| 751 |
|
|
|
| 752 |
|
|
Client settings and command syntax evolve independently of this distribution. |
| 753 |
|
|
These examples show the connection choices; consult the linked client |
| 754 |
|
|
documentation if its interface differs. Replace illustrative paths and |
| 755 |
|
|
credentials with your own. |
| 756 |
root |
1.1 |
|
| 757 |
root |
1.5 |
=head2 OpenAI Codex CLI |
| 758 |
root |
1.1 |
|
| 759 |
root |
1.5 |
For the first direct filesystem connection: |
| 760 |
root |
1.1 |
|
| 761 |
root |
1.5 |
codex mcp add code -- \ |
| 762 |
|
|
mcp-fs --stdio --name code /home/alice/src/project |
| 763 |
root |
1.1 |
codex mcp list |
| 764 |
|
|
|
| 765 |
root |
1.5 |
For a multibroker connection: |
| 766 |
|
|
|
| 767 |
|
|
codex mcp add mytools -- \ |
| 768 |
|
|
mcp-multibroker --stdio \ |
| 769 |
|
|
code 'stdio:mcp-fs --name code /home/alice/src/project' |
| 770 |
|
|
|
| 771 |
root |
1.1 |
Use C</mcp> within Codex to inspect connections. |
| 772 |
|
|
See L<Codex MCP documentation|https://learn.chatgpt.com/docs/extend/mcp>. |
| 773 |
|
|
|
| 774 |
root |
1.5 |
=head2 Anthropic Claude Code |
| 775 |
root |
1.1 |
|
| 776 |
root |
1.5 |
For the direct connection: |
| 777 |
root |
1.1 |
|
| 778 |
root |
1.5 |
claude mcp add --transport stdio --scope user code -- \ |
| 779 |
|
|
mcp-fs --stdio --name code /home/alice/src/project |
| 780 |
root |
1.1 |
claude mcp list |
| 781 |
|
|
|
| 782 |
root |
1.5 |
Replace the launched command with the multibroker command above when you |
| 783 |
|
|
want several servers. Use C</mcp> for connection status. See |
| 784 |
root |
1.1 |
L<Claude Code MCP documentation|https://code.claude.com/docs/en/mcp>. |
| 785 |
|
|
|
| 786 |
root |
1.5 |
=head2 Google Gemini CLI |
| 787 |
root |
1.1 |
|
| 788 |
root |
1.5 |
Merge a direct server entry into C<~/.gemini/settings.json>: |
| 789 |
root |
1.1 |
|
| 790 |
|
|
{ |
| 791 |
|
|
"mcpServers": { |
| 792 |
root |
1.5 |
"code": { |
| 793 |
|
|
"command": "mcp-fs", |
| 794 |
root |
1.1 |
"args": [ |
| 795 |
root |
1.5 |
"--stdio", "--name", "code", "/home/alice/src/project" |
| 796 |
|
|
] |
| 797 |
root |
1.1 |
} |
| 798 |
|
|
} |
| 799 |
|
|
} |
| 800 |
|
|
|
| 801 |
root |
1.5 |
For a combined connection, use C<mcp-multibroker> as the command and its |
| 802 |
|
|
C<--stdio> and prefix/server pairs as the argument array. |
| 803 |
|
|
Use C</mcp> to inspect the connection. See |
| 804 |
|
|
L<Gemini CLI MCP documentation|https://geminicli.com/docs/tools/mcp-server/>. |
| 805 |
|
|
|
| 806 |
|
|
=head2 Hosted clients, including ChatGPT web |
| 807 |
|
|
|
| 808 |
|
|
A hosted client cannot spawn your local stdio command or reach your |
| 809 |
|
|
machine's loopback address directly. Run the server or multibroker in HTTP |
| 810 |
|
|
mode and configure a supported tunnel or reachable endpoint. |
| 811 |
|
|
|
| 812 |
|
|
For ChatGPT, use its custom MCP setup and, for a private server, an |
| 813 |
|
|
appropriately configured Secure MCP Tunnel. Availability depends on the |
| 814 |
|
|
client's plan, workspace and feature permissions. See |
| 815 |
|
|
L<ChatGPT custom MCP servers|https://developers.openai.com/api/docs/guides/custom-mcp-server> |
| 816 |
|
|
and L<Secure MCP Tunnel|https://developers.openai.com/blog/connect-private-mcp-servers-to-openai-products>. |
| 817 |
|
|
|
| 818 |
|
|
=head1 TROUBLESHOOTING |
| 819 |
|
|
|
| 820 |
|
|
=head2 The server does not start |
| 821 |
|
|
|
| 822 |
|
|
Read stderr or the client's server log. Missing Perl modules, a missing |
| 823 |
|
|
workdir, unsuitable utilities or an unavailable bubblewrap executable can |
| 824 |
|
|
fail startup. Confirm that the client launches the same executable and |
| 825 |
|
|
arguments you intended, with the expected C<PATH> and Perl installation. |
| 826 |
|
|
|
| 827 |
|
|
For a local sandbox check, run from the project directory: |
| 828 |
|
|
|
| 829 |
|
|
mcp-fs --exec-cmd workdir-read -- ls |
| 830 |
root |
1.1 |
|
| 831 |
root |
1.5 |
This runs C<ls> with the named grants and trusted baseline mounts, without |
| 832 |
|
|
MCP or saved permission rules. A failure here can identify a bubblewrap |
| 833 |
|
|
or runtime problem. It does not test the client connection or approval UI. |
| 834 |
|
|
C<--sandbox none> disables isolation and changes worker authority; it is |
| 835 |
|
|
not a fix that preserves the same permission boundary. |
| 836 |
root |
1.1 |
|
| 837 |
root |
1.5 |
=head2 The client cannot connect |
| 838 |
|
|
|
| 839 |
|
|
For stdio, configure a command the client launches, rather than a URL. |
| 840 |
|
|
A separately running stdio process is not the client's connection. |
| 841 |
|
|
Do not put banners or diagnostics on stdout. |
| 842 |
|
|
|
| 843 |
|
|
For HTTP, leave the server running and check its address and port. |
| 844 |
|
|
C<--print-url> exits without starting it. Loopback binds accept local |
| 845 |
|
|
connections only; hosted or remote clients need the appropriate route or |
| 846 |
|
|
tunnel. An occupied port causes a listener error, so check the server log. |
| 847 |
|
|
|
| 848 |
|
|
=head2 Authentication fails |
| 849 |
|
|
|
| 850 |
|
|
Obtain the URL with the same name, bind/token overrides and configuration |
| 851 |
|
|
environment as the running process. Use the complete path, including any |
| 852 |
|
|
required trailing slash. A clean URL needs an accepted bearer token. |
| 853 |
|
|
|
| 854 |
|
|
A multibroker child credential is not necessarily the upstream listener's |
| 855 |
|
|
credential. C<--bearer> after a child pair and C<--token> before the pairs |
| 856 |
|
|
configure different sides of the connection. |
| 857 |
|
|
|
| 858 |
|
|
If the server warns that it cannot save the master secret, another process |
| 859 |
|
|
may derive a different token. Fix ownership and write access to the private |
| 860 |
|
|
configuration. Do not replace an existing secret simply to add a setting. |
| 861 |
|
|
|
| 862 |
|
|
=head2 Connected, but there are no tools |
| 863 |
|
|
|
| 864 |
|
|
Inspect the server's stderr for omitted utilities. mcp-fs's C<workdirs> |
| 865 |
|
|
tool reports configuration even when a utility-dependent tool is absent. |
| 866 |
|
|
For a multibroker, call C<discover-brokers> to see individual connection |
| 867 |
|
|
errors, then C<list-tools> to refresh definitions. |
| 868 |
|
|
|
| 869 |
|
|
A third-party child might require initialization or features this client |
| 870 |
|
|
implementation does not support. See L<AnyEvent::MCP::Client> and its |
| 871 |
|
|
transport documentation for limitations. |
| 872 |
|
|
|
| 873 |
|
|
=head2 There is no approval dialog |
| 874 |
|
|
|
| 875 |
|
|
First check whether the tool was denied by a saved rule or is waiting for |
| 876 |
|
|
the client's own approval. An allowed operation needs no server prompt. |
| 877 |
|
|
|
| 878 |
|
|
The default helper runs on the server machine. A background service may |
| 879 |
|
|
have neither a usable display nor C</dev/tty>, even though your interactive |
| 880 |
|
|
shell has both. Supply the appropriate display environment, a usable helper, |
| 881 |
|
|
or C<--ask auto> with a modern client supporting form elicitation. |
| 882 |
|
|
C<--ask mcp> reports an error if that support is absent. |
| 883 |
|
|
|
| 884 |
|
|
Setting an asking mode cannot make an unsupported client display a form. |
| 885 |
|
|
Check stderr and the tool error instead of assuming a missing dialog is |
| 886 |
|
|
an approval. |
| 887 |
|
|
|
| 888 |
|
|
=head2 It asks again after I chose allow |
| 889 |
root |
1.1 |
|
| 890 |
root |
1.5 |
Allow-once covers one tool invocation, including its permission retries. |
| 891 |
|
|
The next invocation asks again. Use allow-always to save a rule. |
| 892 |
root |
1.1 |
|
| 893 |
root |
1.5 |
Inspect the saved rule's action, workdir and grants. Listing names and |
| 894 |
|
|
reading contents are different actions. A rule for one exact workdir |
| 895 |
|
|
spelling will not match a differently spelled startup argument. |
| 896 |
|
|
A request for extra authority, such as networking, does not match a |
| 897 |
|
|
workdir-read-only allow rule. Earlier ask or deny rules take precedence. |
| 898 |
root |
1.1 |
|
| 899 |
root |
1.5 |
Confirm that the prompt's permanent rule was successfully saved and that |
| 900 |
|
|
you are editing the rules for the actual child name, not merely its |
| 901 |
|
|
multibroker prefix. |
| 902 |
root |
1.1 |
|
| 903 |
root |
1.5 |
=head2 The worker cannot see a directory or executable |
| 904 |
root |
1.1 |
|
| 905 |
root |
1.5 |
The worker sees granted mounts and trusted baseline mounts, not everything |
| 906 |
|
|
the server process can see. Check C<workdirs> for the selected path, mounts |
| 907 |
|
|
and runtime paths. A symlink target outside those mounts is unavailable. |
| 908 |
root |
1.1 |
|
| 909 |
root |
1.5 |
For tools or libraries under C</opt>, add an appropriate trusted mount |
| 910 |
|
|
as shown earlier and restart mcp-fs. A configured executable path alone |
| 911 |
|
|
does not mount the executable or its dependencies inside the worker. |
| 912 |
|
|
A trusted mount supplies baseline access to every worker using it; a |
| 913 |
|
|
writable mount likewise supplies baseline write authority. |
| 914 |
root |
1.1 |
|
| 915 |
root |
1.5 |
An arbitrary command might also need its user's configuration or repository |
| 916 |
|
|
credentials under HOME, or network access. Request the corresponding grants |
| 917 |
|
|
when needed; do not assume C<workdir-read> includes them. |
| 918 |
root |
1.7 |
For example, CVS over SSH can use C<workdir-read> and C<ssh-agent>. |
| 919 |
|
|
The latter includes network access, the agent socket and C<~/.ssh/known_hosts>, |
| 920 |
|
|
without exposing private key files or the rest of HOME. The broker must |
| 921 |
|
|
inherit C<SSH_AUTH_SOCK> from your environment. User-configured helpers |
| 922 |
|
|
outside the runtime mounts need an explicit trusted mount. |
| 923 |
|
|
An explicit exec grant array replaces the default rather than adding to it. |
| 924 |
root |
1.1 |
|
| 925 |
root |
1.5 |
=head2 My configuration change seems to be ignored |
| 926 |
root |
1.1 |
|
| 927 |
root |
1.5 |
Check which file and section the process actually selects. Global settings |
| 928 |
|
|
use the server user's C<HOME>/C<XDG_CONFIG_HOME>. Instance names, program |
| 929 |
|
|
basenames and multibroker prefixes serve different purposes. |
| 930 |
root |
1.1 |
|
| 931 |
root |
1.5 |
Restart after changing startup settings, mounts or utilities. Permission |
| 932 |
|
|
rules need no restart, but their order still matters. Refresh discovery |
| 933 |
|
|
after a child restart; reconnect a client that retains an old tool list. |
| 934 |
|
|
C<--print-url> reads the current configuration, which can differ from an |
| 935 |
|
|
older running process. |
| 936 |
root |
1.1 |
|
| 937 |
root |
1.5 |
=head2 The command failed, but the MCP request succeeded |
| 938 |
root |
1.1 |
|
| 939 |
root |
1.5 |
C<exec> reports exit status, signal or timeout as a normal tool result. |
| 940 |
|
|
A successful MCP exchange is not a successful Unix command. |
| 941 |
|
|
Conversely, a transport failure does not prove a command did nothing: |
| 942 |
|
|
it may have completed before the connection was lost. Calls are not |
| 943 |
|
|
automatically replayed after a transport failure. |
| 944 |
root |
1.1 |
|
| 945 |
root |
1.11 |
=head1 TESTING |
| 946 |
|
|
|
| 947 |
|
|
The default test level is 0. It checks protocol behaviour, permissions, |
| 948 |
|
|
validation and ordinary process operation, including worker cancellation |
| 949 |
|
|
and reaping. Watchdogs allow slow machines time to finish; they do not |
| 950 |
|
|
make successful tests wait for the whole timeout. |
| 951 |
|
|
|
| 952 |
|
|
prove -Ilib t |
| 953 |
|
|
|
| 954 |
|
|
Set C<PERL_ANYEVENT_MCP_TESTS> to 1 to include the extended tests: |
| 955 |
|
|
|
| 956 |
|
|
PERL_ANYEVENT_MCP_TESTS=1 prove -Ilib t |
| 957 |
|
|
|
| 958 |
|
|
Level 1 adds GNU find/grep/sed/patch operations, real Vim scripting, browser |
| 959 |
|
|
transfer integration, short idle-lifetime tests, a helper descendant holding |
| 960 |
|
|
a pipe open, and tests which deliberately wait for a command timeout or |
| 961 |
|
|
cancel a form helper across several processes. Run this level before releases. |
| 962 |
|
|
Values greater than 1 currently select the same tests as level 1. |
| 963 |
|
|
|
| 964 |
|
|
Missing GNU utilities or required Vim functions cause explicit skips even |
| 965 |
|
|
at level 1. The permission and form UI tests use a YAD stand-in: neither |
| 966 |
|
|
level requires YAD, X11 or an interactive display. The filesystem tests |
| 967 |
|
|
use a bubblewrap stand-in and check arguments and worker behaviour; they |
| 968 |
|
|
do not test kernel isolation. The browser tests use simulated peers. |
| 969 |
|
|
|
| 970 |
root |
1.5 |
=head1 WHERE TO GO NEXT |
| 971 |
root |
1.1 |
|
| 972 |
root |
1.5 |
For available tools and server-specific options: |
| 973 |
root |
1.1 |
|
| 974 |
|
|
perldoc mcp-fs |
| 975 |
|
|
perldoc mcp-multibroker |
| 976 |
root |
1.5 |
perldoc mcp-vim |
| 977 |
|
|
perldoc mcp-ask-user |
| 978 |
root |
1.1 |
perldoc anyevent-mcp |
| 979 |
|
|
|
| 980 |
root |
1.5 |
For a complete first Perl server, options, replies, permission checks and |
| 981 |
|
|
asynchronous work, see L<AnyEvent::MCP::Server::Simple/TUTORIAL>. |
| 982 |
|
|
For the module map and shared configuration reference, see L<AnyEvent::MCP>. |
| 983 |
|
|
For permission rule details, see L<AnyEvent::MCP::Server::Permissions>. |
| 984 |
root |
1.1 |
|
| 985 |
|
|
=head1 SEE ALSO |
| 986 |
|
|
|
| 987 |
|
|
L<AnyEvent::MCP>, L<AnyEvent::MCP::Server::Simple>, |
| 988 |
root |
1.5 |
L<mcp-fs>, L<mcp-multibroker>, L<mcp-vim>, L<mcp-ask-user>, |
| 989 |
|
|
L<AnyEvent::MCP::Server::Permissions> |
| 990 |
root |
1.1 |
|
| 991 |
|
|
=cut |