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