Linux MCP daemon
A Linux MCP daemon exposing typed MCP tools/resources to inspect and control a Linux host via JSON-RPC/SSE.
Files: list, read, create/overwrite, edit, find, MIME type, chmod, chown.
Disks: free space, directory usage, block devices, mounts, partitions, I/O counters, SMART health.
Processes: top snapshot, list/filter, signal/kill.
Network: DNS lookup, HTTP requests, ARP cache, TCP ping, socket connections, traceroute.
Memory/CPU: memory usage, CPU info, load average.
Services/logs: manage/list systemd services, timers, journal, dmesg, login history.
Kernel: read/write sysctl parameters.
Users/auth: list accounts, view your privileged grants.
Docker: containers, images, volumes, networks, logs, exec, lifecycle, prune.
Cron: read/replace crontabs.
Daemon admin: reload mcpd config without restart.
Resources: read static/template resources by URI (OS, processes, services, Docker, network, etc.).
Provides tools for interacting with the Linux operating system, enabling AI agents to introspect and manage processes, memory, disks, logs, network connections, services, and system settings via /proc, /sys, and systemd over D-Bus.

Linux MCP Daemon
A high-performance, Go-based Model Context Protocol (MCP) daemon (mcpd) designed to securely bridge AI agents directly with the Linux operating system.
Overview
This project implements a zero-dependency (kernel-first) philosophy. It allows AI agents to introspect and interact with the host Linux system directly via raw syscalls and the Virtual File System (/proc, /sys) without requiring bloated third-party parsing libraries.
Communication happens directly between the AI agent and the daemon via Server-Sent Events (SSE) and JSON-RPC over HTTPS on port 9091 (TLS is on by default, with a self-signed certificate generated on first start).
Related MCP server: linux-ssh-mcp-server
Why
An AI agent that helps run a server needs to see it - load, memory, disks, processes, services, logs, the network - and sometimes to act on it. The usual way is an SSH shell, and a shell is everything at once: any command, any file the account can reach, with sudo all of root, and hard to tell afterwards what was done. mcpd gives the agent typed tools instead of a shell:
Diagnose without a shell. "Why is the site slow?" -
processes/top,memory/usage,disks/usage,logs/journal-control,logs/dmesg,network/connections,services/listanswer it, with structured output (json/yaml) the agent doesn't have to scrape fromtopordf.Root per tool, not per session. A user runs every tool as its own OS account; root is granted per tool in
mcp-sudo.yamland limited by paths, network destinations and sysctl keys - "may read/var/logas root and restart services" rather than "is root".One agent, one account, one token. Each agent gets its own user, and every call is logged with the user, tool, arguments (secrets redacted) and result - an audit trail of what the agent did.
Small and self-contained. One static Go binary, reading
/proc,/sysand systemd over D-Bus itself; it runs on a bare host, in Docker or in Kubernetes, andlinuxctlgives people the same tools as a kubectl-like CLI.
Grant carefully. A root grant is root for an agent that follows instructions found in what it reads. Some grants that look narrow are full root (writes to
/etc,services/manage, sysctl writes). Read Permissions and Risks before granting anything.
How It Works
Every tool/resource call spawns a fresh worker process and exits. There's no long-lived state per call -
internal/worker/spawner.gore-execs themcpdbinary itself inworkermode (arguments on stdin, never argv), withsyscall.Credential{Uid, Gid, Groups}set to a real OS account resolved viauser.Lookup(). This is the actual privilege isolation, not a config flag: an unprivileged user's worker process is a genuinely different Linux UID than a privileged one's.configs/mcp-sudo.yamldecides, per user and per tool, whetherprivileged: trueis honored. Two grants exist for resources specifically (seeARCHITECTURE.md's gotcha section) - one for the resource URI itself, one for the internal worker tool name behind it.When
mcpdruns containerized (configs/daemon.yaml'sworker.containerized: true, this project's actual Kubernetes deployment), a privileged worker also joins the real host's mount namespace (setns(CLONE_NEWNS)on/proc/1/ns/mnt, no externalnsenterbinary) - soprivileged: truemeans root on the real host, not just root inside the daemon's own container image.Bearer tokens are salted+hashed in
users.yaml(token_salt+token_hash,sha256, constant-time compared; the file is0600), not stored in plaintext. Users and grants are edited only locally, on the host, vialinuxctl <verb> mcpd userandlinuxctl edit mcpd config(validated likevisudo) - there is no MCP tool that edits them, so nothing with just a bearer token can grant itself anything. The running daemon applies changes without a restart throughdaemon/reload-config, which only re-reads the files and rejects invalid ones (see Daemon User Administration).Every read is schema-driven, not hand-listed.
linuxctlfetchestools/list/resources/list/resources/templates/listfrom the live daemon on every invocation and resolves its<verb> <group> [keyword]grammar against that - a new tool added server-side is immediately usable client-side with zero code changes.
Features
Direct AI Interaction: HTTP/SSE transport for immediate agent-to-daemon communication.
Strict Security: Rate limiting, salted+hashed Bearer token authentication, and directory traversal protection.
Privilege Separation: Master daemon runs as root, spinning up ephemeral unprivileged/privileged workers based on rules defined in
configs/mcp-sudo.yaml.High Performance: Uses
singleflightdeduplication and TTL caching for efficient system introspection.Docker & Kubernetes Ready: Fully containerized with a multi-stage Docker build and Kubernetes deployment manifests that allow safe host introspection.
Get started
Install on Linux (systemd)
curl -fsSL https://raw.githubusercontent.com/nucleusv/linux-mcp-daemon/main/scripts/install.sh | sudo bashNeeds sudo and curl on an amd64/arm64 host (in a bare ubuntu/debian container: apt update && apt install -y curl ca-certificates, then pipe to bash as root). This downloads the latest release for your architecture (amd64/arm64), verifies its sha256 checksum, installs mcpd and linuxctl to /usr/local/bin, writes clean configs to /etc/mcpd/configs (no default users or tokens), creates a first user mcp and prints its token once, and starts the mcpd systemd service. Then:
export MCP_SERVER=https://127.0.0.1:9091
export MCP_TLS_FINGERPRINT=<printed by the installer>
export MCP_TOKEN=<token printed by the installer>
linuxctl get system os-release
linuxctl get processes topUpgrade: run the same command again - configs are kept, the service restarts only if
mcpdchanged. From v0.1.0, grant your first userdaemon/reload-configonce - see Upgrading.Pin a version / name the user:
... | sudo bash -s -- --version v0.1.0 --user aliceMore users: each needs an OS account of the same name - see Adding more users.
Uninstall:
... | sudo bash -s -- --uninstall(add--purgeto delete/etc/mcpd; themcpOS account stays -sudo userdel -r mcp)Packages:
.deband.rpmfor amd64/arm64 on every release -sudo apt install ./linux-mcp-daemon_<version>_amd64.deborsudo dnf install ./linux-mcp-daemon-<version>-1.x86_64.rpm, then the next steps it prints.Container image:
ghcr.io/nucleusv/linux-mcp-daemon(amd64/arm64) - setup steps in the installation docs.macOS (CLI only): the same script installs just
linuxctl-curl -fsSL .../install.sh | bash -s -- --bin-dir ~/.local/bin, thenexport PATH="$HOME/.local/bin:$PATH"(not on macOS's default PATH) - to drive a remote mcpd.
mcpd listens on all interfaces over TLS (a self-signed certificate it creates on first start; clients pin its fingerprint). Plain HTTP is off by default - bearer tokens would travel in clear text. Root access for tools is granted per user and per tool in
mcp-sudo.yaml.
Full guide: Installation · Connect an AI agent · mcp-sudo.yaml
Development: build from source
1. Build and Deploy the Server (mcpd)
Build the Docker image:
./scripts/build.shDeploy to your local Kubernetes cluster:
./scripts/deploy.sh
2. Build the Client (linuxctl)
You can build the CLI client directly on your host machine (e.g. macOS):
./scripts/build-cli.sh # writes executables/linuxctl
export PATH="$PWD/executables:$PATH" # so the examples below run as writtenInstalled from a release (install.sh, .deb/.rpm), linuxctl is already on your PATH.
3. Usage (local development)
The daemon runs on port 9091. You can connect via your AI client using SSE, or use the linuxctl CLI tool:
# Set your token as an environment variable
export MCP_TOKEN="your_token_here"
# Ping the daemon
linuxctl pinglinuxctl speaks a small verb/group grammar (linuxctl <verb> <group> [target-keyword] [args]) and dynamically discovers every tool and resource from the running daemon - there's no separate client-side command list to keep in sync. Full reference: linuxctl docs or man linuxctl. Every example below shows both forms: linuxctl, and the raw MCP JSON-RPC curl call it resolves to - the full per-tool/resource reference with these side by side for every single one lives at MCP API docs.
Calling the API directly with curl
mcpd speaks JSON-RPC 2.0 over HTTP + SSE, not plain request/response HTTP - every call is a two-step handshake: open an SSE stream to get a one-time POST endpoint, then POST the JSON-RPC request there (the actual result streams back on the SSE connection, not in the POST's response body):
# 1. Open the SSE stream in the background and capture the endpoint it prints
curl -N -s --cacert mcpd.crt -H "Authorization: Bearer $MCP_TOKEN" https://localhost:9091/sse &
# server sends: event: endpoint / data: /message?session_id=...
# 2. POST a request to that endpoint
curl -s --cacert mcpd.crt -X POST "https://localhost:9091/message?session_id=<from step 1>" \
-H "Authorization: Bearer $MCP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": "1", "method": "tools/list"}'
# 3. Watch the SSE stream from step 1 for the matching "id": "1" responseEvery example below follows this exact pattern - only the -d payload changes.
Files
# List a directory, as a table (get is the sole read verb - one result or many, same as kubectl)
$ linuxctl get files list /var/log --output table
MODIFIED NAME SIZE IS_DIR
2026-09-22 18:38:14 alternatives.log 6522 false
2026-09-22 18:38:10 apt 4096 true
...curl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"files/list","arguments":{"path":"/var/log","output_format":"table"}}}'# Read a single file's contents (bare - no keyword needed, files' only other read candidate)
linuxctl get files /etc/hostscurl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"files/read","arguments":{"path":"/etc/hosts"}}}'Resources (direct by URI)
# Read a static resource directly by URI (resource URIs always use scheme://path)
$ linuxctl resource os://uname
Sysname: Linux
Nodename: desktop-control-plane
Release: 7.0.12-linuxkit
...curl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"resources/read","params":{"uri":"os://uname"}}'Disks
# Native partition geometry - parsed from /sys/class/block, no fdisk dependency
linuxctl get disks partitions vda --output jsoncurl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"disks/partitions","arguments":{"device":"vda","output_format":"json"}}}'# Run a privileged tool (requires a root rule in configs/mcp-sudo.yaml)
linuxctl get disks free / --privileged truecurl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"disks/free","arguments":{"path":"/","privileged":true}}}'Processes: one result vs many, and rich detail
# Same underlying tool - bare form lists many, a specific PID filters to one
linuxctl get processes --sort_by mem --limit 5
linuxctl get processes 1234curl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"processes/list","arguments":{"pid":1234}}}'# Rich aggregated detail (combines several reads, excludes secret-shaped data like environ)
linuxctl describe processes 1234# describe aggregates multiple resources/read calls client-side - e.g. one of them:
curl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"resources/read","params":{"uri":"process://1234/status"}}'Logs (host-only tool, requires privileged: true in containerized deployments)
# journalctl only exists on the host, never in this daemon's own image
linuxctl get logs journal --unit kubelet.service --boot true --privileged truecurl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"logs/journal-control","arguments":{"unit":"kubelet.service","boot":true,"privileged":true}}}'Mutations (services, kernel)
linuxctl restart system services nginx.service --privileged true
linuxctl update kernel sysctl net.ipv4.ip_forward 1 --privileged truecurl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"services/manage","arguments":{"service":"nginx.service","action":"restart","privileged":true}}}'Docker (read, lifecycle, exec)
Talks to the Docker Engine API over its socket - no docker CLI needed. Every docker/* tool needs its own grant in mcp-sudo.yaml; the ones that name a container also need a containers: list, so an agent only touches the containers you list.
linuxctl get docker containers --all true # running and stopped
linuxctl get docker images
linuxctl get docker network bridge # one network's full configuration
linuxctl get docker container web-1 status # computed runtime summary (state, health, uptime, limits)
linuxctl resource docker-container://web-1/stats # the same templates by URI: docker-container://, docker-image://, docker-volume://, docker-network://
linuxctl get docker logs web-1 --lines 50
# needs docker/manage and docker/exec grants that list web-1
linuxctl restart docker web-1
linuxctl exec docker web-1 ls /usr/share/nginx/html
linuxctl exec docker web-1 -- ls --color /etc # after `--` everything goes to the container as-isCrontabs
Read, list and replace crontabs with the crontab command's own rules (cron.allow/cron.deny still apply). Writing a crontab schedules commands as that user, and the job survives the end of the session and the revocation of the token - read the crontab risks before you grant it.
linuxctl get crontabs # my own crontab, exactly as `crontab -l` prints it
linuxctl update crontabs --content "$(cat mycron.txt)" # replace my whole crontab
linuxctl edit crontabs # open it in $EDITOR, write back if unchanged meanwhile
# another user's crontab: sudo plus a rule naming that account in mcp-sudo.yaml
linuxctl get crontabs --privileged true # the users you may view that have a crontab
linuxctl get crontabs test_user --privileged true
linuxctl update crontabs test_user --privileged true --content "$(cat test_user.cron)"Introspecting the MCP protocol itself
linuxctl get mcp-api info # raw initialize response: protocol version + declared capabilities
linuxctl get mcp-api tools # every tool, by literal name
linuxctl get mcp-api resources # every static resource + template
linuxctl get mcp-api prompts # reports plainly that mcpd doesn't implement this MCP capabilitycurl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'Direct-by-name escape hatches (bypassing the verb grammar)
linuxctl tool files/list --path /tmp # symmetric with `resource <uri>` abovecurl -s -X POST "$ENDPOINT" -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"files/list","arguments":{"path":"/tmp"}}}'Daemon user/token administration (local-only, no network call at all)
linuxctl create mcpd user alice # generates a token, prints it once, writes to configs/*.yaml directly
linuxctl list mcpd usersThere's no curl equivalent for this group - see Daemon User Administration for why it's deliberately kept off the network entirely.
Project Structure
cmd/mcpd/: Main server application entrypoint.cmd/linuxctl/: The CLI client application.configs/: Configuration files (Daemon config, Sudo rules).internal/: Encapsulated business logic:auth/: Per-user rate limiting.config/:daemon.yaml,users.yamlandmcp-sudo.yamlparsing and validation (shared by mcpd andlinuxctl).rpc/: MCP JSON-RPC handlers - tool/resource registry, authorization, config reload.worker/: Spawns each call as a short-lived worker under the caller's OS account (or root).tools/,resources/: One package per tool and resource.fsafe/: Opening paths without following symlinks (openat with O_NOFOLLOW).kernel/,procstat/: Parsing/proc(sockets, processes).logging/: Leveled, structured logging.netpolicy/: Network destination policy fornetwork/curlandnetwork/ping.
k8s/: Kubernetes deployment manifests.scripts/: Build and deployment automation.
Releases
Pushing a SemVer tag (git tag -a v0.1.0 -m v0.1.0 && git push origin v0.1.0) runs .github/workflows/release.yml: tests, then GoReleaser publishes per-platform archives, checksums.txt and a changelog to GitHub Releases, and a multi-arch image to ghcr.io/nucleusv/linux-mcp-daemon.
License
Apache License 2.0 - see also NOTICE.
Available Tools
48 toolsauth/sudo-rulesARead-onlyIdempotent
Shows which tools YOU may run as root: your privileged grants from mcp-sudo.yaml with their paths, containers, prune, network and sysctl restrictions. It does not list which tools you may call at all: unprivileged calls need no grant, except docker/* and daemon/reload-config, which always do. Read-only and answered by the daemon itself. Call it before a privileged: true request or after a permission-denied error. Text is Your authorized privileged tools: followed by JSON; output_format: json returns only that JSON, whose keys are capitalised Go field names (Tools, Resources, Allowed, Paths, Containers, Prune, Network, Sysctl). No grants gives You have no privileged tools authorized in mcp-sudo.yaml. (JSON: {}). After an operator edits grants, daemon/reload-config applies them.
| Name | Required | Description | Default |
|---|---|---|---|
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses the exact output text, the JSON key shape (capitalised Go field names), the no-grants sentinel string, and the fact that grants are applied by daemon/reload-config. It also confirms it is read-only and daemon-answered, matching the readOnlyHint.
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?
Dense but front-loaded, leading with what the tool returns and what it excludes. Every sentence carries information (scope, usage trigger, output format, edge case, reload coupling), though the middle sentences pack multiple facts into one long clause.
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 fully compensates by specifying return format, JSON key names, the empty-grant case, and how grants get refreshed. An agent has everything needed to call it and interpret the result.
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 schema already documents output_format, but the description adds behavioral meaning: it explains what text mode emits versus json-only output and that yaml/table/wide collapse to the same JSON. That is more than the schema conveys, though not exhaustive.
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 (shows your privileged root grants) and precisely scopes what it covers versus what it does not ('It does not list which tools you may call at all'). The distinction from siblings like daemon/reload-config and docker/* is made explicit, so an agent can select it without opening a 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 explicit triggers: call before a `privileged: true` request or after a permission-denied error. It also names the exception set (docker/*, daemon/reload-config) that always needs a grant, so the when/when-not logic is complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cpu/listARead-onlyIdempotent
Lists the machine's CPUs from /proc/cpuinfo. Read-only. Text output shows the number of logical processors and, for the FIRST processor only, vendor, model name, MHz (or BogoMIPS) and cache size. output_format: json (also yaml/table/wide) returns an array with one object per logical CPU using /proc/cpuinfo's own field names, which differ by architecture (x86 model name, cpu MHz, flags; ARM CPU implementer). It does not report sockets, cores or threads separately, and topology_only has no effect. For current load use cpu/load-average, for per-process CPU processes/top, for OS and kernel system/os-release.
| Name | Required | Description | Default |
|---|---|---|---|
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text | |
| topology_only | No | Has no effect: accepted but ignored, the output is the same |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, but the description adds substantial context beyond them: text output only details the FIRST processor, json returns one object per logical CPU with architecture-dependent field names, and it explicitly discloses that it does not report sockets/cores/threads and that topology_only is inert.
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-loaded with purpose and read-only status, and each sentence carries distinct information (output shape, architecture caveats, sibling routing). It is dense and slightly long, but nothing 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?
With no output schema, the description carries the return-value burden and does so: it explains both the text and JSON output shapes plus the architecture-dependent field names. Nothing needed to call it correctly 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 meaning beyond it: output_format json/yaml/table/wide all return the same JSON array, and field names vary by architecture (x86 vs ARM). It restates topology_only's no-op, which is already in 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 and resource ('Lists the machine's CPUs from /proc/cpuinfo') and immediately differentiates itself from cpu/load-average, processes/top and system/os-release. An agent can select it 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?
Explicitly routes the agent to alternatives with the selecting condition: 'For current load use cpu/load-average, for per-process CPU processes/top, for OS and kernel system/os-release.' Both when-to-use and when-not-to-use are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cpu/load-averageARead-onlyIdempotent
Returns the 1, 5 and 15 minute load averages from sysinfo(2). Read-only; the only parameter is output_format. Load counts runnable plus uninterruptible tasks, not CPU percent: compare it with the number of logical CPUs from cpu/list. Text is Load Average: 0.52, 0.48, 0.45; output_format: json (also yaml/table/wide) returns an object with numbers 1_min, 5_min, 15_min. For per-process CPU use processes/top, for memory memory/usage.
| Name | Required | Description | Default |
|---|---|---|---|
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover readOnly/idempotent/destructive, and the description adds meaning beyond them: the exact metric semantics (runnable plus uninterruptible tasks, not a percentage), how to interpret it against cpu/list, and the concrete return shapes for text and structured formats. That is real behavioral context, not restatement.
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?
Text is dense but front-loaded with the core definition first, then interpretation, then format details, then sibling routing. Every sentence carries information an agent would otherwise have to guess.
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 appropriately supplies the return format (text example and JSON field names). Combined with the safety annotations and the interpretation guidance, an agent has everything needed to call and use it 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 already 100%, so the baseline is 3, but the description adds value beyond the schema by naming the returned fields (`1_min`, `5_min`, `15_min`) and noting that yaml/table/wide yield the same JSON as json. Minor redundancy on the default-text point keeps it from a 5.
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 (Returns) and resource (1, 5 and 15 minute load averages from sysinfo(2)), and immediately clarifies the semantics of 'load' (runnable + uninterruptible tasks, not CPU percent). An agent can distinguish it from cpu/list and processes/top without opening a 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: compare load against logical CPU count from cpu/list, use processes/top for per-process CPU, and memory/usage for memory. Both when-to-use and named alternatives are given, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cron/manageADestructiveIdempotent
Reads or replaces a user's crontab, the list of commands cron runs for that account on a schedule, and lists which accounts have one. Without content it reads: your own crontab as raw text exactly as crontab -l prints it (empty when you have none), or with privileged: true and no user, a table of the accounts that have a crontab and that your grant lets you view. With content it writes: the WHOLE crontab is replaced (an empty string clears it); the crontab command rejects a file it cannot parse and then the old crontab is unchanged; a missing final newline is added; the limit is 64 KiB. Your own crontab needs no grant and runs as you. Another account's needs privileged: true and a rule naming that account in your cron/manage grant (users: {name: {view: true, edit: true}}); edit implies view, root's crontab can be viewed but never edited, and cron.allow/cron.deny still apply to that account. WARNING: writing a crontab schedules commands as that user, and the job outlives this session and the revocation of your token; every write is audit-logged (size, lines, hash, never the content). To avoid overwriting a change made meanwhile, pass if_match with the sha256 you read (output_format: json returns it). For systemd timers use timers/list. Needs the crontab command on the host; inside a container a call sees the container's own crontabs.
| Name | Required | Description | Default |
|---|---|---|---|
| user | No | Account whose crontab to read or replace; default is your own. Another account needs privileged: true and a rule for it | |
| content | No | The complete new crontab; present = write (empty string clears it), absent = read. Standard crontab syntax: `m h dom mon dow command`, `@daily`, and NAME=value lines | |
| if_match | No | sha256 of the crontab as you read it; the write is refused if it has changed since | |
| privileged | No | Needed to list crontabs or to act on another account (needs a cron/manage grant); ignored for your own crontab | |
| output_format | No | 'json' (also yaml/table/wide, which return the same JSON) returns {user, exists, lines, jobs, bytes, sha256, content} for a read; default is the raw text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far exceeds the annotations (destructiveHint/readOnlyHint/idempotentHint): discloses whole-crontab replacement, empty-string clearing, rejection of unparseable files leaving the old crontab intact, added final newline, 64 KiB limit, audit logging (size/lines/hash, never content), job persistence beyond session/token revocation, and container scoping. This is exactly the behavioral context annotations cannot carry.
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 core read/write distinction is front-loaded and every sentence is functional, but it is a dense single paragraph carrying a lot of interleaved detail (grants, edge cases, limits, warnings) that would benefit from tighter structuring.
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 destructive read/write tool with no output schema, it covers permissions, concurrency, failure semantics, size limits, audit trails, and the container caveat. Nothing an agent needs to call it safely 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 baseline is 3, but the description adds real meaning: `content` presence triggers write vs read, `if_match` enables optimistic-concurrency protection, and `output_format: json` returns the sha256 needed for `if_match`. It also clarifies that `privileged` is ignored for your own crontab.
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 specific verbs and resource: 'Reads or replaces a user's crontab' plus the listing behavior. It explicitly distinguishes itself from the sibling timers/list ('For systemd timers use timers/list'), so an agent can route correctly without opening either 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 explicit mode selection: without `content` it reads, with `content` it writes; spells out the `privileged`+`user` combinations, the grant rule requirement, and the alternative tool for systemd timers. When-to-use and prerequisites are fully covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
daemon/reload-configAIdempotent
Re-reads mcpd's config files (daemon.yaml, users.yaml, mcp-sudo.yaml) and applies them without a restart: users and tokens, per-user grants, rate limits and tool timeouts. The files themselves are edited on the host (linuxctl); this only reloads them. Mutating (replaces the in-memory config) and always needs allowed: true for daemon/reload-config in the caller's grant; there is no unprivileged mode. The files are validated strictly first (a misspelled key is an error): if any is invalid nothing changes and the error is returned. Sessions of removed users and of users whose token changed are closed, possibly the caller's own. Server settings (port, TLS, worker.containerized, Docker socket) still need a restart. Returns free text listing what changed. Takes no parameters; verify grants afterwards with auth/sudo-rules.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses the grant requirement (`allowed: true`, no unprivileged mode), the strict validate-then-apply atomicity (a misspelled key means nothing changes and an error is returned), and the side effect that sessions of removed or re-tokened users are closed, possibly the caller's own. It also states the return is free text and that it takes no parameters.
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-loaded with the core action, and nearly every clause carries distinct information (files, affected settings, auth requirement, validation semantics, side effects, restart caveat). It is dense as a single run-on paragraph, so readability is slightly below ideal, but there is little 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, but the description states the return is free text listing what changed. Combined with the disclosed auth requirement, atomicity, session-closure side effects, and restart boundary, an agent has everything needed to invoke and interpret this 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?
Zero parameters, so the baseline is 4; the description explicitly confirms 'Takes no parameters', which is consistent with the empty schema. There is no further parameter meaning to add.
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 (re-reads mcpd's config files) and enumerates exactly what gets applied: users/tokens, per-user grants, rate limits, tool timeouts. It names the concrete files (daemon.yaml, users.yaml, mcp-sudo.yaml) and is clearly distinguishable from every sibling, none of which touch daemon configuration.
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 delineates when this is the right tool versus alternatives: the files are edited on the host via linuxctl and this only reloads them, server settings (port, TLS, worker.containerized, Docker socket) still require a restart, and grants should be verified afterwards with auth/sudo-rules. Both boundaries and follow-up routing are spelled out, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disks/freeARead-onlyIdempotent
Reports space on the ONE filesystem holding path (statfs, like df for a single path): total, used and free bytes and use percent (human_readable for GiB). Read-only; path must be absolute. It does not name the device or mount point: use disks/mounts for that, disks/list for block devices, disks/usage to see which folders use the space. There is no all-filesystems mode; call it once per mount point. free is what non-root users can use, and used is total minus that. inodes: true returns inode counts as plain text and ignores output_format and human_readable. Text output is three lines; output_format: json returns an object (path, total_bytes, used_bytes, free_bytes, use_percent, plus total_human, used_human, free_human with human_readable). privileged: true (a grant, and a paths: entry for root) only for paths you cannot stat.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path to check | |
| inodes | No | Report inode counts instead of block usage (-i); the reply is always plain text and ignores output_format and human_readable | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text | |
| human_readable | No | Sizes like 53.2 GiB (df -h); default is bytes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly/idempotent/non-destructive), and the description adds substantial context beyond them: the semantics of `free` vs `used`, that `inodes: true` forces plain text and ignores other flags, and that `privileged: true` requires a grant plus a `paths:` entry or it is refused.
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?
Dense and front-loaded — the core purpose and the 'single filesystem' constraint come first, then routing, then flag behavior. Almost every clause carries information, though the single paragraph is long and would read better split.
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 carries the return-value burden and does so: three text lines, or a JSON object enumerating path, total_bytes, used_bytes, free_bytes, use_percent plus human variants. Combined with the documented flag interactions and privilege requirements, nothing needed to call it correctly 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 real meaning: `free` is what non-root users can use and `used` is total minus that, and it documents cross-parameter interactions (inodes overriding output_format/human_readable) that the per-field schema descriptions do not fully capture.
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 ('Reports space on the ONE filesystem holding `path` (statfs, like `df` for a single path)') with exact scope (single filesystem, not all). It explicitly distinguishes itself from disks/mounts, disks/list, and disks/usage, so an agent can route without opening a 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?
Names each sibling alternative and the condition that selects it ('use disks/mounts for that, disks/list for block devices, disks/usage to see which folders use the space'). It also states the negative case explicitly: 'There is no all-filesystems mode; call it once per mount point.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disks/healthARead-onlyIdempotent
Returns a drive's SMART data as smartctl's JSON (wraps smartctl -j -a; the smartmontools package must be installed or the call fails saying so). Read-only, but normally needs root: use privileged: true (needs a grant), since without it smartctl usually cannot open the device. device is a bare kernel name such as sda or nvme0n1, never a path; find names with disks/list. The reply is smartctl's JSON verbatim (keys such as smart_status, temperature, ata_smart_attributes or nvme_smart_health_information_log vary by drive type); a non-zero smartctl exit is not an error when it printed JSON, and virtual disks report SMART as unsupported. For I/O counters use disks/performance.
| Name | Required | Description | Default |
|---|---|---|---|
| device | Yes | Bare kernel device name such as 'sda' or 'nvme0n1' (never a path) | |
| privileged | No | Run as root - required to read SMART data. Needs a grant for this tool in mcp-sudo.yaml |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safe-read profile, and the description adds context they cannot: root is normally required, privileged:true needs a grant, failure mode when smartmontools is absent, that a non-zero smartctl exit is not an error when JSON was printed, and that virtual disks report SMART as unsupported.
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?
Dense but front-loaded with the return value first, then prerequisites, then parameter semantics, then edge cases. Slightly long, yet each sentence carries distinct operational information rather than restating structured fields.
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 compensates by describing the return shape (smartctl JSON verbatim, keys varying by drive type) plus the error/edge-case behavior, leaving nothing an agent needs to call it correctly unaddressed.
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 baseline is 3, but the description adds value beyond the schema: it clarifies `device` must be a bare kernel name never a path, and explains why `privileged` is needed (smartctl usually cannot open the device without root).
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, resource, and output form ('Returns a drive's SMART data as smartctl's JSON'), and clearly separates itself from siblings by routing I/O counters to disks/performance and device-name discovery to disks/list.
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 when-to-use routing ('find names with disks/list', 'For I/O counters use disks/performance') and prerequisites (smartmontools installed, privileged:true with a grant). Nothing about when to reach for this tool is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disks/listARead-onlyIdempotent
Lists block devices as a tree (like lsblk): disks, partitions, and LVM/dm-crypt/RAID volumes nested under the devices they are built on, with MAJ:MIN, RM, SIZE, RO, TYPE and MOUNTPOINTS, read from /sys/class/block (no lsblk needed). Read-only. Empty devices and RAM disks are hidden unless all: true; SIZE is in bytes unless human_readable. output_format: json (also yaml/table/wide) returns an object blockdevices, an array of objects (name, kname, maj:min, rm, size, size_bytes, ro, type, mountpoints) with nested children. In containerized deployments use privileged: true (needs a grant) to see the host's mount points. For free space or inodes use disks/free, for folder sizes disks/usage, for the mount table disks/mounts, for partition boundaries disks/partitions, for I/O counters disks/performance, for SMART disks/health.
| Name | Required | Description | Default |
|---|---|---|---|
| all | No | Include empty devices and RAM disks (lsblk -a) | |
| privileged | No | Run as root - in containerized deployments, reads the host's mount table for MOUNTPOINTS | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text | |
| human_readable | No | SIZE like lsblk (60G); default is bytes (lsblk -b) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and non-destructive, so the safety burden is lower. The description still adds real behavioral context: default filtering of empty devices and RAM disks, SIZE units (bytes vs human_readable), and the privileged/container mount-point caveat. It doesn't disclose pagination or output size, but for a listing tool this is rich.
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-loaded with purpose, then filters, then output shape, then sibling routing. Dense but every sentence carries information. The long sibling enumeration is slightly list-like but each entry is a distinct routing decision, so it 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?
No output schema exists, and the description compensates by naming the returned JSON shape (blockdevices array with nested children and field names). Combined with the filtering, unit, and privilege caveats and explicit sibling routing, an agent has everything needed to call it 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 params are documented in the schema (baseline 3). The description goes beyond by explaining the consequences of the flags — output_format json returns a blockdevices object with nested children, and privileged 'needs a grant' — adding meaning the schema's one-line descriptions don't fully convey.
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 ('Lists block devices as a tree (like lsblk)') with concrete scope (disks, partitions, LVM/dm-crypt/RAID volumes) and the data source (/sys/class/block). It explicitly routes the agent away from siblings with different purposes ('For free space or inodes use disks/free...'), making it unambiguous against disks/partitions, disks/mounts, and others.
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 when-to-use signals (empty devices hidden unless all:true, containerized deployments need privileged:true) and names seven alternative sibling tools with the condition that selects each (free space, folder sizes, mount table, partition boundaries, I/O counters, SMART). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disks/mountsARead-onlyIdempotent
Lists mounted filesystems (device, mount point, type, options) from /proc/thread-self/mounts, sorted by mount point. Read-only. fs_type filters by exact type (ext4, overlay, tmpfs; no globs). It reads the daemon's own mount namespace, so in a container use privileged: true (needs a grant) to get the host's mounts. Text lines look like /dev/sda1 on /mnt type ext4 (rw,...); output_format: json returns an array of objects (device, mount_point, fs_type, options), or null rather than [] when nothing matches (text is then empty). For block devices use disks/list, for the space used on a mount disks/free.
| Name | Required | Description | Default |
|---|---|---|---|
| fs_type | No | Exact filesystem type, no globs (e.g. 'ext4', 'overlay', 'tmpfs') | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower; the description still adds real context: it reads the daemon's own mount namespace, container usage requires a privileged grant, and it documents an edge case (returns null rather than [] when nothing matches). This is behavioral information not present in annotations or schema.
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-loaded with the core purpose and data source, then constraints, then output shape, then sibling routing. It is a dense single block but nearly every clause carries actionable information; only the textual line-format example is arguably illustrative 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, but the description compensates by describing both the text line format and the JSON array shape (device, mount_point, fs_type, options) plus the null-when-empty behavior. Combined with the routing and privilege notes, nothing needed to call it correctly 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 3 is the baseline, but the description adds meaning beyond it: fs_type is an exact match with no globs, privileged needs a sudo grant or is refused, and json vs text output behavior (with the null edge case). It enriches the parameters rather than merely restating them.
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?
Specific verb+resource: 'Lists mounted filesystems (device, mount point, type, options)' with an explicit data source (/proc/thread-self/mounts) and ordering. It also names the neighboring tools it is not ('For block devices use disks/list, for the space used on a mount disks/free'), so an agent can disambiguate without opening a 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 to alternatives: disks/list for block devices and disks/free for mount usage. It also states the precondition for host mounts in a container (privileged: true, which needs a grant), covering when-to-use and a key constraint rather than leaving it to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disks/partitionsARead-onlyIdempotent
Lists the partitions of a disk with start sector and size in sectors and bytes, read natively from /sys/class/block (no fdisk). Read-only. device names the PARENT DISK (sda, nvme0n1), not a partition; without it every disk's partitions are listed. A sector size of 512 bytes is assumed. It does not report partition type, label, UUID or filesystem: use disks/list or disks/mounts for those, and disks/list to find device names. A named disk without partitions is an error (no partitions found for device). Output is a text table; when output_format is set to any non-empty value (the parameter is accepted although not listed in the schema) it is an indented JSON array of objects (device, parent_disk, number, start_sector, size_sectors, size_bytes).
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Parent disk name such as 'sda' or 'nvme0n1' (not a partition); omit for all disks |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only/idempotent safety profile, and the description goes well beyond them: native /sys/class/block read path, the 512-byte sector-size assumption, the error case for a named disk with no partitions, and both output shapes (text table vs indented JSON). This is the kind of behavioral context annotations cannot express.
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-loaded with the core purpose and read-only note, then the device semantics and alternatives follow in a logical order. It is dense but nearly every clause carries information; only the device restatement slightly duplicates 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?
With no output schema, the description supplies the return shape (text table or JSON array with named fields), the key assumption (512-byte sectors), and the error behavior. An agent has everything needed to call it correctly and interpret the result.
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% and the schema already documents 'device' as a parent disk name, so the description's re-statement is redundant. It does add value by explaining the omission default and by disclosing an accepted but schema-undocumented output_format parameter, which meaningfully expands the invocation surface.
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 ('Lists the partitions of a disk') plus the exact data returned (start sector, size in sectors and bytes) and the data source (/sys/class/block, no fdisk). It explicitly distinguishes itself from disks/list and disks/mounts, which cover label/UUID/filesystem information.
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 when-not guidance ('does not report partition type, label, UUID or filesystem: use disks/list or disks/mounts') and routes the agent to disks/list for discovering device names. It also clarifies the meaning of the optional device argument, including the default behavior when omitted.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disks/performanceARead-onlyIdempotent
Returns block-device I/O counters from /proc/diskstats: reads and writes completed and merged, sectors (512 bytes) and milliseconds spent, in-flight I/Os and weighted I/O time. Values are CUMULATIVE since boot, not rates and not iostat's per-interval figures; there is no %util or await, so sample twice and subtract to get a rate. Read-only. Without device all devices are listed except loop* and ram*; a name such as sda (find them with disks/list) selects one, and an unknown name gives no such block device. Text output is a table; output_format: json and yaml (real YAML here) return an array of objects with 14 fields (major, minor, device_name, reads_completed, ..., weighted_time_ios_ms). For capacity use disks/free, for SMART health disks/health.
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Block device name such as 'sda' (see disks/list); omit for all except loop* and ram* | |
| output_format | No | json or yaml (real YAML) for structured output; default is a text table |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered; the description nonetheless adds meaningful behavior: values are cumulative since boot (not rates), no %util or await exist, loop*/ram* are excluded by default, and an unknown device yields 'no such block device'. The one gap is that it never describes pagination or output size limits for the all-devices case, which keeps this from 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?
It is dense but front-loaded: the first sentence establishes source and payload, then semantics, then caveats, then alternatives. Almost every clause carries information, though the parenthetical field enumeration ('major, minor, device_name, ...') is slightly over-long for what it conveys.
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 carry return-value semantics itself, and it does: text table by default, JSON/YAML array of 14 named fields, plus cumulative-vs-rate interpretation. Combined with device filtering and error behavior, an agent has everything needed to call and interpret this 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 genuine semantics beyond the schema: 'a name such as sda', the exact default-filtering rule (all except loop* and ram*), the error string for an unknown name, and that yaml means real YAML with 14 named fields in JSON/YAML mode.
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 and resource ('Returns block-device I/O counters from /proc/diskstats') and enumerates exactly which counters are returned. It also distinguishes itself from siblings by naming disks/free (capacity), disks/health (SMART) and disks/list (device discovery) as different tools.
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 when this tool is the wrong choice ('For capacity use disks/free, for SMART health disks/health'), how to obtain a rate (sample twice and subtract), and how to resolve a device name (find them with disks/list). Both the use case and the alternatives are explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disks/usageARead-onlyIdempotent
Measures how much disk space a directory tree uses (native walk, like du). Read-only. For the free space of a whole filesystem use disks/free; to find individual big files use files/find with size. By default the reply is one grand total; max_depth: N also lists directories up to N levels deep, largest first; all: true adds a per-file list (text output only). Sizes are allocated blocks unless apparent_size: true; hard links count once, symlinks are never followed. exclude patterns containing / match the full path (/proc, /var/lib/*), others the base name. Unreadable directories are skipped silently, so an unprivileged total can under-count: use privileged: true (a grant with a paths: entry). Results are cached for 60 s per user and arguments. The shipped config allows 300 s, otherwise the default is 30 s. Text ends with Total size of PATH: N; output_format: json returns an object (path, total_size, human_size with human_readable, directory_sizes as a path-to-bytes map only when max_depth > 0).
| Name | Required | Description | Default |
|---|---|---|---|
| all | No | Also list every file, largest first (text output only) | |
| path | Yes | Absolute path of the directory to measure | |
| exclude | No | Patterns to skip: one containing '/' matches the full path (e.g. '/proc', '/var/lib/*'), others the base name (e.g. '*.tmp') | |
| max_depth | No | 0 or omitted: grand total only; N: also list directories up to N levels deep, largest first | |
| threshold | No | Bytes: a positive value hides entries smaller than this, a negative value hides larger ones (printed lines only) | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused | |
| apparent_size | No | Report logical file sizes instead of allocated disk blocks | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text | |
| separate_dirs | No | For directories do not include size of subdirectories (-S) | |
| human_readable | No | Sizes like du -h (4.0 KiB); default is bytes | |
| one_file_system | No | Skip directories on different file systems (-x) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial context beyond them: 60 s per-user result caching, the 300 s shipped vs 30 s default timeout, silent skipping of unreadable directories (and the resulting possible under-count), hard-link/symlink handling, and the `privileged` grant requirement via mcp-sudo.yaml. The one meaningful gap is that it doesn't say whether `exclude` or `threshold` interact with the cached result set, but overall this is unusually rich behavioral disclosure.
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 purpose and sibling routing are front-loaded, followed by dense but relevant behavioral and parameter detail. Every sentence carries information, though the single long paragraph is heavy and could be broken up for 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?
For an 11-parameter tool with no output schema, the description compensates well: it explains default vs max_depth vs all output modes, the text trailer ('Total size of PATH: N'), and the JSON object shape including directory_sizes only when max_depth > 0. Nothing an agent needs to call or interpret the result 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; the description goes further by tying parameters to output behavior ('By default the reply is one grand total; max_depth: N also lists directories...; all: true adds a per-file list (text output only)') and clarifying that allocated blocks are the default unit unless apparent_size. It leaves `threshold`, `separate_dirs`, and `one_file_system` entirely to the schema, so it isn't a full complement.
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 ('Measures how much disk space a directory tree uses') and explicitly frames it against siblings, calling out `disks/free` for filesystem free space and `files/find` for individual big files. An agent can distinguish this from the other disks/* tools 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 names the two alternatives (whole-filesystem free space -> `disks/free`; individual big files -> `files/find` with `size`) and the conditions that select them. This is textbook when-to-use/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
docker/containersARead-onlyIdempotent
Lists Docker containers through the Engine API on the local socket (no docker CLI needed): name, image, state, status, ports. Read-only. Only running containers unless all: true; state (created, running, paused, exited, ...) filters to one state and implies all; pattern is a glob on the container name (web-*); limit returns the newest N. Every container is listed: the grant's containers: list applies only to docker/manage, docker/logs and docker/exec. Text is a block per container plus a hint line, or No containers found matching the criteria.; output_format: json (also yaml/table/wide) returns an array of objects (name, names, id, full_id, image, image_id, command, state, status, created, ports, labels), [] when empty. For logs use docker/logs, to start or stop docker/manage, for one container's details the docker-container://<name>/status resource. Always runs as root: no privileged argument, refused unless the user's grant has allowed: true.
| Name | Required | Description | Default |
|---|---|---|---|
| all | No | Include stopped containers (docker ps -a) | |
| limit | No | Return at most this many containers (newest first) | |
| state | No | Only containers in this state (implies all) | |
| pattern | No | Only containers whose name matches this glob (e.g. 'web-*') | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent, but the description adds substantial behavioral context beyond them: it always runs as root with no privileged argument, caller requires grant allowed: true or it is refused, empty-result text differs by format, and JSON returns [] when empty. These are exactly the operational facts an agent cannot infer from the annotations.
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-loaded with purpose and scope, and every sentence carries routing, filtering, or auth information. It is dense and somewhat long for a listing tool, and the output-format behavior is described in two passes (text hint line, then json/yaml/table/wide), which is slightly redundant.
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 five-parameter read-only listing tool with no output schema, the description covers filtering semantics, both return shapes (text block + hint line, or JSON array with named fields), empty-result behavior, and the authorization prerequisite. Nothing an agent needs to call it correctly 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 cross-parameter semantics (state implies all, limit returns the newest N) and worked examples (glob 'web-*') that clarify how the filters interact. It does duplicate some schema text, keeping it from a 5.
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 (Lists), resource (Docker containers), and mechanism (Engine API on the local socket, no docker CLI), then names the exact fields returned. It explicitly distinguishes itself from docker/logs, docker/manage, docker/exec, and the docker-container:// status resource, so an agent can route correctly 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?
Gives explicit routing rules: 'For logs use docker/logs, to start or stop docker/manage, for one container's details the docker-container://<name>/status resource.' It also states the condition that selects each filter mode (all vs. state vs. pattern vs. limit) and notes the grant's containers: list does not apply here.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
docker/execADestructive
Runs ONE command inside a running container and returns its stdout, stderr and exit code: no TTY, no stdin, no follow. The highest-risk docker tool: arbitrary code, as the image's user (often root) unless user is set, with its own containers: grant list. Always runs as root at the Docker socket: no privileged argument, refused unless the grant has allowed: true. command is an argv array, not a shell line: ["sh", "-c", "ls /app"] for a shell. A non-zero exit code is not a tool error; read exit_code. timeout (seconds, default 30, capped at 300) is bounded by the worker limit, which is 30 s unless the operator sets timeout_seconds for docker/exec in daemon.yaml: then the answer is timed out after N seconds and the command keeps running in the container. Output is capped at 1 MiB. Text shows Exit code: N and the output; output_format: json returns container, id, command, exit_code, running, stdout, stderr. To read logs use docker/logs, to manage the container docker/manage.
| Name | Required | Description | Default |
|---|---|---|---|
| user | No | Run as this user inside the container (name or uid[:gid]); default is the image's user | |
| command | Yes | argv array, e.g. ["sh", "-c", "ls /app"] | |
| timeout | No | Seconds to wait (default 30, values above 300 are capped at 300); the worker limit (30 s unless raised in daemon.yaml) ends the call first | |
| container | Yes | Container name, full ID or ID prefix | |
| working_dir | No | Working directory inside the container | |
| output_format | No | json returns container, id, command, exit_code, running, stdout, stderr; default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive/non-readonly/non-idempotent, but the description goes well beyond them: no TTY/stdin/follow, runs as root at the socket, as the image's user unless `user` is set, non-zero exit is not a tool error, timeout interaction with the worker limit and continued execution after timeout, and a 1 MiB output cap. This is exactly the extra behavioral context that matters for a high-risk 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?
Dense and front-loaded: purpose, then risk profile, then argument semantics, then timeout/output behavior, then sibling routing. It is long, but each sentence carries distinct operational information rather than 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, yet the description documents the return shape for both text ('Exit code: N' plus output) and json (container, id, command, exit_code, running, stdout, stderr). Combined with risk, timeout and argument semantics, an agent has everything needed to call it 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 genuine meaning the schema does not: `command` is an argv array rather than a shell line (with an sh -c example), and `timeout` is bounded by the worker limit which can override it. These nuances materially affect correct invocation.
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+scope ('Runs ONE command inside a running container and returns its stdout, stderr and exit code') and immediately narrows it ('no TTY, no stdin, no follow'). It names the siblings it is not (docker/logs, docker/manage), so an agent can route correctly without opening schemas.
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 to alternatives ('To read logs use docker/logs, to manage the container docker/manage') and states the conditions for use: refused unless the grant has allowed: true, and the grant-list requirement. Both when-to-use and when-not-to-use are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
docker/imagesARead-onlyIdempotent
Lists Docker images through the Engine API on the local socket: tags, ID, size, creation time. Read-only (no pull, build or remove). Untagged intermediate layers are hidden unless all: true; untagged images that are shown appear as <none>:<none>. pattern is a glob on any tag or repository (nginx*, */api:*). Text is tag lines with ID | Size | Created; output_format: json (also yaml/table/wide) returns an array of objects (id, full_id, repo_tags, repo_digests, size_bytes, created, containers = how many containers use it, labels), [] when empty. To delete unused images use docker/prune (target images, dangling only); for containers docker/containers; for one image's config the docker-image://<ref>/inspect resource. Always runs as root: no privileged argument, refused unless the grant has allowed: true.
| Name | Required | Description | Default |
|---|---|---|---|
| all | No | Include intermediate and untagged images (docker images -a) | |
| pattern | No | Only images whose tag or repository matches this glob (e.g. 'nginx*', '*/api:*') | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: discloses that untagged layers are hidden unless all:true, how untagged images render (<none>:<none>), that it always runs as root with no privileged argument, and that it is refused unless the grant has allowed:true. That is auth and filtering behavior the readOnly/idempotent hints do not convey.
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 purpose, then filtering semantics, then output shape, then routing and auth. Information-dense, but it is one long paragraph and the root/refusal clause is buried at the end when it is a critical operational constraint.
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 fully compensates by describing both the text format (tag lines with ID | Size | Created) and the JSON object shape, plus empty-result behavior ([]). Combined with sibling routing and the root requirement, an agent has everything needed to call it 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 real meaning: pattern is a glob over tag or repository with concrete examples, all:true controls intermediate/untagged visibility, and output_format's array is itemized by field (id, full_id, repo_tags, size_bytes, containers, labels). Field-level return detail exceeds 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 (Lists) and resource (Docker images) with scope (on the local socket via Engine API) and enumerates what is returned (tags, ID, size, creation time). It also carves itself out from siblings by naming docker/prune, docker/containers and the docker-image inspect resource.
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: deletion goes to docker/prune (target images, dangling only), containers go to docker/containers, and per-image config goes to the docker-image:// resource. The when-to-use boundary is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
docker/logsARead-onlyIdempotent
Reads one container's recent logs, the container counterpart of logs/journal-control: stdout and stderr interleaved in Docker's order, the last lines lines (default 100), never a follow. Read-only. since/until take a unix timestamp (1759005000) or an RFC3339 time; stdout and stderr default to true (both false returns nothing); timestamps prefixes each line. The answer is capped at 1 MiB and an oversized tail is cut at the END without a marker, so the newest lines can be lost: ask for fewer lines. Only containers in the grant's containers: list; always runs as root, refused unless the grant has allowed: true. Plain log text by default (Container X (ID) has no log output for this selection. when empty); output_format: json returns container, id, lines, logs. To run a command use docker/exec; for host logs logs/journal-control.
| Name | Required | Description | Default |
|---|---|---|---|
| lines | No | Tail this many lines (default 100) | |
| since | No | Only entries after this time: unix timestamp (e.g. 1759005000) or RFC3339 | |
| until | No | Only entries before this time: unix timestamp or RFC3339 | |
| stderr | No | Include stderr (default true) | |
| stdout | No | Include stdout (default true) | |
| container | Yes | Container name, full ID or ID prefix | |
| timestamps | No | Prefix every line with Docker's own timestamp | |
| output_format | No | json returns container, id, lines, logs; default is raw log text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safe-read profile (readOnlyHint, idempotentHint, destructiveHint=false), yet the description adds substantial context beyond them: interleaved stdout/stderr ordering, never-follow semantics, a 1 MiB cap with the oversized tail silently cut at the END (so newest lines can be lost), the auth/grant refusal condition, and the empty-result message. This is the kind of operational detail that prevents silent surprises.
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-loaded with the core purpose and alternatives, and every clause carries information (defaults, truncation, auth, output shape). It is dense and semicolon-heavy, which slightly reduces scanability, but there is essentially no filler to cut.
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 output schema, the description covers everything an agent needs: return format (plain text vs `output_format: json` fields), empty-result behavior, auth/grant requirements, and the lossy truncation case. Nothing material is left to inference.
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 each parameter already carries its own description; the description still adds value by disclosing interaction and edge-case semantics, e.g. "stdout and stderr default to true (both false returns nothing)" and tying `lines` to the truncation cap. It reinforces rather than merely repeats the schema, though it does not add syntax detail beyond the timestamps example already in 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 and resource ("Reads one container's recent logs") and immediately anchors it against a named sibling ("the container counterpart of logs/journal-control"). The ordering, default line count, and no-follow constraint are all specified, so the agent knows exactly what this tool returns.
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 away to alternatives: "To run a command use docker/exec; for host logs logs/journal-control." It also states the preconditions that gate invocation ("Only containers in the grant's containers: list; always runs as root, refused unless the grant has allowed: true"), which is exactly the when/when-not guidance an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
docker/manageADestructive
Changes a container's lifecycle: start, stop, restart, kill, pause, unpause or remove; the container counterpart of services/manage. Mutating. Only containers in the grant's containers: list may be touched (name and ID are both checked; an empty list refuses everything). Always runs as root: no privileged argument, refused unless the grant has allowed: true. stop uses Docker's default 10 s grace. remove is irreversible for the container and deliberately fenced: it never sends force or volume removal, so a running container is refused (stop or kill it first) and anonymous volumes are kept. start on a running or stop on a stopped container reports unchanged, not an error. container is a name, full ID or ID prefix. Text: Container NAME (ID12): stop succeeded.; output_format: json returns container, id, action and result (ok or unchanged). For bulk cleanup use docker/prune, to run a command inside docker/exec, to check state first docker/containers.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | Action to perform | |
| container | Yes | Container name, full ID or ID prefix | |
| output_format | No | json returns container, id, action, result; default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far exceeds what annotations provide: authorization model (name and ID checked, empty list refuses everything, runs as root, no privileged argument, requires allowed: true), the 10 s stop grace, and remove's deliberately fenced behavior (never sends force or volume removal, running container refused, anonymous volumes kept). This is exactly the mutation context an agent needs, which annotations alone (destructiveHint=true) cannot supply.
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-loaded with purpose and action list, then layered constraints, edge cases, output format, and sibling routing. Dense but nearly every clause carries unique information; slightly long for a 3-parameter tool.
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 supplies both the text format ('Container NAME (ID12): stop succeeded.') and the JSON fields (container, id, action, result). Authorization, irreversibility, and no-op semantics are all covered, leaving nothing an agent needs to call it 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 description coverage is 100%, so container/output_format semantics are already documented. The description restates 'container is a name, full ID or ID prefix' and the JSON return fields, adding little beyond the schema; baseline 3 is correct 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?
Opens with a specific verb and resource ('Changes a container's lifecycle') and enumerates all seven actions. It explicitly positions itself as 'the container counterpart of `services/manage`', so an agent can distinguish it from the sibling without opening either 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?
Explicit routing at the end: bulk cleanup → docker/prune, run a command → docker/exec, check state first → docker/containers. It also states preconditions (grant containers list, allowed: true) and the no-op cases ('start on a running or stop on a stopped container reports unchanged').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
docker/networksARead-onlyIdempotent
Lists Docker networks (not the host's: for host interfaces and routes use the network:// resources and network/* tools) with driver, scope, subnet, gateway and the containers attached with their addresses. Read-only. pattern is a glob on the name; driver an exact driver (bridge, host, none, overlay, macvlan). Text shows Attached: (nothing) for an empty network; output_format: json (also yaml/table/wide) returns an array of objects (name, id, full_id, driver, scope, created, internal, attachable, ingress, ipam_driver, subnets, gateways, containers, options, labels). Removing unused networks is docker/prune (target networks); one network's full detail is the docker-network://<name>/inspect resource. Always runs as root: no privileged argument, refused unless the grant has allowed: true.
| Name | Required | Description | Default |
|---|---|---|---|
| driver | No | Only networks using this driver (bridge, host, none, overlay, macvlan, ...) | |
| pattern | No | Only networks whose name matches this glob (e.g. 'app-*') | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/destructive/idempotent/openWorld, so the safety profile is covered. The description adds context beyond them: the root-execution requirement, refusal unless the grant has `allowed: true`, and the text-mode rendering (`Attached: (nothing)` for empty networks). These are genuine behavioral details, though return-shape nuances could be richer.
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?
Dense but front-loaded: purpose and scoping lead, then outputs, then sibling routing. Nearly every sentence earns its place, though the single long paragraph packs many clauses and could be slightly tighter.
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, yet the description enumerates the JSON object fields (name, id, full_id, driver, scope, created, internal, attachable, ingress, ipam_driver, subnets, gateways, containers, options, labels), so the agent knows the return shape. Combined with sibling routing and auth requirements, nothing essential 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 baseline is 3, but the description adds real meaning: `pattern` is a glob on the name, `driver` is an exact driver match with valid values (bridge, host, none, overlay, macvlan), and it documents what `output_format: json` returns. This goes beyond the schema's own descriptions.
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 ('Lists Docker networks') and enumerates exactly what is returned: driver, scope, subnet, gateway, and attached containers with addresses. It actively distinguishes itself from the host-interface siblings (`network/*`, `network://`) and other docker tools, so an agent can identify it 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?
Explicitly routes the agent: host interfaces/routes go to `network://` resources and `network/*` tools, unused-network removal is `docker/prune` (target `networks`), and single-network detail is the `docker-network://<name>/inspect` resource. When-to-use and when-not-to-use are both spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
docker/pruneADestructiveIdempotent
Deletes ONE kind of unused Docker object per call: target is containers (stopped), images (dangling only), volumes (anonymous, unused only; named volumes are never touched), networks (unused) or build-cache. Mutating and irreversible, and it deletes objects you did not name; call again for the next kind (pruning containers is what makes images dangling). The user's grant needs a prune: list containing the target, otherwise the call is refused before anything is deleted. Always runs as root: no privileged argument, refused unless the grant has allowed: true. The 30 s worker limit can end the call while the Engine keeps pruning. Text is TARGET: N removed, X MiB reclaimed plus the removed IDs (networks report no size); output_format: json returns target, deleted, count, space_reclaimed_bytes. To remove one named container use docker/manage (remove); to see what exists first docker/containers, docker/images, docker/volumes, docker/networks.
| Name | Required | Description | Default |
|---|---|---|---|
| target | Yes | The one kind to reclaim: containers (stopped), images (dangling), volumes (anonymous, unused), networks (unused) or build-cache | |
| output_format | No | json returns target, deleted, count, space_reclaimed_bytes; default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, but the description goes well beyond them: needed grant (`prune:` list containing the target, else refused before deletion), root execution with no `privileged` argument, `allowed: true` requirement, and the 30 s worker timeout that can end the call while the Engine keeps pruning. It also describes the exact return text and the JSON shape, which the annotations cannot convey.
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, front-loaded with the target enumeration and the irreversibility warning before the routing and output detail. Every sentence carries information, though the return-format sentence is long enough that a human reader would benefit from splitting it out.
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, and the description compensates by describing both text and json return shapes. Combined with grant/permission requirements, timeout caveats, irreversibility, and sibling alternatives, an agent has everything needed to call this correctly on the first try.
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 volume distinction (anonymous/unused only; named volumes never touched) and the concrete json fields (target, deleted, count, space_reclaimed_bytes) plus the fact that networks report no size. That is more than restating the enum.
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 (deletes) and resource (unused Docker objects), then enumerates the exact five targets and each one's scope (stopped containers, dangling images, anonymous unused volumes, unused networks, build-cache). It explicitly separates itself from docker/manage (`remove`) and the listing tools, so an agent can disambiguate 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?
Gives explicit when-to-use routing (prune for bulk unused objects; `docker/manage` with `remove` for one named container) and when-not (named volumes are never touched). It also explains the ordering prerequisite that pruning containers is what makes images dangling, which is real operational guidance, not filler.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
docker/volumesARead-onlyIdempotent
Lists Docker volumes with driver, mountpoint (a host path) and the names of the containers, running or stopped, that mount each. Read-only: volumes are never created or removed here. pattern is a glob on the volume name. Text is a block per volume; output_format: json (also yaml/table/wide) returns an array of objects (name, driver, mountpoint, created, scope, labels, options, in_use_by), [] when empty. docker/prune with target volumes removes anonymous unused volumes only. For one volume's details use the docker-volume://<name>/inspect resource, for containers docker/containers. Always runs as root: no privileged argument, refused unless the grant has allowed: true.
| Name | Required | Description | Default |
|---|---|---|---|
| pattern | No | Only volumes whose name matches this glob | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (which already declare read-only/idempotent/non-destructive), it discloses that the tool always runs as root, has no privileged argument, and is refused unless the grant has allowed: true. It also distinguishes its behavior from docker/prune (anonymous unused volumes only) and documents the empty-result and output-format behavior.
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?
Purpose is front-loaded and every sentence earns its place: read-only scope, glob semantics, output formats, the prune distinction, sibling routing, and the root/grant requirement are all non-redundant and useful.
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 still documents return values and the empty case, plus auth requirements and alternatives. Nothing an agent needs to call this tool correctly 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 baseline is 3. The description adds value by explaining the json output shape (an array of objects with name, driver, mountpoint, created, scope, labels, options, in_use_by) and the [] empty case, though the pattern glob is already documented in 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 (Lists) and resource (Docker volumes) plus exactly what is returned: driver, mountpoint, and mounting container names. An agent can immediately distinguish it from docker/containers, docker/images, and docker/networks.
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 to alternatives: the docker-volume://<name>/inspect resource for single-volume details, docker/containers for containers, and docker/prune target volumes for removal. It also clarifies the read-only boundary ('volumes are never created or removed here').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
files/chmodADestructiveIdempotent
Changes a file's or directory's permission bits (chmod). Mutating and idempotent; for owner or group use files/chown, to check the result files/list. Never follows symbolic links: a path containing a symlink in any component is refused, and recursive changes skip symlinks and report them. Numeric modes follow GNU chmod semantics (on directories a 4-digit mode keeps setuid/setgid; use 5 digits, e.g. 00755, to set them exactly); a bare 755 is octal. Changing a file you do not own needs privileged: true (a grant, and a paths: entry for root). Single change returns PATH: 0644 (-rw-r--r--) -> 0755 (-rwxr-xr-x), or ... unchanged if already set. A recursive run prints one line per changed entry, then changed N, unchanged M (plus skipped symlinks) and per-entry errors; it is not atomic, so partial success is possible.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | Yes | Octal (644, 0755, 4755) or symbolic (u+x, go-w, a=r, +X, u+s, +t; comma-separated) | |
| path | Yes | Absolute path | |
| recursive | No | Also apply to everything below a directory (symlinks are skipped, never followed) | |
| privileged | No | Run as root - needed for files you don't own. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare mutating/destructive/idempotent, but the description adds substantial context beyond them: symlinks are never followed and any symlinked component is refused, recursive runs skip and report symlinks, GNU numeric-mode semantics (4-digit vs 5-digit setuid handling), the exact return format for single and recursive runs, and that recursive runs are non-atomic with possible partial success.
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 purpose and the sibling routing, and almost every clause carries distinct information. It is dense and somewhat run-on with heavy semicolon chaining, which slightly hurts scanability, but little 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 complex mutating, non-atomic tool with 4 parameters and no output schema, the description is complete: it discloses return formats, symlink policy, elevation requirements, mode semantics, and partial-failure behavior, so an agent has everything needed to call it 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 description coverage is already 100%, so the baseline is 3, but the description adds real meaning: it clarifies numeric vs symbolic mode behavior (a bare `755` is octal, 4 vs 5 digits control setuid/setgid), and that `privileged` requires both a grant in mcp-sudo.yaml and a `paths:` entry. This meaningfully elaborates on 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 and resource ('Changes a file's or directory's permission bits (chmod)') and explicitly distinguishes itself from siblings by naming `files/chown` for owner/group and `files/list` to check results. An agent can identify and route to it 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?
Explicitly states when to use alternatives (`files/chown` for owner/group, `files/list` to verify) and the condition that requires elevation (`privileged: true` plus a grant and `paths:` entry for files you don't own). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
files/chownADestructiveIdempotent
Changes a file's or directory's owner and/or group (chown). Mutating and idempotent; for permission bits use files/chmod, to check the result files/list. Never follows symbolic links: a path containing a symlink in any component is refused, and recursive changes skip symlinks and report them. Changing the owner requires privileged: true (a grant, and a paths: entry for root). owner is user, user:group, :group or user: (the user's login group), with names or numeric ids; names are looked up in the host's /etc/passwd and /etc/group and an unknown one fails (no such user). Returns PATH: old -> new as owner:group, or unchanged; a recursive run prints one line per changed entry then a summary with skipped symlinks and per-entry errors, and is not atomic.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path | |
| owner | Yes | user, user:group, :group, or user: (the user's login group); names or numeric ids | |
| recursive | No | Also apply to everything below a directory (symlinks are skipped, never followed) | |
| privileged | No | Run as root - required to change ownership. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (destructive/idempotent/not-readOnly): it discloses that symlinks are never followed and any symlinked component is refused, that recursive runs skip and report symlinks, that ownership change needs privileged elevation, and that recursive runs are non-atomic. This is exactly the class of mutation-risk detail the description should carry.
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?
Purpose and mutating nature are front-loaded in the first clause, and each subsequent sentence carries distinct value (symlink semantics, privilege requirement, return format). It is dense and somewhat clause-heavy, but nothing 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?
With no output schema, the description still explains return values ("PATH: old -> new", `unchanged`, recursive per-entry lines plus a summary). Combined with the annotations covering the safety profile, an agent has everything needed to call it 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 schema already documents all four parameters (baseline 3). The description adds real meaning beyond the schema, though: the owner format variants, that names are resolved via /etc/passwd and /etc/group, and that an unknown name fails with "no such user".
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: "Changes a file's or directory's owner and/or group (chown)." It also distinguishes itself from siblings by routing permission-bit changes to `files/chmod`, so an agent can differentiate without opening a 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 names alternatives and the condition that selects them: use `files/chmod` for permission bits and `files/list` to check the result. It also states the prerequisite (privileged: true with a grant and paths entry) for ownership changes, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
files/createADestructiveIdempotent
Writes a whole file: creates it, or REPLACES the content of an existing one entirely. Mutating and not atomic. Missing parent directories are created (mode 0755); a new file gets mode 0644, an existing file keeps its mode. With content omitted or empty it only touches: creates an empty file or refreshes the modification time and never truncates an existing file. To change part of an existing file use files/update (append or replace lines); to check first whether a path exists use files/list or files/find; afterwards set mode or owner with files/chmod/files/chown. content is text and no trailing newline is added; path must be absolute. Writing where your account cannot needs privileged: true (a grant, and for root a paths: entry covering the path, which also refuses symlinks in the path; otherwise a symlink at the path is followed). Returns one line, Successfully created and wrote to PATH or Successfully touched PATH; failures are plain text such as failed to write to file.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path of the file; missing parent directories are created | |
| content | No | Text to write; replaces any existing content entirely, no newline is added. Omit or leave empty to only create an empty file or refresh its mtime (never truncates) | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (destructiveHint=true, idempotentHint=true): not atomic, parent dirs created at 0755, new file 0644, existing file keeps mode, empty content only touches and never truncates, privileged mode needs a grant plus a paths entry covering the path and refuses symlinks, and the exact success/failure return strings.
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 that front-loads the core behavior (whole-file write, replacement, non-atomic) before alternatives and edge cases. Every sentence carries information, though the volume makes it slightly heavy for a three-parameter tool.
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 supplies the return contract (one success line, plain-text failures), plus privileged-mode prerequisites and symlink behavior. Nothing an agent needs to call it safely 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 real meaning: content is text with no trailing newline appended, path must be absolute, and privileged requires both a grant and a covering paths entry. It largely mirrors the schema for path but enriches the privileged and content semantics.
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 with scope: 'Writes a whole file: creates it, or REPLACES the content of an existing one entirely.' It immediately distinguishes itself from the closest sibling by noting it replaces entire content versus files/update which changes parts.
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 to alternatives with conditions: use files/update to change part of a file, files/list or files/find to check existence, files/chmod/files/chown to set mode or owner. It also clarifies the empty-content touch semantics versus truncation, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
files/filetypeARead-onlyIdempotent
Returns a file's MIME type, like file -b --mime-type, detected natively from its first 8 KiB (no file(1) needed); read-only, path must be absolute. A symlink is reported as inode/symlink (never followed); directories, devices, fifos and sockets as inode/.... Use it before files/read, which refuses binary files. For size, permissions or ownership use files/list; for contents files/read. The reply is always one plain-text line (no output_format). privileged: true (a grant, and for root a paths: entry) reads files your account cannot.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path to the file | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations: it discloses that symlinks are never followed (reported as inode/symlink), that directories/devices/fifos/sockets report as inode/..., the 8 KiB detection window, and that privileged mode requires a grant plus a `paths:` entry or is refused. It also states the reply shape (one plain-text line, no output_format).
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-loaded with the core behavior and organized by purpose, alternatives, and return format. It is densely packed with semicolon-chained clauses, but virtually every clause carries distinct information, so little 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?
With no output schema, the description compensates by stating the return format ('always one plain-text line, no output_format'). Combined with the symlink/special-file behavior and privileged prerequisites, an agent has everything needed to call it 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% and both parameter descriptions already state 'absolute path' and the privileged grant/paths requirement, so the description largely restates what the schema provides. The added 'otherwise refused' phrasing is marginal value, 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 ('Returns a file's MIME type') plus the exact detection mechanism ('like `file -b --mime-type`, detected natively from its first 8 KiB'). It explicitly differentiates from siblings by naming files/read and files/list and what each is for.
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 an explicit trigger ('Use it before `files/read`, which refuses binary files') and routes the other use cases away to named alternatives: files/list for size/permissions/ownership, files/read for contents. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
files/findARead-onlyIdempotent
Searches a directory tree (default /) by name, type, age or size, like find. Read-only; never follows symlinks; skips /proc, /sys, /dev and /run when the search starts at / or above them (not when path is inside one). Use files/list to see one known directory and disks/usage to see which folders take the space. All filters are ANDed and none is required. There is NO result cap: path: / without a filter lists every file on the host, so give name, type or max_depth; the 30 s worker timeout applies. Syntax: name is a case-sensitive glob on the base name only (*.log, not a path); type is one of f d l b c p s or a comma list (f,d); mtime in days: +7 older than 7 days, -1 within the last day, 7 exactly 7 days; size: +100M larger, -10k smaller (units b c w k M G, rounded up); max_depth 1 = direct children, omitted or 0 = unlimited. Unreadable directories are skipped silently. Text output: one SIZE PATH line per match, sorted by path (no size for directories; empty output = no match). output_format: json returns an array of objects (path, size in bytes, type).
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Glob on the file's base name only, case-sensitive, e.g. '*.log' (not a path pattern) | |
| path | No | Absolute starting directory (default /). A large tree with no filter can take longer than the 30 s worker limit | |
| size | No | '+100M' larger than 100 MiB, '-10k' smaller than 10 KiB; units b c w k M G, rounded up to the unit | |
| type | No | f file, d directory, l symlink, b, c, p, s; or a comma list such as 'f,d' | |
| mtime | No | Days since modification: '+7' older than 7 days, '-1' within the last day, '7' exactly 7 days | |
| max_depth | No | Levels below path to descend (1 = direct children); omit or 0 for unlimited | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused | |
| output_format | No | json (yaml, table and wide return the same JSON) gives an array of objects with path, size, type; default is text | |
| human_readable | No | Text output only: sizes like 1.5 KiB; default is bytes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld=false, yet the description still adds substantial behavior: never follows symlinks, the /proc /sys /dev /run skip rule (and its path-dependent exception), the absence of a result cap, the 30 s worker timeout, and silent skipping of unreadable directories. This is exactly the contextual detail annotations cannot express.
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?
Well front-loaded: purpose and safety first, alternatives next, then filter semantics, syntax, and output format. It is dense and every section earns its place, though the syntax recap is lengthy for a schema that already documents the same rules.
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 9 optional params and no output schema, the description still specifies the filter combination rule, the destructive-risk caveat, and the exact return shape (per-line SIZE PATH sorted by path, empty output = no match; json array of path/size/type). Nothing an agent needs to call it correctly 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 baseline is 3, but the description adds non-schema semantics: all filters are ANDed and none is required, plus the relative-vs-absolute mtime/size operators and max_depth defaults. Most per-parameter syntax restates the schema, so it is value-adding but partly redundant.
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 (searches) and resource (a directory tree) plus the filter axes (name, type, age, size) and the `find` analogy. It positively distinguishes itself from `files/list` (single known directory) and `disks/usage` (space consumers), so an agent can route without opening a 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 names the alternatives and their conditions ('Use `files/list` to see one known directory and `disks/usage` to see which folders take the space'), and warns when a filter is mandatory to avoid an unbounded scan. When-to-use and when-NOT-to-scan-without-a-filter are both covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
files/listARead-onlyIdempotent
Lists the entries of ONE directory like ls -l (dotfiles, . and .. are hidden unless all: true): type and permissions, link count, owner, group, size, modification time and symlink targets (symlinks are shown, never followed). Read-only, not recursive, no entry cap; path must be absolute. For a recursive or filtered search use files/find, for a directory's total size disks/usage, for a file's MIME type files/filetype. On permission denied retry with privileged: true if granted (root calls also need a paths: entry covering the path). Text output is ls -l lines (Directory is empty. when empty; long: false gives names only, directories suffixed /). output_format: json returns an array of objects (name, type, mode, mode_octal, links, owner, group, uid, gid, size, modified, is_dir, target), [] when empty.
| Name | Required | Description | Default |
|---|---|---|---|
| all | No | Include dotfiles, . and .. (ls -a) | |
| long | No | Long listing like ls -l: type+permissions, links, owner, group, size, date, symlink target. Default true; false lists names only | |
| path | Yes | Absolute path of the directory to list | |
| sort | No | Sort by name (default), size (largest first) or time (newest first) | |
| reverse | No | Reverse the sort order (ls -r) | |
| dirs_first | No | List directories before files | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused | |
| numeric_ids | No | Show numeric uid/gid instead of names (ls -n) | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text | |
| human_readable | No | Sizes like 4.0K, 1.5M (ls -h); default is bytes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations: not recursive, no entry cap, symlinks shown but never followed, root calls require a `paths:` entry in mcp-sudo.yaml, and the exact empty-result markers ('Directory is empty.' / []) are disclosed.
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-loaded with the core semantics and every clause carries information (scope, exclusions, failure mode, output format). It is dense to the point of being a single long paragraph, which slightly hurts scanability.
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 compensates by enumerating the JSON return fields and the text/empty formats; all 10 parameters and the recommended fallbacks are covered, so an agent can call it correctly without further context.
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 cross-parameter behavior the schema does not state: the list of JSON object fields returned, that non-text formats all yield the same JSON, and the symbolic-link non-following guarantee tied to the listing.
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 (lists the entries of ONE directory) with the exact scope and output shape ('like ls -l'), and explicitly names the sibling tools it is not (files/find, disks/usage, files/filetype) with the condition that selects each.
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 routing rules for alternatives (recursive/filtered → files/find, total size → disks/usage, MIME → files/filetype) and a concrete remediation path for failure ('on permission denied retry with privileged: true if granted').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
files/readARead-onlyIdempotent
Reads a text file and returns its contents as raw text (no line numbers or metadata). Read-only; path must be absolute. To find a file use files/find, for size or mode files/list, to check whether it is binary files/filetype (binary files are refused with cannot read binary file). Selection: start_line/end_line (1-indexed, inclusive; start_line alone reads to the end, end_line alone starts at line 1) take precedence over the byte range offset/limit. With no selection, or offset without limit, at most 10240 bytes come back followed by a [WARNING: File truncated ...] line, so page large files with start_line/end_line or pass limit. There is no streaming: one call reads into memory, and a line over 64 KiB fails line mode. A start_line past the end is an error; an empty file returns an empty string. privileged: true (needs a grant, and a paths: entry for root) reads files your account cannot.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path of the file to read | |
| limit | No | Number of bytes to return (no upper cap). With no selection at all, the first 10240 bytes are returned | |
| offset | No | Byte offset to start at; ignored when start_line/end_line is given. Without limit at most 10240 bytes are returned | |
| end_line | No | Last line to return (inclusive); alone it starts at line 1. Ignored if below start_line | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused | |
| start_line | No | First line to return (1-indexed). With or without end_line it takes precedence over offset/limit; alone it reads to the end of the file |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, but the description adds substantial behavior beyond them: the 10240-byte truncation with a `[WARNING: File truncated ...]` line, no streaming (one call reads into memory), line-mode failure for lines over 64 KiB, error on start_line past end, empty string for empty files, and the grant/paths requirement for privileged. This is rich, non-obvious disclosure.
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?
Dense but front-loaded: reads as raw text, read-only, absolute path first, then routing, then selection semantics, then edge cases. Every sentence carries information, though the prose is packed tightly enough that it borders on overloading a single paragraph.
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 read tool with no output schema, the description covers return format, truncation, error conditions, and privilege requirements completely. Nothing an agent needs to invoke it correctly 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 meaningfully adds precedence rules not fully captured by the schema: start_line/end_line take precedence over offset/limit, start_line alone reads to end, end_line alone starts at line 1, and offset without limit caps at 10240 bytes. Useful cross-parameter semantics, though most individual param meaning is already in 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 and resource ('Reads a text file and returns its contents as raw text') and explicitly scopes the return format ('no line numbers or metadata'). It also names three siblings (files/find, files/list, files/filetype), so an agent can distinguish it 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?
Gives explicit routing to alternatives: 'To find a file use files/find, for size or mode files/list, to check whether it is binary files/filetype'. This is when-to-use-this-vs-others guidance with concrete alternatives, not just implied context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
files/updateADestructive
Edits part of an EXISTING file in place: appends text or replaces an inclusive line range. Mutating and not atomic; the file keeps its mode and owner. To write a whole file use files/create; to see the lines first use files/read with start_line/end_line. With append: true exactly content is added at the end (no newline is added, include your own) and the file is created if missing, though not its parent directories; append wins over any line range. Otherwise start_line AND end_line are both required (1-indexed, end_line >= start_line), the file must exist, and those lines are replaced by content (one trailing newline of content is ignored; an end_line past the end is clamped; a start_line past the end adds content as a new last line). There is no insert or delete mode: replacing with empty content leaves one empty line. Returns Successfully appended to PATH or Successfully updated lines A-B in PATH, no diff. path must be absolute; privileged: true (a grant, and for root a paths: entry) edits files you cannot write.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path of the file to edit | |
| append | No | If true, append content at the end (creates the file if missing); takes precedence over start_line/end_line | |
| content | Yes | Text to append, or to replace the line range with (no newline is added when appending) | |
| end_line | No | Last line to replace (inclusive, >= start_line; past the end of the file is clamped) | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused | |
| start_line | No | First line to replace (1-indexed); required together with end_line unless append is true |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=false, but the description adds non-atomicity, that mode and owner are preserved, the exact return strings, the absence of a diff, and the privileged-grant requirement. It also discloses subtle behavioral edge cases (trailing newline ignored, end_line clamped, start_line past end appends) that no annotation covers.
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 purpose and alternatives before edge cases, and nearly every sentence carries essential semantics. It is on the long side, but the density of non-obvious behavior (clamping, newline rules, no insert/delete mode) justifies most of the length.
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 supplies the return values directly and covers preconditions (file must exist, path absolute, parent dirs not created), mode/owner preservation, and failure modes for privileged edits. Nothing an agent needs to invoke it correctly appears 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 already 100%, yet the description still adds semantics the schema lacks: append precedence over line ranges, that start_line AND end_line are jointly required and 1-indexed with end_line >= start_line, the newline handling on append, and the privileged grant mechanics. This meaningfully exceeds the schema text.
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 (Edits), resource (file), and the two distinct modes (append vs. replace line range) in the first sentence. Explicitly contrasts itself with `files/create` for whole-file writes and `files/read` for inspecting lines, so an agent can distinguish it from siblings without opening a 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?
Names both alternatives and the condition that selects each ('To write a whole file use files/create; to see the lines first use files/read with start_line/end_line'). It also spells out when append mode applies versus line-range mode, including that append wins over a supplied range.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
kernel/system-controlADestructiveIdempotent
Reads or writes a kernel parameter (sysctl) at runtime through /proc/sys. With value omitted it reads: key (dotted net.ipv4.ip_forward or slash form; a directory such as net.ipv4 prints its subtree) returns key = value lines, and read_all: true (only when key is empty) prints every parameter, thousands of lines, uncapped. Reading needs no grant. With value it WRITES: that needs privileged: true and a grant, is refused for keys outside the user's sysctl.write_keys globs in mcp-sudo.yaml, and the reply shows the value the kernel now holds. Writes last until reboot; nothing is persisted to /etc/sysctl.d. For OS and kernel version use system/os-release, for memory figures memory/usage.
| Name | Required | Description | Default |
|---|---|---|---|
| key | No | Kernel parameter name, dotted (net.ipv4.ip_forward) or slash form (net/ipv4/conf/eth0.100/rp_filter). A directory (e.g. net.ipv4) reads its whole subtree. | |
| value | No | Value to write (single line). If omitted, the parameter is read. Writing needs privileged: true and a matching sysctl.write_keys grant | |
| read_all | No | Only when key is empty: read every parameter (thousands of lines, uncapped) | |
| privileged | No | Run as root - required for writes. Needs a grant for this tool in mcp-sudo.yaml |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (destructiveHint=true, readOnlyHint=false) by disclosing that reads need no grant, writes require privileged:true plus a sysctl.write_keys grant from mcp-sudo.yaml, are refused outside those globs, last only until reboot, and are never persisted to /etc/sysctl.d. This is exactly the mutation-risk context an agent needs.
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?
Dense but front-loaded: read semantics first, then write semantics, then persistence caveats, then sibling routing. Every clause carries information, though the single long paragraph could be broken up slightly for scanability.
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 complex dual-mode tool with no output schema, the description covers return format ('key = value' lines, subtree listing, uncapped read_all output), permission model, persistence, and alternatives. Nothing an agent needs to invoke it correctly 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 the schema already documents all four parameters including dotted/slash key forms and the read_all/key dependency. The description largely reinforces that content, adding only minor framing (reply shows resulting value), 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?
States a precise verb+resource: reads or writes a kernel parameter (sysctl) via /proc/sys, and immediately disambiguates read vs write mode by the presence of `value`. An agent can distinguish this from siblings like system/os-release or memory/usage 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?
Explicitly routes elsewhere for adjacent needs ('For OS and kernel version use system/os-release, for memory figures memory/usage') and states the condition governing read_all ('only when key is empty'). Reading vs writing selection is spelled out with prerequisites for each.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
logs/dmesgARead-onlyIdempotent
Reads the kernel ring buffer (wraps dmesg --human, relative timestamps). Read-only. Output is cut to the LAST 30 KiB with a [WARNING: Output truncated to last 30KB] prefix and cannot be paged; narrow it with level, a comma list of emerg, alert, crit, err, warn, notice, info, debug (err,warn). On hosts with kernel.dmesg_restrict=1 an unprivileged call fails (dmesg's error is returned); use privileged: true (needs a grant). output_format is accepted and ignored: the reply is always plain text. For older history or service logs use logs/journal-control, for login records logs/logins, for drive faults disks/health.
| Name | Required | Description | Default |
|---|---|---|---|
| level | No | Comma-separated levels from emerg, alert, crit, err, warn, notice, info, debug (e.g. 'err,warn') | |
| privileged | No | Run as root - needed when kernel.dmesg_restrict=1. Needs a grant for this tool in mcp-sudo.yaml | |
| output_format | No | Ignored - the reply is always plain text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent safety, but the description adds substantial behavior: output is truncated to the last 30 KiB with a warning prefix, cannot be paged, fails under dmesg_restrict unless privileged with a grant, and output_format is accepted but ignored. These are real operational constraints not derivable from structured fields.
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?
Dense but front-loaded: purpose first, then truncation constraint, then the filtering parameter, then the failure mode, then the sibling routing. Every sentence carries distinct, actionable information 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 carries the return-value burden and does so: plain text, 30 KiB truncation, non-pageable. Combined with the failure-mode and routing guidance, an agent has everything needed to call this 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 description coverage is 100%, so the meaning of level, privileged, and output_format is already documented in the schema, including the enum values and the 'ignored' note. The description restates the level enum and the privilege/grant requirement without adding syntax or format detail beyond the schema, 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?
States a specific verb and resource ('Reads the kernel ring buffer') and names the wrapped command, so an agent knows exactly what is returned. It also distinguishes itself from siblings by pointing to logs/journal-control, logs/logins, and disks/health for other log sources.
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 routing rules: journal-control for older history/service logs, logins for login records, disks/health for drive faults. It also states when privileged is required (kernel.dmesg_restrict=1) and how to narrow output with level.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
logs/journal-controlARead-onlyIdempotent
Reads the systemd journal (wraps journalctl -n LINES --no-pager). Read-only. Returns the last lines entries (default 100, the only size limit), oldest first unless reverse. Filter with unit (sshd.service), since/until in journalctl syntax (1 hour ago, yesterday, 2026-09-29 10:00), boot: true (current boot) or boot_offset (-1 = previous boot; takes precedence over boot). Without root an ordinary user sees only their own entries unless in the systemd-journal or adm group. Requires privileged: true in containerized deployments (needs a grant), since journalctl only exists on the host, never in this daemon's own image. Plain text by default; output_format: json gives one JSON object per line (journalctl -o json), not an array. For kernel messages use logs/dmesg, for logins logs/logins, for container output docker/logs, for unit state services/list.
| Name | Required | Description | Default |
|---|---|---|---|
| boot | No | Restrict output to the current boot (journalctl -b) | |
| unit | No | Filter by systemd unit (e.g., 'kubelet.service') | |
| lines | No | Number of entries to tail (default 100; the only size limit) | |
| since | No | journalctl time syntax, e.g. '1 hour ago', 'today', '2026-09-29 10:00' | |
| until | No | Filter logs until a specific time (e.g., 'yesterday', '12:00') | |
| reverse | No | Output newest entries first | |
| privileged | No | Run as root and join the host mount namespace - required in containerized deployments (needs a grant for this tool in mcp-sudo.yaml) | |
| boot_offset | No | Select a prior boot relative to the current one, e.g. -1 for the previous boot (implies boot) | |
| output_format | No | json returns one JSON object per line (journalctl -o json); default is plain text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description goes well beyond them: ordinary users see only their own entries without root or systemd-journal/adm group membership, privileged:true is needed in containers because journalctl lives only on the host, and boots are scoped with offset precedence. These are non-obvious operational constraints an agent must know.
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 paragraph that front-loads what the tool does before constraints and alternatives. Nearly every clause earns its place; it is long for nine parameters but not padded.
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 read tool with no output schema, the description covers defaults, output format semantics, permission/privilege prerequisites, and sibling routing. Nothing needed to invoke it correctly 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 the baseline is 3, but the description adds real meaning beyond the schema: boot_offset 'takes precedence over boot', lines is 'the only size limit', and the JSON output is 'one JSON object per line, not an array'. The since/until syntax examples largely duplicate 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 the specific verb+resource ('Reads the systemd journal') and even names the underlying command it wraps. It explicitly distinguishes itself from four siblings by use case (logs/dmesg for kernel, logs/logins for logins, docker/logs for containers, services/list for unit state).
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?
Explicit routing rules to alternatives are given for each overlapping scenario, plus when root/group membership matters and when privileged:true is required. No conditions are left for the agent to infer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
logs/loginsARead-onlyIdempotent
Lists login history (wraps last) or failed login attempts (type: "failed", wraps lastb). Read-only; returns raw text, not JSON. limit keeps the N most recent entries and user filters by username; the trailing wtmp begins... summary line is dropped and an empty history returns an empty line. last/lastb must be installed on the host. For account details use users/list, for authentication messages logs/journal-control.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | "success" (default, wraps `last`) or "failed" (wraps `lastb`) | |
| user | No | Only return entries for this username | |
| limit | No | Only return this many most recent entries | |
| privileged | No | Run as root - typically required for type "failed". Needs a grant for this tool in mcp-sudo.yaml |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description adds genuinely new behavioral context: raw text rather than JSON output, the trailing 'wtmp begins...' line being dropped, empty history returning an empty line, and the root/grant requirement for failed logins.
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?
Dense and front-loaded: the primary purpose and mode mapping come first, then output caveats, then routing. Every sentence carries information, though the parenthetical tool-name references make it slightly heavy 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?
With no output schema, the description compensates by explicitly stating the return is raw text, how the summary line and empty cases behave, and what host dependencies must exist. Nothing an agent needs to call this correctly 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 including the enum are already documented. The description restates limit ('keeps the N most recent entries') and user ('filters by username') but adds no format or ordering detail beyond the schema, 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?
States a specific verb and resource (login history / failed login attempts) and names the two underlying tools it wraps (`last` and `lastb`), so the agent knows exactly what is returned and which mode maps to which behavior.
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 elsewhere when appropriate: 'For account details use users/list, for authentication messages logs/journal-control.' It also states the host prerequisite (`last`/`lastb` must be installed) and the grant requirement tied to the privileged parameter.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory/usageARead-onlyIdempotent
Reports memory and swap use from /proc/meminfo. Read-only. used is total - free - (buffers + cached + reclaimable slab); available is the kernel's MemAvailable. Text output is a free-like table with Mem: and Swap: rows (bytes, or e.g. 1.8Gi with human_readable); detailed: true returns the raw /proc/meminfo instead, but only for text output (it is ignored with output_format: json). JSON (also yaml/table/wide) returns an object (total, used, free, shared, buffCache, available, swap_total, swap_used, swap_free) in bytes; human_readable is ignored there. For per-process memory use processes/top or processes/list, for CPU load cpu/load-average.
| Name | Required | Description | Default |
|---|---|---|---|
| detailed | No | Return the raw /proc/meminfo instead of the summary (text output only; ignored with output_format json) | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text | |
| human_readable | No | Sizes like free -h (1.8Gi); default is bytes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotent/destructive=false, so the safety profile is covered; the description adds genuinely new behavioral facts, notably that `detailed` is silently ignored with output_format json and that `human_readable` is ignored in json/yaml/table/wide output. That silent-ignore behavior is exactly the kind of trait structured fields don't capture.
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?
Purpose and read-only status are front-loaded, and the dense middle section on formats and formulas is all decision-relevant rather than filler. It is heavier than it needs to be for a three-flag read tool, which keeps it short of a 5.
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 carries the return-shape burden and does it fully: it describes the text `free`-like table, the JSON object and its keys, byte vs human-readable units, and the raw-meminfo alternative. Nothing needed to call it correctly 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 real meaning beyond the schema: the exact formula for `used`, that `available` maps to the kernel's MemAvailable, the enumerated JSON keys, and the cross-parameter interactions between detailed/human_readable and output_format.
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 ('Reports memory and swap use from /proc/meminfo') and explicitly separates itself from siblings by naming processes/top, processes/list and cpu/load-average as the right tools for adjacent concerns. An agent can pick this 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?
Routes the agent explicitly: per-process memory goes to processes/top or processes/list, CPU load goes to cpu/load-average. It also states when to use each mode (detailed for raw /proc/meminfo, json for structured output), leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
network/arpARead-onlyIdempotent
Shows the kernel's ARP cache (IPv4 address to MAC address) from /proc/net/arp in the daemon's network namespace. Read-only. It is a cache, not a scan: only hosts contacted recently appear, and IPv6 neighbours are not included. interface is an exact device name (eth0); omit it for all. For sockets and connections use network/connections, for reachability network/ping. Always returns JSON: an array of objects (ip_address, hw_type and flags as raw hex such as 0x1, hw_address, mask, device). When nothing matches the output is null, not [].
| Name | Required | Description | Default |
|---|---|---|---|
| interface | No | Exact interface name such as eth0; omit for all interfaces |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, non-destructive, closed-world), and the description still adds substantial behavioral context beyond them: the cache's staleness limitation, IPv6 exclusion, the namespace scoping, and the null-vs-[] return quirk.
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-loaded with the core purpose, then scope, limitations, alternatives, and return shape in a tight sequence. Every sentence carries distinct information; none is padding.
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 fully specifies the return contract – always JSON, an array of objects with named fields, and null (not []) when empty. Combined with the cache caveats, nothing an agent needs to call and interpret this tool 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% and the schema already documents `interface` as the exact interface name with omission meaning all. The description's elaboration ('exact device name (eth0); omit it for all') largely restates the schema, 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?
States a specific verb+resource (shows the kernel's ARP cache), its exact data source (/proc/net/arp), and its scope (daemon's network namespace). It explicitly distinguishes itself from network/connections and network/ping, so an agent can select it without opening a 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?
Names the alternatives explicitly with conditions: network/connections for sockets/connections and network/ping for reachability. It also tells the agent when NOT to expect results (cache, not a scan; IPv6 excluded), leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
network/connectionsARead-onlyIdempotent
Lists TCP and UDP sockets in every state with their owning processes, like ss -tuanp, read natively from /proc/net (no ss needed). Read-only; unix and raw sockets are not included. state (case-insensitive, _ and - interchangeable) filters by LISTEN (includes unconnected UDP), ESTABLISHED, TIME_WAIT, CLOSE_WAIT, SYN_SENT, ... or the groups connected/synchronized; an invalid state is an error listing the valid names. port matches the local OR peer port. The owning process (pid, fd) is shown only for sockets whose /proc/PID/fd you can read; other users' processes need privileged: true (needs a grant). Text output has ss -tuanp columns; output_format: json returns an array of objects (netid, state, recv_q, send_q, local_address, local_port, peer_address, peer_port, uid, inode, processes), [] when empty. For the ARP cache use network/arp, for interfaces and IPs the network://interfaces resource, for process details processes/list.
| Name | Required | Description | Default |
|---|---|---|---|
| port | No | Match sockets whose local or peer port equals this | |
| state | No | Filter by TCP state, case-insensitive (LISTEN/listening, ESTABLISHED, TIME_WAIT, CLOSE_WAIT, SYN_SENT, ...). Omit to list all sockets - active connections and listening ports. | |
| privileged | No | Run as root to see PIDs of other users. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, but the description adds substantial undisclosed context: data sourced from /proc/net, unix/raw sockets excluded, other users' PIDs require `privileged: true` plus a grant, and an invalid state raises an error listing valid names. It stops short of describing ordering or performance characteristics on large hosts, keeping it just below the top.
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 purpose and is free of filler sentences, but it is a dense single block of parenthetical-heavy clauses (state list, privilege caveat, output fields, sibling routing), which costs some 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?
With no output schema, the description still documents return shape: text mirrors `ss -tuanp` columns and JSON returns an array of objects with netid, state, recv_q, send_q, addresses, uid, inode and processes, plus `[]` when empty. Combined with the privilege and error behavior notes, nothing an agent needs 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 already 100%, so the baseline would be 3, but the description goes well beyond the schema: state is case-insensitive with `_`/`-` interchangeable, valid enumerations and the connected/synchronized groups are listed, and `port` is clarified as matching local OR peer port.
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?
Opens with a specific verb+resource ('Lists TCP and UDP sockets in every state with their owning processes') and anchors it to a familiar tool via 'like `ss -tuanp`, read natively from /proc/net'. It also explicitly scopes out unix and raw sockets, so an agent can immediately distinguish it from network/arp and the other network 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?
Names concrete alternatives with conditions: 'For the ARP cache use `network/arp`, for interfaces and IPs the `network://interfaces` resource, for process details `processes/list`.' Usage is triggered implicitly by the state/port filters and the privileged note, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
network/curlADestructive
Makes one HTTP(S) request with Go's HTTP client and returns status, headers and body. NOT read-only: any method (default GET) is sent as given, so POST, PUT or DELETE change the remote system. Follows redirects (up to 10); a non-2xx status is not an error, check status_code. The default timeout is 10 s (timeout, whole seconds) and the 30 s worker limit caps anything larger. The body is cut at max_body (default 1 MiB, max 10 MiB) and truncated is then true. insecure skips TLS verification. The daemon's proxy environment is honored unless the user has a network: policy in mcp-sudo.yaml; such a policy applies to every call and redirect hop, and a blocked destination fails to connect. Header and body values are redacted in the audit log. Returns JSON with status_code, status, headers (values comma-joined), body, truncated; output_format is ignored. For DNS use network/nslookup, for TCP reachability network/ping, for local files files/read.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Full URL including scheme, e.g. https://example.com/api | |
| body | No | Request body | |
| method | No | HTTP method, default GET; any method is sent as given | |
| headers | No | Request headers, e.g. {"Content-Type": "application/json"} | |
| timeout | No | Whole seconds (default 10; the 30 s worker limit caps it) | |
| insecure | No | Skip TLS certificate verification | |
| max_body | No | Return at most this many bytes of the response body (default 1048576 = 1 MiB, max 10 MiB); a cut body has truncated: true |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and openWorldHint=true, but the description goes well beyond them: method is sent as given so POST/PUT/DELETE mutate remote state, redirects follow up to 10, non-2xx is not an error, the 10 s default timeout and 30 s worker cap, body truncation at max_body with truncated=true, insecure skipping TLS, the proxy/policy interaction (network: policy in mcp-sudo.yaml applies to every call and redirect hop), and audit-log redaction. This is unusually complete behavioral disclosure.
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 purpose and the NOT-read-only warning, then stacks behavioral facts, and closes with sibling routing — a sensible order. It is dense and long for a one-call tool, but nearly every clause carries distinct operational information, so little 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 7-parameter tool with a nested headers object and no output schema, the description still enumerates the returned JSON fields (status_code, status, headers, body, truncated) plus the ignored output_format. Combined with the safety, timeout, truncation, and policy notes, an agent has everything needed to call it 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 baseline is 3, but the description meaningfully enriches it: method is sent as given with GET default, timeout is whole seconds with the 30 s cap, and max_body's default (1 MiB) and max (10 MiB) with the truncated flag tie the parameter to observable output. It adds real meaning over the schema rather than restating 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+resource ('Makes one HTTP(S) request') and the exact return shape (status, headers, body). It actively distinguishes itself from siblings by routing DNS to network/nslookup, TCP reachability to network/ping, and local files to files/read — an agent can pick this tool without opening any other 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 names three alternative tools and the condition that selects each (DNS, TCP reachability, local files). It also sets usage context: a non-2xx status is not an error, and one call is one request. Nothing about when to reach for this tool is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
network/nslookupARead-onlyIdempotent
Resolves DNS records for a hostname through the host's resolver (/etc/resolv.conf; a DNS server cannot be chosen), so answers may come from a local cache. Read-only, but it sends queries off-host. record_type (case-insensitive) is A, AAAA, CNAME, TXT, MX, NS or ANY; the default ANY is not a DNS ANY query but runs the CNAME, A/AAAA, TXT, MX and NS lookups in turn. Other types (SOA, PTR, SRV) are rejected, and host must be a name: an IP address is not reverse-resolved. Always returns JSON: an object with host and records (array of objects with type and value; an MX value looks like 10 mail.example.com.). Empty records means the name exists but has no record of that type; a name that does not exist is an error (HOST: no such host). To test reachability use network/ping, to fetch a URL network/curl.
| Name | Required | Description | Default |
|---|---|---|---|
| host | Yes | Hostname to resolve, e.g. example.com (an IP address is not reverse-resolved) | |
| record_type | No | A, AAAA, CNAME, TXT, MX, NS or ANY (default ANY: all of these are looked up in turn) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/openWorld, and the description adds genuinely new behavior: queries go off-host, answers may come from a local cache, the resolver is fixed, and failures surface as a specific error ('HOST: no such host'). It even discloses the exact return payload shape and MX formatting.
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-loaded with the core purpose and dense with useful detail, and every clause earns its place (default-ANY semantics, error string, sibling routing). It is a long single paragraph, but there is 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?
Even without an output schema, the description fully specifies the JSON return shape ('host' plus 'records' of 'type'/'value'), the MX value format, and the empty-records vs. non-existent-name distinction. Nothing an agent needs to call or interpret it 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 baseline would be 3, but the description adds real meaning beyond the schema: record_type is case-insensitive, default ANY is not a DNS ANY query but a sequential multi-type lookup, unsupported types are rejected, and host must be a name rather than an IP.
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 ('Resolves DNS records for a hostname') and immediately scopes it ('through the host's resolver, a DNS server cannot be chosen'), which no sibling shares. An agent can distinguish this from network/ping, network/curl, and network/trace-path without opening their schemas.
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: 'To test reachability use network/ping, to fetch a URL network/curl.' It also states when-not conditions — IP addresses are not reverse-resolved and SOA/PTR/SRV types are rejected — leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
network/pingARead-onlyIdempotent
Tests TCP reachability: opens one TCP connection to host:port and closes it. This is NOT ICMP, so it needs a listening port (default 80) and says nothing about other ports or ICMP. Single attempt, no loss statistics; latency includes DNS resolution. Read-only, but it connects off-host and honors the user's network: policy in mcp-sudo.yaml. timeout is whole seconds (default 5). A failed connect is not a tool error: the JSON has success: false and an error text. Returns JSON with host, port, success, latency_ms and error. For DNS only use network/nslookup, for the hop path network/trace-path, for an HTTP check network/curl.
| Name | Required | Description | Default |
|---|---|---|---|
| host | Yes | Hostname or IP address to connect to | |
| port | No | TCP port, whole number (default 80) | |
| timeout | No | Seconds, whole number (default 5) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations: notes it connects off-host, honors the user's network: policy in mcp-sudo.yaml, that failure is not a tool error but a JSON success:false, that latency includes DNS, and that it is a single attempt with no loss statistics. Annotations only signal read-only/idempotent/open-world; the description adds the operational realities an agent needs.
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?
Dense but front-loaded: behavior, caveats, then sibling routing. Nearly every clause earns its place, though it is information-heavy in one paragraph and could be split for scanability.
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 3-param network probe with no output schema, it covers return fields (host, port, success, latency_ms, error), the failure model, policy interaction, and alternatives. Nothing essential to correct invocation 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 baseline is 3; the description adds non-obvious semantics the schema omits - port defaults to 80 because a listening port is required, timeout is whole seconds with default 5, and failure semantics attach to the connect result. Adds meaning beyond the schema wording.
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 ('Tests TCP reachability: opens one TCP connection') and explicitly disambiguates from ICMP. It names four siblings (nslookup, trace-path, curl) with the condition selecting each, so an agent can route without opening schemas.
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?
Explicit when-to-use routing ('For DNS only use network/nslookup, for the hop path network/trace-path, for an HTTP check network/curl') plus when-not ('This is NOT ICMP'). Covers alternatives and scope exclusions directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
network/trace-pathARead-onlyIdempotent
Traces the network path to a host by running the external traceroute binary (not tracepath; it must be installed on the host). Read-only, but it sends probe packets. host is a hostname or IP; max_hops defaults to traceroute's 30 and is capped at 255. There is no timeout parameter and the 30 s worker limit kills slow traces (30 hops x 3 probes can take minutes), so set a low max_hops such as 15. Non-responding hops show as * * *. Returns traceroute's raw text; there is no output_format. Use network/ping first for basic reachability, network/nslookup for DNS problems.
| Name | Required | Description | Default |
|---|---|---|---|
| host | Yes | Target hostname or IP address | |
| max_hops | No | Maximum hops (default 30, capped at 255); keep it low, the 30 s worker limit kills slow traces |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover safety (readOnlyHint=true, idempotentHint=true, destructiveHint=false), so the bar is covered there. The description goes further: it discloses that it runs an external binary that must be installed, sends probe packets, has no timeout parameter, and that the 30 s worker limit kills slow traces (30x3 probes can take minutes). Non-responding hops show as '* * *'. This is rich behavioral context beyond what annotations provide.
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 operation and binary distinction, then layers in caveats and routing to siblings. Every sentence adds distinct value; no fluff. Efficient for the amount of information conveyed.
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?
Covers the things an agent needs to call this correctly that aren't in the schema: external dependency requirement, probe-packet behavior, no timeout, worker limit, and the * * * output convention. Routing to ping/nslookup completes the picture. Nothing material 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 schema documents both parameters. The description reiterates host semantics and the max_hops default/cap, but adds only the worker-limit context, which is already implied in the schema description. Baseline 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?
States a specific verb+resource ('traces the network path to a host') and distinguishes itself from the similarly-named tracepath by naming the exact external binary used. Sibling differentiation is explicit via 'Use network/ping first... network/nslookup for DNS problems.'
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?
Explicit routing: 'Use network/ping first for basic reachability, network/nslookup for DNS problems.' Also gives concrete guidance on when to lower max_hops and why. This is exactly the when/when-not/alternatives structure.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
processes/deleteADestructive
Sends ONE signal to ONE process by PID (kill(2)); the default SIGTERM asks the process to exit. Mutating and not idempotent: it returns as soon as the signal is delivered and does not check that the process exited, and signalling a PID that is gone fails with no such process. Allowed signal values: SIGTERM, SIGKILL, SIGHUP, SIGINT, SIGQUIT, SIGUSR1, SIGUSR2, SIGSTOP, SIGCONT, SIGABRT (SIG prefix optional, case-insensitive, numbers rejected), so it can also pause (SIGSTOP) and resume (SIGCONT). Refuses PID 1 and the mcpd daemon itself. Another user's process fails with not permitted unless privileged: true (needs a grant). Find the PID first with processes/list or processes/top. To stop a managed service use services/manage (systemd may restart a killed one), for a container docker/manage. Returns one text line, Successfully sent signal SIGTERM to process N; output_format has no effect.
| Name | Required | Description | Default |
|---|---|---|---|
| pid | Yes | PID to signal (positive integer; PID 1 and mcpd itself are refused) | |
| signal | No | SIGTERM (default), SIGKILL, SIGHUP, SIGINT, SIGQUIT, SIGUSR1, SIGUSR2, SIGSTOP, SIGCONT or SIGABRT; SIG prefix optional, case-insensitive | |
| privileged | No | Run as root to signal other users' processes. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused | |
| output_format | No | Ignored - the reply is always text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint/not-idempotent, and the description goes well beyond them: it states the signal is fire-and-forget with no exit verification, documents failure modes ('no such process', 'not permitted'), refusal of PID 1 and mcpd, the privileged-grant requirement, and that output_format is ignored. This is unusually rich behavioural disclosure.
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-loaded with the core action and default, then constraints and alternatives. It is dense and long for a single-signal tool, but nearly every sentence adds a distinct operational fact, so little 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?
Despite the absence of an output schema, the description specifies the exact return line ('Successfully sent signal SIGTERM to process N') and notes output_format has no effect. Combined with the error and permission notes, nothing an agent needs to call this correctly 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 already 100%, so the baseline is 3, but the description adds genuinely new constraint information: numbers are rejected as signal values, the SIG prefix is optional and case-insensitive, and privileged requires a grant from mcp-sudo.yaml. Only minor duplication of enum values keeps it from a 5.
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 (send ONE signal to ONE process by PID via kill(2)), its default behaviour (SIGTERM), and explicitly distinguishes itself from siblings like processes/list, processes/top, services/manage and docker/manage. An agent can identify this tool's role without ambiguity.
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 explicit when-to-use guidance ('Find the PID first with processes/list or processes/top') and when-not-to-use alternatives ('To stop a managed service use services/manage ... for a container docker/manage'), including the reason (systemd may restart a killed one). Routing is fully specified.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
processes/listARead-onlyIdempotent
Lists processes (PID, PPID, user, state, RSS, command) read from /proc. Read-only. Use it to find a PID, filter by user or one pid, or sort by memory. For the CPU/memory header and %CPU on every row use processes/top; for the process that owns a port network/connections; to signal a process processes/delete; for deep per-PID metrics the process://<pid>/<target> resource. Sorted by PID unless sort_by is mem (RSS, largest first) or cpu (samples for 0.5 s, so the call takes at least that long, and only then does cpu_percent appear); limit applies after sorting. Kernel threads appear as [name]. Command lines can contain secrets passed as arguments. Text output is a table; output_format: json returns an array of objects (pid, user, comm, state, ppid, rss_bytes, cmdline, cpu_percent). Sizes are bytes unless human_readable.
| Name | Required | Description | Default |
|---|---|---|---|
| pid | No | Filter to a single specific PID | |
| user | No | Exact username | |
| limit | No | Maximum rows returned, applied after sorting | |
| sort_by | No | pid (default), mem (RSS, largest first) or cpu (samples for 0.5 s) | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text | |
| human_readable | No | RSS like 10Mi; default is bytes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the safety profile (readOnly, idempotent, non-destructive); the description goes well beyond that by disclosing that cpu sorting samples for ~0.5 s and only then emits cpu_percent, that limit is applied after sorting, that kernel threads render as [name], that cmdlines can leak secrets, and how output_format changes the shape. These are non-obvious behavioral traits an agent cannot infer elsewhere.
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?
Information-dense and front-loaded with the core purpose and result fields before branching into alternatives and behavior. The paragraph is long but nearly every clause carries new constraints; only marginal tightening is possible.
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 compensates by naming the JSON array fields, noting the text-table default, and explaining sort/limit interaction and the conditional cpu_percent column. Nothing an agent needs to invoke or interpret results 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 real meaning: sort_by semantics (RSS largest-first, cpu costs 0.5 s), limit-after-sorting ordering, human_readable vs bytes, and the note that yaml/table/wide all collapse to JSON. That extra context lifts it above the schema baseline, though it stops short of covering every parameter.
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 ('Lists processes') and enumerates the exact fields returned (PID, PPID, user, state, RSS, command), plus names the data source (/proc). It explicitly distinguishes itself from siblings (processes/top, network/connections, processes/delete, the process:// resource), so an agent can pick it 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?
Gives concrete use cases ('find a PID, filter by user or one pid, or sort by memory') and routes each alternative scenario to the correct sibling tool. This is close to an ideal when-to-use map for a crowded processes/* namespace.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
processes/topARead-onlyIdempotent
Snapshot like top -b -n 1, read from /proc: header (uptime, users, load average, task counts by state, CPU us/sy/ni/id/wa/hi/si/st, memory and swap) plus the process table (PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND), sorted by sort_by (default cpu). Read-only. %CPU is measured over interval_ms (default 1000, max 10000), so the call takes about that long. For a lighter PID list or a single PID use processes/list; to signal a process processes/delete; for memory totals only memory/usage; for which process owns a port network/connections. limit defaults to all processes; user is an exact username. Sizes are bytes (MiB with human_readable). output_format: default and table give top's layout, wide adds PPID, THR and full command lines, json/yaml return an object with summary and processes (memory in bytes).
| Name | Required | Description | Default |
|---|---|---|---|
| user | No | Only this user's processes | |
| limit | No | Maximum processes to list (default: all) | |
| sort_by | No | Sort column: cpu (default, like top), mem/res (resident memory), time (total CPU time), pid | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused | |
| interval_ms | No | %CPU sampling interval in milliseconds (default 1000, max 10000) | |
| output_format | No | Default/table: top's own layout. wide: adds PPID, THR and full command lines (like top -c). json/yaml: structured {summary, processes}, memory in bytes (mem_bytes, swap_bytes, virt_bytes, res_bytes, shr_bytes) | |
| human_readable | No | Memory like top (MiB header, m/g columns); default is bytes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent/non-destructive, so the safety profile is covered. The description adds genuinely new behavioral context: the %CPU sampling window means the call blocks for roughly interval_ms (default 1000, max 10000), and %CPU is measured over that interval rather than instantaneous. It does not discuss permission requirements for privileged mode beyond what the schema says.
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-loaded with the core behavior, then alternatives, then parameter notes. Dense but every clause carries information; the output_format sentence is long and partly mirrors the schema, which keeps it from being maximally tight.
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 specifies the shape of/yaml output ({summary, processes}, bytes) and the wide/table layouts, so an agent knows what it will receive. All defaults and side effects an agent needs are present.
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. The description goes slightly beyond by restating the operative defaults (sort_by cpu, limit all, interval_ms 1000/10000) and clarifying that `user` is an exact-match username and that memory is bytes unless human_readable. Much of this duplicates the schema, keeping it below 5.
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 ('Snapshot like `top -b -n 1`, read from /proc') and enumerates exactly what it returns (header fields plus process table columns). It is unmistakably distinct from processes/list and memory/usage.
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 four alternatives by task: processes/list for a lighter PID list, processes/delete to signal, memory/usage for totals, network/connections for port ownership. Conditions for choosing each are stated, not implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
services/listARead-onlyIdempotent
Lists systemd .service units that systemd currently has loaded, with load, active and sub state (D-Bus ListUnits). Read-only. An installed but never-loaded unit file may be missing, and timers, sockets and other unit types are not included. pattern supports only a leading and/or trailing * (kube*, *ssh*); without * it is an exact unit name including .service. The state filters are exact strings: active_state active/failed/inactive, sub_state running/exited/dead, load_state loaded/not-found. Text output is a block per unit plus a hint line, or No services found matching the criteria.; output_format: json returns an array of objects (name, description, load_state, active_state, sub_state), [] when empty. To change a service use services/manage, for one unit's details the service://<name>/status resource, for its logs logs/journal-control.
| Name | Required | Description | Default |
|---|---|---|---|
| pattern | No | Only a leading and/or trailing * is supported ('kube*', '*ssh*'); without * an exact unit name including '.service' | |
| sub_state | No | Exact state: 'running', 'exited' or 'dead' | |
| load_state | No | Exact state: 'loaded' or 'not-found' | |
| privileged | No | Run as root (may be required depending on policies) | |
| active_state | No | Exact state: 'active', 'failed' or 'inactive' | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld=false, so the 'Read-only' restatement is redundant. However the description adds real behavioral context: installed-but-never-loaded units may be missing, other unit types are excluded, and empty results return a specific message or `[]`. That goes meaningfully beyond the annotations.
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?
Purpose is front-loaded in the first sentence, followed by caveats and routing hints in a compact block. It is dense and largely earn-its-place, though slightly long with some duplication of the schema's pattern/state wording.
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 fully documents return behavior: per-unit text blocks plus a hint line, the exact empty-result string, and the JSON array shape with its field list. Combined with the filtering caveats, an agent has everything needed to call and interpret 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?
Schema coverage is 100%, so the schema already documents all six parameters, including the pattern syntax and exact state values. The description restates the same pattern and state facts but adds no new syntax or defaults beyond the schema, 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?
Opens with a specific verb and resource: 'Lists systemd .service units that systemd currently has loaded', then bounds the scope by naming what is excluded (timers, sockets, other unit types, never-loaded installed files). This lets an agent distinguish it from services/manage and timers/list 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 elsewhere: 'To change a service use services/manage', the status resource for a single unit, and logs/journal-control for logs. It also gives the filtering context (loaded vs installed units). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
services/manageADestructive
Starts, stops, restarts, reloads, enables or disables ONE systemd service over D-Bus (.service is appended when missing). Mutating. Ordinary users are usually refused by polkit, so privileged: true (needs a grant in mcp-sudo.yaml) is normally required. start, stop, restart and reload wait for the systemd job and return Job N completed with status: done (or failed, canceled, timeout, dependency, skipped); a slow one can hit the 30 s worker limit. reload asks the service to re-read its config without stopping it, only if the unit supports it. enable and disable only change whether it starts at boot; they do not start or stop it. To see state use services/list or the service://<name>/status resource, for logs logs/journal-control, for containers docker/manage, for a raw signal to a PID processes/delete.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | start, stop, restart and reload wait for the systemd job; enable and disable only change start at boot | |
| service | Yes | Unit name; '.service' is appended if missing (e.g. 'kubelet' or 'kubelet.service') | |
| privileged | No | Run as root. Normally required (polkit); needs a grant for this tool in mcp-sudo.yaml |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the mutation profile (readOnlyHint=false, destructiveHint=true, idempotentHint=false), but the description adds substantial context beyond them: polkit refusals, the privileged grant requirement, job-waiting behavior with concrete completion statuses, the 30 s worker timeout, and the semantic distinction between reload and enable/disable. This is exactly the behavioral detail that annotations cannot express.
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-loaded with the core verb set and scope before branching into prerequisites, return semantics, and sibling routing. It is dense and every clause carries information, though the run-on middle section could be split for easier scanning.
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 3-parameter mutating tool with no output schema, the description covers the full operational picture: permission prerequisites, job-completion outcomes, timeout risk, action-specific semantics, and where to go for adjacent needs. Nothing an agent needs to call it correctly 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 the enum values and the '.service' append rule are already documented in the schema itself. The description restates those semantics (reload re-reads config only if supported; enable/disable only affect boot) with little that the schema does not already provide, 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 specific verbs (starts, stops, restarts, reloads, enables, disables) against a specific resource (ONE systemd service over D-Bus). It further disambiguates scope with the '.service is appended when missing' detail, so an agent can distinguish it from services/list or process control siblings 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?
Explicitly routes to alternatives by intent: services/list or the service://<name>/status resource for state, logs/journal-control for logs, docker/manage for containers, processes/delete for raw signals to a PID. It also states the normal prerequisite (privileged: true with an mcp-sudo.yaml grant) rather than leaving it to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
system/os-releaseARead-onlyIdempotent
Returns the Linux distribution and kernel version: the contents of /etc/os-release plus the uname line (system, host name, release, version, machine). Read-only. In a containerized daemon /etc/os-release is the container image's, not the host's. Text has an OS Release Info: block with the raw file and a Kernel Info: line; output_format: json (also yaml/table/wide) returns an object with os_release (the raw file text, not parsed into fields) and kernel (the uname line). For CPU details use cpu/list, for kernel parameters kernel/system-control.
| Name | Required | Description | Default |
|---|---|---|---|
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent behavior, and the description adds genuinely material context beyond them: the containerization caveat that /etc/os-release reflects the image rather than the host. It also discloses the resulting output shape (OS Release Info block, Kernel Info line, JSON object keys), which the annotations cannot convey.
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?
Dense but front-loaded: purpose first, then container caveat, then output format, then sibling routing. Every sentence carries information, though the middle output-format sentence is heavy and 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?
With no output schema, the description compensates by describing return content in both text and JSON modes, notes the container caveat, and points to the right siblings for adjacent data. An agent has everything needed to call it and interpret the result.
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 meaning beyond the schema by explaining the accepted values' behavior and what the json object actually contains (os_release raw text, kernel line). That is useful interpretation the schema does not supply.
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 ('Returns the Linux distribution and kernel version') and enumerates exactly what the data comprises (/etc/os-release contents plus the uname line). It also differentiates itself from siblings by routing CPU and kernel-parameter questions elsewhere.
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 names alternatives with the condition that selects them ('For CPU details use cpu/list, for kernel parameters kernel/system-control'), which gives clear routing. It stops just short of a full when/when-not statement for the tool itself, so 4 rather than 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
system/packagesARead-onlyIdempotent
Lists installed packages by parsing the package database (dpkg on Debian/Ubuntu, apk on Alpine); rpm-based systems return an error, not supported yet. Read-only. The whole list is returned with no cap (hundreds of entries), so filter with name: an exact name or a glob (openssh-*, *ssl*). Only packages with status installed are listed. Text has a header N packages installed (dpkg) and a NAME VERSION ARCH table; output_format: json returns an array of objects (name, version, architecture), [] when none; there are no description or size fields. For OS and kernel version use system/os-release.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Only packages whose name matches this glob or exact name (e.g. 'openssh-*', '*ssl*', 'curl') | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, non-destructive), yet the description adds substantial context beyond them: the unsupported rpm path, that the full list is uncapped (hundreds of entries), the installed-only filter, and exactly what the text and JSON outputs contain, including which fields are absent.
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-loaded with the core purpose and tightly packed with only useful facts; every clause carries information. It is dense and somewhat long as a single block, but there is no filler to cut.
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 fully specifies the return shape for both text and JSON, notes empty-result behavior (`[]`), and covers platform limits and filtering. An agent has everything needed to call and interpret it 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 meaning: it explains why `name` matters (unbounded result set) and gives glob/exact examples, plus clarifies that output_format json returns an array of {name, version, architecture} objects and that other format values collapse to JSON.
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 (lists installed packages) and adds the mechanism (parsing dpkg/apk package database) plus the platform boundary (rpm-based systems error out). An agent can distinguish this from system/os-release and other system tools without opening a 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: use this for installed packages, filter with `name`, and use `system/os-release` for OS/kernel version. It also states the when-not condition (rpm-based systems unsupported) and the scoping constraint (only status=installed).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
timers/listARead-onlyIdempotent
Lists the systemd timers of the host - systemd's scheduler, the modern counterpart of cron - each with the unit it starts, its schedule (OnCalendar= and monotonic settings such as OnBootSec=), its next and last run, whether it is Persistent (catches up runs missed while the host was off) and its last result. Read-only. Use it to answer "what runs on a schedule, and when next": services/list shows only .service units, so timers never appear there. To inspect the unit a timer starts, use linuxctl describe system <name> or the service://<name>/status resource; a timer's own state is in this listing. Times are RFC 3339 UTC, and never means systemd reports none (a timer that has not fired yet, or one with no upcoming trigger). pattern accepts a leading and/or trailing * (apt*, *.timer, *daily*); the timer name includes .timer. Unprivileged calls need the host's systemd bus (a bare-metal or VM host); inside a container use privileged: true, which joins the host. output_format: json returns an array with the same fields; text is the default. Empty result means no timer matched. Managing timers (start, stop, enable) is not offered by this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| pattern | No | Wildcard on the timer name (e.g. 'apt*', '*.timer', '*daily*'); no other wildcards | |
| privileged | No | Run as root (needed inside a container to reach the host's systemd; needs a grant) | |
| active_state | No | Only timers in this active state (e.g. 'active', 'inactive', 'failed') | |
| output_format | No | 'json' (also yaml/table/wide, which return the same JSON) for an array of objects; default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent/non-destructive, so safety is covered; the description adds genuinely new behavioral context beyond that: unprivileged calls require the host's systemd bus, containers need `privileged: true` (which joins the host), `never` means systemd reports no trigger, and an empty result means no timer matched. This is rich disclosure that goes well past the structured fields.
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-loaded with purpose and the key sibling distinction, then behavior and edge cases. It is dense and lengthy, but nearly every sentence carries operational content (RFC 3339 UTC, `never` semantics, container privilege, empty-result meaning) rather than padding.
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 compensates by describing the returned fields (unit started, schedule, next/last run, Persistence, last result), the JSON array shape, timestamp format, and edge-case meanings. An agent has everything needed to call and interpret this 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 description coverage is 100%, so all four parameters are already documented in the schema. The description restates `pattern` wildcard rules, `output_format: json` returning an array, and the `privileged` container rationale, adding only slight emphasis rather than new semantics. Baseline 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?
States a specific verb and resource ('Lists the systemd timers of the host') and immediately grounds it with a definition ('systemd's scheduler, the modern counterpart of cron'). It explicitly distinguishes itself from the closest sibling by noting `services/list` shows only `.service` units, so an agent can tell them apart without opening a 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 names the question it answers ('what runs on a schedule, and when next'), routes inspection of a started unit to `linuxctl describe system <name>` or the `service://<name>/status` resource, and states the exclusions outright ('Managing timers (start, stop, enable) is not offered by this tool'). When-to-use, alternatives, and when-not are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
users/listARead-onlyIdempotent
Lists local user accounts from /etc/passwd and /etc/group (uid, gid, home, shell, supplementary group memberships), sorted by uid. Read-only. Never reads /etc/shadow - this reports account identity, not credentials. Local files only: LDAP/SSSD users are not listed. min_uid (e.g. 1000) hides system accounts. Text lines look like name (uid=N gid=N(group)) home=... shell=... groups=a,b; output_format: json returns an array of objects (username, uid, gid, group_name, comment, home_dir, shell, groups). For who logged in use logs/logins, for your own root grants auth/sudo-rules.
| Name | Required | Description | Default |
|---|---|---|---|
| min_uid | No | Only include users with UID >= this value (e.g. 1000 to exclude system accounts) | |
| privileged | No | Run as root. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused | |
| output_format | No | Use json for structured output (yaml, table and wide return the same JSON); default is text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, non-destructive and closed-world, so the safety profile is covered. The description still adds real behavioral context beyond that: the exact source files, that /etc/shadow is never read, and that results are sorted by uid with local-only scope. It stops short of discussing cost or auth mechanics, keeping it just below top marks.
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 verb and source are front-loaded, followed by scope guardrails, output formats, and routing. Despite being a dense single paragraph, every clause carries distinct information with no filler or repetition of the annotations.
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 fully compensates by documenting both text and JSON return shapes and field names. Purpose, scope limits, exclusions, and alternatives are all covered, leaving nothing an agent needs to call this 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. The description nevertheless adds meaning beyond the schema by showing the text output shape and naming the JSON object fields (username, uid, gid, group_name, comment, home_dir, shell, groups), and by giving a concrete min_uid example.
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 (Lists) and resource (local user accounts from /etc/passwd and /etc/group), enumerates the fields returned, and names the sibling tools (logs/logins, auth/sudo-rules) it is not. An agent can distinguish this from every sibling without opening a 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 explicit when-to-use routing ('For who logged in use logs/logins, for your own root grants auth/sudo-rules') and a clear exclusion ('LDAP/SSSD users are not listed'). min_uid's role in hiding system accounts is also stated, so selection conditions are unambiguous.
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.
1 tool update
v0.5.1- Added
cron/manage
47 tool updates
v0.4.1- Changed
auth/sudo-rules1 field changed- changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text"
- Changed
cpu/list2 fields changed- changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text" - changed
Input schema / properties / topology_only / descriptionPrevious value: -"Only return basic core topology"New value: +"Has no effect: accepted but ignored, the output is the same"
- Changed
cpu/load-average1 field changed- changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text"
- Added
daemon/reload-config - Changed
disks/free3 fields changed- changed
Input schema / properties / inodes / descriptionPrevious value: -"List inode information instead of block usage (-i)"New value: +"Report inode counts instead of block usage (-i); the reply is always plain text and ignores output_format and human_readable" - changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to run as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused"
- Changed
disks/health2 fields changed- changed
Input schema / properties / device / descriptionPrevious value: -"Specific block device to query (e.g., 'sda')"New value: +"Bare kernel device name such as 'sda' or 'nvme0n1' (never a path)" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root - required to read SMART data"New value: +"Run as root - required to read SMART data. Needs a grant for this tool in mcp-sudo.yaml"
- Changed
disks/list1 field changed- changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text"
- Changed
disks/mounts3 fields changed- changed
Input schema / properties / fs_type / descriptionPrevious value: -"Only include mounts of this filesystem type (e.g. 'ext4', 'overlay', 'tmpfs')"New value: +"Exact filesystem type, no globs (e.g. 'ext4', 'overlay', 'tmpfs')" - changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused"
- Changed
disks/partitions1 field changed- changed
Input schema / properties / device / descriptionPrevious value: -"Optional specific block device to query (e.g., 'sda')"New value: +"Parent disk name such as 'sda' or 'nvme0n1' (not a partition); omit for all disks"
- Changed
disks/performance2 fields changed- changed
Input schema / properties / device / descriptionPrevious value: -"Optional specific block device to query (e.g., 'sda')"New value: +"Block device name such as 'sda' (see disks/list); omit for all except loop* and ram*" - changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table). Defaults to text"New value: +"json or yaml (real YAML) for structured output; default is a text table"
- Changed
disks/usage8 fields changed- changed
Input schema / properties / all / descriptionPrevious value: -"Write counts for all files, not just directories (-a)"New value: +"Also list every file, largest first (text output only)" - changed
Input schema / properties / apparent_size / descriptionPrevious value: -"Print apparent sizes rather than device usage (--apparent-size)"New value: +"Report logical file sizes instead of allocated disk blocks" - changed
Input schema / properties / exclude / descriptionPrevious value: -"Patterns to exclude"New value: +"Patterns to skip: one containing '/' matches the full path (e.g. '/proc', '/var/lib/*'), others the base name (e.g. '*.tmp')" - changed
Input schema / properties / max_depth / descriptionPrevious value: -"How deep to recurse (0 for summarize only)"New value: +"0 or omitted: grand total only; N: also list directories up to N levels deep, largest first" - changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text" - changed
Input schema / properties / path / descriptionPrevious value: -"Target directory to measure"New value: +"Absolute path of the directory to measure" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to run as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused" - changed
Input schema / properties / threshold / descriptionPrevious value: -"Exclude entries smaller than SIZE if positive, or greater than SIZE if negative (-t)"New value: +"Bytes: a positive value hides entries smaller than this, a negative value hides larger ones (printed lines only)"
- Added
docker/containers - Added
docker/exec - Added
docker/images - Added
docker/logs - Added
docker/manage - Added
docker/networks - Added
docker/prune - Added
docker/volumes - Changed
files/chmod1 field changed- changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root - needed for files you don't own"New value: +"Run as root - needed for files you don't own. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path"
- Changed
files/chown1 field changed- changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root - required to change ownership"New value: +"Run as root - required to change ownership. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path"
- Changed
files/create3 fields changed- changed
Input schema / properties / content / descriptionPrevious value: -"Text content to write to the file"New value: +"Text to write; replaces any existing content entirely, no newline is added. Omit or leave empty to only create an empty file or refresh its mtime (never truncates)" - changed
Input schema / properties / path / descriptionPrevious value: -"Path to the file to create"New value: +"Absolute path of the file; missing parent directories are created" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to write as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused"
- Changed
files/filetype1 field changed- changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to run as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused"
- Changed
files/find9 fields changed- changed
Input schema / properties / human_readable / descriptionPrevious value: -"Sizes like 1.5 KiB; default is bytes"New value: +"Text output only: sizes like 1.5 KiB; default is bytes" - changed
Input schema / properties / max_depth / descriptionPrevious value: -"Maximum depth for directory recursion"New value: +"Levels below path to descend (1 = direct children); omit or 0 for unlimited" - changed
Input schema / properties / mtime / descriptionPrevious value: -"Modification time (e.g. '+7' for older than 7 days)"New value: +"Days since modification: '+7' older than 7 days, '-1' within the last day, '7' exactly 7 days" - changed
Input schema / properties / name / descriptionPrevious value: -"Glob pattern to match filenames"New value: +"Glob on the file's base name only, case-sensitive, e.g. '*.log' (not a path pattern)" - changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format. Defaults to text"New value: +"json (yaml, table and wide return the same JSON) gives an array of objects with path, size, type; default is text" - changed
Input schema / properties / path / descriptionPrevious value: -"Starting directory for the search. Defaults to '/'"New value: +"Absolute starting directory (default /). A large tree with no filter can take longer than the 30 s worker limit" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to search as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused" - changed
Input schema / properties / size / descriptionPrevious value: -"File size (e.g. '+100M' for larger than 100MB)"New value: +"'+100M' larger than 100 MiB, '-10k' smaller than 10 KiB; units b c w k M G, rounded up to the unit" - changed
Input schema / properties / type / descriptionPrevious value: -"File type ('f' for file, 'd' for directory, 'l' for symlink)"New value: +"f file, d directory, l symlink, b, c, p, s; or a comma list such as 'f,d'"
- Changed
files/list3 fields changed- changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text" - changed
Input schema / properties / path / descriptionPrevious value: -"Directory path to list"New value: +"Absolute path of the directory to list" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to run as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused"
- Changed
files/read6 fields changed- changed
Input schema / properties / end_line / descriptionPrevious value: -"Ending line number (inclusive)."New value: +"Last line to return (inclusive); alone it starts at line 1. Ignored if below start_line" - changed
Input schema / properties / limit / descriptionPrevious value: -"Number of bytes to read."New value: +"Number of bytes to return (no upper cap). With no selection at all, the first 10240 bytes are returned" - changed
Input schema / properties / offset / descriptionPrevious value: -"Starting byte offset."New value: +"Byte offset to start at; ignored when start_line/end_line is given. Without limit at most 10240 bytes are returned" - changed
Input schema / properties / path / descriptionPrevious value: -"Path to the file to read"New value: +"Absolute path of the file to read" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to read as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused" - changed
Input schema / properties / start_line / descriptionPrevious value: -"Starting line number (1-indexed). Takes precedence over byte offsets."New value: +"First line to return (1-indexed). With or without end_line it takes precedence over offset/limit; alone it reads to the end of the file"
- Changed
files/update6 fields changed- changed
Input schema / properties / append / descriptionPrevious value: -"If true, appends the content to the end of the file"New value: +"If true, append content at the end (creates the file if missing); takes precedence over start_line/end_line" - changed
Input schema / properties / content / descriptionPrevious value: -"Text content to insert or append"New value: +"Text to append, or to replace the line range with (no newline is added when appending)" - changed
Input schema / properties / end_line / descriptionPrevious value: -"End of the line range to replace (inclusive)"New value: +"Last line to replace (inclusive, >= start_line; past the end of the file is clamped)" - changed
Input schema / properties / path / descriptionPrevious value: -"Path to the file to edit"New value: +"Absolute path of the file to edit" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to edit as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml and a `paths:` entry covering the path, otherwise refused" - changed
Input schema / properties / start_line / descriptionPrevious value: -"Start of the line range to replace (1-indexed)"New value: +"First line to replace (1-indexed); required together with end_line unless append is true"
- Changed
kernel/system-control3 fields changed- changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root - required for writes"New value: +"Run as root - required for writes. Needs a grant for this tool in mcp-sudo.yaml" - changed
Input schema / properties / read_all / descriptionPrevious value: -"If true, reads all available parameters. Ignored if key is set."New value: +"Only when key is empty: read every parameter (thousands of lines, uncapped)" - changed
Input schema / properties / value / descriptionPrevious value: -"Value to set for the parameter. If omitted, reads the parameter."New value: +"Value to write (single line). If omitted, the parameter is read. Writing needs privileged: true and a matching sysctl.write_keys grant"
- Changed
logs/dmesg3 fields changed- changed
Input schema / properties / level / descriptionPrevious value: -"Filter by log level (e.g., 'err,warn')"New value: +"Comma-separated levels from emerg, alert, crit, err, warn, notice, info, debug (e.g. 'err,warn')" - changed
Input schema / properties / output_format / descriptionPrevious value: -"Output format"New value: +"Ignored - the reply is always plain text" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root"New value: +"Run as root - needed when kernel.dmesg_restrict=1. Needs a grant for this tool in mcp-sudo.yaml"
- Changed
logs/journal-control4 fields changed- changed
Input schema / properties / lines / descriptionPrevious value: -"Number of lines to tail (default: 100)"New value: +"Number of entries to tail (default 100; the only size limit)" - changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json). Defaults to text"New value: +"json returns one JSON object per line (journalctl -o json); default is plain text" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root and join the host mount namespace - required in containerized deployments"New value: +"Run as root and join the host mount namespace - required in containerized deployments (needs a grant for this tool in mcp-sudo.yaml)" - changed
Input schema / properties / since / descriptionPrevious value: -"Filter logs since a specific time (e.g., '1 hour ago', 'today')"New value: +"journalctl time syntax, e.g. '1 hour ago', 'today', '2026-09-29 10:00'"
- Changed
logs/logins1 field changed- changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root - typically required for type: \"failed\""New value: +"Run as root - typically required for type \"failed\". Needs a grant for this tool in mcp-sudo.yaml"
- Changed
memory/usage2 fields changed- changed
Input schema / properties / detailed / descriptionPrevious value: -"Set to true to return raw /proc/meminfo instead of summary"New value: +"Return the raw /proc/meminfo instead of the summary (text output only; ignored with output_format json)" - changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text"
- Changed
network/arp1 field changed- added
Input schema / properties / interface / descriptionAdded value: +"Exact interface name such as eth0; omit for all interfaces"
- Changed
network/connections3 fields changed- changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text" - changed
Input schema / properties / port / descriptionPrevious value: -"Filter by port"New value: +"Match sockets whose local or peer port equals this" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root to see PIDs of other users"New value: +"Run as root to see PIDs of other users. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused"
- Changed
network/curl3 fields changed- added
Input schema / properties / method / descriptionAdded value: +"HTTP method, default GET; any method is sent as given" - added
Input schema / properties / timeout / descriptionAdded value: +"Whole seconds (default 10; the 30 s worker limit caps it)" - added
Input schema / properties / url / descriptionAdded value: +"Full URL including scheme, e.g. https://example.com/api"
- Changed
network/nslookup2 fields changed- added
Input schema / properties / host / descriptionAdded value: +"Hostname to resolve, e.g. example.com (an IP address is not reverse-resolved)" - changed
Input schema / properties / record_type / descriptionPrevious value: -"e.g. A, TXT, MX, CNAME, NS, or ANY"New value: +"A, AAAA, CNAME, TXT, MX, NS or ANY (default ANY: all of these are looked up in turn)"
- Changed
network/ping3 fields changed- added
Input schema / properties / host / descriptionAdded value: +"Hostname or IP address to connect to" - changed
Input schema / properties / port / descriptionPrevious value: -"Defaults to 80"New value: +"TCP port, whole number (default 80)" - added
Input schema / properties / timeout / descriptionAdded value: +"Seconds, whole number (default 5)"
- Changed
network/trace-path2 fields changed- changed
Input schema / properties / host / descriptionPrevious value: -"Target hostname or IP"New value: +"Target hostname or IP address" - changed
Input schema / properties / max_hops / descriptionPrevious value: -"Maximum number of hops (optional)"New value: +"Maximum hops (default 30, capped at 255); keep it low, the 30 s worker limit kills slow traces"
- Changed
processes/delete4 fields changed- changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Ignored - the reply is always text" - changed
Input schema / properties / pid / descriptionPrevious value: -"The PID to kill"New value: +"PID to signal (positive integer; PID 1 and mcpd itself are refused)" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root to kill other user's processes"New value: +"Run as root to signal other users' processes. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused" - changed
Input schema / properties / signal / descriptionPrevious value: -"Signal to send (e.g., SIGTERM, SIGKILL)"New value: +"SIGTERM (default), SIGKILL, SIGHUP, SIGINT, SIGQUIT, SIGUSR1, SIGUSR2, SIGSTOP, SIGCONT or SIGABRT; SIG prefix optional, case-insensitive"
- Changed
processes/list5 fields changed- changed
Input schema / properties / limit / descriptionPrevious value: -"Limit returned processes"New value: +"Maximum rows returned, applied after sorting" - changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to run as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused" - changed
Input schema / properties / sort_by / descriptionPrevious value: -"Sort by cpu, mem, or pid"New value: +"pid (default), mem (RSS, largest first) or cpu (samples for 0.5 s)" - changed
Input schema / properties / user / descriptionPrevious value: -"Filter by username"New value: +"Exact username"
- Changed
processes/top1 field changed- changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to run as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused"
- Changed
services/list5 fields changed- changed
Input schema / properties / active_state / descriptionPrevious value: -"Filter by active state (e.g., 'active', 'failed', 'inactive')"New value: +"Exact state: 'active', 'failed' or 'inactive'" - changed
Input schema / properties / load_state / descriptionPrevious value: -"Filter by load state (e.g., 'loaded', 'not-found')"New value: +"Exact state: 'loaded' or 'not-found'" - changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text" - changed
Input schema / properties / pattern / descriptionPrevious value: -"Wildcard pattern to match service names (e.g., 'kube*', '*ssh*')"New value: +"Only a leading and/or trailing * is supported ('kube*', '*ssh*'); without * an exact unit name including '.service'" - changed
Input schema / properties / sub_state / descriptionPrevious value: -"Filter by sub state (e.g., 'running', 'exited', 'dead')"New value: +"Exact state: 'running', 'exited' or 'dead'"
- Changed
services/manage3 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Action to perform on the service"New value: +"start, stop, restart and reload wait for the systemd job; enable and disable only change start at boot" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Run as root"New value: +"Run as root. Normally required (polkit); needs a grant for this tool in mcp-sudo.yaml" - changed
Input schema / properties / service / descriptionPrevious value: -"Service name (e.g., 'kubelet.service')"New value: +"Unit name; '.service' is appended if missing (e.g. 'kubelet' or 'kubelet.service')"
- Changed
system/os-release1 field changed- changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text"
- Changed
system/packages2 fields changed- changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to run as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused"
- Added
timers/list - Changed
users/list2 fields changed- changed
Input schema / properties / output_format / descriptionPrevious value: -"Desired output format (e.g. json, yaml, table, wide). Defaults to text"New value: +"Use json for structured output (yaml, table and wide return the same JSON); default is text" - changed
Input schema / properties / privileged / descriptionPrevious value: -"Set to true to run as root"New value: +"Run as root. Needs a grant for this tool in mcp-sudo.yaml, otherwise refused"
37 tool updates
- First observed
auth/sudo-rules - First observed
cpu/list - First observed
cpu/load-average - First observed
disks/free - First observed
disks/health - First observed
disks/list - First observed
disks/mounts - First observed
disks/partitions - First observed
disks/performance - First observed
disks/usage - First observed
files/chmod - First observed
files/chown - First observed
files/create - First observed
files/filetype - First observed
files/find - First observed
files/list - First observed
files/read - First observed
files/update - First observed
kernel/system-control - First observed
logs/dmesg - First observed
logs/journal-control - First observed
logs/logins - First observed
memory/usage - First observed
network/arp - First observed
network/connections - First observed
network/curl - First observed
network/nslookup - First observed
network/ping - First observed
network/trace-path - First observed
processes/delete - First observed
processes/list - First observed
processes/top - First observed
services/list - First observed
services/manage - First observed
system/os-release - First observed
system/packages - First observed
users/list
TDQS
Scored across 48 tools
Tools are grouped by domain prefixes (docker/, files/, disks/, etc.) and each has a clearly distinct purpose, with descriptions that explicitly cross-reference sibling tools to guide selection. Some overlap exists in listing tools (e.g., processes/list vs processes/top, multiple disk tools) but descriptions resolve ambiguity effectively.
All names follow a consistent namespace/identifier pattern using lowercase and slashes (e.g., files/list, docker/containers, network/ping). The pattern mixes verb-style and noun-style identifiers, so it is not a pure verb_noun convention, but the structure is predictable throughout.
48 tools is far above the typical 3–15 range and well into the 'too many' category. While the server covers a broad Linux administration domain, many tools are very granular (e.g., seven disk-related tools) and could be consolidated without losing functionality.
Significant lifecycle gaps exist: no file delete, move, or copy; no user creation/modification; no Docker container creation, image pull, or build; no package installation. These missing operations will cause agent failures for common administrative tasks, though read-heavy coverage and mutation via grants are present.
Maintenance
Related MCP Connectors
Self-hosted MCP server: 26 deterministic dev, security, and EVM tools.
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
MCP server for Superserve sandboxes: create, exec, and manage Firecracker microVMs
Go MCP server for GitLab: 2 dynamic tools reach 1000+ REST/GraphQL actions. Free/CE, no paid tier.
Related MCP Servers
- AlicenseAqualityCmaintenanceMCP server for Webmin system administration. 61 tools across 12 modules covering system monitoring, services, users, cron, packages, files, storage (SMART + LVM), security (Fail2ban), MySQL databases, Webmin ACL, and disk quotas. Four-tier safety framework with safe mode on by default. Python, MIT license, Docker and local deployment supported.617MIT
- AlicenseNot gradedqualityCmaintenanceRemote Linux operations via SSH, exposed as an MCP server, with tools for filesystem, systemd, Docker, network, and more, using per-user AD authentication and optional sudo elevation.1MIT
- AlicenseAqualityDmaintenanceLinux system administration via AI agents — MCP server for managing services, processes, disk, network and logs on Linux systems.15MIT
- AlicenseNot gradedqualityDmaintenanceExposes a Linux host with shell, Python, and filesystem tools as MCP tools over HTTPS, enabling AI agents to execute commands and manage files remotely.8 npmMIT