avo-mcp-terminal
v0.1.1
Published
Sandboxed filesystem/terminal tools for agents, exposed both as a real MCP stdio server and as a human-relay TUI (copy/paste bridge) for agents with no direct tool access.
Downloads
45
Readme
mcp-terminal
Sandboxed filesystem + shell tools for agents, exposed two ways from one shared tool registry:
npm run mcp— a real MCP server (stdio) for clients that can connect directly (Claude Code, Claude Desktop, any MCP-speaking agent).npm run relay— a local web page for agents with no direct tool access (a plain chat session): it hostswindow.__mcpToolsand imports the same<human-mcp-relay>popup used by htmlpaint.com/mindfoo (human-mcp-relay.js, loaded live from--relay-url, defaulthttps://htmlpaint.com/human-mcp/relay.js) — copy a primer into the chat, pasteHUMAN-MCP CALLblocks back into the popup, no new UI to learn if you've used that popup before.
Both modes share one ToolRegistry (src/tools/registry.ts), so the tool
set and its safety envelope are identical either way.
Tools
| Tool | Description |
|---|---|
| list_dir | List entries in a directory, optionally recursive |
| stat | Check whether a path exists and get its type/size/mtime, without reading it |
| read_file | Read a text file (paginated via offset) |
| read_files | Read many text files in one call, given a list of paths |
| write_file | Overwrite/create a text file |
| write_files | Overwrite/create many text files in one call (a whole tree at once) |
| apply_patch | Apply a unified diff (diff -u/git diff style) to one or more files. Good for small, precisely-counted hunks; for large or repeatedly-failing patches, fall back to read_file + write_file with the full new content instead of hand-counting hunk lines |
| mkdir | Create a directory (like mkdir -p) |
| move_path | Move/rename a file or directory |
| delete_path | Delete a file or directory (irreversible) |
| find_files | Find files by glob-ish name pattern |
| grep | Search file contents by substring/regex |
| run_command | Run a shell command — scaffolding, installs, builds, tests, git. Disabled by default. |
Safety
- Sandbox jail: every path tool resolves through
src/sandbox.ts, which rejects any path (relative.., absolute, or via a symlink) that resolves outside the sandbox root. The root defaults to the directorymcp-terminalwas started in and is only settable via--dirat launch — never by a tool call — so a confused or adversarial agent can't widen its own jail mid-session. run_commandis opt-in: it's the one tool that can do real damage or reach outside the file sandbox's guarantees (network access, arbitrary binaries). It throws immediately unless the process was started with--allow-exec. Output is capped (100 KB) and time-limited (default 60s, max 10 min) so a hanging/runaway command can't wedge the session.delete_path/move_path/write_file/write_files/apply_patch/run_commandare flaggeddestructive: truein the tool manifest so any UI (or client policy) can surface a confirmation step before calling them.- Every session's first message to the agent (the MCP
instructionsfield, or__mcpSummaryin relay mode) states the host OS, shell, node version, and sandbox root up front — the agent shouldn't need a probing round-trip to find out it's on macOS vs. Linux before proposing a command.
Run it
Via npx
Direct MCP (stdio) only — point an MCP client at this command:
npx avo-mcp-terminal --dir ./my-project --allow-exec(Relay mode isn't part of the published package yet — run it from a clone of this repo, below.)
From this repo
npm install
# Direct MCP (stdio) — point an MCP client at this command:
npm run mcp -- --dir ./my-project --allow-exec
# Human relay — opens a browser tab, paste primer into chat:
npm run relay -- --dir ./my-project --allow-execFlags (both entry points):
--dir <path>— sandbox root (default: cwd)--allow-exec— enablesrun_command(default: disabled)--relay-url <url>— where to import the relay popup from (relay mode only; defaulthttps://htmlpaint.com/human-mcp/relay.js)--port <n>— relay server port (relay mode only, default 8799)--no-open— don't auto-open a browser tab (relay mode only)
How the relay mode works
relay-server.tsstarts a local HTTP+WS server and serves one page.- The page's
client.jsfetches/manifest.json(the tool registry minusfn) and buildswindow.__mcpTools, wiring each tool'sfnto a WebSocket round-trip back into the Node process — same contractjs-bridge-mcpandmindfoo'smcpbridge.tsuse, just server-backed instead of DOM-backed. - The page then dynamically imports the relay popup from
--relay-url(unmodified — it's already host-agnostic, reading onlywindow.__mcpTools/__mcpSummary/document.title). - Open the popup (
Cmd/Ctrl+Shift+A), copy the primer into your agent chat, pasteHUMAN-MCP CALLblocks back as the agent sends them.
No multi-tenant/WebSocket-tenant-id machinery is needed here (unlike
js-bridge-mcp) — this server only ever serves one page to one local user.
