TerminalMCP
TerminalMCP gives an AI agent full control of a machine—shell, filesystem, git, browser, desktop, and more—with token-efficient batching and server-side state.
Run commands:
shell_execfor short tasks;shell_exec_async/shell_jobfor long-running background jobs;shell_bulkruns many commands in one call with conditions, retries, and output controls.Manage files: read/write/edit files, list directories, copy/move/delete, archive (zip/tar/gz), and search text or filenames across trees.
Work with git: status, log, diff, commit, branches, merge, push/pull, and more through a compact
gittool.Inspect the system: hardware info, processes, disk usage, environment variables, and network probes (DNS, ports, ping).
Use HTTP: make requests, test APIs, assign responses to variables.
Understand projects: package manager detection, dependency/framework analysis, code outlines, TODOs, and language stats.
Manipulate data: JSON queries/patches, diffs and patch application, encodings, hashes, UUIDs, JWT decoding.
Automate a browser: launch/attach to Chrome-family browsers, navigate, snapshot pages as actionable elements, click/type/fill, screenshots, PDFs, downloads, console/network logs.
Control the desktop: capture screen (full/monitor/window/region), view images, simulate mouse/keyboard input, and batch input sequences with screenshots.
Carry state: store variables server-side, reuse them via
${vars.…}, including secrets that are never echoed.Extend via plugins: optional Discord, Telegram, and FiveM integrations for messaging and game-server management.
Choose tool profiles: pick which tool groups to expose to save tokens; run over stdio or HTTP (with MCP streamable/SSE support).
Apply guardrails: read-only mode, allowed roots, deny lists, and audit logging for safer operation.
Provides an optional plugin for reporting work results to Discord, enabling the agent to send messages and updates to a Discord server.
Provides a plugin for FiveM game servers, allowing server status checks, resource management via RCON or txAdmin, and reading client-side F8 console errors.
Provides an optional plugin for sending messages and files to Telegram, and can block waiting for replies so a question costs a single call.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@TerminalMCPrun npm ci, then tests, then build in this repo — stop and show me logs if tests fail"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
TerminalMCP
Give your AI agent a real terminal — and stop paying for it in tokens.
A zero-dependency MCP server that hands an AI complete control of a machine — shell, filesystem, git, package managers, processes, network, a real browser and the screen itself — plus optional plugins for the places that work actually gets reported: Discord, Telegram, and FiveM servers. Built so the whole thing costs a fraction of the tokens a naive tool server burns.
git clone https://github.com/Fonlogen/TerminalMCP && cd TerminalMCP
./start.sh --doctor # or: start.cmd --doctor on WindowsNo npm install. No build step. No dependencies. Just Node 18+.
The problem this solves
Most shell MCP servers expose run_command and stop there. That works, and it
is ruinously expensive, because of something easy to miss:
Tool schemas are re-sent to the model on every single request.
On this server's full profile that is ~11,500 tokens of JSON schema per call. An agent that runs five commands one at a time pays it five times — roughly 57,000 tokens of schema, where one batched call would have spent 11,500 — plus the whole conversation, re-sent five times instead of once. The five commands themselves were under 600 bytes.
So token efficiency here is not a nice-to-have that got bolted on. It is the constraint the whole design answers:
Naive approach | TerminalMCP | |
Five commands in sequence | 5 round-trips | 1 ( |
Find a symbol in a repo | read the files |
|
Change 3 lines of a 2,000-line file | rewrite the file |
|
Understand an unfamiliar repo | a dozen | 1 ( |
Reuse a value from an earlier step | re-send it every time |
|
Find the button on a web page | read the page's HTML |
|
Tools you don't need this session | pay for them anyway |
|
Everything else — 28 tools, two transports, cross-platform shells — exists so the agent never has to fall back to an expensive pattern to get something done.
Related MCP server: vps-mcp-server
Quick start
1. Check the environment
./start.sh --doctor # Linux / macOS / Git Bash / WSL
start.cmd --doctor # Windows--doctor reports the platform, which shells it found, the working directory,
the active limits and what the current tool profile costs per request.
2. Register it with your client
node bin/terminalmcp.js --print-configThat prints ready-to-paste snippets with the correct absolute path. In short:
claude mcp add terminal -- node "/absolute/path/to/TerminalMCP/bin/terminalmcp.js"{
"mcpServers": {
"terminal": {
"command": "node",
"args": ["C:\\path\\to\\TerminalMCP\\bin\\terminalmcp.js"],
"env": { "TERMINALMCP_SHELL": "gitbash" }
}
}
}{
"servers": {
"terminal": {
"type": "stdio",
"command": "node",
"args": ["/path/to/TerminalMCP/bin/terminalmcp.js"]
}
}
}3. Install the skill (optional, recommended)
npm run install-skill # → ~/.claude/skills/terminalmcp
node scripts/install-skill.mjs --project # → ./.claude/skills/terminalmcpThe bundled skill teaches the model how to use the server cheaply — which tool to reach for, when to batch, how to avoid reading whole files. Without it the tools still work; with it they get used well.
What this makes possible
Concrete things that are awkward or impossible with a bare run_command:
Autonomous build-test-fix loops. shell_bulk runs a whole pipeline with
conditions and retries in one call, so the agent plans the sequence up front
instead of narrating it step by step:
{
"cwd": "/srv/app",
"capture": "on_failure",
"steps": [
{ "id": "deps", "command": "npm ci" },
{ "id": "test", "command": "npm test", "timeout_ms": 600000 },
{ "id": "build", "command": "npm run build", "when": "step.test.ok" },
{ "id": "deploy", "command": "./deploy.sh",
"when": "step.build.ok", "retry": { "count": 2, "delay_ms": 5000 } },
{ "id": "smoke", "command": "curl -fsS localhost:8080/health",
"when": "step.deploy.ok", "delay_before_ms": 3000,
"retry": { "count": 5, "delay_ms": 2000 } }
]
}capture: "on_failure" means: silence while everything passes, full output
exactly where it broke.
Running dev servers and long builds without blocking. Start it in the background, then read new output with a single blocking call instead of a polling loop:
shell_exec_async { command: "npm run dev", name: "dev" } → job_id=job1
shell_job { action: "output", job_id: "job1", wait_ms: 30000, offset: 4096 }Driving a remote machine. The same server speaks HTTP, so an agent can operate a build box, a NAS or a VPS from anywhere on your network.
Working in repos it has never seen. project_info returns languages,
package manager, dependencies, frameworks, scripts, entry points, likely
test/build commands and git state in one call.
Carrying state between calls. Capture a value once and reference it forever, without it travelling back through the conversation:
shell_exec { command: "git rev-parse --short HEAD", assign: "sha" }
shell_exec { command: "docker build -t app:${vars.sha} ." }Using secrets without exposing them. A variable marked secret: true works
everywhere ${vars.…} works but is never echoed back — not in listings, not in
results, not in the audit log.
Testing the web app it just changed. It drives a real browser over the DevTools Protocol — the same protocol Playwright is built on, with no driver to install and no browser to download — and reads a page as a short list of things it can act on rather than as HTML:
browser { action: "launch", url: "localhost:3000" }
browser { action: "snapshot" }
e4 email "Email" name=user placeholder="you@example.com"
e5 password "Password" name=pass
e8 button "Sign in"
browser { action: "fill", ref: "e4", text: "ada@example.com" }
browser { action: "fill", ref: "e5", text: "hunter2", press_enter: true }
browser { action: "screenshot" } it can see the result
browser { action: "console", level: "error" } and read what the page complained aboutOr attach to the browser already open on the desktop — its profile, its
extensions, its logged-in sessions. No extension to install: start Chrome once
with --remote-debugging-port=9222 and the agent can drive the session you are
already signed into.
Seeing what is on the screen. Desktop capture, for everything that is not a
web page — a native app, an installer, a chart in a viewer — plus view, which
turns any image already on disk into something the model can actually look at:
screen { action: "shot" } the whole desktop
screen { action: "shot", mode: "window", window: "Figma" } one window
screen { action: "shot", mode: "region", x: 0, y: 0, width: 900, height: 240 }
screen { action: "view", path: "designs/mockup.png" }Acting on what you see. Some software has no other way in: an installer
with no silent switch, a launcher, a native dialog, a legacy admin panel. The
loop is capture, decide, act, capture again — and shot: true makes the last
two one call:
screen { action: "windows" } what is open
input { action: "click", x: 812, y: 455, window: "Setup", shot: true }
input { action: "type", text: "D:\\Games\\server" }
input { action: "key", keys: "enter", shot: true }Once the coordinates are known, the whole sequence is one call:
input_bulk { window: "Setup", delay_ms: 150, steps: [
"click 812 455", "type D:\\Games\\server", "key enter",
{ action: "wait", ms: 1500 }, "shot" ] }Closing the loop with a person. The work is only finished when somebody
knows about it. Optional plugins put the result where they already are — and
wait blocks until they answer, so asking a question costs one call rather
than a polling loop:
screen { action: "shot", mode: "window", window: "Grafana" }
telegram { action: "send_file", path: ".terminalmcp/shots/…png", caption: "before the fix" }
telegram { action: "updates", wait: 120 } blocks until they replyRunning a game server. The fivem plugin answers "is it up and who is on
it" with no credentials at all, then drives the rest over RCON or txAdmin —
including the F8 client console, which is where client-side script errors
actually appear:
fivem { action: "status" }
fivem { action: "resource", resource: "esx_ambulancejob", op: "restart" }
fivem { action: "f8", errors: true }The four ideas that make it different
1. Batching — shell_bulk
One call, many commands, with real control flow. Each step supports:
Field | Effect |
| Name the step, so later steps can test |
| Run only if a condition holds |
| Which exit codes count as success — a number, an array, or |
|
|
|
|
| Wait for a service to come up |
| Capture the output into a variable, for later steps and later calls |
| How much output to return: |
| Per-step overrides |
Conditions are a real (if small) expression language, evaluated by a dedicated
parser — no eval, no access to arbitrary functions:
prev.ok the step before succeeded
prev.exit == 0 && contains(prev.stdout, "0 failing")
step.build.ok && !step.lint.ok by step id
steps[0].exit == 0 by position
vars.branch == "main"
failed_count == 0Shorthands: always, never, prev_success, prev_failure, all_success,
any_failure. Functions: contains, icontains, matches, empty,
exists, len, lines, first_line, last_line, int, num, lower,
upper, trim. Operators: == != > < >= <= && || !, plus =~ / !~ for
regex and and / or as words.
2. Server-side variables
Values the agent captures can stay on the server. Store once, reference as
${vars.<name>} in any later call — the value itself never returns to the
conversation.
vars { action: "set", name: "api", value: "https://api.example.com" }
vars { action: "list" } names, types, sizes — never full values
vars { action: "get", name: "api" }
vars { action: "load", name: "conf", path: "config.json", json: true }Three tools write straight into the store: shell_exec assign,
http_request assign, and per-step assign in shell_bulk.
${...} expands in commands, cwd, env values, stdin, file paths, URLs,
request headers, query params, git messages and refs, and every bulk step.
Deliberately not in file content, regex patterns or patch bodies — a
JavaScript template literal, a GitHub Actions workflow and a regex all
legitimately contain ${...}, and rewriting them silently would be worse than
asking. The eligible fields are declared in a single table
(src/tools/interpolate.js) rather than scattered
across handlers, so the expansion surface is auditable at a glance.
It does not fight the shell. ${...} is shell syntax too. Anything that
does not name a variable the server knows is passed through untouched, so
echo ${HOME}, ${PATH%%:*} and ${#arr} reach bash intact. A
${vars.typo} that looks like ours but matches nothing is passed through
literally and reported in the result, so a mistyped name reads as a mistake
rather than becoming a silent empty string.
3. Tool profiles
Since schemas cost tokens on every request, you choose how many you want to carry. Measured on this repo:
Profile | Tools | Schema tokens per request |
| 10 | ~4,800 |
| 18 | ~8,500 |
| 20 | ~9,200 |
| 17 | ~9,800 |
| 28 | ~13,900 |
node bin/terminalmcp.js --tools core # shell, jobs, bulk, files, vars
node bin/terminalmcp.js --tools dev # + search, git, fs, dev, data
node bin/terminalmcp.js --tools web # + browser, screen, net, search
node bin/terminalmcp.js --tools core,git,search # pick groups
node bin/terminalmcp.js --tools all,-browser # everything except onecore and vars are always included. --list-tools and --doctor print the
cost of every group, and shell_info reports it to the model at runtime — so
trimming is an informed decision rather than a guess. Nothing is ever lost:
whatever isn't exposed as a tool is still reachable through shell_exec.
4. Reading a web page without reading its HTML
Handing a model 400KB of markup to find a login button is the browser
equivalent of cat-ing a whole file to find one function. So the primary way
to read a page is snapshot: every element you can actually act on, named the
way a person would name it, each with a short ref.
browser { action: "snapshot" }
https://example.com/login — Example — Sign in
e1 h1 "Sign in to Example"
e2 link "Forgot your password?" -> /reset
e3 email "Email" name=user placeholder="you@example.com" required
e4 password "Password" name=pass
e5 select "Free Pro" name=plan options=["free","pro"]
e6 checkbox "Remember me" name=remember unchecked
e7 button "Sign in"Then click { ref: "e7" }. A few hundred tokens for a page instead of tens of
thousands — and it survives a redesign of the markup, which a hand-written CSS
selector does not. Refs live in the page itself, so navigating away invalidates
them and a stale ref says so rather than quietly clicking the wrong thing.
html is still there for when you genuinely need the markup, with
clean: true to drop scripts, styles and comments first.
The same logic applies to images. A vision model is billed by area — roughly
width × height / 750 tokens — so a raw 4K screenshot is about 11,000 tokens
and the same screenshot at 1200px wide is about 1,100 and just as readable.
Every capture is therefore scaled to max_width (1200 by default) before it is
returned, and the reply tells you what that cost:
viewport of http://localhost:3000/
saved .terminalmcp/shots/2026-04-11_18-22-03.png (184320 bytes, 1280x800)
1280x800 scaled to 1200x750, ~1200 image tokensTool reference
28 tools in 13 groups. Most use an action parameter rather than one tool per
verb — git alone would otherwise be twenty tools, and browser thirty.
core — always on
Tool | Purpose |
| Run a command and wait. Exit code, stdout, stderr. |
| Start a command in the background, return a |
|
|
| Many commands in one call, with delays, conditions, retries, variables. |
| Whole file, a line range, the tail, or only lines matching a regex. |
|
|
| Several surgical edits in one atomic call. |
| Directory listing with depth and glob filter. |
| Platform, shells, config, guardrails, active profile. |
vars — always on
Tool | Purpose |
|
|
search
Tool | Purpose |
| Grep a whole tree: regex or literal, matching lines with optional context. Skips |
| Find files and directories by glob, name, size or age. Sort by path, size or mtime. |
git
One tool, ~30 actions, compact output, plus action: "raw" for anything not
covered.
Read: status, log, diff, show, blame, branches, tags,
remotes, stash_list, file_history, current, root, config_get
Write: add, unstage, commit, checkout, branch_create,
branch_delete, merge, rebase, reset, revert, restore, stash,
stash_pop, tag_create, fetch, pull, push, apply, clean, init
git is invoked directly rather than through a shell, so a commit message
containing quotes, newlines or $ needs no escaping.
fs
Tool | Purpose |
|
|
archive
Tool | Purpose |
|
|
sys
Tool | Purpose |
|
|
|
|
net
Tool | Purpose |
| HTTP(S) client: status, timing, headers, body. JSON is pretty-printed, long bodies truncated. |
|
|
dev
Tool | Purpose |
| Drive whichever package manager the project actually uses, detected from its lockfile: npm, pnpm, yarn, bun, deno, pip, uv, poetry, pipenv, cargo, go, composer, bundler, maven, gradle, dotnet. Actions: |
| Orient yourself in an unfamiliar repository in one call. |
|
|
data
Tool | Purpose |
|
|
|
|
| base64 / hex / url / html encode and decode, |
watch
Tool | Purpose |
|
|
browser
One tool, thirty actions, driving Chrome / Chromium / Edge / Brave over the DevTools Protocol.
Group | Actions |
Lifecycle |
|
Tabs |
|
Navigation |
|
Reading |
|
Interaction |
|
Waiting |
|
Capture |
|
Files |
|
State |
|
Diagnostics |
|
Every element target accepts one of three things: ref from the last snapshot
(cheapest and sturdiest), selector for a CSS selector, or text to find an
element by what it says. Ambiguous text prefers the thing you can act on and
the innermost match, so text: "Sign in" picks the button rather than the
heading above it that says the same words.
Downloads
A download is the one thing a browser does that produces no page, which is why
it used to look broken: navigating to a file URL aborts its own navigation —
Chromium hands the bytes to the download manager and no document is ever
committed — so navigate reported a failure while the file was, in fact,
arriving.
browser { action: "download", url: "https://example.com/pack.zip" }
browser { action: "download", text: "Download release" } a link or button
browser { action: "download" } just wait for what the page started
browser { action: "downloads", wait: true }download blocks until the file is on disk and answers with its real name,
its size and its path. The point is the session: a file behind a login comes
down with the cookies the browser already has, which is the whole reason not to
reach for http_request. navigate now recognises a download too, instead of
reporting a navigation failure.
Files land in .terminalmcp/downloads (configurable with browser.downloadDir),
named by what the server suggested — sanitised, because a Content-Disposition
filename is attacker-controlled input, and never overwriting: a second
pack.zip becomes pack (2).zip.
Browsers are found automatically: the usual install locations per platform,
then $CHROME_PATH, then a Playwright or Puppeteer cache if you already have
one on disk. Nothing is downloaded.
screen
Tool | Purpose |
|
|
Captures are saved at full resolution and shown scaled to max_width, so the
file on disk stays the good copy while the reply stays cheap.
When every shot fails but displays and windows work
That combination is not a broken tool — it is the signature of a process that can see the desktop's furniture but not its pixels. Enumerating monitors and windows works from any session; copying pixels needs the interactive desktop, which a Windows service, a scheduled task, session 0 and an SSH/WinRM login do not have.
screen { action: "probe" }reports the window station (only WinSta0 can capture), the Windows session
id, the PowerShell version, and the result of a one-pixel test capture with the
exact exception — then tries a real 8×8 capture end to end. The fix is almost
always to start the server from a terminal inside your own logged-in session.
input
Tool | Purpose |
|
|
| A whole sequence of those, plus screenshots and waits, in one call — with delays between steps, conditions, retries and a capped set of images. |
Two things make it usable rather than merely present:
shot: truereturns a screenshot taken straight after the action, so one call both acts and shows the result. Acting blind and then capturing is two calls and a race.windowraises that window first. Input follows the focus, and the window that had focus is not always the one you meant — this is the difference between typing a path into an installer and typing it into somebody's chat.
input { action: "key", keys: "ctrl+shift+esc" } a chord
input { action: "key", keys: "alt+f x" } a sequence, in order
input { action: "key", keys: "w", hold_ms: 800 } held down, not tapped
input { action: "type", text: "città" } characters, not keystrokes
input { action: "drag", x: 100, y: 100, to_x: 400, to_y: 300 }readOnly blocks all of it. position and probe still answer.
input_bulk — a whole sequence in one call
What shell_bulk is to commands, input_bulk is to the mouse and keyboard.
Steps run in order and take every input action, plus shot (a screenshot,
any screen mode) and wait:
input_bulk {
window: "Notepad", raised once, before step 1 — if it cannot be, nothing is sent
delay_ms: 150, pause between steps (default 100): UIs need a beat
final_shot: "on_failure", a picture of where it broke
steps: [
"key ctrl+n",
"type Hello from TerminalMCP",
{ action: "key", keys: "ctrl+s", delay_after_ms: 800 },
{ id: "dlg", action: "shot", mode: "window", window: "Save as" },
"type C:\\temp\\hello.txt", "key enter"
] }Strings are shorthand:
"click 400 300","click","move 10 20","scroll -3","type …","key ctrl+s","focus Title","wait 500","shot","position".Delays:
delay_msbetween steps, and per stepdelay_before_ms/delay_after_ms, andwaitas a step of its own.Flow:
when,on_failure,retryandstop_on_failurework as inshell_bulk, readingprev.ok,step.<id>.ok,vars.<name>. Apositionstep exposesstep.<id>.x/.y, and numeric fields accept"${…}", so a later step can click where the pointer was.Checked before it starts: an unknown action, a misspelt key chord, a
typewith no text or adragwith no destination is refused before the first event is sent. So is the whole run underreadOnly, unless it only waits.Images are capped at
max_shots(default 4). Past the cap the oldest pictures are dropped first, and the report says which ones.
What "HID" does and does not mean here
Input is synthesised by the operating system — SendInput on Windows,
xdotool on X11, osascript or cliclick on macOS. Applications receive
those events through the same path as real ones and cannot tell the difference.
What they are not is physical. Software that reads raw HID and deliberately checks — which is what anti-cheat does — can refuse injected input, and no setting changes that. A game that ignores this needs a microcontroller presenting itself as a real USB keyboard, which is a different backend and not a flag. Everything that is not actively looking for injection works.
Wayland refuses input injection by design; there ydotool (pointer, via
/dev/uinput) and wtype (keyboard) are the way through, and probe says
which of them is installed. An X11 session needs only xdotool.
macOS: why the pointer does not go through AppleScript
The obvious route is tell application "System Events" to click at {x, y}, and
it is a trap. That is an accessibility command asking the application to click
for itself; when the coordinates resolve to no UI element it can simply never
answer. The Apple event sits there until something kills it — no error, no
refusal, nothing on stderr, and no TCC prompt. Granting Accessibility does not
change it, which is what makes it so hard to diagnose: every permission looks
correct and the call still hangs.
So the pointer goes through CGEventPost instead — the same path a real mouse
takes — reached with osascript -l JavaScript and the Objective-C bridge, which
ships with macOS. Nothing to install. cliclick is still used when it is
present, because it is battle-tested, but it is no longer required for moves or
drags.
Accessibility is still needed, and it belongs to the application that launched
the server — the terminal, the editor, the Claude app — not to node, which
merely inherits it. When the grant is missing, macOS does not refuse a posted
event: it drops it silently. probe therefore posts a one-pixel move and checks
whether the pointer actually moved, which is the only way to tell the two apart
from the outside.
Everything still on System Events — typing, key chords, raising a window — now
carries with timeout of, so a hung Apple event comes back as an error rather
than as twenty seconds of silence.
Every failure the Windows side can hit comes back named rather than as a
generic "capture failed": no interactive desktop, a temp directory that cannot
be written, a pwsh install without the Windows Desktop runtime, a minimized
window (pass activate: true), a title that matches nothing. And a web page
never needs a desktop at all — browser screenshot renders headlessly,
including the full scrolling page.
Optional plugins
Three integrations ship with the server and none of them are on by default. That is the same logic as tool profiles: a schema in the model's context costs tokens on every single request, and most sessions have no business talking to Discord.
node bin/terminalmcp.js --plugin discord
node bin/terminalmcp.js --plugin fivem --plugin telegramor in the config file:
{ "plugins": ["fivem", "telegram"] }A plugin is never part of all — naming it is what enables it. Once loaded it
behaves like any other group, so --tools all,-telegram still removes it, and
--doctor reports whether it is actually configured:
plugins
fivem server 10.0.0.5:30120, rcon password set, txAdmin http://10.0.0.5:40120 (env token)
telegram token set (…4f2a), default chat -1001234567890Credentials
Secrets never have to live in the config file. Any string value may be written
"env:NAME" and is read from that environment variable instead:
{
"plugins": ["telegram"],
"pluginConfig": {
"telegram": { "token": "env:TELEGRAM_BOT_TOKEN", "defaultChat": "-1001234567890" }
}
}An unset variable is reported as not configured, with instructions — not as a mysterious 401 three calls later.
Every plugin registers its secrets with a redactor, and everything it returns
passes through it. This matters more than it sounds: the Telegram Bot API puts
the token in the URL, so a naive error message publishes it to the
transcript and the audit log. Here it comes back as <redacted>, and there is a
test that fails if it ever does not.
fivem — FiveM / RedM servers
Four different things get called "the console", and the plugin is explicit about which is which.
Action | What it uses |
| The public |
| The resource's own |
| RCON — the Quake-style UDP protocol, implemented here by hand. Needs |
| The game client's |
| The optional bridge resource (below). |
| txAdmin. |
inspect: which files of a resource can actually be read
Most paid FiveM resources ship through Cfx.re asset escrow. The scripts are
encrypted, the server decrypts them at runtime, an .fxap file sits in the
resource root, and the manifest lists under escrow_ignore the files the author
left in the clear — normally the config and whatever is meant to be edited.
That list is the entire readable surface of the resource, and nothing about
reading the rest fails: file_read succeeds, bytes come back, and thousands of
tokens buy ciphertext. search_text across the folder is worse, because it
reads every encrypted file to match nothing.
fivem { action: "inspect", resource: "esx_policejob" }
fivem { action: "inspect" } every resource under the cwd, at a glanceesx_policejob — ESCROWED
D:\Server\resources\[esx]\esx_policejob
fxmanifest.lua, fx_version cerulean, game gta5
an .fxap file is present; escrow_ignore lists 3 pattern(s); it depends on '/assetpacks'
readable — 5 file(s):
config.lua 4.7 KB
client/cl_open.lua 1.0 KB
…
encrypted — 4 script(s), do not read:
client/cl_main.lua, server/sv_main.lua, …It distinguishes ESCROWED — an .fxap is present, so this build really is
encrypted — from ESCROW-READY, where the manifest declares escrow_ignore but
no .fxap is there, which is what the source copy looks like and is entirely
readable. Claiming the first when it is the second would send someone hunting
for ciphertext that does not exist, so it says which one it found and how to
settle it.
The skill tells the model to run this before opening any file of a resource.
Two honest notes rather than marketing:
If TerminalMCP started the FXServer, don't use RCON.
shell_exec_async+shell_jobgives you its real stdout and stdin — nothing to lose to a dropped datagram, and you can type into it. The plugin says so in its own error messages.Only
/host/statusis a documented txAdmin API. The othertx_*actions drive txAdmin's own panel interface, which can change between versions. They work, they are tested against the shapes txAdmin's source actually uses, and they will tell you plainly when a version has moved underneath them.
Typing into a player's F8 console is not something any remote protocol can
do — so an optional in-game resource ships in
plugins/fivem/resource/. Install it and f8_exec
runs a command in a chosen player's console for real, while client_lua and
server_lua evaluate Lua and hand back the value:
fivem { action: "client_lua", player: "3", lua: "GetEntityCoords(PlayerPedId())" }Read its README before installing it. It grants arbitrary Lua execution on your server and on connected clients to whoever holds its secret. That is the feature, and it is not for every server.
One thing to know because it is the easiest way to lose an afternoon: FiveM
routes an HTTP request to a resource by the first path segment, which is the
resource's folder name — not the name in fxmanifest.lua. If you install
the bridge under a different folder name, set bridge.resource to it.
fivem { action: "bridge" } reads the server's own resource list when it
cannot connect, and tells you which name to use.
discord
Works with a bot token, a webhook URL, or both. A webhook needs no application and no permissions but can only post; a bot can read, edit, react and list.
discord { action: "send", text: "Deploy finished: 3 services updated" }
discord { action: "upload", path: "build.log", caption: "the failure" }
discord { action: "read", limit: 20 }
discord { action: "wait", wait: 60 } blocks until someone replies@everyone and role pings are suppressed unless you pass mentions: true.
A tool that can ping four thousand people by accident is a bad tool.
Rate limits are handled: a 429 is answered by waiting exactly as long as Discord asks, once.
telegram
telegram { action: "send", text: "Backup finished, 4.2GB in 6m12s" }
telegram { action: "send_file", path: "shot.png", caption: "the dashboard" }
telegram { action: "updates", wait: 60 }updates uses Telegram's own long polling, so it returns the instant a message
arrives rather than on a timer, and the read offset is kept server-side — each
message reaches you exactly once.
Writing your own
A plugin is an ES module exporting TOOLS and createHandlers — the same
shape as src/tools/*.js. There is no plugin API to learn beyond
that. Point at it by path:
{ "plugins": ["./my-plugins/jira.js"] }Two extras are worth declaring. MUTATING_ACTIONS lists the actions that
change something outside this machine, and readOnly then refuses them
centrally rather than in each handler. describe() returns the one line
--doctor prints, so "is this thing configured" is answerable without making a
call.
A plugin that fails to load is reported on stderr and skipped. It never stops the server — everything else on the machine still works.
Transports
stdio (local, default)
The normal way to run an MCP server. Your client spawns the process and talks over stdin/stdout.
HTTP (remote)
The same server can run as a network service. There is no authentication — see Security before exposing it.
./start-http.sh # 0.0.0.0:8787, reachable from other machines
start-http.cmd # same, on Windows
PORT=9000 ./start-http.sh
./start.sh --http # local only (127.0.0.1:8787)
node bin/terminalmcp.js --http --host 0.0.0.0 --port 8787Both MCP HTTP transports are served at once, so current and older clients work against the same port:
Method | Path | Purpose |
|
| Streamable HTTP (MCP 2025-03-26 / 2025-06-18) |
|
| SSE stream for server-initiated messages |
|
| End the session |
|
| Legacy HTTP+SSE (MCP 2024-11-05) handshake |
|
| Legacy message channel |
|
| Status, tools, sessions, running jobs, as JSON |
claude mcp add --transport http terminal http://<ip>:8787/mcp
curl http://<ip>:8787/health
node bin/terminalmcp.js --print-config --http --host 0.0.0.0Sessions. initialize issues an Mcp-Session-Id, returned as a header and
echoed back by the client. Each session keeps its own negotiated protocol
version, so clients on different MCP revisions can talk to one server
simultaneously. Idle sessions expire after 30 minutes. By default an unknown
session id is still served rather than 404'd — nothing here is authenticated,
so strictness would only break clients that forget the header; --strict-sessions
turns that on.
Shared state, deliberately. Jobs and variables are shared across sessions, because this server drives one machine: a job started by one client stays readable from another, and from the same client after a reconnect.
Long commands. HTTP-level timeouts are disabled, so a ten-minute command
isn't cut off. Behind a reverse proxy that closes idle responses, add
--sse-replies for keepalive comments — though shell_exec_async plus
shell_job is the better answer regardless.
Configuration
Precedence, strongest first: per-call parameters → TERMINALMCP_* environment
variables → config file → defaults.
The config file is looked up in this order:
$TERMINALMCP_CONFIG./terminalmcp.config.json./.terminalmcp.json~/.terminalmcp/config.json
cp terminalmcp.config.example.json terminalmcp.config.json// comments and trailing commas are tolerated.
Choosing a shell
"auto" picks the system default: pwsh → powershell → cmd on Windows,
$SHELL then bash → zsh → sh elsewhere.
Value | Shell |
| Bash (finds Git Bash on Windows) |
| Git Bash, Windows only |
| The respective POSIX shells |
|
|
| Windows PowerShell 5.x |
| PowerShell 7+ |
| bash inside WSL |
| any absolute path |
Custom shells can be named and then selected per call:
{
"shells": {
"docker": { "command": "docker", "args": ["exec", "-i", "web", "sh", "-c"] }
}
}On Windows, cmd and PowerShell commands run via a temporary script file, so
multi-line scripts and quoting behave the way you expect.
Main options
Field | Default | Meaning |
|
| Shell to use. |
|
| Use a login shell ( |
| start dir | Default working directory. |
|
| Per-command timeout. Kills the whole process tree. |
|
| Byte cap per returned stream (~4 bytes per token). |
|
| In-memory buffer per stream for background jobs. |
|
| Environment variables injected into every command. |
|
| Keep ANSI colour codes (they cost tokens). |
|
| Concurrent background jobs. |
|
| How long finished jobs stay readable. |
|
| Tool profile — see Tool profiles. |
|
| Optional plugins to load — see Optional plugins. Never implied by |
|
| Per-plugin settings, keyed by name. |
|
| Mirror the variable store to this file so it survives a restart. |
|
| Also write |
|
| Variable store limits. |
|
| Path to a Chromium-family binary. |
|
|
|
|
| Profile directory, so logins survive between runs. |
|
| Window and viewport size for browsers we launch. |
|
| What to do with |
|
| Where the browser puts downloads, so the file tools can find them. |
|
| Extra browser command-line flags. |
|
| Where captures are saved. |
|
| Scale images to this width before returning them. The real token dial. |
|
| Refuse to return an image larger than this. |
Command-line options
node bin/terminalmcp.js --help--cwd, --shell, --config, --timeout-ms, --max-output-bytes,
--login, --tools, --vars-file, --persist-secrets, --max-vars,
--max-var-bytes, --read-only, --allowed-root, --log-file.
Browser and screen: --browser-path, --no-headless, --shots-dir,
--max-image-width.
Plugins: --plugin <name|path>, repeatable.
HTTP: --http, --host, --port, --path, --no-cors, --strict-sessions,
--sse-replies, --max-body-bytes.
Commands: --doctor, --print-config, --list-tools, --help, --version.
Environment variables
TERMINALMCP_SHELL, TERMINALMCP_CWD, TERMINALMCP_TIMEOUT_MS,
TERMINALMCP_MAX_OUTPUT_BYTES, TERMINALMCP_LOGIN, TERMINALMCP_KEEP_ANSI,
TERMINALMCP_READ_ONLY, TERMINALMCP_LOG_FILE, TERMINALMCP_ALLOWED_ROOTS,
TERMINALMCP_CONFIG, TERMINALMCP_TOOLS, TERMINALMCP_VARS_FILE,
TERMINALMCP_BROWSER_PATH, TERMINALMCP_BROWSER_HEADLESS,
TERMINALMCP_SHOTS_DIR, TERMINALMCP_PLUGINS, TERMINALMCP_HTTP,
TERMINALMCP_HTTP_HOST, TERMINALMCP_HTTP_PORT, TERMINALMCP_HTTP_PATH,
TERMINALMCP_HTTP_CORS.
Plugins also read their own conventional variables when the config says so:
TELEGRAM_BOT_TOKEN, DISCORD_BOT_TOKEN, DISCORD_WEBHOOK_URL,
FIVEM_RCON_PASSWORD, TXADMIN_PASSWORD, TXHOST_API_TOKEN,
FIVEM_BRIDGE_SECRET.
Security
Be clear-eyed about what this is. TerminalMCP gives an AI the same privileges as the user account running it. There is no sandbox, and that is the point — a sandboxed terminal cannot install a dependency, restart a service or read a log. Run it where you would be comfortable handing someone a shell.
Network exposure
The library default binds 127.0.0.1, because opening up should be a
deliberate act. start-http.sh / start-http.cmd bind 0.0.0.0 — they exist
for remote use — and the server says so loudly at startup.
There is no authentication, so the port is the credential. Two cheap measures that change a lot:
Keep it off the public internet. A LAN, a VPN (Tailscale, WireGuard) or an SSH tunnel is enough:
ssh -L 8787:127.0.0.1:8787 user@host, then point the client athttp://127.0.0.1:8787/mcpwhile the server stays bound to localhost.On an untrusted network, put a reverse proxy (Caddy, nginx) in front with TLS and Basic Auth. The server neither knows nor cares.
The browser and the screen deserve their own thought
Two of the newer capabilities reach further than a shell does, and it is worth knowing exactly how far.
browser attachinherits a real session. Attaching to a browser you started with--remote-debugging-portgives the agent that browser's profile: your cookies, your logged-in accounts, your extensions. It can act as you on every site you are signed into. That is precisely why the feature is useful, and precisely whyattachshould be a decision you make rather than a default.launchis the safer sibling — a throwaway profile that is signed into nothing.A screenshot captures whatever is on the screen, including windows that have nothing to do with the task: a password manager, somebody else's chat, a medical record.
mode: "region"andmode: "window"exist so a capture can be narrow on purpose.readOnlyblocksbrowser launch(it starts a process) and blocks writing captures to disk, but it cannot police what a page does once it is open.macOS will ask for permission the first time: Screen Recording for captures, Accessibility for listing windows. Nothing can be captured until you grant it, and the error says so rather than returning a black image.
The
screentool needs a desktop, and on Windows specifically the interactive one: a service or an SSH login can list windows but not copy pixels.screen { action: "probe" }says which case you are in. On a server, in a container or over plain SSH there is nothing to capture, and it says so — browser screenshots still work there, because they render headlessly.
Plugins reach outside the machine
A shell command affects this computer. Sending a Discord message, kicking a player or restarting a game server affects other people, and cannot be undone by deleting a file.
Each plugin declares which of its actions mutate, and
readOnlyrefuses exactly those while leaving the read-only ones working. So--read-onlygives you a server that can look at your Discord, your Telegram and your game server without being able to say or break anything.allowedChannels,allowedChatsand the FiveMallowCommands/denyCommandslists narrow what is reachable at all. A refusal is reported asPolicy: …so the model knows it was a deliberate setting rather than a bug to route around.Discord pings are suppressed unless explicitly allowed.
Plugin secrets are registered with a redactor and scrubbed from every result and every error, including the audit log.
Optional guardrails
All off by default, because the server's purpose is unrestricted access. Turn them on to narrow capability rather than network:
Field | Effect |
| File tools cannot leave these directories — symlink escapes included. |
| Regexes; a matching command is refused. |
| Regexes; a matching write is refused. |
| Blocks all writes and all command execution. |
| Appends one JSONL audit line per tool call. |
A refusal reaches the model as Policy: …, so it understands this is an
operator decision rather than an error to route around. Guardrails apply
uniformly: a git write and a pkg install pass through the same gates as
shell_exec, not around them.
Handling of secrets
A variable marked secret: true is usable via ${vars.…} but never returned:
listings show (secret), get masks it unless reveal: true, the audit log
records <secret>, and it is not written to the store file unless
persistSecrets is explicitly enabled.
Architecture
bin/terminalmcp.js CLI: arguments, --doctor, --print-config, startup
src/server.js JSON-RPC 2.0, MCP methods, sessions, audit log
src/http.js HTTP transport: Streamable HTTP + legacy HTTP+SSE
src/exec.js spawning, timeouts, process-tree kills, buffering
src/jobs.js background job registry
src/bulk.js sequential runner: conditions, retries, variables
src/expr.js the mini-language for `when` and `${...}`
src/vars.js variable store: TTL, caps, secrets, atomic persistence
src/diff.js line diff (LCS) and unified-patch application
src/glob.js glob matching and .gitignore semantics
src/walk.js one directory walker, shared by every crawling tool
src/archive.js ZIP and TAR, written by hand
src/files.js file_read / file_write / file_edit / fs_list
src/ws.js a WebSocket client, written by hand (RFC 6455)
src/cdp.js Chrome DevTools Protocol: discovery, launch, sessions
src/browser.js page operations: snapshot, input, capture, network
src/image.js PNG decode / resize / encode, and image token maths
src/screen.js desktop capture per platform, display and window lists
src/input.js mouse and keyboard per platform, key tables, chords
src/shells.js shell detection and per-platform invocation
src/config.js configuration loading and precedence
src/guards.js optional guardrails
src/plugins.js plugin loading, secret resolution, redaction
plugins/fivem/ RCON, txAdmin, the F8 log, and an in-game bridge
plugins/discord/ bot REST API and webhooks
plugins/telegram/ bot API with server-side long polling
src/format.js output cleanup and truncation
src/tools/index.js registry: groups, profiles, token cost
src/tools/interpolate.js which fields accept ${...}, declared in one place
src/tools/*.js one module per tool group
skills/terminalmcp/ the skill that teaches a model to use it wellRoughly 18,000 lines of source, 4,800 lines of tests, zero dependencies.
Implementation notes
The MCP protocol is implemented by hand (JSON-RPC 2.0, newline-delimited on stdio) specifically to keep the dependency count at zero. Clone and run.
stdoutcarries only protocol. Every diagnostic goes tostderr.Requests don't block each other. A long
shell_execdoesn't stop a concurrentshell_jobpoll.Timeouts kill the whole process group —
process.kill(-pid)on POSIX,taskkill /T /Fon Windows — so a command that spawned children doesn't leave orphans behind. There's a regression test for exactly that.Over HTTP, replies are plain JSON when the client accepts JSON. Clients send
Accept: application/json, text/event-streamon every request, so wrapping every short reply in an event stream would buy nothing. SSE is used when the client won't take JSON, or on demand via--sse-replies.whenand${...}use a dedicated parser. Noeval, no reachable arbitrary functions.The browser is driven over a hand-written WebSocket client. Node 22 has a global
WebSocket, Node 18 does not, and addingwsfor one transport would have ended the zero-dependency promise. RFC 6455 is a handshake plus a frame header; the fiddly part is that a full-page screenshot arrives as one multi-megabyte message, so frames are read from a chunk queue rather than by re-concatenating a growing buffer.PNG is decoded, resized and re-encoded in process. Shelling out to ImageMagick would mean the feature silently degrades on machines that do not have it — which is most Windows machines. The encoder picks a row filter per row and drops the alpha channel when nothing is transparent, which takes a flat UI screenshot from 1.4MB of raw pixels to a couple of kilobytes.
Atomic where it matters.
file_editis all-or-nothing;diff applyrefuses a partial patch rather than leaving a half-edited file; the variable store persists via write-then-rename.
Output shaping
Every result passes through the same pipeline, because this is where tokens quietly disappear:
ANSI escape codes stripped, trailing whitespace trimmed, runs of blank lines collapsed.
Truncation in the middle, keeping head and tail — errors live at the end of a log — with a note of how many bytes were dropped.
Empty sections omitted entirely. No
stderr: (empty).Background job output read incrementally by offset, so bytes already seen never come back.
Testing
npm test # 990 assertions
npm run test:smoke # stdio protocol, exec, jobs, bulk, files, profiles (101)
npm run test:guards # guardrails: readOnly, allowedRoots, deny* (14)
npm run test:tools # extended tools: search, git, fs, archive, … (156)
npm run test:vars # variables, interpolation, secrets, persistence (67)
npm run test:image # PNG codec, resizing, capture back-end selection (68)
npm run test:screen # the screen tool: real captures on a virtual X display (99)
npm run test:input # the input tool: real clicks and keys, witnessed by xev (123)
npm run test:plugins # loader + fivem, discord, telegram vs mocks (183)
npm run test:browser # a real browser: 32 actions end to end, downloads (130)
npm run test:http # HTTP transport: streamable + legacy SSE (49)The tests spawn the real server and speak MCP to it — over stdio for the
main suites, over real HTTP (sessions, SSE, CORS, batching, 413s) for the
transport suite. So they cover the handshake, JSON-RPC framing and protocol
negotiation, not just internal logic. Fixtures include a synthetic repository
and a local HTTP server, so git, pkg, search_text and http_request are
exercised against something real.
The browser suite is the same kind of thing rather than a mock: it serves fixture pages over HTTP, launches an actual Chromium, and drives a login form through snapshot, fill, select, click and submit, checking that the page received the values. Two parts degrade honestly instead of pretending:
No browser installed — the browser suite reports that and exits 0. A missing browser is a missing browser, not a broken server.
No desktop — when
Xvfbis installed, the screen suite starts a virtual X display, puts a window on it and captures it for real: the whole screen, one display, one window, an exact rectangle, saved to disk and viewed back. That is the test that matters, because the bugs live in the commands, not around them. WithoutXvfbthe suite says so and skips that block, and what remains still runs: the PNG codec, the token maths, the back-end decision table, and — for Windows — the failure protocol, the explanation each failure produces, and the temp path Node and .NET have to agree on.
The plugin suite needs no accounts and no secrets: it stands up local mock
servers that speak the real wire formats — including an actual UDP socket that
checks the RCON packet byte for byte, and a Telegram mock that holds a long
poll open until a message arrives. It asserts the things that would be
embarrassing to get wrong: that a token never appears in an error, that
readOnly refuses exactly the outward-facing actions, and that an allow-list
refusal happens before anything goes out on the wire.
When tools go missing in your client
The server logs what it exposes; the client decides what it keeps. Those two numbers can disagree, and nothing in the protocol reports it.
Seen in the wild: a server reporting tools=29 while the client listed 26.
The three missing ones were the last three in the list — the tail had been
dropped silently, at around 41 KB of accumulated schema. The server was sending
all of them, over a working transport, as valid JSON.
So when a tool you expect is not there:
node bin/terminalmcp.js --list-tools # what the server exposes
curl localhost:8787/health # the same, over HTTPIf those show the tool and your client does not, the client dropped it. Two things fix it, both about making the list smaller:
--tools all,-browser # drop the biggest single tool (~6 KB)
--tools core,screen,fivem # or name only what this session needsGroups are sent in the order you name them. --tools screen,git puts
screen first, so it survives a client that truncates; all and the bundles
keep registry order. That ordering is the only lever you have over which tools
live through a cap you cannot see, so it belongs to you rather than to the
registry.
The server prints a note at startup once the schema passes 40 KB, so this is signposted rather than discovered.
Compatibility
Status | |
Node.js | 18 and later |
Linux | Supported and tested |
macOS | Supported; shares the POSIX code paths with Linux |
Windows | Supported and tested — Git Bash, |
MCP protocol | 2024-11-05, 2025-03-26, 2025-06-18 (negotiated per session) |
Browser control | Chrome, Chromium, Edge, Brave, Vivaldi — anything Chromium-family, on all three platforms. Not Firefox: it dropped most of its CDP surface in favour of WebDriver BiDi, which is a different protocol. |
Desktop capture | Windows: PowerShell + System.Drawing, nothing to install — but it must run in the interactive desktop session, and |
Mouse and keyboard | Windows: |
Plugins | Platform-independent: HTTPS and UDP. The FiveM client log that |
The browser paths are tested on Linux against a real Chromium, and the Windows
and macOS browser paths use the same protocol code — only the search for the
binary differs per platform. Desktop capture is the one part where the
per-platform commands differ substantially: the Linux ones are now captured for
real against a virtual X display, and the PowerShell script is parsed and its
failure protocol exercised by an actual PowerShell — but a successful Windows
capture, and every macOS capture, still depend on a machine we cannot run here.
If one misbehaves, please open an issue: screen { action: "probe" } output is
the useful thing to paste.
Things worth knowing
Every command runs in a fresh shell.
cd,exportandsourcedo not carry across calls or bulk steps. Usecwd,env, or chain inside one command string (cd x && make).Output is middle-truncated at
maxOutputBytes. Raise it if you genuinely need the middle of a long log, or read the log file withfile_read { tail_lines: n }instead.search_texthonours.gitignoreby default. Passrespect_gitignore: falsewhen you're looking for something in build output.code outlineis pattern-based, not a real parser. It's for orientation;file_readis the source of truth.Browser refs are invalidated by navigation, deliberately: they live in the page as
window.__tmcpRefs, so a reload or a new URL makes them stale and using one then says exactly that. Callsnapshotagain.JavaScript dialogs are answered automatically (
acceptby default), else the page would sit frozen forever waiting for a click nobody can make. The message is kept and reported, since an unexplainedalert()is usually the reason something appeared not to work.Only a browser this server launched is ever closed by it.
closeon a browser you attached to disconnects and leaves it running; killing the browser a person is using would be unforgivable.Screenshots and downloads land under
.terminalmcp/in the working directory. Worth adding to.gitignore— this repo already does.A JPEG screenshot is scaled by the renderer rather than afterwards, because this server can resize PNG but not JPEG. That also means the saved JPEG is the scaled one, while a saved PNG is full resolution.
Roadmap
Parallel step groups in
shell_bulkPersistent shell sessions (keeping
cd/exportstate)Mouse and keyboard control of the desktop, not just capture of it
Firefox via WebDriver BiDi, alongside CDP
The Discord gateway, for push delivery instead of polled
waitA SQL client
An optional token for the HTTP transport
Contributions and issues are welcome. The test suite is the contract: if you add a tool, add assertions that drive it through the real server.
License
Available Tools
26 toolsarchiveA
Create, list and extract archives: zip, tar, tar.gz (tgz) and plain gzip. Implemented in process, so it behaves the same on Windows, macOS and Linux with no zip/tar binary needed. create takes a directory or a file list (with glob filters); extract refuses paths that escape the destination.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | extract: destination directory. gzip/gunzip: output file. | |
| base | No | create: strip this leading path from stored names. Default: the "from" directory. | |
| from | No | create: directory (or single file) to pack. | |
| glob | No | create/extract: only these paths (globs). | |
| path | Yes | The archive file. For create, the archive to write. | |
| files | No | create: explicit file list instead of "from". | |
| level | No | create/gzip: compression level 0-9. Default 6; 0 stores without compressing. | |
| action | Yes | What to do. | |
| format | No | Override the format. Default: inferred from the file name, then the magic bytes. | |
| exclude | No | create/extract: skip these paths (globs). | |
| max_bytes | No | Byte cap on returned output. | |
| overwrite | No | extract: replace existing files. Default false (they are skipped). | |
| skip_dirs | No | create: directory names not to pack. | |
| show_hidden | No | create: include dotfiles. Default true. | |
| strip_components | No | extract: drop this many leading path segments, like tar --strip-components. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden, and it adds real value: it discloses the cross-platform, in-process implementation (consistent behavior with no external binary) and a security-relevant guard for extract. It does not cover what 'list' returns, permission/auth requirements, or how overwrite/skip semantics interact, but the core traits an agent needs are present.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with no filler: capability and formats first, then the implementation trait, then the safety/behavior note. Every clause earns its place and the most important information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 15-parameter tool with no annotations and no output schema, the description is adequate but incomplete: it never mentions the gzip/gunzip actions that the schema declares, nor what 'list' produces, leaving the agent to reconcile actions between description and schema. The 100% schema coverage and the extract safety note keep it at minimum viable rather than deficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 15 parameters in detail. The description adds only marginal framing: that 'create' accepts either a directory or a file list with glob filters, and that extract path-escapes are rejected. That is a baseline 3 when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names concrete verbs (create, list, extract) and the exact resource and formats (zip, tar, tar.gz/tgz, plain gzip), so the tool's scope is unambiguous. It also hints at a differentiator from shell-based siblings by noting it works 'in process' with 'no zip/tar binary needed', though it never names an alternative tool explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied through the action list and a few conditional phrases ('create takes a directory or a file list', 'extract refuses paths that escape the destination'). There is no explicit statement of when to reach for this tool versus shell_exec/shell_bulk, nor any when-not guidance or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
codeA
Structural views of source code: outline (functions, classes, types in a file, with line numbers — read this before reading the file), imports (what a file depends on), todos (TODO/FIXME/HACK/XXX across the tree), stats (lines of code by language).
| Name | Required | Description | Default |
|---|---|---|---|
| glob | No | todos/stats: restrict to these globs. | |
| path | No | outline/imports: the file. todos/stats: directory to scan. Default: server cwd. | |
| tags | No | todos: which markers to look for. Default TODO, FIXME, HACK, XXX, BUG. | |
| limit | No | todos: max results. Default 100. | |
| action | Yes | Which view. | |
| max_bytes | No | Byte cap on returned output. | |
| max_depth | No | todos/stats: recursion depth. Default 24. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full behavioral burden. It implies a read-only inspection tool and mentions a byte cap via parameter, but says nothing about permissions, whether output is truncated/ordered, or the cost of tree-wide todos/stats scans. It adds some value but leaves meaningful behavioral gaps for a 7-parameter tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence, front-loaded with the domain and then broken into four clearly labeled action clauses. Every clause earns its place by explaining what a distinct action returns, with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully summarizes each action's return shape (functions/classes/types with line numbers, dependencies, markers, LOC by language), which is what an agent needs to pick an action. It omits output ordering, truncation behavior, and how limit/max_bytes interact with results, so it is strong but not exhaustive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents path, glob, tags, limit, max_bytes and max_depth. The description only restates the per-action applicability (outline/imports vs todos/stats) that the schema itself already encodes, adding no new parameter meaning. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific domain (structural views of source code) and enumerates the four actions with their return content, so an agent can tell it apart from file_read or search_text. It stops short of naming a sibling explicitly or summarizing a single unifying verb beyond 'views', which keeps it out of the top band.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit usage rule for one action ('read this before reading the file' for outline) and each action's parameter descriptions state the applicable scope (path is a file for outline/imports, a directory for todos/stats). There is no guidance on when to prefer search_text or fs_list over this tool, so it falls short of 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diffA
Compare and patch text: files (unified diff between two files), text (between two inline strings), apply (apply a unified diff to a file — hunk line numbers are matched by context, so a patch still applies after unrelated edits shifted the file).
| Name | Required | Description | Default |
|---|---|---|---|
| a | No | text: the "before" string. | |
| b | No | text: the "after" string. | |
| to | No | files: the second file. | |
| path | No | files: the first file. apply: the file to patch. | |
| stat | No | Report only the added/removed line counts. | |
| patch | No | apply: the unified diff to apply. | |
| action | Yes | What to do. | |
| context | No | Lines of context per hunk. Default 3. | |
| dry_run | No | apply: report what would happen without writing. | |
| max_bytes | No | Byte cap on returned output. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It adds a valuable trait for apply—context-based hunk matching so patches survive shifted lines—but omits mutation/permission details, and does not mention dry_run or what the tool returns.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence, front-loaded with the core purpose, followed by parenthetical mode definitions. Every clause contributes information, though bullets would be slightly easier to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter tool with three modes and no output schema, the description covers mode selection and a key apply behavior. However, it does not describe return values, dry_run semantics, or error handling, leaving gaps that the missing output schema cannot fill.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameter meanings are already documented. The description adds action-to-parameter grouping (files uses path/to, text uses a/b, apply uses path/patch), but no syntax or format details beyond the schema; baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource (compare/patch text) and enumerates the three modes: files, text, apply. Each mode is defined concisely, so an agent can immediately tell this tool apart from file_edit or search_text without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context for when to use each action: files for two file paths, text for inline strings, apply for a unified diff. There are no exclusions or explicit alternatives (e.g., use file_edit instead), but the mode descriptions provide strong selection guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
encodeA
Small conversions: base64/hex/url/html encode and decode, hash (md5/sha1/sha256/sha512), uuid, random bytes, jwt_decode (header and payload — signature is NOT verified), timestamp (epoch <-> ISO). Reads inline text or a file.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Read the input from this file instead of "text". | |
| text | No | Input text. For timestamp: an epoch number or an ISO string. | |
| count | No | uuid: how many. random: how many bytes. Default 1 / 32. | |
| action | Yes | Which conversion. | |
| encoding | No | random: output encoding. Default hex. | |
| algorithm | No | hash: digest. Default sha256. | |
| max_bytes | No | Byte cap on returned output. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully flags that jwt_decode does NOT verify the signature and mentions a max_bytes cap on output, which are real behavioral facts. It omits error behavior, file-size limits for path reads, and whether random output is cryptographically secure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense capability sentence is front-loaded with the operation list, followed by a short input-source sentence. No filler, though the enumeration is long and could be tabular.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description conveys enough for a multi-action converter: the action set, input source, and the key cryptographic caveat. It is close to complete; return-value specifics per action remain implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description's parentheticals (hash algorithms, jwt header/payload, input from text or file) largely restate what the schema fields already document, adding little beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the exact operation set (base64/hex/url/html encode-decode, hash, uuid, random, jwt_decode, timestamp) matching the enum verbatim, so an agent knows precisely what it does. It is scoped as 'small conversions', but does not explicitly differentiate itself from siblings like shell_exec or json_tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the enumerated action list and the 'Reads inline text or a file' input note, and 'Small conversions' bounds the intended scope. However, there is no explicit when-to-use-vs-alternatives guidance (e.g., vs shell_exec), leaving routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
file_editA
Patch parts of a file — several edits in ONE call. ops types: replace_lines, delete_lines, insert_before, insert_after, replace_text (exact string), regex_replace, append, prepend. Line numbers in every op refer to the ORIGINAL file and line ranges must not overlap, so you can plan all edits from a single file_read. replace_text fails unless it matches expect_count times (default 1) — pass all=true for every occurrence. Use dry_run=true to preview a diff first.
| Name | Required | Description | Default |
|---|---|---|---|
| eol | No | Line endings. Default keep. | |
| ops | Yes | Edits applied atomically: nothing is written unless all of them succeed. | |
| path | Yes | File to patch. | |
| dry_run | No | Preview the diff without writing. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the reference-frame rule (line numbers are against the ORIGINAL file), a hard constraint (line ranges must not overlap), failure semantics (replace_text fails unless it matches expect_count, default 1), and a safe preview path via dry_run. Missing are permission/backup behavior and what the dry_run output actually looks like, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, each front-loaded with high-value constraints: batching first, then op list, then the line-number/overlap rule, then failure and preview semantics. No filler and no repetition of the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a multi-op mutation tool with no output schema and no annotations, the description covers the operation model, ordering constraints, failure conditions, and preview path — enough to call it correctly. It leaves the return value of a write/dry_run unexplained and does not address concurrent-edit or stale-file handling beyond expect_match's mention in the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds genuine meaning beyond the schema: the non-overlap constraint and original-file line numbering for start_line/end_line, expect_count's default of 1 and all=true override for replace_text, and dry_run's diff-preview behavior. It doesn't explain eol or expect_match/allow_no_match, which the schema covers.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with scope ('Patch parts of a file — several edits in ONE call') and enumerates the op types, which makes it unmistakably the incremental-edit tool rather than file_write. It does not explicitly name a sibling or draw the boundary against file_write, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives real usage context: plan all edits from a single file_read because line numbers refer to the original file, and preview with dry_run=true. It also distinguishes replace_text (with expect_count/all) from the line-based ops. There is no explicit 'when not to use' or named alternative (e.g. use file_write for a full rewrite), so it is clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
file_readA
Read a file, or just the part you need: a line range (start_line/end_line, negatives count from the end), head_lines/tail_lines, or match="regex" to return only matching lines with optional context — far cheaper than reading a whole file. Output is line-numbered and middle-truncated at max_output_bytes.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | File path, absolute or relative to the server cwd. | |
| match | No | Regex: return only lines that match (grep mode). | |
| context | No | Lines of context around each match. Default 0. | |
| encoding | No | base64 to read binary bytes. | |
| end_line | No | 1-based last line, inclusive. Negative counts back from the end. | |
| max_bytes | No | Byte cap on returned output before middle-truncation. Lower it to save tokens. | |
| force_text | No | Read as UTF-8 even if the file looks binary. | |
| head_lines | No | Just the first N lines. | |
| start_line | No | 1-based first line. Negative counts back from the end. | |
| tail_lines | No | Just the last N lines. | |
| ignore_case | No | Shorthand for match_flags="i". | |
| match_flags | No | Regex flags for match, e.g. "i". | |
| max_matches | No | Cap on matches in grep mode. Default 200. | |
| line_numbers | No | Prefix lines with numbers. Default true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the burden. It usefully discloses output shape (line-numbered, middle-truncated at max_output_bytes) and negative-index semantics, which is real behavioral context. It says nothing about error behavior for missing files, permissions, or how conflicting modes (e.g. start_line vs head_lines) resolve.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One dense, front-loaded sentence with the primary capability ('Read a file') first and the qualifiers following. It is information-rich with no filler, though the em-dash chain makes it slightly harder to scan than a short bulleted breakdown would be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 14-parameter tool with no annotations and no output schema, the description covers the headline modes and truncation behavior adequately. It stops short of explaining error handling, parameter conflicts, or binary/base64 handling, leaving some gaps that the schema only partially fills.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema description coverage, the schema already documents all 14 parameters including defaults and enums; baseline is 3. The description reinforces the most important ones (start_line/end_line negatives, head_lines/tail_lines, match regex) but adds no syntax or precedence detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Read a file') and immediately enumerates the access modes (line range, head/tail, regex match), so an agent knows exactly what capability it offers. The 'middle-truncated at max_output_bytes' and 'line-numbered' phrasing further pins down the behavior in a way that distinguishes it from raw shell reads.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear usage rationale ('far cheaper than reading a whole file') that steers the agent toward partial reads rather than whole-file reads. However, it never names the sibling tools (search_text, search_files) or states when those should be preferred over match= mode, so no explicit exclusions are provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
file_writeA
Write a whole file. mode: overwrite (default) | append | prepend | create_new (fails if it exists). Creates parent directories and keeps the file existing EOL style. For a small change to a big file use file_edit.
| Name | Required | Description | Default |
|---|---|---|---|
| eol | No | Line endings. Default keep (detect from the file, else LF). | |
| mode | No | Default overwrite. | |
| path | Yes | File path, absolute or relative to the server cwd. | |
| content | Yes | Full new content (or the chunk to append/prepend). | |
| encoding | No | base64 to write binary content. | |
| create_dirs | No | Create missing parent directories. Default true. | |
| ensure_trailing_newline | No | End the file with a newline. Default true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses side effects: parent directories are created and existing EOL style is preserved, and create_new fails on existing files. However, it never states that the default 'overwrite' destroys existing content irreversibly, nor anything about permissions or failure behavior for the other modes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, zero filler, with the core action first and the alternative-tool routing last. Every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-param mutation tool with no annotations and no output schema, the description covers the destructive default, the mode failure case, and side effects like directory creation and EOL preservation. The main remaining gap is not flagging the data-loss risk of the default overwrite mode.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds semantics the schema lacks: the per-mode behavior of overwrite/append/prepend and the failure condition for create_new, which the enum only labels 'Default overwrite'. Other params (eol, encoding, create_dirs) are left entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Write a whole file') with explicit scope ('whole', as opposed to partial edits), and names the sibling it is not by routing to file_edit. An agent can distinguish it from file_edit or shell-based writes without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: 'For a small change to a big file use file_edit.' It also documents the discriminating condition for create_new ('fails if it exists'). No guidance on when-not to use it versus shell_bulk or other write paths, but the primary alternative is covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fs_listB
List a directory (or stat one path). Recurses to "depth", filters with a glob "pattern", and skips .git/node_modules/dist and friends by default.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Directory (or file) to list. Default: server cwd. | |
| depth | No | Recursion depth. Default 1. | |
| details | No | Include file sizes. Default true. | |
| pattern | No | Glob filter on the relative path, e.g. "*.ts" or "src/**/*.js". | |
| max_bytes | No | Byte cap on returned output before middle-truncation. Lower it to save tokens. | |
| skip_dirs | No | Directory names not to descend into. | |
| max_entries | No | Cap on listed entries. Default 500. | |
| show_hidden | No | Include dotfiles. Default false. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose non-obvious default behavior: recursion to depth, glob filtering, and default skipping of .git/node_modules/dist. However, it does not describe permissions, error behavior, or the fact that output is middle-truncated (that detail lives only in the schema), and 'and friends' is vague about the actual skip list.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tight sentence with the primary action front-loaded and the modifier behaviors trailing. No filler, though 'and friends' sacrifices precision for brevity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter read tool with no annotations and no output schema, the description covers the core behaviors but never explains the shape of what is returned or the truncation semantics. Adequate, not complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter is already documented, setting the baseline at 3. The description echoes depth and pattern and adds the default skip behavior, but contributes no additional syntax or constraint detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('List a directory') and extends it to the stat case ('or stat one path'), which an agent can act on immediately. It does not explicitly contrast itself with overlapping siblings like search_files or file_read, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance and no mention of alternatives, despite siblings such as search_files, file_read, and shell_exec plausibly covering some of the same ground. The only routing-ish information is implicit in the behavior sentence.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fs_opB
Filesystem operations other than reading/writing content: copy, move, delete, mkdir, touch, stat, chmod, symlink, readlink, hash (md5/sha1/sha256/sha512), disk_usage (recursive size, biggest files), tree (indented listing). Works on files and directories; recursive where it makes sense. delete refuses a non-empty directory unless recursive=true.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Destination path for copy, move and symlink. | |
| top | No | disk_usage: how many biggest entries to list. Default 15. | |
| mode | No | chmod: octal mode as a string, e.g. "755". mkdir: mode for new directories. | |
| path | Yes | Target path (the source, for copy/move). | |
| depth | No | tree: levels to show (default 3). disk_usage: levels to break down (default 2). | |
| force | No | copy/move: overwrite the destination if it exists. delete: ignore a missing path. | |
| action | Yes | Operation to perform. | |
| algorithm | No | hash: digest to use. Default sha256. | |
| max_bytes | No | Byte cap on returned output. | |
| recursive | No | copy/delete: include directory contents. Required to delete a non-empty directory. | |
| skip_dirs | No | tree/disk_usage: directory names not to enter. | |
| max_entries | No | tree: cap on listed entries. Default 400. | |
| show_hidden | No | tree/disk_usage: include dotfiles. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It adds one specific rule (delete refuses a non-empty directory unless recursive=true) and a vague 'recursive where it makes sense,' but omits critical context: whether delete is permanent, what happens on overwrite (force), permission requirements, error modes, and return formats. For a tool performing destructive operations, this is a significant gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded paragraph that efficiently packs scope, action list, and one behavioral note. It avoids redundancy and is appropriately sized for a 13-parameter tool, though minor structural improvements (e.g., separating the behavioral note) could enhance scannability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (12 actions, 13 parameters, no output schema, no annotations), the description adequately covers selection by stating scope and exclusions, and the schema covers parameter invocation. However, it lacks detail on what each action returns or how errors surface — gaps that could mislead an agent about output expectations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each parameter is fully documented in the schema. The description restates the list of actions and hash algorithms, which duplicates the enum values with no added syntax or format detail. Per the rubric, a baseline of 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (filesystem) and enumerates all supported operations, with an explicit exclusion: 'other than reading/writing content.' This immediately distinguishes it from siblings like file_read and file_write, giving an agent a precise sense of what the tool does and does not cover.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The exclusion of reading/writing content implies that file_read and file_write should be used for those tasks, but no explicit when-to-use guidance or named alternatives are provided. The delete condition (needs recursive=true for non-empty dirs) is a behavioral rule, not usage routing. Overall, usage is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gitA
Run git with compact, token-cheap output. Read: status, log, diff, show, blame, branches, tags, remotes, stash_list, file_history, current, root, config_get. Write: add, unstage, commit, checkout, branch_create, branch_delete, merge, rebase, reset, revert, restore, stash, stash_pop, tag_create, fetch, pull, push, apply, clean, init. Anything else: action="raw" with args=["..."]. git runs directly, not through a shell, so commit messages with quotes and newlines need no escaping.
| Name | Required | Description | Default |
|---|---|---|---|
| all | No | add: stage everything. commit: stage tracked changes first (-a). branches: include remotes. | |
| cwd | No | Repository directory. Default: server cwd. | |
| key | No | config_get: the config key, e.g. user.email. | |
| ref | No | Branch, tag, commit or range — depends on the action (show, diff, checkout, merge, reset, ...). | |
| args | No | For action="raw": the full git argv, e.g. ["bisect","start"]. For other actions: extra flags appended to the command. | |
| hard | No | reset: --hard (DISCARDS working tree changes) instead of --mixed. | |
| stat | No | diff/show/log: summarise as changed files + line counts instead of full patch. Much cheaper. | |
| amend | No | commit: amend the previous commit. | |
| force | No | push/branch_delete/clean: force the operation. | |
| limit | No | log/file_history: how many commits. Default 20. | |
| patch | No | apply: the unified diff text to apply. | |
| paths | No | Files/paths the action applies to (add, diff, checkout, restore, blame, file_history, ...). | |
| action | Yes | What to do. Use "raw" with args for any git command not listed. | |
| remote | No | fetch/pull/push: remote name. Default origin. | |
| staged | No | diff: show the staged changes (--cached). | |
| message | No | commit/tag_create/stash: the message. | |
| max_bytes | No | Byte cap on returned output. | |
| timeout_ms | No | Kill git after this long. Network actions default to 120000. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does meaningful work: it discloses the token-cheap output preference, that git runs directly without a shell, and that quoting/newlines need no escaping — all non-obvious execution-model facts. It stops short of warning about destructive write actions (force push, reset --hard, clean) or auth needs for fetch/pull/push, so it is not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is deliberately compressed: the main behavior and routing rule are front-loaded, action lists are comma-dense, and the closing escaping note is one clause. No sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 18-parameter mutation-capable tool with no output schema and no annotations, the description covers action coverage and execution semantics well. It could do more on destructive-operation consequences and output shape, but the schema's explicit warnings (e.g. hard: 'DISCARDS working tree changes') fill part of that gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 18 parameters including enum values and per-action flags; the baseline of 3 applies. The description reinforces the raw-action pattern and the no-escape rule for messages, but adds little parameter meaning the schema does not already provide.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Run git') with an explicit quality goal ('compact, token-cheap output'), then enumerates the read and write action families so the agent immediately knows the tool's surface. It is trivially distinguishable from shell_exec because it is git-specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description partitions the supported actions into Read and Write lists and gives a clear fallback ('Anything else: action="raw" with args'), which tells the agent exactly when to use which mode. It does not, however, say when to prefer this over the sibling shell_exec/shell_exec_async tools, which is the main remaining gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
http_requestA
Make an HTTP(S) request and report status, timing, headers and body — for testing the API you are building or calling. JSON bodies are pretty-printed; large bodies are truncated. Pass json= for a JSON body (sets Content-Type), or body= for anything else.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Full URL. http:// is assumed if no scheme is given. | |
| body | No | Raw request body. | |
| form | No | Body sent as application/x-www-form-urlencoded. | |
| json | No | Body sent as JSON (any value). Sets Content-Type: application/json. | |
| query | No | Query parameters appended to the URL. | |
| assign | No | Store the response body in the server variable of this name instead of relying on it coming back through the conversation. See the vars tool. | |
| method | No | GET (default), POST, PUT, PATCH, DELETE, HEAD, OPTIONS... | |
| headers | No | Request headers. | |
| insecure | No | Accept invalid TLS certificates (self-signed dev servers). | |
| max_bytes | No | Byte cap on the returned body. Default: server maxOutputBytes. | |
| timeout_ms | No | Abort after this long. Default 30000. | |
| headers_only | No | Report status and headers, skip the body. | |
| follow_redirects | No | Follow 3xx. Default true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full load and does disclose genuinely non-obvious behavior: JSON bodies are pretty-printed, large bodies are truncated, and json= sets Content-Type. It omits error-surface behavior, auth/credential handling, and side effects of the `assign` variable write.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core capability and outcome, then the body-mode distinction. No filler and nothing repeated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 13-parameter, no-output-schema tool with no annotations, the description covers purpose, return shape and body semantics; the per-parameter detail is fully carried by the schema. It would be complete if it mentioned the variable-storage side effect and TLS/redirect caveats at a high level, but nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all 13 parameters are already documented in the schema; baseline is 3. The description only re-frames the json-vs-body choice, which the schema already covers, and adds no syntax or format detail beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (make an HTTP(S) request) plus exactly what it reports (status, timing, headers, body) and its intended context. It does not distinguish itself from the sibling `net`, which is the only remaining ambiguity for an agent choosing between them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"for testing the API you are building or calling" gives a clear usage context, and the json=/body= sentence steers the two main body modes. It stops short of stating when NOT to use it (e.g. versus shell_exec + curl) or naming alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
json_toolA
Query and patch JSON without rewriting the whole file: get (read a path), set, delete, merge (deep), keys (list a level), validate, format (pretty-print or minify). Paths look like "scripts.build" or "items[0].name". Works on a file (path=) or inline text (content=).
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | JSON file to read (and write, for set/delete/merge/format). | |
| value | No | set: the new value (any JSON type). merge: the object to merge in. | |
| action | Yes | What to do. | |
| indent | No | Indent for written/formatted output. Default 2; 0 minifies. | |
| content | No | Inline JSON text instead of a file. Nothing is written in this mode. | |
| json_path | No | Dotted/bracketed path inside the document, e.g. "a.b[0].c". Omit for the root. | |
| max_bytes | No | Byte cap on returned output. | |
| create_missing | No | set: create intermediate objects that do not exist. Default true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the burden, and it does useful work: 'without rewriting the whole file' discloses the partial-mutation behavior, and 'Nothing is written in this mode' clearly marks the content= mode as non-destructive. It omits auth/permission needs, error behavior on missing paths, and write scope beyond path=.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One dense paragraph with the core value proposition ('without rewriting the whole file') front-loaded, followed by the action list, path syntax, and mode selection. Every clause earns its place, though the action enumeration and examples make it slightly list-heavy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter, 7-action tool with no annotations and no output schema, the description covers actions, path syntax, and file-vs-inline modes well. It does not describe return values or per-action error semantics, which is a modest gap given there is no output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description adds value by giving concrete path syntax ('scripts.build', 'items[0].name') and clarifying that content= is inline and produces no writes. It still leaves the value/create_missing/max_bytes semantics to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb+resource and enumerates every action (get, set, delete, merge, keys, validate, format) so the agent knows exactly what the tool covers. It also distinguishes itself from generic file siblings with 'without rewriting the whole file', signaling a JSON-aware partial-patch tool rather than file_read/file_write/file_edit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly states the two operating modes ('Works on a file (path=) or inline text (content=)'), which tells the agent when to supply which parameter. It does not explicitly say when to prefer this over file_edit or file_read, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
netA
Network probes: dns (A/AAAA/MX/TXT/CNAME/NS/PTR lookup), tcp_check (is host:port accepting connections, with timing), listening (which ports are open on this machine, and which pid owns them), interfaces (local addresses), ping.
| Name | Required | Description | Default |
|---|---|---|---|
| host | No | Hostname or IP for dns, tcp_check and ping. | |
| port | No | tcp_check: port to connect to. listening: only report this port. | |
| type | No | dns: record type. Default A. | |
| count | No | ping: how many packets. Default 3. | |
| ports | No | tcp_check: several ports at once. | |
| action | Yes | Which probe to run. | |
| max_bytes | No | Byte cap on returned output. | |
| timeout_ms | No | Per-probe timeout. Default 5000. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose some traits the schema does not: tcp_check reports timing, listening identifies the owning pid, and ping is packet-based. It omits what happens on failure, whether elevated privileges are needed for port/pid enumeration, and the default timeouts and byte caps that the schema only names.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence front-loads the tool's identity ('Network probes') and then itemizes each action with its defining detail. No filler, no restatement of the name, and every clause adds distinguishing information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an eight-parameter, no-annotation, no-output-schema tool, the description covers what each action does but says nothing about return shape, error behavior, or privilege requirements for the more sensitive probes (listening, interfaces). It is adequate but leaves gaps an agent would need to discover by trial.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and all eight parameters are documented there, including which action each one belongs to, so the description need not repeat them. The description adds nothing about parameter interaction beyond what the schema already states, which is the baseline for a fully covered schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description enumerates five concrete probes (dns, tcp_check, listening, interfaces, ping) and states what each one returns, so the agent knows exactly what the tool does. It does not, however, differentiate itself from siblings like http_request or shell_exec, which could also answer some of these questions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Enumerating the five actions with their meaning implies when each sub-action applies, which is useful selection guidance. But there is no explicit 'use this instead of X' routing against siblings (http_request, shell_exec, sys_info), and no stated prerequisites such as privileges for the listening probe.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pkgA
Drive whichever package manager the project uses, without having to know which: npm, pnpm, yarn, bun, deno, pip, uv, poetry, pipenv, cargo, go, composer, bundler, maven, gradle, dotnet. Actions: detect, install, add, remove, run (a script/task), scripts (list them), list, outdated. Detection reads lockfiles, so it picks the manager the repo actually uses.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | Project directory. Default: server cwd. | |
| dev | No | add: install as a dev dependency. | |
| args | No | run: arguments passed to the script. | |
| action | No | What to do. Default detect. | |
| script | No | run: the script or task name. | |
| manager | No | Force a manager instead of detecting one. | |
| packages | No | add/remove: package names (versions allowed, e.g. "lodash@4"). | |
| max_bytes | No | Byte cap on returned output. | |
| timeout_ms | No | Timeout. Installs default to 600000 (10 min). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose the detection mechanism (lockfile reads). However it never distinguishes read-only actions (detect/scripts/list/outdated) from mutating ones (install/add/remove), nor warns about long install durations, required permissions, or network access needed by the underlying managers.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core value proposition, then the action list, then the detection detail—logical and mostly waste-free. The 15-manager enumeration is long but earns its place by scoping applicability; overall appropriately sized.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter tool with no annotations and no output schema, the description covers actions and detection well but omits return format, output truncation behavior (max_bytes), timeouts, and mutation semantics. Adequate but with visible gaps for such a broad tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents every parameter including the action enum and per-action parameters. The description's action list adds minor mapping value (run a script, list scripts, detect) but does not go beyond the structured fields, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (drive a package manager) and enumerates the exact managers and actions supported, so an agent immediately knows this wraps npm/pnpm/cargo/etc. rather than being another generic shell runner. It is clearly distinguishable from siblings like shell_exec or proc.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the key selection condition: detection reads lockfiles so it picks the manager the repo actually uses, and manager can be forced. It gives clear context for when to reach for this over a raw shell tool, but offers no explicit when-not guidance or edge cases (e.g., no lockfile present).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
procB
Processes on this machine: list (filter by name, sort by cpu/memory), tree (parent/child hierarchy), info (one pid in detail), kill (by pid, or every process matching a name — which requires confirm=true). Uses ps on Unix and PowerShell/tasklist on Windows.
| Name | Required | Description | Default |
|---|---|---|---|
| pid | No | info/kill/tree: the process id. | |
| name | No | list/kill: regex matched against the process name and command line. | |
| sort | No | list: ordering. Default cpu. | |
| tree | No | kill: also kill the children of the target. | |
| limit | No | list: how many processes to show. Default 25. | |
| action | No | What to do. Default list. | |
| signal | No | kill: SIGTERM (default), SIGKILL, SIGINT. Ignored on Windows, which always force-kills. | |
| confirm | No | Required to kill by name, since a regex can match more than you meant. | |
| max_bytes | No | Byte cap on returned output. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It does add real value: the confirm=true guardrail for killing by name, the destructive kill semantics, and the cross-platform implementation (ps on Unix vs PowerShell/tasklist on Windows). It omits permissions required, reversibility, and output characteristics for a tool that can terminate processes, so it is not fully transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is a single dense sentence that is front-loaded with the resource and organized as labeled per-action clauses, so nothing is wasted. The heavy parenthetical nesting and run-on length keep it from being maximally scannable, but it is efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter, multi-action, destructive-capable tool with no annotations and no output schema, the description covers the action surface and cross-platform behavior but leaves gaps: no return/output shape is described (only a max_bytes hint exists in schema) and no safety or permission caveats beyond confirm=true. Adequate but not complete for the complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter is already documented in the schema and the baseline is 3. The description largely restates schema content (filter by name, sort by cpu/memory, kill by pid) rather than adding syntax or edge-case meaning beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (processes on this machine) and enumerates four distinct operations (list/tree/info/kill) with what each does, so an agent immediately knows this is a process-inspection/control tool rather than general shell execution. It does not explicitly name any sibling to rule out (e.g., shell_exec), so it stops short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied through the action-by-action breakdown (filter by name, sort by cpu/memory, kill by pid or name), which gives an agent enough to select the right action. However, there is no explicit when-to-use vs. when-not guidance and no alternative named (e.g., sys_info for machine stats or shell_exec for arbitrary commands), leaving the routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
project_infoA
Orient yourself in an unfamiliar repository in ONE call: languages by file count and lines, package manager and manifests, dependencies and detected frameworks, available scripts, entry points, test/build/lint commands, git branch and dirty state, and config files. Much cheaper than exploring the tree by hand.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | Project directory. Default: server cwd. | |
| deps | No | Include the dependency list. Default true. | |
| max_bytes | No | Byte cap on returned output. | |
| max_files | No | Cap on files scanned for language stats. Default 20000. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full disclosure burden, and it does reasonably well: it enumerates the returned fields (git dirty state, entry points, build/test/lint commands, config files) and notes the cost advantage of a single aggregated call. It does not explicitly state that the operation is read-only/side-effect free, nor anything about the effect of the max_bytes cap on truncation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The scoping statement is front-loaded, and the enumeration is dense but every clause earns its place by telling the agent what it will get back. The closing comparative sentence justifies the single-call design in six words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must describe return contents, and it does so thoroughly enough for an agent to decide and call correctly. Combined with the fully documented input schema and self-evident read-only nature, nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters (cwd, deps, max_bytes, max_files) are already documented in the schema. The description adds no additional meaning about any parameter, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific action ('orient yourself in an unfamiliar repository') and exhaustively enumerates the resource it returns: languages, package manager, dependencies, frameworks, scripts, entry points, commands, git state, config files. That content list makes it clearly distinguishable in practice from fs_list, search_files, or git, though no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states a clear use context ('unfamiliar repository', 'ONE call') and contrasts with the alternative approach ('cheaper than exploring the tree by hand'). However it never names a sibling tool or states when not to use it (e.g. when you only need one targeted file read), so no exclusions are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_filesA
Find files and directories by name glob, size, age or type — the find you would otherwise shell out for, with consistent output on every platform. Sorts by path, size or mtime.
| Name | Required | Description | Default |
|---|---|---|---|
| glob | No | Only these paths, as globs: ["*.ts","src/**/*.js"]. A pattern without "/" matches the basename at any depth. | |
| name | No | Regex on the file name (alternative to glob). | |
| path | No | File or directory to search. Default: server cwd. | |
| sort | No | Ordering. size and mtime sort descending. | |
| type | No | What to return. Default file. | |
| limit | No | Max entries returned. Default 300. | |
| details | No | Include size and mtime. Default true. | |
| exclude | No | Globs to skip. | |
| max_size | No | Only entries at most this many bytes. | |
| min_size | No | Only entries at least this many bytes. | |
| max_bytes | No | Byte cap on the returned text. Lower it to save tokens. | |
| max_depth | No | Recursion depth. Default 24. | |
| skip_dirs | No | Directory names not to enter. | |
| show_hidden | No | Include dotfiles. | |
| respect_gitignore | No | Honour .gitignore. Default true. | |
| modified_before_hours | No | Only entries untouched for at least N hours. | |
| modified_within_hours | No | Only entries touched in the last N hours. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden; it usefully discloses cross-platform consistent output and default sort direction, which goes beyond the bare name. However, it never confirms this is a read-only/non-mutating operation, nor mentions traversal safety, performance, or output shape for a 17-param tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tight sentence with zero filler that front-loads the verb and resource before the differentiator and sort options. Nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 17-parameter tool with no annotations and no output schema, the description is thin — it says nothing about return values or how the many filtering parameters interact. The rich schema compensates somewhat, but the description stops at minimum viability.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema fully documents all 17 parameters, making the baseline 3 appropriate. The description's mention of sorting by path/size/mtime merely restates what the schema already provides and adds no new parameter meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Find) and resource (files and directories) with the full dimension set (name glob, size, age, type). The phrase 'the find you would otherwise shell out for' implicitly distinguishes it from shell_exec/shell_bulk, while the file-oriented framing separates it from the content-oriented search_text sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'instead of shelling out for find' line implies usage but never states explicit when-to-use vs the shell_* or search_text siblings. No exclusions, prerequisites, or decision criteria are given, so routing relies on inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_textA
Grep a whole tree: regex (or literal) across files, returning only matching lines with file:line and optional context. Skips .git/node_modules/build dirs and binaries, honours .gitignore. Use files_only=true to just locate files, count_only=true for tallies. Set replace= to rewrite every match (dry_run=true first shows a diff).
| Name | Required | Description | Default |
|---|---|---|---|
| glob | No | Only these paths, as globs: ["*.ts","src/**/*.js"]. A pattern without "/" matches the basename at any depth. | |
| path | No | File or directory to search. Default: server cwd. | |
| word | No | Match whole words only. | |
| context | No | Lines of context on both sides of each match. | |
| dry_run | No | With replace: show the diff without writing. | |
| exclude | No | Globs to skip. | |
| literal | No | Treat pattern as plain text, not a regex. | |
| pattern | Yes | Regex to search for (JS syntax), or a literal string when literal=true. | |
| replace | No | Replacement text ($1 backrefs work). Rewrites the files unless dry_run=true. | |
| max_bytes | No | Byte cap on the returned text. Lower it to save tokens. | |
| max_depth | No | Recursion depth. Default 24. | |
| max_files | No | Stop after this many files with matches. Default 100. | |
| multiline | No | Let the pattern span lines (. matches newline). | |
| skip_dirs | No | Directory names not to enter (replaces the default list). | |
| count_only | No | Return just a match count per file. | |
| files_only | No | Return just the list of matching file paths — the cheapest mode. | |
| ignore_case | No | Case-insensitive match. | |
| max_results | No | Stop after this many matching lines. Default 200. | |
| show_hidden | No | Search dotfiles too. | |
| max_file_bytes | No | Skip files bigger than this. Default 2000000. | |
| respect_gitignore | No | Honour .gitignore. Default true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the default exclusions (.git/node_modules/build, binaries), .gitignore honouring, and — critically — that replace rewrites files on disk while dry_run only shows a diff. It stops short of stating permission requirements or interaction with respect_gitignore/skip_dirs overrides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, zero filler, and the core capability plus the two most decision-relevant modes are front-loaded before the riskier replace/dry_run note.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 21-parameter tool with no output schema, the description supplies the essentials an agent needs: what it searches, what it skips, what the output contains, and the one dangerous mode. It is reasonably complete, though it could say more about the interaction between user-supplied skip_dirs/glob/exclude and the built-in defaults.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 21 parameters thoroughly. The description restates a handful of them (files_only, count_only, replace, dry_run) in workflow terms, which is modest added value, but most parameter meaning lives in the schema and the description adds no syntax or default detail beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ("Grep a whole tree") and describes the output shape ("matching lines with file:line and optional context"), which is concrete and unambiguous. It never differentiates itself from the sibling search_files, so an agent must still infer the routing between the two.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit mode-selection guidance: "Use files_only=true to just locate files, count_only=true for tallies" and the replace/dry_run workflow. This covers when to pick each mode, but offers no guidance on when to prefer this tool over siblings like search_files or shell_exec, and no exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shell_bulkA
Run MANY commands in one call, in order — the token-efficient way to work. Each step supports: delay_before_ms/delay_after_ms, when (condition), expect_exit, retry, on_failure, assign (capture output into a variable) and capture (how much output to return). Conditions and ${...} interpolation can read earlier steps: prev.ok, prev.exit, prev.stdout, step..ok, steps[0].exit, vars., failed_count. Prefer capture="on_failure" for long pipelines: silent on success, full output where it broke.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | Working directory. Relative paths resolve against the server cwd. Default: server cwd. | |
| env | No | Extra environment variables. | |
| vars | No | Extra variables for this run, layered over the persistent store. Everything already in the store is readable as vars.<name> without repeating it here. | |
| shell | No | Override shell for this call: auto|bash|gitbash|zsh|fish|sh|cmd|powershell|pwsh|wsl, a configured name, or an absolute path. | |
| steps | Yes | Steps executed sequentially. A plain string is shorthand for {command: "..."}. | |
| capture | No | Default capture mode for every step. Default full. | |
| timeout_ms | No | Kill the command (whole process tree) after this many ms. 0 = no limit. | |
| max_total_bytes | No | Total output budget for the whole run; later steps get suppressed once spent. Default 40000. | |
| stop_on_failure | No | Abort the run at the first failing step. Default true. | |
| max_output_bytes | No | Byte cap on returned output before middle-truncation. Lower it to save tokens. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does disclose meaningful behavior: in-order sequential execution, per-step retry/condition/failure handling, cross-step state reading (prev.*, steps[i], vars.<name>, failed_count), and token-cost tradeoffs via capture. It omits the risky part of the picture: no warning about destructive side effects, no statement of permissions or sandboxing, and no hint about the shape of what comes back. Adequate but incomplete for a shell-execution tool with zero annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, front-loaded with the core purpose and then the step capabilities and expression namespaces. Dense but readable, with no filler prose. The middle list partially mirrors schema fields, which is slight redundancy, but it earns its place by framing the features before the agent opens the nested schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter tool with nested step objects, no output schema and no annotations, the description covers the essential mental model: batching, ordering, per-step conditions, retries, failure policy, variable assignment, and output capture. What is missing is the return structure of a run and explicit positioning against the other shell siblings, but the condition namespaces (prev.ok, failed_count) hint at the result shape.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description still adds value beyond the schema: it enumerates the readable namespaces for conditions and ${...} interpolation (prev.ok, prev.exit, prev.stdout, step.<id>.ok, steps[0].exit, vars.<name>, failed_count), which the schema only gestures at with an example. It also paraphrases assign and capture succinctly, so an agent can grasp the semantics without reading every nested property.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with a distinguishing scope: 'Run MANY commands in one call, in order', which implicitly separates it from the single-command siblings like shell_exec. It also tags the value proposition ('token-efficient way to work'). It stops short of naming an alternative tool outright, so the differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives one concrete usage preference ('Prefer capture="on_failure" for long pipelines') with the reason why (silent on success, full output where it broke). However, it never says when to choose shell_bulk over shell_exec or shell_exec_async, nor when sequential batching is inappropriate. Usage is implied by the batching framing rather than asserted.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shell_execA
Run a shell command and wait for it to finish. Returns exit code, stdout and stderr. Full system access via the default shell (or the one you name). Use for anything short-lived.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | Working directory. Relative paths resolve against the server cwd. Default: server cwd. | |
| env | No | Extra environment variables. | |
| login | No | Run through a login shell so ~/.profile aliases and PATH apply. | |
| quiet | No | Return only the exit code line, no output. Default false. | |
| shell | No | Override shell for this call: auto|bash|gitbash|zsh|fish|sh|cmd|powershell|pwsh|wsl, a configured name, or an absolute path. | |
| stdin | No | Text piped to the command on stdin. | |
| assign | No | Store the trimmed stdout in the server variable of this name, reusable later as ${vars.<name>} without passing it back. See the vars tool. | |
| command | Yes | Command line to run in the shell. Multi-line scripts are supported. | |
| timeout_ms | No | Kill the command (whole process tree) after this many ms. 0 = no limit. | |
| merge_streams | No | Report stderr inside stdout as one block (fewer tokens). Default false. | |
| max_output_bytes | No | Byte cap on returned output before middle-truncation. Lower it to save tokens. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does disclose meaningful traits: 'Full system access' signals the elevated privilege/risk, and it names the exact return surface (exit code, stdout, stderr) plus the blocking wait. It omits auth/permission requirements and side-effect warnings, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with the core action, return values, privilege scope, and usage condition all front-loaded. No filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-param, mutation-capable tool with no output schema, the description supplies the missing return-value semantics (exit code/stdout/stderr) and the privilege level, while the rich schema covers parameters. It stops short of only because destructive/irreversibility guidance is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 11 parameters in detail. The description adds only 'or the one you name' for the shell override and the return-value surface; it contributes little semantic detail beyond the schema, which is the correct baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Run a shell command') and scopes it behaviorally with 'wait for it to finish' and 'short-lived', which implicitly separates it from shell_exec_async. It never names the async sibling outright, so it falls just short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use for anything short-lived' gives clear positive guidance and, combined with 'wait for it to finish', implies that long-running work belongs elsewhere (shell_exec_async/shell_job). No explicit exclusion or named alternative, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shell_exec_asyncA
Start a command in the background and return a job_id immediately. For long builds, dev servers, watchers and tailing logs. Read or stop it later with shell_job.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | Working directory. Relative paths resolve against the server cwd. Default: server cwd. | |
| env | No | Extra environment variables. | |
| name | No | Label for the job, to recognise it in shell_job list. | |
| login | No | Run through a login shell. | |
| shell | No | Override shell for this call: auto|bash|gitbash|zsh|fish|sh|cmd|powershell|pwsh|wsl, a configured name, or an absolute path. | |
| command | Yes | Command line to run in the shell. Multi-line scripts are supported. | |
| timeout_ms | No | Kill the command (whole process tree) after this many ms. 0 = no limit. | |
| interactive | No | Keep stdin open so you can send input with shell_job action="write". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose key behavior: non-blocking start, immediate job_id return, and lifecycle management via shell_job. It doesn't cover output capture/buffering, resource cleanup, or permission needs, leaving some behavioral gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loading the core behavior, then use cases, then the follow-up tool. Every sentence earns its place with zero filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description does explain the key return value (job_id) and how to interact with it later via shell_job. Covers the essentials for an 8-param tool; only minor gaps remain around output handling and cleanup.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% – cwd, env, name, login, shell, timeout_ms, and interactive are all documented in the schema. The description adds no parameter-level detail beyond what the schema provides, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource+behavior ('Start a command in the background and return a job_id immediately'), which clearly distinguishes it from the foreground shell_exec and pairs it with shell_job. An agent knows exactly what this does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete use cases ('long builds, dev servers, watchers and tailing logs') and names the companion tool shell_job for reading/stopping the job. It does not explicitly state when NOT to use it (e.g., use shell_exec for short/blocking commands), but the async framing implies it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shell_infoA
Report the environment: platform, server cwd, active shell, which shells are installed, effective config and any active guardrails. Call this once at the start if you need to know what you are driving.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. 'Report' plus 'call this once' implies a safe, idempotent read with no side effects, and it discloses that guardrails and effective config are included. It does not explicitly confirm read-only/no-mutation behavior, nor describe the output shape, so the behavioral picture is only partially filled in.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the scope enumeration and closed with the actionable usage cue. No filler, no restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description must convey what comes back, and listing the reported categories (platform, cwd, shell, config, guardrails) does that reasonably well. It could be slightly more explicit about return structure, but an agent has enough to decide to call it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to document beyond what the schema already shows; the baseline of 4 applies. The description correctly does not invent parameter guidance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Report') and resource ('the environment') and enumerates exactly what is covered: platform, server cwd, active shell, installed shells, effective config, guardrails. It is clearly an inspection tool, though it never explicitly differentiates itself from the nearby sys_info or project_info siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Call this once at the start if you need to know what you are driving" gives a clear when-to-use condition and a frequency constraint ('once'). It stops short of naming alternatives (sys_info, vars) that an agent might choose instead for overlapping information.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shell_jobA
Inspect and control background jobs. actions: list | status | output | write | kill | wait | remove. output/wait can block up to wait_ms until new output appears, so one call replaces a polling loop; pass the returned next_offset back as offset to stream without re-reading what you already saw.
| Name | Required | Description | Default |
|---|---|---|---|
| data | No | For action="write": text to send to stdin (add \n yourself). | |
| action | Yes | list: all jobs. status: one job without output. output: incremental output. wait: block until the job exits. write: send stdin. kill: terminate. remove: kill and forget. | |
| job_id | No | Required for every action except "list". | |
| offset | No | Byte offset to read from (use next_offset from the previous call). Default 0. | |
| signal | No | For action="kill": SIGTERM (default), SIGKILL, SIGINT. | |
| stream | No | Which stream to read. Default combined. | |
| wait_ms | No | Block up to this long for new output / for exit. Default 0 (return at once). | |
| max_output_bytes | No | Byte cap on returned output before middle-truncation. Lower it to save tokens. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and usefully discloses that output/wait can block up to wait_ms and that offset supports incremental streaming via next_offset. It does not discuss permissions, side effects of kill/remove, or default behavior beyond what the schema already states, but the key blocking and streaming behaviors are surfaced.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences: purpose and action list first, then blocking behavior, then offset streaming. Every sentence adds useful information with no repetition or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an eight-parameter control tool with no output schema, the description covers the core mental model and the critical streaming protocol. It leaves some return-value and destructive-action context to the schema, but it is complete enough to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaningful semantics for offset and wait_ms by explaining how next_offset enables streaming without re-reading. It does not explain every parameter, but it improves the most important ones beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Inspect and control background jobs.' It enumerates all seven actions, making clear that this is the job-management tool rather than an execution tool like shell_exec or shell_exec_async.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context for using output and wait, including that blocking up to wait_ms replaces a polling loop and that next_offset should be reused as offset. It does not explicitly name alternatives such as shell_exec_async or state when not to use this tool, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sys_infoA
Facts about the machine: overview (default), cpu, memory, disk (free space per mount), network (interfaces), env (environment variables), uptime, user. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | Which facts to return. Default overview. | |
| filter | No | env: regex on the variable name, e.g. "^(PATH|NODE)". | |
| max_bytes | No | Byte cap on returned output. | |
| show_values | No | env: include values. Default true; set false to list names only. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose "Read-only" and clarifies scope for disk (free space per mount) and network (interfaces), but says nothing about output truncation despite max_bytes, nor about whether env output can expose sensitive values.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence front-loads the resource, then enumerates modes compactly, closing with the safety trait. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so describing what each action returns (free space per mount, interfaces, env variables) is the right move and it is done adequately. Minor gaps: no truncation behavior for max_bytes and the omitted "all" mode.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description glosses the enum values (memory, disk, network, env) with short parentheticals, which adds marginal meaning, but filter/show_values/max_bytes semantics live entirely in the schema and the "all" action is never mentioned.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (machine facts) and enumerates the specific fact categories it returns, so an agent knows exactly what it will get. It does not differentiate itself from plausible siblings such as proc or shell_info, leaving the boundary to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"overview (default)" implies the common usage path and "Read-only" frames the operation, which is useful implied guidance. There is no explicit when-to-use/when-not guidance and no mention of when a sibling like proc would be preferable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
varsA
Server-side variables that persist between calls, so a value never has to be re-sent through the conversation. Store once, then reference it as ${vars.} in later calls — in a command, cwd, env, a path, a URL, a header, a git message, a bulk step. list shows names, types and sizes but NOT full values (that is the saving). Mark a token secret:true and it stays usable via ${vars.…} while never being echoed back. shell_bulk assign, shell_exec assign and http_request assign all write here.
| Name | Required | Description | Default |
|---|---|---|---|
| json | No | load: parse the file as JSON instead of storing it as text. | |
| name | No | Variable name. Letters, digits, _ . - starting with a letter or _. | |
| path | No | load: file to read into the variable. save: file to write the variable to. | |
| text | No | append: the text (or array element) to add. | |
| delta | No | incr: how much to add. Default 1. | |
| names | No | get/delete: act on several names at once. | |
| value | No | set: the value — any JSON type. A string is itself ${...}-expanded, so you can compose from other variables. | |
| action | Yes | set | get | list | delete | clear | append (to a string/array) | incr (numeric) | load (read a file into a variable) | save (write a variable to a file). | |
| reveal | No | get: return a secret value in plain text. Only when you actually need to read it. | |
| secret | No | set/load: never echo this value back in get or list. It still works in ${vars.…}. | |
| ttl_ms | No | set: forget the variable after this long. | |
| confirm | No | clear: required, since it drops every variable. | |
| max_bytes | No | get: byte cap on the returned value. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it does well: it discloses that list shows names/types/sizes but not full values, that secret:true values remain usable via ${vars.…} while never being echoed, and that clear drops every variable. It omits permission/auth requirements and error behavior, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core concept and followed by reference syntax and behavioral notes. The middle list of contexts is long but each item is informative; little is wasted, though it could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-action, 13-parameter tool with no output schema, the description covers the crucial cross-cutting behaviors (persistence, reference syntax, secret handling, list redaction) that an agent cannot infer from the schema. The per-action semantics rest on the 100%-covered schema, so the combination is nearly complete; only auth/permission context is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds genuine semantics beyond the schema: the ${vars.<name>} expansion syntax, that a set value string is itself ${...}-expanded for composition, and the secret/reveal trade-off. These enrich interpretation rather than merely restating parameter names.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the resource (server-side variables that persist between calls) and its core value proposition (store once, reference via ${vars.<name>}). It conveys the multi-action nature by naming list, secret marking, and the writing tools, though it never frames itself explicitly as an action-dispatched store, so an agent must open the schema to grasp the full action set.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear when-to-use rationale ('so a value never has to be re-sent through the conversation') and enumerates the contexts where references work (command, cwd, env, path, URL, header, git message, bulk step). It also clarifies that secret values are excluded from list output, but gives no explicit when-not-to-use or disambiguation against sibling read/write tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
watchA
Watch a file or directory for changes. start returns a watch_id; poll blocks up to wait_ms for new events and returns them (so one call replaces a polling loop); list shows active watchers; stop ends one. Events are coalesced per path, so a save that fires three times is reported once.
| Name | Required | Description | Default |
|---|---|---|---|
| glob | No | start: only report paths matching these globs. | |
| path | No | start: file or directory to watch. | |
| clear | No | poll: drop the returned events from the buffer. Default true. | |
| action | Yes | What to do. | |
| exclude | No | start: ignore paths matching these globs. | |
| wait_ms | No | poll: block up to this long for the first event. Default 0 (return at once). | |
| watch_id | No | poll/stop: which watcher. | |
| max_bytes | No | Byte cap on returned output. | |
| recursive | No | start: watch subdirectories. Default true. | |
| settle_ms | No | poll: after the first event, wait this long for related ones before returning. Default 300. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses that start returns a watch_id, that poll blocks up to wait_ms, and that events are coalesced per path so a triple-save is reported once. It omits error/failure behavior and permission requirements, so it's strong but not complete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences with no waste, front-loaded with the tool's purpose before the action semantics. Every clause (watch_id return, poll blocking, coalescing) earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter, multi-action tool with no annotations and no output schema, the description covers the action lifecycle and key behaviors adequately. It doesn't describe the shape of returned events, but it covers enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all ten parameters with per-action notes and defaults. The description adds only the coalescing and blocking semantics, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Watch a file or directory for changes') and enumerates the four sub-actions, so the tool's scope is unmistakable. It doesn't explicitly contrast itself with siblings like fs_list or search_files, which keeps it short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It tells the agent how to use poll effectively ('one call replaces a polling loop') and what each action does, which is genuine usage guidance. However, there is no explicit when-to-use-this-vs-alternatives or when-not, so it stays at implied usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
26 tool updates
v0.1.0- First observed
archive - First observed
code - First observed
diff - First observed
encode - First observed
file_edit - First observed
file_read - First observed
file_write - First observed
fs_list - First observed
fs_op - First observed
git - First observed
http_request - First observed
json_tool - First observed
net - First observed
pkg - First observed
proc - First observed
project_info - First observed
search_files - First observed
search_text - First observed
shell_bulk - First observed
shell_exec - First observed
shell_exec_async - First observed
shell_info - First observed
shell_job - First observed
sys_info - First observed
vars - First observed
watch
TDQS
Scored across 26 tools
Most tools target a distinct resource or action, and descriptions explicitly clarify usage (e.g. shell_exec vs shell_bulk vs shell_exec_async). However, there are overlapping areas such as shell_info vs sys_info, fs_list vs fs_op stat, and pkg vs project_info that could cause hesitation.
All names use lower_snake_case, and multi-word tools follow a clear resource-oriented pattern (file_read, fs_list, http_request, shell_exec). Minor deviations exist: search_text/search_files invert the order to action_resource, and several single-word names (git, net, vars) break the verb_noun expectation.
26 tools is borderline heavy, sitting just above the 25-tool threshold. The breadth of the terminal domain justifies many of them, but there is some redundancy (shell_info/sys_info, fs_list/fs_op, pkg/project_info) that suggests consolidation could reduce the count.
Coverage is very broad for a terminal server: shell execution, filesystem, git, process management, networking, HTTP, packages, code introspection, JSON, diffing, encoding, archives, and watching. Missing or thin areas include remote/SSH operations, service/daemon management, and structured config formats beyond JSON, but agents can work around these via shell_exec.
Maintenance
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Remote shell and detached long-running jobs on your own machines — no SSH, open ports or VPN.
- emisarOAuthdev.emisar
Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.
Remote Linux boxes for coding agents: Docker, a browser, screenshots, logs, human takeover.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to SSH into Linux servers, run commands, deploy code, and manage servers via natural language, also doubles as a CLI for manual use.3MIT
- FlicenseAqualityDmaintenanceGives AI assistants full control over a VPS via SSH, enabling command execution, file management, service control, Docker and firewall management.96-
- AlicenseNot gradedqualityCmaintenanceEnables AI clients to manage files and documents, search code, run shell commands, and control processes locally across Windows, Linux, and macOS.1MIT
- FlicenseNot gradedqualityBmaintenanceEnables AI coding agents to run shell commands, spawn persistent background tasks, and read/write files inside isolated remote container sandboxes on a VPS. It also provides project workspace listing, task attach/kill controls, and a searchable knowledge graph for memory continuity across sessions.-