Skip to main content
Glama
cygnussystems

cygnus-ssh-mcp

Official

cygnus-ssh-mcp

Cross-platform SSH MCP server with 46 purpose-built tools for real server management by AI agents

PyPI version Python License: GPL v3 Tests

Give Claude, OpenCode, or any MCP-compatible AI assistant full control of your Linux, macOS, and Windows servers with 46 specialized tools

Prerequisites · Installation · Quick Start · Features · Documentation


TIP

A note from the author: I've been running this daily since April 2025 — over a year now — to manage a dozen+ machines and devices, plus a Proxmox host running 30+ containers, across a network tied together with Tailscale. It started as a tool to solve my own problem, and it's saved me a huge amount of manual work ever since. After a year of running it against Linux, I've since added support for Windows, macOS, and other devices with reduced shells like BusyBox. I'm open-sourcing it now because I think anyone running real infrastructure will find it just as useful. This is a young public repo, but the tool behind it isn't new or unproven — it's been battle-tested against my own servers for over a year.

If you find it useful, a ⭐ star or a mention to someone who manages their own infrastructure goes a long way for a project this new — thank you!


Why cygnus-ssh-mcp?

cygnus-ssh-mcp is an MCP server - usable from Claude Desktop, Claude Code, OpenCode, or any other MCP-compatible client - that connects your AI assistant directly to your remote servers over SSH, exposing 46 purpose-built tools instead of one generic command-runner. It turns natural-language requests into real systems administration - connecting by alias, editing files, managing background processes, handling sudo - across Linux, macOS, and Windows targets alike.

Doing that properly means solving a pile of genuinely hard, per-platform problems that a naive ssh wrapper never has to face - and that this project hit and fixed the hard way, including:

  • Getting a real PID back from a Windows target, instead of a meaningless local channel number

  • Recovering the actual exit code when Win32-OpenSSH silently flattens it to 1

  • Reading file contents via SFTP instead of Get-Content, because PowerShell's console encodes stdout in its OEM code page and corrupts anything non-ASCII

  • Killing a sudo'd background process without leaving its privileged child orphaned or blindly firing SIGKILL at the wrong PID

None of this shows up until you actually run these tools against real Linux, macOS, and Windows targets under real conditions - which is exactly how every one of these was found and fixed here, not guessed at from documentation.

What you get

Basic SSH MCP

cygnus-ssh-mcp

Run commands

✅

✅

Pre-configured hosts with aliases

❌

✅

Sudo support (Linux/macOS)

Limited

✅

Windows Server support

❌

✅

Background task management

❌

✅

Line-level file editing

❌

✅

Command history with output

❌

✅

Recursive directory operations

❌

✅

Archive create/extract

❌

✅

Full Unicode support

Varies

✅

Beyond Linux, macOS, and Windows, cygnus-ssh-mcp can also reach further - routers, NAS boxes, and other non-standard SSH targets connect too, via a flex platform type and a capability probe that detects what each device's shell can actually do. See Connecting to Alternate Platforms below.

WARNING

Alternate-platform (flex) support is a work in progress. It's been verified against several real devices, but the space of routers/NAS/embedded systems is huge - expect rough edges on hardware that hasn't been tried yet.

Example agent tasks

Ask your MCP-capable agent to:

  • "Check disk space, memory, uptime, and recent logs on my web host."

  • "Patch this remote config file safely and show me the diff."

  • "Upload this build artifact, extract it, and restart the service."

  • "Start this command in the background and fetch the output later."

  • "Inspect running processes on my Windows SSH host."


Related MCP server: remote-admin-mcp

Prerequisites: SSH on Your Target Servers

cygnus-ssh-mcp connects over standard SSH - it doesn't provide SSH itself, so each server you want to manage needs an SSH server already installed and running.

Linux - usually pre-installed on server distros; if not:

sudo apt install openssh-server   # Debian/Ubuntu
sudo systemctl enable --now ssh

macOS - enable Remote Login in System Preferences → Sharing, or from the terminal:

sudo systemsetup -setremotelogin on

Windows (Server 2019+, or Windows 10/11) - OpenSSH Server is an optional feature:

Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

See Windows Support for Windows Server 2016 and other edge cases.


Installation

Pick one of the two options below - they're independent tools that don't share storage, so commands from one won't see or affect what the other did.

Option A: pip (a persistent install)

pip install cygnus-ssh-mcp

Uninstalling or upgrading:

pip uninstall cygnus-ssh-mcp
pip install --upgrade cygnus-ssh-mcp

Option B: uvx (no install at all)

NOTE

What's uvx? It's part of uv (a fast Python package manager) - uvx <package> downloads a package into a disposable, isolated cache and runs it immediately, without installing it into your system Python, a project, or anywhere pip can see. Nothing lingers afterward for you to manage. It's the easiest option if you just want your MCP client to launch this server without thinking about Python environments at all.

uvx cygnus-ssh-mcp

There's nothing to "uninstall" - uvx re-resolves and re-fetches the latest version on every run anyway. To force a fresh fetch or clear its cache instead:

uvx --refresh cygnus-ssh-mcp   # force this run to ignore the cache
uv cache clean                 # clear uv's entire package cache

If you want a uvx-style setup that does persist (so it doesn't re-fetch every time) and can be upgraded deliberately, use uv tool install cygnus-ssh-mcp instead - manage that with uv tool uninstall cygnus-ssh-mcp / uv tool upgrade cygnus-ssh-mcp. This is still separate from pip (Option A) - don't mix pip commands with anything set up via uv/uvx, they can't see each other.


Quick Start

1. Add your hosts

You don't need to create anything by hand - the first time the server starts, it automatically creates an empty host config file at ~/.mcp_ssh_hosts.toml (secure 0o600 permissions) if nothing is there yet. Just open that file (or use ssh_conn_add_host from within your AI assistant) and add entries like:

# Minimal (password auth) - only required fields
["user@server.example.com"]
password = "your_password"
port = 22

# With alias and sudo (most common setup)
["admin@production.example.com"]
password = "your_password"
port = 22
sudo_password = "sudo_pass"        # optional: for use_sudo operations
alias = "prod"                     # optional: connect by alias
description = "Production server"  # optional: for documentation

# SSH key authentication
["deploy@staging.example.com"]
keyfile = "~/.ssh/id_ed25519"
port = 22
alias = "staging"

# Windows Server (requires OpenSSH)
["administrator@winserver.example.com"]
password = "your_password"
port = 22
alias = "win-prod"

Required fields: port + (password OR keyfile) Optional fields: alias, description, sudo_password, key_passphrase

sudo_password is optional if your account uses password auth - when omitted, the regular password is reused for use_sudo operations too. It's only required if your sudo password differs from your login password, or if you're using SSH key auth (keyfile) with no password field at all - in that case, either set sudo_password explicitly or configure passwordless sudo on the server.

TIP

Host file locations: Default is ~/.mcp_ssh_hosts.toml. Falls back to ./mcp_ssh_hosts.toml if not found. Use --config /path/to/hosts.toml for a custom location. If a file already exists at whichever path is used, it is never overwritten or reset - auto-creation only ever happens when nothing is there yet.

WARNING

Watch for hidden file extensions. If you create this file yourself in Notepad or TextEdit, Windows and macOS both hide known extensions by default - a file you named mcp_ssh_hosts.toml can silently actually be saved as mcp_ssh_hosts.toml.txt, and the server will never find it. Turn on "show file extensions" in Explorer/Finder, or verify from a terminal: ls -la ~/.mcp_ssh_hosts.toml* (macOS/Linux) or dir %USERPROFILE%\.mcp_ssh_hosts.toml* (Windows) - either should show exactly one file, with no extra extension after .toml.

2. Add to your MCP client

Most MCP clients (Claude Desktop, Claude Code, OpenCode, Cursor, Cline, Windsurf, and others) use the same mcpServers JSON shape shown below - only the config file's name and location differ per client. Claude Desktop is used as the concrete example here; see the Claude Code note further down for one client that differs, or check your own client's docs for its config file's path.

WARNING

Python must be on PATH for "command": "cygnus-ssh-mcp" (below) to work at all. This is the most common reason an MCP client fails to start the server (or the tool list never appears) - and with Python often installed in several different places on one machine, it's easy to hit. Check first with:

python --version   # Windows/macOS/Linux
python3 --version  # macOS/Linux, if the above isn't found

If that fails with "not recognized"/"command not found", Python isn't on PATH - fix that first (reinstall Python with "Add to PATH" checked on Windows, or add it to your shell profile), or work around it entirely by finding the full path to the installed executable instead: where cygnus-ssh-mcp (Windows) or which cygnus-ssh-mcp (macOS/Linux), then use that directly as command:

{
  "mcpServers": {
    "ssh": {
      "command": "C:\\Users\\yourname\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\cygnus-ssh-mcp.exe",
      "args": ["--config", "C:\\Users\\yourname\\.mcp_ssh_hosts.toml"]
    }
  }
}

For Claude Desktop, edit claude_desktop_config.json:

{
  "mcpServers": {
    "ssh": {
      "command": "cygnus-ssh-mcp"
    }
  }
}

Or with a custom hosts file location:

{
  "mcpServers": {
    "ssh": {
      "command": "cygnus-ssh-mcp",
      "args": ["--config", "/path/to/my_hosts.toml"]
    }
  }
}

On Windows, use an absolute path with escaped backslashes (JSON needs \\, not a single \):

{
  "mcpServers": {
    "ssh": {
      "command": "cygnus-ssh-mcp",
      "args": ["--config", "C:\\Users\\yourname\\.mcp_ssh_hosts.toml"]
    }
  }
}

Using Claude Code instead of Claude Desktop? It reads its own project-level .mcp.json file (in your project root) rather than claude_desktop_config.json, and its schema supports a couple of extra fields Desktop doesn't have:

{
  "mcpServers": {
    "cygnus_ssh": {
      "command": "cygnus-ssh-mcp",
      "args": ["--config", "/path/to/.mcp_ssh_hosts.toml"],
      "working_dir": "/path/to/your/project",
      "auto_start": true
    }
  }
}
  • working_dir - the directory the server process runs from. Claude Desktop has no equivalent - it doesn't expose a configurable working directory at all, which is exactly why the Desktop examples above always use absolute paths.

  • auto_start - whether Claude Code starts this server automatically. Claude Desktop always auto-starts every configured server; there's no toggle for it.

Everything else - the --config argument, and the PATH/backslash caveats from the warning above - applies the same way to both clients.

3. Start managing servers

NOTE

PROD in the examples below is just an example alias (alias = "prod" in the hosts file from step 1) - it's not a magic name. If a host doesn't have an alias configured, refer to it by its full user@host key instead, e.g. "Connect to admin@203.0.113.10 and..." or "Connect to deploy@myserver.example.com and...".

Depending on which LLM/client you're using, it may not automatically realize it should reach for this MCP server - if it tries to answer without connecting, or claims it can't access remote servers, explicitly tell it to use the SSH MCP tools (e.g. "use the ssh MCP to connect to PROD and...").

Just say:

"Connect to PROD and tell me about the machine - hardware, status, everything"

"Connect to the GPU box and tell me how many graphics cards it has and how much total VRAM"

"Edit /etc/nginx/nginx.conf and change worker_connections to 2048"

"Find all .log files larger than 100MB in /var/log"

It handles multi-step jobs just as easily - install packages, edit configs, open firewall ports, and restart services, all in one request:

"Install PostgreSQL, set it to listen on all interfaces, add a pg_hba.conf rule for remote connections, open port 5432 in the firewall, and create a database called analytics"

"Set up a full LAMP stack, download the latest WordPress, configure wp-config.php with a new database, and get the site running at /var/www/wordpress"

"Get a Let's Encrypt certificate for example.com, configure nginx to serve it over HTTPS, and redirect all HTTP traffic to it"

"My Node app in /opt/api keeps crashing - check the logs, find out why, and set it up as a systemd service that restarts automatically"

"Audit PROD's security - check what ports are open, what's actually listening on them, whether the firewall rules match, and flag anything that looks like it shouldn't be exposed to the internet"


Platform Support

cygnus-ssh-mcp works from any client (Windows, Linux, macOS) to any target server:

From (Client)

To (Target)

Status

Windows

Linux

✅ Tested

Windows

Windows

✅ Tested

Linux

Linux

✅ Tested

Linux

Windows

✅ Tested

macOS

Any

✅ Supported

Windows targets require OpenSSH Server installed and running.


Connecting to Alternate Platforms

WARNING

This is a work in progress. It's been verified against several real devices below, but routers/NAS/embedded systems vary enormously - expect to hit devices that don't work yet, and please open an issue if you do.

Beyond Linux, macOS, and Windows, cygnus-ssh-mcp connects to any SSH target that responds to a basic shell command - routers, NAS boxes, BSD-kernel appliances, and other embedded Linux devices. These report os_type: "flex".

On connect, a one-time capability probe checks the specific shell/coreutils features this project's tools depend on (GNU find -printf, stat -c, du -sb, tar --strip-components, ps -o pgid=, xargs -0, and more) - many embedded/BusyBox-based devices only support a smaller flag set than full GNU coreutils. The results come back from ssh_conn_connect as capabilities and, for anything missing, capability_warnings. A tool that needs a missing capability fails with a clear error naming exactly what's unavailable and, where one exists, a concrete fallback - nothing silently degrades. Where a portable alternative exists (e.g. glob search and directory size without GNU find -printf), the tool simply uses it.

The probe also checks that SFTP is usable: some devices have no SFTP at all (OpenWrt), and some offer an SFTP that shows a different filesystem than the shell (Synology DSM's share-only SFTP). Either way, SFTP-based file tools then say so and point to ssh_cmd_run, instead of giving wrong answers.

Verified against (each by an automated suite that walks an everyday administration workflow and checks every tool's answer against the shell):

Device

Result

Alpine Linux (BusyBox)

Connects as linux; no bash/sudo/GNU find -printf/ps -o pgid= - gated tools fail with clear fallback messages, everything else works

OpenWrt

Connects as linux; root-only, no SFTP, most GNU extensions absent - shell-based tools work, file work goes through ssh_cmd_run

FreeBSD

Connects as flex; no bash by default, sudo/task tooling adapted to use sh

Synology DSM (NAS)

Connects as linux; full GNU coreutils and sudo, but its SFTP only shows shared folders, so SFTP-based file tools are disabled and file work goes through ssh_cmd_run

Known limitation: some devices reject SSH shell access entirely for an account, even one with admin-level permissions - this shows up as every command (even a bare echo) failing immediately after a successful login. No capability probe can fix that; ssh_conn_connect explains the situation in that failure rather than a generic error.

Full details, capability list, and current gaps: docs/26-alternate-platforms.md.


Features

Host Configuration

Stop typing credentials. Connect by alias.

["admin@server.com"]
password = "secret"
port = 22
alias = "web"

Then just: "Connect to WEB"

Supports password, SSH key, and encrypted keys with passphrase.

Update a field on an existing host without losing the rest (ssh_host_update), or switch every host tool to an alternate config file for the session (ssh_host_use_config) - handy for keeping separate host lists per project or environment.


Line-Level File Editing

Edit config files with surgical precision—no download/upload needed.

# Replace a single line
ssh_file_replace_line(
    file_path="/etc/nginx/nginx.conf",
    match_line="worker_connections 1024;",
    new_line="worker_connections 4096;"
)

# Insert lines after a match
ssh_file_insert_lines_after_match(
    file_path="/etc/hosts",
    match_line="# Custom entries",
    lines_to_insert=["192.168.1.10 app.local", "192.168.1.11 db.local"]
)

Safety built-in: Operations fail if the match isn't unique—no accidental mass edits.


Background Task Management

Launch long-running processes and check back later.

# Start a backup (returns immediately)
ssh_task_launch(command="./backup.sh", stdout_log="/var/log/backup.log")

# Check status anytime
ssh_task_status(pid=12345)  # → 'running' or 'exited'

# Kill if needed
ssh_task_kill(pid=12345, force=True)

Comprehensive Sudo Support

Every tool supports use_sudo. Password is handled automatically.

ssh_file_write(file_path="/etc/app/config.yaml", content="...", use_sudo=True)
ssh_dir_mkdir(path="/opt/myapp", use_sudo=True)
ssh_archive_extract(archive_path="/backup.tar.gz", destination_path="/", use_sudo=True)

Three-Way Timeout System

Never get stuck on a hanging command - and never lose track of a long one either.

ssh_cmd_run(
    command="./long_script.sh",
    io_timeout=60.0,        # Check back in if silent for 60s (does NOT kill it)
    wait_timeout=20.0,      # Or check back in every 20s regardless of activity
    runtime_timeout=3600.0  # Hard safety cap - the only one that actually kills it
)

io_timeout and wait_timeout never kill the remote command - they hand off to background monitoring so you can check back later (ssh_cmd_check_status), read output collected so far (ssh_cmd_output), or decide to end it early (ssh_cmd_kill). Only runtime_timeout ever terminates anything.

A single call never blocks longer than 50 seconds (--max-wait / MCP_SSH_MAX_WAIT), because many MCP clients (e.g. OpenCode) abort a tool call at 60s and the handoff would be lost. Longer commands just return a normal wait_timeout handoff with wait_capped: true - poll them, or use ssh_task_launch for anything that runs for minutes.


Full Unicode Support

Write and read files with emojis, international text, and special characters—on all platforms.

✅ ❌ 🎉 • → ≥ ∞ │ ┌ ─ 你好 مرحبا Привет café naïve

How it works: ssh_file_read and ssh_file_write use SFTP for direct binary transfer, completely bypassing shell encoding issues. This means Unicode works perfectly even on Windows targets where PowerShell's console encoding would normally corrupt special characters. The server's own PowerShell scripts write UTF-8 too, so file names in Windows results (delete previews, glob search, listings) keep their exact spelling. Line edits keep a file's own line endings (CRLF stays CRLF).


Windows Server Support

Full support for Windows targets with OpenSSH Server:

  • PowerShell & CMD command execution

  • Windows path handling (backslashes, drive letters, UNC paths)

  • Administrator detection — shows if session has elevated privileges

  • SFTP-based file operations — Unicode-safe, no encoding issues

Note: use_sudo is ignored on Windows (no sudo equivalent). For elevated operations, connect with an Administrator account.


And Much More...

  • Command history with output retention and pattern filtering

  • Recursive directory operations: search, copy, delete with dry-run

  • Archive operations: create and extract tar.gz

  • System info: OS version, memory, disk, CPU, uptime

  • Pattern search: regex and plain text in files

  • Alternate host config files: switch host lists per project/environment without restarting


All 46 Tools

Connection & Host Management (12 tools)

Tool

Description

ssh_conn_connect

Connect using pre-configured host (by key or alias)

ssh_conn_is_connected

Check if SSH connection is active

ssh_conn_status

Get connection status (user, host, OS, cwd)

ssh_conn_host_info

Get detailed system information

ssh_conn_verify_sudo

Verify sudo access

ssh_conn_add_host

Add new host to configuration

ssh_host_list

List all configured hosts

ssh_host_update

Update fields on an existing host (rotate password, change port, etc.) in place

ssh_host_remove

Remove host from configuration

ssh_host_use_config

Switch to an alternate host config file for the session

ssh_host_disconnect

Disconnect current session

list_tools

List all available tools

Command Execution (6 tools)

Tool

Description

ssh_cmd_run

Execute command with I/O, wait, and runtime timeouts

ssh_cmd_kill

Terminate running command

ssh_cmd_check_status

Check command status

ssh_cmd_output

Retrieve output from command

ssh_cmd_history

Get command history with filtering

ssh_cmd_clear_history

Clear command history

Background Tasks (3 tools)

Tool

Description

ssh_task_launch

Launch command in background

ssh_task_status

Check if task is running

ssh_task_kill

Send signal to task

File Operations (12 tools)

Tool

Description

ssh_file_stat

Get file metadata

ssh_file_read

Read file contents via SFTP (Unicode-safe)

ssh_file_write

Create/overwrite/append file

ssh_file_copy

Copy file

ssh_file_move

Move or rename file

ssh_file_transfer

Upload or download files

ssh_file_find_lines_with_pattern

Search for pattern in file

ssh_file_get_context_around_line

Get context around match

ssh_file_replace_line

Replace single line

ssh_file_replace_line_multi

Replace with multiple lines

ssh_file_insert_lines_after_match

Insert lines after match

ssh_file_delete_line_by_content

Delete line by content

Directory Operations (11 tools)

Tool

Description

ssh_dir_mkdir

Create directory

ssh_dir_remove

Remove directory

ssh_dir_list_files_basic

Basic directory listing

ssh_dir_list_advanced

Recursive listing with metadata

ssh_dir_search_glob

Search files by pattern

ssh_dir_search_files_content

Search text in files

ssh_dir_calc_size

Calculate directory size

ssh_dir_delete

Delete with dry-run support

ssh_dir_batch_delete_files

Batch delete by pattern

ssh_dir_copy

Copy directory recursively

ssh_dir_transfer

Upload or download whole directories (archive-based)

Archive Operations (2 tools)

Tool

Description

ssh_archive_create

Create tar.gz archive

ssh_archive_extract

Extract archive


Documentation

Full docs site: cygnussystems.github.io/cygnus-ssh-mcp — searchable, with navigation. Or browse the raw files directly in docs/:


Use Cases

  • DevOps Automation — Deploy, configure, and manage servers via AI

  • Log Analysis — Search and analyze logs across multiple servers

  • Configuration Management — Edit configs with precision line operations

  • Backup & Recovery — Create archives, transfer files, restore backups

  • System Monitoring — Check status, verify services, monitor processes

  • Security Auditing — Search for sensitive patterns, verify configurations


License

GPL-3.0 — Free and open source.


Built by Cygnus Systems

Star this repo if you find it useful!

Available Tools

46 tools
list_toolsA

Retrieves a list of all available tools on this MCP server, along with their descriptions.

Returns: A list of dictionaries, where each dictionary contains the 'name' and 'description' of an available tool.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the burden of behavioral disclosure. It mentions the return format (list of dictionaries with name and description) but omits details like ordering, filtering, authentication needs, or potential side effects. It is adequate for a simple read operation but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences: the first explains the purpose, the second the return value. It is concise, front-loaded, and contains no unnecessary information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given zero parameters and an output schema that is described in the description, the description is fairly complete. It could mention whether the list is user-specific or static, but it is adequate for the tool's simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the baseline is 4. The description adds no parameter information, but that is acceptable because no parameters exist and the schema coverage is complete.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool retrieves a list of all available tools with their descriptions, using a specific verb and resource. It naturally distinguishes from sibling SSH tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for usage (listing all tools), but does not explicitly state when not to use it or mention alternatives. However, given no sibling tools serve this purpose, it is still effective.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_archive_createA

Create a compressed archive from a directory.

IMPORTANT cross-platform caveat: on Windows, tar.gz/tar are NOT natively available - requesting either one silently creates a .zip file instead (via Compress-Archive), and archive_path's extension is auto-corrected to .zip if needed. The only way to tell this happened is the returned format field saying 'zip' even though you asked for tar.gz/tar. An archive created this way on Windows can only be extracted with ssh_archive_extract on another Windows host - Linux/macOS's extractor only recognizes .tar/.tar.gz/.tgz files, not .zip. There is no cross-platform-portable archive format currently available through this tool.

Returns: On success: {'status': 'success', 'success': True, 'archive_created' (the actual path used, which may differ from archive_path if the extension was corrected on Windows), 'format' (the ACTUAL format used - 'tar.gz'/'tar' on Linux/macOS, always 'zip' on Windows), 'size_bytes'}. On failure: {'status': 'error', 'message': str} - not a raised exception.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
formatNoArchive formattar.gz
use_sudoNoUse sudo for the operation
source_pathYesDirectory to archive
archive_pathYesPath for the created archive

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so richly: it discloses the silent Windows format substitution, the archive_path extension auto-correction, that failures return an error dict rather than raising, and the long-running in_progress/handle_id contract with ssh_cmd_check_status polling plus the single-concurrent-operation 'busy' limit. This is behavior an agent cannot infer from schema or annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and the critical cross-platform caveat are front-loaded, and each caveat sentence carries distinct, actionable information. The 'Returns' block partially restates fields already covered by the output schema, which is the main source of redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a cross-platform archive tool with no annotations, the description covers the exact traps an agent needs: format degradation, extension correction, non-exception failure mode, and the async polling contract. Nothing required 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.

Parameters4/5

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: it explains that requesting tar.gz/tar on Windows actually yields zip and that archive_path may be auto-corrected. It says nothing extra about use_sudo, so it stops short of a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Create a compressed archive from a directory'), which cleanly distinguishes it from the sibling ssh_archive_extract that does the inverse operation. An agent can identify the tool's job from the first line alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The Windows caveat effectively guides format selection by telling the agent that tar.gz/tar are silently degraded to zip and that no cross-platform-portable format exists, and it names ssh_archive_extract as the counterpart extractor. However, it never states plainly when to choose this tool over alternatives such as ssh_dir_transfer or ssh_cmd_run, so guidance is strong but implicit rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_archive_extractA

Extract an archive to a directory. The accepted format is platform-specific and determined purely by archive_path's file extension (not by inspecting the archive's actual content):

  • Linux/macOS: .tar.gz, .tgz, or .tar only. A .zip file (e.g. created by ssh_archive_create on Windows) will fail here with an unsupported-format error.

  • Windows: .zip only. A .tar/.tar.gz file (e.g. created by ssh_archive_create on Linux/macOS) will fail here the same way. There is no cross-platform-portable archive format currently available through this tool - archives must be created and extracted on the same OS family.

overwrite=False (default) does not fail outright if some files already exist at the destination - on Linux/macOS it extracts everything else and just logs a warning about the skipped files (no per-file detail returned); on Windows the behavior follows Expand-Archive's own overwrite handling.

On a 'linux'/'flex' connection with a BusyBox-style tar (check ssh_conn_connect/ssh_conn_host_info's capabilities), this can raise a clear error instead of running - unlike the wrong-format/extraction-error cases below, which return an error dict, this is a raised exception. Two independent gaps: missing --strip-components blocks extraction entirely (no clean single-tool fallback - extract without stripping via ssh_cmd_run, the archive's own top-level directory will remain, then relocate its contents up one level yourself); missing --keep-old-files only blocks when overwrite isn't explicitly True - passing overwrite=True avoids that one specifically.

Returns: On success: {'status': 'success', 'success': True, 'destination_path', 'files_extracted' (number of files), 'directories' (number of folders), 'extracted_files' (the first 50 file paths, relative to destination_path), 'extracted_files_truncated' (True if there are more), 'note' (how to list them all, and whether existing files were kept because overwrite=False)}. On failure: {'status': 'error', 'message': str, 'extracted_files': []} - not a raised exception.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
use_sudoNoUse sudo for the operation
overwriteNoOverwrite existing files
archive_pathYesPath to the archive file
destination_pathYesDirectory to extract to

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden and does so: it distinguishes raised exceptions (BusyBox tar gap) from returned error dicts, explains that overwrite=False degrades to a warning on Linux but defers to Expand-Archive on Windows, and discloses the single-operation-at-a-time 'busy' constraint. These are non-obvious traits an agent could not infer from schema alone.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action and the platform rule, and each paragraph carries real operational content. It is long and somewhat dense, with a few passages (the two 'independent gaps') that could be tightened, and it re-describes return fields already covered by the output schema, which costs a point.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 4-parameter mutation-adjacent tool with no annotations, it covers platform constraints, failure vs exception behavior, overwrite edge cases, fallback procedures, and the async in_progress/polling contract. An agent has everything needed to call it correctly and recover from its failure modes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 beyond it by explaining that archive_path's extension alone determines the accepted format (not content sniffing) and by detailing the partial-success semantics of overwrite=False rather than just restating the flag. It does not add much on use_sudo or destination_path, keeping it short of a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ('Extract an archive to a directory') and immediately scopes it against the sibling ssh_archive_create by explaining that the two operate on platform-specific formats. An agent can tell exactly what this does and how it relates to the archive-creation tool 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when extraction succeeds and when it fails (Linux/macOS tar-only vs Windows zip-only, with a worked example of the mismatch), notes that no cross-platform format exists, and names the fallback path via ssh_cmd_run for the BusyBox --strip-components gap. It also routes the agent to ssh_cmd_check_status for long calls and forbids re-invoking meanwhile.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_cmd_check_statusA

Wait for the specified duration, then check the status of a command started with ssh_cmd_run. Call this repeatedly - it's designed to be polled - after ssh_cmd_run returns status='io_timeout' or 'wait_timeout' (the remote command is still genuinely running in both cases - background monitoring keeps collecting its output/exit code), until you get a TERMINAL status below. Do not rerun the original command while polling.

Terminal status values (nothing left to wait for, stop polling):

  • 'completed': confirmed finished, exit_code is populated - including for commands that survived an io_timeout/wait_timeout, since background monitoring keeps watching for the real exit code.

  • 'killed': the remote process was confirmed terminated (e.g. runtime_timeout killed it, or a prior ssh_cmd_kill call found it already gone) - exit_code is not known.

  • 'completed_exit_code_unknown': rare fallback - monitoring stopped without a confirmed exit code (should only really happen from before background monitoring existed, or after an unexpected error) and a live check now confirms the remote process is no longer running. Only its output (via ssh_cmd_output) is available, not its exit code.

Non-terminal status values (keep polling):

  • 'running': still being actively monitored, not yet finished.

  • 'unknown_still_running': rare fallback (same caveat as 'completed_exit_code_unknown') where a live check confirms the remote command is still actually running. Not a failure - call this tool again to keep checking.

Other:

  • 'not_found': the handle_id doesn't exist (may be from a previous connection - handles don't survive reconnects, but background task PIDs from ssh_task_launch do).

  • 'unknown': the handle exists but its metadata is missing from history (rare, internal inconsistency) - treat like 'not_found'.

Fallback behavior: if handle_id doesn't match any ssh_cmd_run handle, this tool also tries treating it as a raw background-task PID (same as ssh_task_status) and, if that succeeds, returns {'pid', 'status': 'running'/'exited'/'invalid'/'error', 'is_background_task': True, ...} instead - a DIFFERENT status vocabulary than the one above. Prefer ssh_task_status directly for PIDs to avoid ambiguity.

Returns: {'handle_id', 'waited_seconds', 'status', 'exit_code', 'pid', 'output_available', 'output_lines', 'timestamp'}, plus 'next_step' (guidance text) when status is non-terminal.

For an OPERATION handle (the handle_id of an 'in_progress' response from a
long-running tool such as ssh_archive_extract or ssh_file_transfer): returns
`{'handle_id', 'status', 'tool', 'operation', 'started', 'ended', ...}` with status
'running', 'completed' (plus 'result': the tool's full normal result) or 'failed'
(plus 'error'). The wait ends early as soon as the operation finishes. While
running it also returns 'elapsed_seconds' and 'progress': the current 'stage'
(e.g. 'uploading archive', 'extracting on host'), 'bytes_done'/'bytes_total'/
'percent' for transfers, counts such as 'files_searched', and 'last_update' /
'seconds_since_update' - if those stop advancing for a long time, the operation
may be stuck rather than just slow.
ParametersJSON Schema
NameRequiredDescriptionDefault
handle_idYesCommand handle ID to check status for - the 'id' returned by ssh_cmd_run, including in its io_timeout/wait_timeout response
wait_secondsNoSeconds to wait before checking. Clamped to the server's per-call wait cap (default 50s, since most MCP clients abort tool calls at ~60s) - the response's waited_seconds shows the wait actually applied. Short waits (1-10s) with repeated polling work best.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: background monitoring keeps collecting output/exit codes after a timeout, handles do not survive reconnects while ssh_task_launch PIDs do, the PID fallback returns a different status vocabulary, and the wait cap exists because MCP clients abort at ~60s. These are non-obvious behavioral traits an agent could not 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.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and polling rules are well front-loaded with clear terminal/non-terminal grouping, but the long 'Returns:' block largely duplicates the existing output schema, and the OPERATION-handle paragraph is verbose. Much earns its place; a meaningful portion does not.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a high-complexity polling tool, the description enumerates every terminal and non-terminal status, explains the rare fallbacks, the not_found/unknown distinction, and the operation-handle variant. An agent has everything needed to poll correctly and interpret each result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

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 both handle_id and wait_seconds (including the clamp and polling advice). The description restates handle_id's origin but adds no syntax, format, or edge-case detail beyond what the schema provides, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb+resource ('check the status of a command started with ssh_cmd_run') and immediately scopes it as a polling companion to ssh_cmd_run. It is clearly distinguishable from ssh_task_status, ssh_cmd_output and ssh_cmd_kill 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use ('after ssh_cmd_run returns status=io_timeout or wait_timeout'), how-often ('call this repeatedly - it's designed to be polled'), what not to do ('Do not rerun the original command while polling'), and an alternative routing rule ('Prefer ssh_task_status directly for PIDs to avoid ambiguity'). All conditions that select this tool versus siblings are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_cmd_clear_historyA

Clear the command history for the current SSH connection, including finished long-running operations (ones still running stay, so they can still be polled).

Returns: Dictionary with operation status

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It discloses a genuinely non-obvious nuance (finished long-running operations are removed, still-running ones survive so they can be polled), which is valuable. However, it omits irreversibility of the clear, any permission requirements, and confirmation behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, with the core action front-loaded and the scope caveat immediately following. The 'Returns' line is slightly redundant given the tool has an output schema, but it is brief and does no real harm.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The scope caveat is well handled and the presence of an output schema means return values need not be elaborated. For a zero-parameter, no-annotation tool, this is nearly complete; only the lack of any usage routing against sibling history/command tools leaves a small gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline of 4 applies. No parameter-level detail is required or missing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Clear') and resource ('command history for the current SSH connection'), which distinguishes it cleanly from the viewing sibling ssh_cmd_history. It does not name that sibling, so it stops short of explicit differentiation, but the verb plus the clarifying parenthetical makes intent unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: an agent can infer this is for wiping history, and the parenthetical hints at the interaction with running operations. There is no explicit when-to-use, when-not, or alternative such as ssh_cmd_history or ssh_cmd_kill.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_cmd_historyB

Retrieve command execution history with optional output snippets.

Returns: List of dictionaries containing command history, ordered from oldest to newest by default. Each entry contains: - id: Command handle ID - command: Executed command - exit_code: Exit status - start_time: Execution start timestamp - end_time: Execution end timestamp - origin: 'user' for a directly user-requested command, or an internal-plumbing label ('tool_internal', 'connection_probe', 'sudo_probe') for a helper command issued by another tool - parent_tool: Name of the MCP tool that triggered this command, when origin != 'user' - output: Stdout snippet (if include_output=True) - stderr is NOT included here, even for a failed command; see the separate 'stderr' field - stderr: Stderr snippet (if include_output=True) - often the more useful stream for a failed command; retrieved the same way ssh_cmd_output(stream='stderr') would

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoNumber of history entries to return
patternNoFilter commands containing this pattern
reverseNoReturn in reverse order (newest first)
output_linesNoNumber of output lines to include (0 for none)
include_outputNoInclude command output snippets
include_internalNoInclude internal/plumbing commands issued by other tools (e.g. ssh_file_write's sudo mv/chown/chmod dance, ssh_conn_connect's OS-detection probe, ssh_conn_verify_sudo's sudo check, ssh_dir_transfer's temp-archive handling). Set False to see only commands the user directly asked for via ssh_cmd_run/ssh_task_launch.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does substantial work: it defines the origin taxonomy ('user' vs tool_internal/connection_probe/sudo_probe), explains parent_tool linkage, and flags the non-obvious behavior that stderr is NOT folded into output even for a failed command. It does not cover permissions, connection requirements, or pagination/cost limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose sentence is front-loaded and good, but the bulk of the text is a field-by-field return-value dump that largely duplicates the existing output schema. That padding dilutes the genuinely useful behavioral notes (origin labels, stderr exclusion).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the description is not obligated to enumerate return fields, yet it does so thoroughly and adds the origin/parent_tool and stderr semantics an agent needs. Missing pieces are usage routing and connection prerequisites, which are moderate rather than critical given the rich schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description reinforces include_output and the output/stderr split but adds no syntax or semantics beyond the schema's own parameter descriptions (limit, pattern, reverse, output_lines, include_internal are all documented there).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a specific verb and resource ('Retrieve command execution history') and the field breakdown makes clear this is a history-listing tool rather than a single-command output fetch. It implicitly contrasts with ssh_cmd_output (by noting stderr is 'retrieved the same way ssh_cmd_output(stream='stderr') would') and with origin/parent_tool fields, but never explicitly states how it differs from siblings like ssh_cmd_check_status.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit when-to-use or when-not-to-use guidance. The description never says to reach for this tool instead of ssh_cmd_output or ssh_cmd_check_status, nor does it state prerequisites (e.g. that a connection must exist). The only scoping hints live in the schema's include_internal description, not in the tool description itself.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_cmd_killA

Terminate a currently running command by its handle ID (the handle_id field - also returned as id - from ssh_cmd_run's response).

This tool is specifically for killing commands started with ssh_cmd_run - it looks up handle_id in this connection's command history, not by raw PID. For background tasks launched with ssh_task_launch, use ssh_task_kill with the PID instead. Raises an error if handle_id doesn't exist in history (e.g. from a previous connection - handles don't survive reconnects) or has no associated PID.

If force=True and the process doesn't exit after wait_seconds, it will be forcibly killed with SIGKILL (signal 9).

Returns: {'handle_id', 'pid', 'result', 'signal', 'force_kill_used', 'timestamp'}. result is one of: - 'not_running': the command was already confirmed not running before any signal was sent (checked first, via a live PID status check) - nothing to do. - 'killed': confirmed terminated (by the signal or the force-kill fallback - see force_kill_used to tell which). - 'already_exited': the process was gone by the time the signal landed. - 'failed_to_kill': still running after the signal (and force-kill, if force=True) - not terminal, the process is still alive. - 'invalid_pid': the command's tracked PID wasn't a valid positive integer. - 'error': the kill attempt itself failed unexpectedly - the process's real state is unknown.

`force_kill_used` is True iff the SIGKILL fallback was actually attempted
(the initial signal alone was not enough), regardless of whether the
fallback itself succeeded - False if the initial signal alone was
sufficient, the process was already gone, or `force=False`.

Note: after a successful kill (`'killed'` or `'already_exited'`, or the early
`'not_running'` case), a later `ssh_cmd_check_status` call for this same
`handle_id` will report status `'killed'`.
ParametersJSON Schema
NameRequiredDescriptionDefault
forceNoForce kill with SIGKILL if process doesn't exit
signalNoSignal to send (15=TERM, 9=KILL)
handle_idYesCommand handle ID to kill - the 'id' field from ssh_cmd_run's response
wait_secondsNoSeconds to wait before force kill

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are supplied, so the description carries the full burden and does so: it enumerates every terminal state a kill can end in, explains the force+wait_seconds escalation to SIGKILL, defines force_kill_used precisely (attempted, not succeeded), and discloses the side effect that ssh_cmd_check_status will later report 'killed'. Permission, reversibility, and ambiguity cases are all addressed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and routing in the first two paragraphs, then error conditions, then returns. It is long, and the Returns block partially restates the output schema, but the per-state semantics justify most of the length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 4-parameter mutation tool with no annotations, the description closes every gap an agent needs: identifier provenance, escalation policy, full result vocabulary including the ambiguous 'failed_to_kill' and 'error' states, and the downstream status effect. Nothing required to invoke or interpret it is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 goes further: it clarifies that handle_id is a history lookup rather than a raw PID, that force only matters if the process survives wait_seconds, and how signal and force interact. It does not add much on wait_seconds beyond the schema default.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (terminate a running command) and immediately scopes the identifier type: the handle_id from ssh_cmd_run, explicitly contrasted with raw PID. An agent can distinguish it from ssh_task_kill 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names the alternative tool and the exact condition for choosing it (background tasks from ssh_task_launch → ssh_task_kill with PID). It also states the failure condition (handle not in this connection's history; handles don't survive reconnects), which is a genuine when-it-won't-work exclusion.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_cmd_outputA

Retrieve captured output from a command started with ssh_cmd_run, identified by its handle_id. Useful after an io_timeout/wait_timeout to see progress so far - including output produced after that call returned, since background monitoring keeps collecting it - to page through output a response didn't include in full (ssh_cmd_run returns at most the last ~32 KB of each stream inline and says so via output_truncated/output_note), or to re-inspect an earlier command's output without rerunning it.

stdout and stderr are captured in separate buffers, not interleaved - stream picks which one to retrieve.

The server keeps up to ~2 MB of each stream per command; beyond that the EARLIEST lines are dropped. Asking for a dropped line with start_line gives an error naming the first line still available. For very large output, redirect it to a file (or use ssh_task_launch) and read that instead.

Raises an error if handle_id doesn't exist (e.g. from a previous connection - handles don't survive reconnects).

Returns: A plain list of output lines from the selected stream - not a dict. For total line counts and whether anything was dropped, use ssh_cmd_check_status (output_lines) or ssh_cmd_history.

ParametersJSON Schema
NameRequiredDescriptionDefault
linesNoHow many lines to return. Without start_line: the most recent N lines (default 50). With start_line: N lines from there (default 50).
streamNoWhich captured stream to retrieve - stdout (default) or stderr. These are NOT interleaved into one combined stream - call this twice (once per stream) if you need bothstdout
handle_idYesCommand handle ID - the 'id' field from ssh_cmd_run's response
start_lineNoPage through the output: return lines starting at this line number (1 = the command's first line). Use it to read what a truncated ssh_cmd_run response didn't include (see its output_note).

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden and does so richly: separate non-interleaved stdout/stderr buffers, ~2 MB per-stream retention with earliest lines dropped, an error naming the first available line for dropped requests, a ~32 KB inline truncation limit on ssh_cmd_run, and handles not surviving reconnects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and useful scoping/alternative guidance in the first two sentences, and clearly sectioned. It is somewhat long, and the explicit 'Returns' block partially restates what the output schema already provides, so a small amount of trimming is possible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 4 params, no annotations, and an available output schema, the description covers limits, error cases, retention behavior, and alternatives thoroughly. An agent has everything needed to call it correctly and interpret its results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

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 lines, stream, handle_id, and start_line semantics. The description reinforces the stream distinction and line-paging idea but adds little syntax or format detail beyond the schema, matching the baseline 3 when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Retrieve captured output from a command started with ssh_cmd_run, identified by its handle_id') and ties the resource directly to its producing sibling. An agent can distinguish it from ssh_cmd_check_status/ssh_cmd_history, which the description explicitly routes elsewhere.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete when-to-use conditions: after an io_timeout/wait_timeout to see progress, to page through output a response didn't include in full, or to re-inspect output without rerunning. It also names alternatives (ssh_cmd_check_status, ssh_cmd_history, ssh_task_launch) for adjacent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_cmd_runA

Execute a command on the remote host and BLOCK until it completes, an io_timeout (silence), a wait_timeout (elapsed cap), or a runtime_timeout (hard cap) occurs.

Timeout semantics (read this before choosing values):

  • io_timeout and wait_timeout firing do NOT mean the remote command stopped - it genuinely keeps running. Monitoring is handed off to a background thread so output/exit code continue to be collected; the response has status='io_timeout'/'wait_timeout', still_running=true, and an id/pid you can use with ssh_cmd_check_status(handle_id=...) to poll again later, or ssh_cmd_output(handle_id=...) to read output collected so far (including output produced after this call returned). Do not rerun the command. You can also still decide to end it early with ssh_cmd_kill(handle_id=...) at any point after either of these fires.

  • io_timeout fires only on SILENCE (no output for N seconds) - a command that keeps producing output never triggers it, however long it runs.

  • wait_timeout fires after N seconds of TOTAL elapsed wait, regardless of activity - use this if you want to check in periodically on a long-running command even while it's actively producing output, rather than being blocked until completion.

  • runtime_timeout is the only knob that DOES attempt to terminate the remote command - a hard safety ceiling, not a UX mechanism. Set it generously (much longer than the command should ever realistically take).

  • A single call never blocks longer than the server's wait cap (default 50s, configurable via --max-wait / MCP_SSH_MAX_WAIT), because most MCP clients abort a tool call at ~60s and the id/pid handoff would be lost. Longer waits are clamped: the response is a normal status='wait_timeout' handoff with wait_capped=true. For anything that may take more than about a minute, ssh_task_launch is usually the better tool.

  • For commands that should survive you disconnecting/reconnecting entirely (not just this call returning), use ssh_task_launch instead - it runs fully detached from this SSH session, whereas a command started here (even after surviving io_timeout/wait_timeout) is still tied to the current connection's lifetime.

You can access command history using 'ssh_cmd_history' to see previous commands and their output. Commands run this way always appear there with origin='user' - pass include_internal=False to ssh_cmd_history to hide unrelated internal plumbing from other tools (e.g. ssh_file_write's sudo dance).

Windows targets: commands run under cmd.exe (CMD syntax), not PowerShell. For PowerShell, run it explicitly: powershell -NoProfile -Command "...".

Working directory: each call is an independent remote process (like a GitHub Actions step or Ansible task, not a continuous shell) - nothing is remembered between calls, including 'cd'. Running ssh_cmd_run("cd /var/log") does NOT affect a later ssh_cmd_run("ls"); it will still list the login directory. Use absolute paths, chain "cd dir && command" within one call, or pass the cwd parameter to run this specific call in a specific directory (Linux/macOS only for now).

Returns: Dictionary containing command output, status, and metadata. The handle identifier is returned here as 'id', but every other tool that accepts it (ssh_cmd_check_status, ssh_cmd_kill, ssh_cmd_output) names the same parameter handle_id - pass this value there. output (stdout) and stderr are always two SEPARATE fields, never interleaved into one combined stream - a command that succeeds can still have written to stderr (warnings, progress meters, non-fatal messages), so check stderr even on status='success'.

Each stream is returned inline up to its most recent ~32 KB. `output_truncated`
and `stderr_truncated` are always present; when true, the response also has
line counts and an `output_note` saying how to read the rest with
ssh_cmd_output(handle_id=..., start_line=...), or that the earliest lines were
dropped (the server keeps ~2 MB per stream per command). For very large output,
redirect it to a file and read that instead.

`status` is one of:
- 'success': command completed with exit code 0. `exit_code`, `output`, `stderr` populated.
- 'command_failed': completed with a non-zero exit code. `exit_code`, `output`, `stderr` populated.
- 'cwd_not_found': the `cwd` parameter didn't exist on the remote host - the
  command was NOT executed at all (fails closed).
- 'io_timeout': no output within `io_timeout` seconds - remote command was NOT
  killed, still_running=true. Poll with ssh_cmd_check_status(handle_id=...).
- 'wait_timeout': `wait_timeout` elapsed regardless of activity - remote command was
  NOT killed, still_running=true. Poll with ssh_cmd_check_status(handle_id=...).
- 'runtime_timeout': `runtime_timeout` exceeded - an attempt was made to kill
  the remote command (see ssh_cmd_check_status's `'killed'` status to confirm).
- 'sudo_required': `use_sudo=True` but elevation isn't available (see
  ssh_conn_verify_sudo before retrying).
- 'busy': another ssh_cmd_run is still WAITING in the foreground on this
  connection - only one call can wait at a time. A command that was already
  handed off (io_timeout/wait_timeout) keeps running in the background and does
  NOT block new ssh_cmd_run calls; several remote commands can be running at once.
- 'error': unexpected failure (e.g. connection dropped).
ParametersJSON Schema
NameRequiredDescriptionDefault
cwdNoRun the command in this directory, for this call only (Linux/macOS only - not yet supported on Windows). Nothing is remembered between calls: each ssh_cmd_run is an independent process, so pass cwd again on every call where it matters, or chain 'cd dir && command' yourself. Fails closed - if the directory doesn't exist, the command is never executed at all (status='cwd_not_found'), so there's no ambiguity about where anything ran.
commandYesCommand to execute on remote host
use_sudoNoRun command with sudo
io_timeoutNoMax seconds of SILENCE (no output) before giving up on waiting. Does NOT kill the remote command - hands off to background monitoring and returns control to you. Note a single call never blocks longer than the server's wait cap (default 50s, since most MCP clients abort tool calls at ~60s) - raising this above that only matters for how long silence is tolerated within the cap. For package installs, Docker pulls, large downloads or compilation, prefer ssh_task_launch. If hit, call ssh_cmd_check_status or ssh_cmd_output to check back rather than rerunning.
wait_timeoutNoMax seconds to wait in THIS call, regardless of output activity - unlike io_timeout, fires even if the command is actively producing output. Does NOT kill the remote command, same non-destructive handoff as io_timeout. Use this when you want to check in periodically on a command that's chatty but long-running (e.g. a verbose Docker pull), rather than being blocked until it finishes or goes quiet. Values above the server's wait cap (default 50s) are clamped to it - the response then has wait_capped=true.
runtime_timeoutNoTotal wall-clock cap in seconds, regardless of output activity. Unlike io_timeout/wait_timeout, hitting this DOES attempt to kill the remote command - it's the only hard ceiling. Set generously for long operations (installs/downloads can need 10-60+ minutes) - this should be a safety net, not a UX mechanism.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden and does so thoroughly. It discloses timeout semantics (io_timeout, wait_timeout, runtime_timeout), handoff behavior, background monitoring, connection lifetime, Windows cmd.exe behavior, working directory independence, output handling, and detailed status values. This goes far beyond what any annotation would typically provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured with clear headings (Timeout semantics, Windows targets, Working directory, Returns). Every section addresses a likely agent question. It is front-loaded with the core behavior, then structured details. While lengthy, it is not redundant and each part earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is extremely complete for a complex tool with 6 parameters and an output schema. It covers timeout semantics, handoff behavior, status meanings, connection lifetime differences from ssh_task_launch, working directory independence, Windows command syntax, output truncation and stream separation, and all status values. Given the complexity, it provides everything an agent needs to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already provides detailed parameter descriptions. The description reiterates and expands on timeout parameters and cwd, but since the schema covers everything, the baseline 3 is appropriate. The description adds meaningful behavioral context for timeouts (e.g., io_timeout fires only on silence) that complements the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb (Execute) and resource (a command on the remote host) and immediately describes the blocking behavior. Clearly distinguises it from siblings like ssh_task_launch and ssh_cmd_check_status by explaining scope and blocking semantics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names when to use this tool vs alternatives: e.g., 'For anything that may take more than about a minute, ssh_task_launch is usually the better tool' and 'For commands that should survive you disconnecting/reconnecting entirely, use ssh_task_launch instead'. Also gives detailed timeout selection guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_conn_add_hostA

Add a new host configuration to the host configuration TOML file. Despite the name, this does NOT update an existing entry - if the user@host key already exists, this returns an error response ({'status': 'error', ...}, not a raised exception) rather than overwriting it; use ssh_host_update for that instead.

Before calling this, check 'ssh_host_list' - the host you want may already be configured, in which case you can call 'ssh_conn_connect' directly without adding anything.

Authentication requires either a password OR a keyfile (or both):

  • Password authentication: Provide password

  • Key-based authentication: Provide keyfile (and optionally key_passphrase if the key is encrypted)

If using key-only authentication and sudo operations are needed, you must explicitly provide sudo_password unless the server has passwordless sudo configured.

Warn the user that credentials will be visible to the LLM and that it would be better for the user to add the host directly in the host configuration file. That said, never read this file yourself (directly or via any file/shell tool) to look up, verify, or copy existing hosts' credentials - ssh_host_list, ssh_conn_add_host, ssh_host_update, ssh_host_remove, and ssh_host_use_config are the only tools you should need for host management, and none of them ever expose a stored password/passphrase back to you. This tool always adds to whichever config file is currently active (the server's default unless ssh_host_use_config was called to switch to an alternate one - check ssh_host_list's config_path if unsure).

The host config file is ~/.mcp_ssh_hosts.toml if it exists, otherwise ./mcp_ssh_hosts.toml in the server's working directory - it stores every host's password, sudo password, and key passphrase in plaintext, which is exactly why the tools above exist instead of editing it by hand. The configuration is stored under a ["user@host"] key.

Optional fields:

  • alias: A short name for connecting (e.g., 'prod' instead of 'deploy@production.example.com')

  • description: A text description of what the host is for

Returns: On success: {'status': 'success', 'message', 'key', 'host', 'user', 'port', 'auth_method' ('key' or 'password'), and 'alias'/'description'/'keyfile' if provided}. On failure (missing auth, duplicate host key, or duplicate alias): {'status': 'error', 'error': <message>} - for a duplicate host key, also includes 'existing_config' (the current host/user/port/alias/description) so you can decide whether to use it as-is via ssh_conn_connect instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
hostYesHostname or IP address
portNoSSH port
userYesUsername for authentication
aliasNoShort name for easy connection (e.g., 'prod', 'staging')
keyfileNoPath to SSH private key file (e.g., ~/.ssh/id_rsa)
passwordNoPassword for authentication
descriptionNoDescription of what this host is for
sudo_passwordNoPassword for sudo operations (defaults to regular password if not provided)
key_passphraseNoPassphrase for encrypted SSH key

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so: it discloses that a duplicate key returns an error dict rather than raising, that credentials are stored in plaintext in ~/.mcp_ssh_hosts.toml, that it writes to whichever config file is active, that credentials become visible to the LLM, and that the agent must not read the file directly. This is exactly the safety/permission context annotations would otherwise supply.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the most decision-critical caveat (no overwrite) and organized with bullets for auth modes and optional fields. It is long and includes some repetition (config-file location stated twice, plus return values already covered by the output schema), which keeps it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers everything an agent needs for a 9-parameter mutation tool: auth prerequisites, duplicate-key failure mode, active-config selection, credential visibility warning, and expected success/error payloads (redundant given the output schema, but harmless). Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 relational meaning the schema cannot: password OR keyfile (or both), key_passphrase only for encrypted keys, and sudo_password being required for key-only auth unless passwordless sudo is configured. These are constraints not expressed in the per-parameter schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb+resource ('Add a new host configuration to the host configuration TOML file'), and the second explicitly disambiguates from the similarly-named ssh_host_update, noting that despite the name it does NOT update existing entries. An agent can distinguish this from ssh_host_list, ssh_host_update, and ssh_host_remove 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing guidance: check 'ssh_host_list' first because the host may already be configured and 'ssh_conn_connect' can be called directly; use ssh_host_update if the entry exists. It also states the preconditions for password vs keyfile auth and when sudo_password is required. This is when-to-use, when-not-to-use, and alternatives all in one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_conn_connectA

Establish an SSH connection using a pre-configured host. The host can be specified by its 'user@hostname' key or by its alias.

Beyond the three fully-supported platforms (Linux, macOS, Windows), any other SSH target that responds to a basic shell command connects too, reported as os_type='flex' (e.g. FreeBSD/OPNsense/pfSense-style routers, or other unrecognized POSIX kernels). For 'linux' and 'flex' connections, a one-time capability probe checks the specific shell/coreutils features this server depends on (some embedded/BusyBox-based devices lack GNU extensions like find -printf or tar --strip-components) - the result is returned as 'capabilities' (raw probe results) and, if anything's missing, 'capability_warnings' (plain-English gaps). Tools that need a missing capability fail with a clear error naming what's missing, rather than a cryptic remote command failure - nothing is silently degraded.

Returns: Dictionary with connection status and detailed system information. 'capabilities'/'capability_warnings' are included for 'linux'/'flex' connections only (empty/omitted for macOS/Windows, which are already fully supported and not probed). Two different "os_version" fields: connection.os_version is a short platform/distro identifier used internally (e.g. 'debian', 'centos', 'windows_server_2016', or 'unknown_linux'/'unknown_windows' if not recognized; None on macOS), while system.os_version is the human-readable version string reported by the OS itself (e.g. '12 (bookworm)', '14.8.9').

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
host_nameYesThe 'user@hostname' identifier or alias of a pre-configured host

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and delivers: it discloses the capability probe behavior for linux/flex targets, that missing capabilities fail with named errors rather than silent degradation, the os_type='flex' fallback for unrecognized POSIX kernels, the in_progress/handle_id long-running contract with polling instructions, and the single-concurrent-operation 'busy' error.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Long but dense; most sentences earn their place (long-running contract, capability model, busy constraint). The two 'os_version' field explanation leans toward restating output-schema detail and is the weakest portion, but overall it is front-loaded and disciplined.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a connection tool that can hang, this covers the async handle/polling flow, the concurrency limit, platform classification, and capability probing. Although an output schema exists, the remaining prose is behavioral rather than shape-describing, so 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.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% for the single host_name parameter, so the schema already documents it. The description reinforces the 'user@hostname or alias' semantics and clarifies hosts must be pre-configured, but adds no syntax or format detail beyond the schema. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: establish an SSH connection to a pre-configured host. It also distinguishes itself from siblings like ssh_conn_status, ssh_conn_is_connected, and ssh_conn_host_info by framing this as the connection-establishment step and explaining the host key/alias resolution.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains how to identify the host (user@hostname or alias) and, crucially, the long-running fallback ('do not call it again', poll ssh_cmd_check_status instead) and the one-operation-at-a-time constraint. However, it gives no explicit guidance on when to use this versus alternatives such as ssh_host_add_host or ssh_host_use_config when a host is not yet configured.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_conn_host_infoA

Get detailed SSH connection status and system information.

Returns: Dictionary containing full connection status and detailed system info including hardware, memory, disk usage, and more. For a 'linux' or 'flex' (non-Linux/macOS/Windows) connection, also includes 'capabilities' (probed GNU/BusyBox-coreutils feature support) and 'capability_warnings' (plain-English list of confirmed gaps) - see ssh_conn_connect's docstring for what these mean.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so thoroughly: it discloses async behavior (in_progress + handle_id after the 50s wait cap), the required polling tool, the prohibition on calling again during the wait, and the one-at-a-time concurrency limit with a 'busy' failure mode. It also describes the returned system details and capability fields for specific connection types.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the purpose and then uses clear sections ('Returns:' and 'Long-running calls:'). It is somewhat long, but the async and concurrency details earn their place because they change how an agent must invoke and follow up on the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that an output schema exists, the description does not need to explain return values, yet the extra return-value context is helpful. It covers the async and concurrency behavior completely, but it still lacks explicit sibling differentiation from ssh_conn_status or ssh_conn_is_connected.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. The empty schema and description correctly reflect that no input arguments are needed, and there are no parameter semantics to clarify.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Get detailed SSH connection status and system information.' It is clear what the tool retrieves, but it does not explicitly distinguish itself from sibling tools like ssh_conn_status or ssh_conn_is_connected, leaving mild ambiguity about which connection-status tool to choose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives useful usage guidance for long-running calls: poll ssh_cmd_check_status with the returned handle_id, do not call again meanwhile, and only one such operation runs at a time. However, it provides no when-to-use guidance relative to alternatives such as ssh_conn_status or ssh_conn_is_connected.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_conn_is_connectedA

Check whether there is a WORKING SSH connection - a real round trip to the host (a few milliseconds normally, at most ~5s), not just a cached flag. A connection that died while idle (e.g. dropped by a firewall overnight) is detected, dropped, and reported as False.

Returns: bool: True if the connection works, False otherwise - then reconnect with ssh_conn_connect(host_name=...).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden, and it does meaningful work: it discloses timing expectations (a few ms normally, at most ~5s) and the side effect that a dead connection is detected and dropped. It does not state whether it blocks, nor whether any auth/permission is needed, but the drop-on-failure behavior is real added value.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core guarantee ('real round trip... not just a cached flag') followed by the failure-recovery hint; every sentence earns its place. The Returns block slightly duplicates the output schema, which costs a point.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, explaining the bool return is not strictly required, and the description covers timing, side effects, and next steps. The one gap is that it never says WHICH connection is checked given the zero-parameter signature (current/default host context is left implicit).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. The description goes slightly further by naming the follow-up call and its argument shape (ssh_conn_connect(host_name=...)), hinting how the host is selected after a failed check.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb+resource — 'Check whether there is a WORKING SSH connection' — and sharpens it by defining 'working' as a real round trip rather than a cached flag. It does not, however, name or differentiate itself from the sibling ssh_conn_status, which an agent must distinguish on its own.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied (use it to detect connections that died while idle) and a follow-up action is given for the False case (reconnect with ssh_conn_connect). But there is no explicit when-to-use/when-not or contrast against ssh_conn_status, leaving the agent to infer which connectivity check to call.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_conn_statusA

Get essential SSH connection status information.

Returns: Dictionary containing basic connection status (user, working directory, OS type)

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it discloses the in_progress/handle_id return shape, the wait cap, the polling contract via ssh_cmd_check_status, and a concurrency constraint ('only one such operation runs at a time... fails with a busy error'). These are non-obvious runtime behaviors not captured by any structured field.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose and return shape, followed by the long-running behavior. The async paragraph is long but every clause (wait cap, handle_id, poll target, busy error) is load-bearing, so it stays efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless read tool with an output schema, the description covers purpose, returned fields, and the full async/concurrency contract. An agent has everything needed to invoke and re-invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so per the rubric the baseline is 4. There is nothing for the description to clarify beyond the empty schema, and it introduces no spurious parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Get essential SSH connection status information') and even enumerates the returned fields (user, working directory, OS type), which helps separate it from ssh_conn_is_connected. However, it never names or contrasts with those siblings, so the agent must infer the distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear guidance for the async case ('Do not call it again meanwhile', poll ssh_cmd_check_status), but offers no guidance on when to use this versus ssh_conn_is_connected or ssh_conn_host_info. Usage is implied by the purpose rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_conn_verify_sudoA

Check whether elevated access is available on the remote system, without running any privileged command. Call this before using use_sudo=True on other tools if you're not sure elevation will succeed.

On Linux/macOS: probes whether sudo is available and whether it needs a password (via a passwordless sudo -n check, then a password-based check if that fails). Tools called afterward with use_sudo=True will use whichever mode this detected.

On Windows: there is no per-command elevation - checks whether the current SSH session itself is already running as Administrator. If it's not, no tool call can become elevated; you must reconnect as an Administrator account instead.

Returns: Dictionary with: - available (bool): True if sudo/elevation can be used at all (passwordless OR password-based on Linux/macOS; same as passwordless on Windows, since there's no separate password-based mode there) - passwordless (bool): True if no password is needed (passwordless sudo, or an already-elevated Windows session) - requires_password (bool): True if sudo works but needs a password (always False on Windows)

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it guarantees no privileged command is executed, explains platform-specific detection logic (passwordless vs. password-based sudo on Linux/macOS; session-level Administrator check on Windows), documents return semantics, and discloses the long-running/in_progress behavior and busy error. 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.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well front-loaded and organized with clear labels ('On Linux/macOS:', 'On Windows:', 'Returns:', 'Long-running calls:'). It is somewhat long, and the detailed Returns block partially duplicates the existing output schema, but every section still aids correct invocation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, cross-platform capability-check tool with long-running behavior, the description covers purpose, platform-specific semantics, return fields, and timeout/polling mechanics. An agent has everything needed to call it and to handle the in_progress case without consulting other sources.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there are no parameter semantics to add; the baseline for 0 params is 4. The description correctly introduces no parameters and instead documents platform behavior, which is the relevant information here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a precise verb and resource ('Check whether elevated access is available on the remote system') with an explicit scope constraint ('without running any privileged command'), which clearly distinguishes it from command-running siblings like ssh_cmd_run. An agent can identify it immediately as a pre-flight capability probe rather than an action tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says when to call it ('Call this before using use_sudo=True on other tools if you're not sure elevation will succeed') and names the sibling to poll for long-running results (ssh_cmd_check_status(handle_id=...)). It also defines the concurrency limit ('Only one such operation runs at a time'), 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.

ssh_dir_batch_delete_filesA

Recursively find and delete files matching a filename glob pattern (same pattern syntax as ssh_dir_search_glob, e.g. *.tmp) under a directory. dry_run DEFAULTS TO True - calling this with no arguments other than path/pattern only PREVIEWS which files would be deleted and deletes NOTHING; you must explicitly pass dry_run=False to actually delete.

On a 'linux'/'flex' connection with a BusyBox-style xargs that doesn't support -0 (check ssh_conn_connect/ssh_conn_host_info's capabilities), this raises a clear error instead of running. Fallback: ssh_cmd_run with find <path> -name '<pattern>' -exec rm -f {} + instead - portable, and still safe with spaces in filenames.

Returns: {'status': 'success'/'error', 'deleted_files': [str, ...] (matching file paths that were/would be deleted)}, plus 'dry_run': True ONLY when this was a preview (check for this key to tell a preview apart from a real deletion) and 'error' (string) on failure. Note the key is deleted_files here, vs. deleted_items on ssh_dir_delete.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesBase directory to search in
dry_runNoPreview deletion without actually deleting
patternYesFile pattern to match for deletion (e.g. *.tmp)
use_sudoNoUse sudo for the operation

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it discloses the dry_run safety default, the BusyBox error condition with a capabilities check, the in_progress/handle_id behavior past the 50s wait cap, polling via ssh_cmd_check_status, and the 'busy' failure mode. These are exactly the behavioral traits an agent cannot infer from the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and the safety-critical dry_run default, then layered with fallback and long-running details. It is long, but nearly every sentence is operationally load-bearing; the Returns block is slightly verbose relative to the existing output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a destructive mutation tool with no annotations, 4 parameters, and a long-running mode, the description covers safety defaults, failure modes, fallbacks, polling, and result-shape differences. Nothing material 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.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3; the description adds real meaning on top by spelling out that dry_run defaults to True and only previews, that pattern uses ssh_dir_search_glob syntax, and that path is the base search directory. It stops short of describing use_sudo semantics, so not a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('recursively find and delete files matching a filename glob pattern') and immediately differentiates from siblings by referencing ssh_dir_search_glob's pattern syntax and contrasting the return key with ssh_dir_delete's `deleted_items`. An agent can identify this tool 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the dry_run default and the consequence of omitting it (preview only, nothing deleted), names the fallback path (ssh_cmd_run with find -exec rm -f) for BusyBox xargs without -0, and explains the long-running polling workflow and the one-at-a-time constraint. When-to-use and when-to-substitute are both covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_dir_calc_sizeA

Calculate the total size of a directory recursively: the sum of the sizes of all regular files under it (directories' own sizes are not counted - same on every platform).

On a 'linux' connection whose find lacks -printf (check ssh_conn_connect/ ssh_conn_host_info's capabilities), this raises a clear error instead of running. Fallback: ssh_cmd_run("du -sk <path>") - kilobytes, and it includes directory overhead, but works on most BusyBox builds.

Returns: {'path', 'size_bytes' (int), 'size_human' (e.g. "1.23 MB", "512.00 KB", "3.50 GB" - 2 decimal places, binary/1024-based units)}.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesDirectory path to calculate size for

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so thoroughly: platform-dependent error conditions, capability preconditions, a viable fallback, the exact return shape, async behavior past the 50s wait cap, the polling tool to use, and a concurrency constraint ('only one such operation runs at a time ... fails with a busy error'). This is unusually complete disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then organized into platform caveat, return format, and long-running behavior sections. Every sentence carries information, though the return-format block restates a documented output schema, adding slight redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with real complexity (platform quirks, async handles, concurrency limits) the description covers everything an agent needs to call it correctly — preconditions, failure modes, polling path, and result shape. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and there is a single required 'path' parameter already documented in the schema. The description adds only implicit meaning via the du example ('<path>' as a directory), which is marginal beyond the schema baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Calculate the total size of a directory recursively') and immediately defines the exact semantics — sum of regular files, directory entries excluded, platform-independent. An agent can distinguish it from ssh_file_stat or ssh_dir_list_advanced 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.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete when-not guidance (raises on 'linux' connections lacking find -printf, with a capability check reference) and an explicit alternative fallback (ssh_cmd_run("du -sk <path>")) along with the tradeoff (KB, includes directory overhead). It stops short of comparing against sibling tools like ssh_file_stat for single-file sizing, but the routing context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_dir_copyA

Copy a directory recursively (remote-to-remote; for local<->remote use ssh_dir_transfer instead).

overwrite controls what happens if destination_path already exists:

  • True: the entire existing destination directory is deleted first, then a fresh copy is made.

  • False (default): does NOT block the copy - it copies into the existing destination as-is, merging with whatever's already there, and any file that shares a name with a source file gets silently overwritten anyway. This does NOT behave like the "fail if destination exists" semantics of ssh_file_move/ssh_file_copy's own overwrite parameter.

Returns: {'status': 'success'/'error', 'files_copied' (int), 'bytes_copied' (int), 'destination_path'} (plus 'message' on error). Note: files_copied/ bytes_copied are computed by counting the destination directory's TOTAL contents after the copy, not just the files newly copied in this call - if merging into a non-empty destination, these counts include pre-existing files too.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
use_sudoNoUse sudo for the operation
overwriteNoOverwrite existing files
source_pathYesSource directory path
destination_pathYesDestination directory path
preserve_symlinksNoPreserve symbolic links
preserve_permissionsNoPreserve file permissions

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations, so the description carries the full burden and does: overwrite=True deletes the entire existing destination first (a destructive detail), overwrite=False merges and silently overwrites name collisions, async in_progress/handle_id behavior past the 50s wait cap, and a single-concurrent-operation constraint. This is exactly the destructive/async context an agent needs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded purpose followed by a scannable bullet for the critical overwrite distinction; nearly every sentence earns its place. The Returns block overlaps with the existing output schema, though the caveat about files_copied/bytes_copied counting total destination contents (not just newly copied files) is real added value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, potentially long-running recursive copy, the description covers routing, overwrite semantics, return shape interpretation, and the async polling contract. Nothing an agent needs to invoke or correctly interpret this call is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 genuine meaning beyond the schema's thin 'Overwrite existing files' label by spelling out delete-then-copy vs merge-and-silently-overwrite, and explicitly contrasts it with the same-named parameter on other tools. use_sudo, preserve_symlinks and preserve_permissions get no added detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (recursive remote-to-remote directory copy) and immediately distinguishes itself from ssh_dir_transfer for local<->remote work, and from ssh_file_move/ssh_file_copy's overwrite semantics. 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use (remote-to-remote) and when-not (local<->remote → ssh_dir_transfer). It also gives operational guidance: poll via ssh_cmd_check_status rather than re-calling, and only one such operation runs at a time with a 'busy' error otherwise.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_dir_deleteA

Delete a directory and all its contents recursively. dry_run DEFAULTS TO True - calling this with no arguments other than path only PREVIEWS what would be deleted and deletes NOTHING; you must explicitly pass dry_run=False to actually delete. Refuses to delete a small set of critical paths outright (root, home directory, C:\Windows, C:\Users, etc.) regardless of dry_run.

For a simpler non-recursive removal without the preview step, see ssh_dir_remove.

Returns: {'status': 'success'/'error', 'deleted_items': [str, ...] (paths that were/would be removed, depth-first order)}, plus 'dry_run': True ONLY when this was a preview (check for this key to tell a preview apart from a real deletion - it's absent, not False, on actual deletions) and 'error' (string) on failure. Also fails (with 'error' set) if path is a recognized critical directory.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesDirectory path to delete
dry_runNoPreview deletion without actually deleting
use_sudoNoUse sudo for the operation

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: it discloses the dry_run=True default and its consequence, the critical-path refusal list, the presence/absence semantics of the 'dry_run' return key, the in_progress handle behavior past the 50s wait cap, and the one-operation-at-a-time 'busy' failure. This is far beyond what the schema conveys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the destructive-recursion purpose and the dry_run default, which are the highest-stakes facts, and every section (return, long-running) earns its place. It is dense and slightly long, with heavy capitalization for emphasis, but not padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, potentially long-running tool with no annotations, the description covers safety defaults, refusal behavior, return shape (even though an output schema exists), and async/polling semantics. 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.

Parameters4/5

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 extends `dry_run` beyond the schema's one-liner by explaining that omitting it previews and nothing is deleted unless `dry_run=False` is passed explicitly. `use_sudo` gains no additional explanation, keeping it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource with scope ('Delete a directory and all its contents recursively') and explicitly names the sibling it is not ('For a simpler non-recursive removal without the preview step, see ssh_dir_remove'). An agent can distinguish it from ssh_dir_remove and ssh_dir_batch_delete_files 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use context (recursive removal with preview) and routes to the alternative (ssh_dir_remove) for the non-recursive case. It also warns against re-calling during a long-running operation and points to ssh_cmd_check_status for polling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_dir_list_advancedA

List contents of a directory recursively with full metadata (size, permissions, ownership, modification time) - use this instead of ssh_dir_list_files_basic (which only returns bare filenames, non-recursive) when you need more than just names, or ssh_dir_search_glob when you only need to filter by filename pattern without full metadata (that tool is also faster for large trees).

max_depth uses standard find -maxdepth semantics: max_depth=1 means path itself plus its immediate children only; omit for unlimited recursion.

On a 'linux'/'flex' connection with a limited BusyBox-style find (no -printf - check ssh_conn_connect/ssh_conn_host_info's capabilities), this raises a clear error instead of running. Fallback: ssh_dir_list_files_basic (non-recursive filenames) plus ssh_file_stat per entry for metadata - both are SFTP-based and unaffected by this, at the cost of one call per directory level.

Returns: List of {'path', 'type', 'size_bytes' (int), 'modified_time' (float Unix timestamp), 'permissions' (string, e.g. "755"), 'user', 'group'}. type is a spelled-out word here ('file'/'directory'/'symlink'/'pipe'/'socket'/ 'block'/'character') - note this differs from ssh_dir_search_glob, which returns single-character type codes ('f'/'d'/'l') for the same concept. On Windows, permissions is always the literal placeholder "0" (Windows has no Unix-style permission bits) and group is always "unknown" - user still reflects the real file owner there.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesDirectory path to list
use_sudoNoUse sudo for the operation
max_depthNoMaximum recursion depth (None for unlimited)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and discharges it well: it discloses the BusyBox `find` failure mode and that it raises an error rather than degrading, the Windows placeholder values for permissions/group, the async long-running behavior (in_progress + handle_id + polling ssh_cmd_check_status, don't re-call), and the single-concurrent-operation 'busy' limit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and routing, then progressively deeper detail; each block (depth semantics, platform caveats, returns, async) earns its place. It is on the long side and the returns section partly overlaps the existing output schema, but nothing is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Complete for a tool of this complexity: it covers routing, depth semantics, platform-specific errors and fallbacks, the return shape including cross-tool type-code differences, and async polling. An agent has everything needed to call it correctly and recover from the documented failure modes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 genuine meaning to `max_depth` by explaining `find -maxdepth` semantics with a concrete example (max_depth=1 = path plus immediate children; omit for unlimited). It does not elaborate on `use_sudo`, though that parameter is self-describing in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List contents of a directory recursively') plus the distinguishing metadata it returns (size, permissions, ownership, modification time). It explicitly differentiates itself from ssh_dir_list_files_basic (bare filenames, non-recursive) and ssh_dir_search_glob (pattern-only, faster on large trees), 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use and when-not-to-use guidance, naming both alternatives and the conditions that select them ('when you need more than just names', 'when you only need to filter by filename pattern'). It also documents a fallback path with concrete steps (list_files_basic + ssh_file_stat per entry) for constrained hosts.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_dir_list_files_basicA

List the immediate contents of a directory (via SFTP - not recursive, no metadata). For recursive listing with size/permissions/type/etc., or to filter by filename pattern, use ssh_dir_list_advanced or ssh_dir_search_glob instead.

Returns: List of bare filenames (strings) directly inside path - not full paths, not recursive, and no indication of which entries are files vs. directories (use ssh_file_stat on an entry, or ssh_dir_list_advanced, if you need that).

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesDirectory path to list

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: it discloses the async long-running pattern (50s wait cap, {"status": "in_progress", "handle_id"} fallback), how to retrieve results via ssh_cmd_check_status, a do-not-retry instruction, and a single-concurrency 'busy' failure mode. This is exactly the behavioral context annotations would otherwise need to supply.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core purpose, then routing alternatives, then a labeled 'Returns' block, then a labeled long-running note. Every sentence earns its place, and the sectioning makes each concern scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-param listing tool with an output schema present, all an agent needs is covered: scope, routing to alternatives, return shape, and the async/polling protocol. Nothing required for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter (path) and schema coverage is 100%, so the schema already fully documents it; per the baseline rule this lands at 3. The description reinforces that listing is of the immediate contents of `path` and returns bare filenames rather than full paths, which adds mild clarity but no new syntax.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (directory contents) with precise scope qualifiers: non-recursive, no metadata, via SFTP. It explicitly names the sibling tools it is not (ssh_dir_list_advanced, ssh_dir_search_glob) so an agent can distinguish it without opening another schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use-else guidance: for recursive/metadata listings or pattern filtering, use ssh_dir_list_advanced or ssh_dir_search_glob, and for file-vs-directory determination use ssh_file_stat or ssh_dir_list_advanced. Alternatives and their selecting conditions are named directly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_dir_mkdirA

Create a directory on the remote system.

Parent-directory creation and mode behavior differ by platform/sudo:

  • Linux/macOS, use_sudo=False (default): uses SFTP mkdir, which is NOT recursive - this FAILS if the parent directory doesn't already exist. mode applies to the created directory.

  • Linux/macOS, use_sudo=True: uses mkdir -p -m <mode>, which DOES create any missing parent directories.

  • Windows: always creates missing parent directories (New-Item -Force, regardless of use_sudo, which has no effect on Windows anyway). The mode parameter is IGNORED entirely on Windows - there's no equivalent to Unix octal permissions there.

Returns: {'status': 'success', 'path', 'mode' (octal string - reflects the requested mode even on Windows, where it was actually ignored), 'message', 'connection'} on success. Raises an exception on failure (e.g. missing parent directory without sudo on Linux/macOS).

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
modeNoDirectory permissions (octal)
pathYesDirectory path to create
use_sudoNoUse sudo for the operation

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does: non-recursive SFTP mkdir vs. sudo mkdir -p, Windows New-Item -Force semantics, mode being silently ignored on Windows, exception-on-failure, and the long-running handle/poll protocol including the single-concurrent-operation 'busy' constraint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and organized into scannable bullets, with no filler prose. It is somewhat long, and the bulleted return-value breakdown partially duplicates the existing output schema, 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.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a platform-divergent mutation tool with an output schema, the description covers what an agent needs: platform/sudo matrix, failure mode, and the async handle handoff to ssh_cmd_check_status. Nothing required 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.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, but the description adds real meaning beyond it: `mode` applies to the created directory, is ignored entirely on Windows, and `use_sudo` not only toggles sudo but changes recursion behavior and is a no-op on Windows.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a precise verb and resource ('Create a directory on the remote system'), which is unmistakable against the delete/remove siblings in the tool list. An agent can identify the operation 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.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It spells out the exact conditions under which the call succeeds or fails per platform and sudo flag, which is effectively usage guidance for invoking it correctly. It does not, however, name an alternative tool or state when to prefer another approach (e.g. batch creation via ssh_cmd_run).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_dir_removeA

Remove a directory on the remote system - this is the simple rmdir/Remove-Item equivalent. There is NO dry-run/preview mode here (unlike ssh_dir_delete below) - it acts immediately. If recursive=False (default) and the directory is not empty, this RAISES an exception rather than returning an error dict - it does not partially delete anything.

For a safer recursive delete with a preview step, use ssh_dir_delete instead, which defaults to dry_run=True and returns a graceful {'status': 'error', ...} on failure instead of raising.

Returns: {'status': 'success', 'path', 'recursive', 'message', 'connection'} on success. Raises an exception on failure (non-empty directory with recursive=False, path not found, permission denied, etc.) rather than returning an error dict.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesDirectory path to remove
use_sudoNoUse sudo for the operation
recursiveNoRemove directory and contents recursively

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: immediate action, exception rather than error dict on non-empty dir with recursive=False, no partial deletion, and the in_progress/handle_id polling contract with the single-operation 'busy' constraint. The only gap is that it does not discuss sudo/permission requirements beyond noting permission-denied as a failure cause.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and the sibling comparison, then structured into failure behavior and long-running behavior. The 'Returns:' block partially restates what the output schema already encodes, adding some redundancy, but the exception and handle_id details are not recoverable from structured fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, alternative routing, failure mode, partial-delete semantics, and the async polling contract for a tool that can exceed the server wait cap. 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.

Parameters4/5

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 goes beyond the schema by spelling out the behavioral consequence of recursive=False (raises rather than partially deleting) and confirming the default. use_sudo is left to the schema alone, so it falls short of a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Remove a directory on the remote system') and immediately anchors it to the familiar rmdir/Remove-Item semantics, which lets an agent distinguish it from ssh_dir_delete 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: use this for simple non-preview removal, use ssh_dir_delete for a safer recursive delete with a dry_run preview step. It also warns there is NO dry-run here, so the when-not is stated, not inferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_dir_search_files_contentA

Recursively search file CONTENTS for a pattern under a directory (unlike ssh_dir_search_glob/ssh_file_find_lines_with_pattern, which match filenames or search within a single already-known file respectively).

Regex flavor differs by platform when regex=True: POSIX extended regex (grep -E) on Linux/macOS - avoid PCRE-only syntax like \d, use [0-9] or [[:digit:]] instead; Python's re module on Windows. When regex=False (default), the pattern is matched as a literal fixed string.

On Windows the whole search runs over SFTP (directory listings + raw file reads, matched locally), so non-ASCII file names and content are handled correctly.

Returns: List of {'file': str, 'line': int, 'content': str} - one entry per matching line, across all files under dir_path. Empty list if nothing matches (not an error) - but only when every file could be searched.

If some files or subdirectories could NOT be searched (unreadable, or on
Windows larger than 10 MB), the result is instead
`{'status': 'incomplete', 'matches': [...same entries...], 'skipped': [{'path',
'reason'}, ...], 'skipped_count': int, 'note': str}` - so "no matches" is never
claimed for files that weren't actually searched. A missing or unreadable
`dir_path` itself is an error.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
regexNoTreat pattern as regular expression
patternYesText or pattern to search for
dir_pathYesDirectory to search in
use_sudoNoUse sudo for the operation
case_sensitiveNoPerform case-sensitive search

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the full burden, and it does so richly: platform-dependent regex flavor (POSIX ERE vs Python re), Windows SFTP fallback handling, the 'incomplete' result shape that avoids false 'no matches' claims, and the async handle_id/polling contract with the single-operation 'busy' constraint. This is exactly the behavioral context annotations would otherwise supply.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose before diving into platform behavior and return shapes, and each sentence conveys distinct operational value. It is longer than typical but not padded; the inline sibling comparison in the first sentence is slightly dense.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a search tool with an output schema, the description still covers the non-obvious return variants ('incomplete' with skipped list, 'in_progress' with handle_id) and the error condition for an unreadable dir_path. An agent has everything needed to invoke and interpret it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 beyond the schema: it clarifies that regex=True changes the regex dialect by platform (with PCRE-avoidance guidance) and that regex=False performs literal fixed-string matching. The use_sudo and case_sensitive params get no extra description, keeping it just short of 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Recursively search file CONTENTS for a pattern under a directory') and immediately distinguishes itself from two named siblings (ssh_dir_search_glob for filenames, ssh_file_find_lines_with_pattern for a single known file). 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly contrasts this tool against its closest alternatives and states the selecting condition for each. It also gives when-to-use regex vs literal mode and platform caveats, 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.

ssh_dir_search_globA

Recursively search for files (or directories, with include_dirs=True) matching a filename glob pattern (e.g. *.log) - matches by NAME only, not content; use ssh_dir_search_files_content instead to search inside files. For metadata beyond just path/type (size, mtime, permissions), use ssh_dir_list_advanced instead.

max_depth uses standard find -maxdepth semantics: this is the same on both Linux/macOS and Windows despite the different underlying commands. max_depth=1 means the given path itself plus its immediate children only (not grandchildren); omit max_depth for unlimited recursion.

On a 'linux'/'flex' connection with a limited BusyBox-style find (no -printf - check ssh_conn_connect/ssh_conn_host_info's capabilities), this raises a clear error instead of running. Fallback: ssh_dir_list_files_basic (non-recursive filenames, match the pattern yourself) - SFTP-based and unaffected by this, at the cost of one call per directory level.

Returns: List of {'path': str, 'type': str} - type is a single-character code (f=file, d=directory, l=symlink) from the underlying find/stat output, not a spelled-out word.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesBase directory to search from
patternYesFilename glob pattern (e.g. *.log)
use_sudoNoUse sudo for the operation
max_depthNoMaximum recursion depth (None for unlimited)
include_dirsNoInclude matching directories in results

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does so well: it discloses the cross-platform max_depth behavior, the BusyBox find failure mode (errors instead of running), the return shape with single-character type codes, and the long-running in_progress/handle_id polling protocol including the one-at-a-time busy constraint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded, then alternatives, then semantics, limitations, and returns in clearly ordered blocks. It is on the long side and the long-running paragraph is dense, but nearly every sentence delivers operative detail rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present the description needn't restate return values, yet it adds the non-obvious type-code decoding. Combined with the BusyBox limitation, fallback path, and async polling contract, an agent has everything needed to call and recover from this tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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: it explains find -maxdepth semantics and that max_depth=1 includes the base path plus immediate children only, and it documents when include_dirs applies. use_sudo is left to the schema, keeping it short of a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (recursively search), resource (files/directories), and scope (filename glob, name-only) in the first sentence. It explicitly differentiates itself from two siblings by name, 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names the alternatives and the exact condition that selects them: ssh_dir_search_files_content for content matching, ssh_dir_list_advanced for metadata, and ssh_dir_list_files_basic as a fallback when BusyBox find lacks -printf. When-to-use and when-not-to-use are both covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_dir_transferA

Transfer directories between local and remote systems.

Uses archive-based transfer for efficiency:

  • Upload: Archives locally, transfers, extracts on remote

  • Download: Archives on remote, transfers, extracts locally

Archive format is automatically selected based on remote OS:

  • Linux/macOS: tar.gz

  • Windows: zip

Where the files end up (check files_location in the result):

  • upload: the CONTENTS of local_path are placed directly in remote_path (local /x/proj/a.txt -> remote_path/a.txt)

  • download: the remote folder itself is placed inside local_path (remote /srv/proj/a.txt -> local_path/proj/a.txt)

What it returns (a dictionary): - success: whether the transfer succeeded - operation: 'upload' or 'download' - local_path, remote_path: as given - files_location: the folder where the transferred files now are - archive_format: 'tar.gz' or 'zip' - files_transferred: number of regular files (folders not counted) - directories: number of subfolders (the top folder itself not counted) - payload_bytes: total size of the transferred files - archive_bytes: size of the compressed archive actually sent - bytes_transferred: same as archive_bytes (kept for compatibility)

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
use_sudoNoUse sudo for remote operations
directionYesTransfer direction
local_pathYesLocal directory path
remote_pathYesRemote directory path

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: archive-based mechanism, OS-dependent format selection, exact destination layout semantics (contents vs enclosing folder), the full result contract, long-running handle behavior, and the concurrency/busy error. 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.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads purpose and uses clean bullets. Some content is redundant: an output schema exists, yet the description enumerates every return field, which consumes space without adding value beyond the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, mutation-oriented transfer tool with async execution, the description covers the tricky edge cases an agent needs: destination layout, format selection, long-running handle polling, and busy errors. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 beyond the schema by explaining the asymmetric destination semantics (upload places contents into remote_path, download places the folder inside local_path). The use_sudo implication is left to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb and resource ('Transfer directories between local and remote systems') and the scope ('directories', not files) implicitly separates it from the ssh_file_transfer sibling. An agent can identify the operation and its two modes (upload/download) 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.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives operational guidance for polling (use ssh_cmd_check_status, don't re-invoke meanwhile) and notes a one-at-a-time busy constraint. However, it never explicitly says when to choose this over the closely-related ssh_file_transfer or ssh_dir_copy siblings, so tool-selection guidance is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_file_copyA

Copy a file on the remote host (source and destination are both remote paths - for local<->remote transfers use ssh_file_transfer instead).

If append_timestamp=True, a timestamp is inserted before the destination's file extension in the format %Y%m%dT%H%M%S, e.g. destination_path="/etc/hosts.bak" becomes /etc/hosts.20260704T153045.bak - not appended after the extension, and not configurable to a different format.

Returns: On success: {'success': True, 'copied_to': <actual destination path used, including the timestamp if applied>}. On failure (source not found, permission error): {'success': False, 'error': str} - not a raised exception.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
use_sudoNoUse sudo for the operation
source_pathYesSource file path
append_timestampNoWhether to append a timestamp to the destination
destination_pathYesDestination file path

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does so thoroughly: it declares that failures return a dict rather than raising, that the timestamp is non-configurable and inserted before the extension, the default 50s wait cap, the in_progress/handle_id escape hatch, the polling tool to use, and the single-concurrent-operation 'busy' constraint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads purpose and the sibling exclusion first, then appends behavioral detail in clearly labeled Returns / Long-running blocks. It is longer than average but nearly every sentence conveys a constraint an agent needs; only minor tightening of the timestamp prose would help.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations, the description supplies the missing safety and control context: failure-not-exception semantics, non-reversibility-adjacent details of timestamping, concurrency limits, and the async handoff. Even though an output schema exists, the added return-shape detail is accurate and complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 goes well beyond the schema on append_timestamp by spelling out the exact format (%Y%m%dT%H%M%S), the insertion point (before the extension), and a concrete example, while flagging what it is not (not appended after, not configurable). use_sudo and the path params get no additional treatment, keeping it just short of a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (copy) and resource (file on remote host) and immediately scopes it: 'source and destination are both remote paths'. It names the sibling it is not (ssh_file_transfer) and the condition that selects that sibling (local<->remote), 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit when-to-use-this vs when-to-use-the-alternative rule ('for local<->remote transfers use ssh_file_transfer instead'), plus the operational condition for the long-running path ('if this takes longer than the server's wait cap...'). 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.

ssh_file_delete_line_by_contentA

Delete a line by its exact content. match_line must match EXACTLY ONE line in the file (whitespace-trimmed, literal text - not a pattern); if it matches zero lines or more than one, the operation fails with a descriptive error rather than guessing which line(s) to delete. Use ssh_file_find_lines_with_pattern first if you're not sure the line is unique. (Equivalent to ssh_file_replace_line_multi(new_lines=[]), provided as a clearer-named shortcut.)

Returns: On success: {'success': True} (no count field - only ever deletes the one matched line). On failure (match not found, match not unique, file not found/unreadable): {'success': False, 'error': str} - not a raised exception.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
forceNoNo longer needed (kept for compatibility): with use_sudo=true the file is read with sudo when the user can't read it. If it can't be read at all, the edit fails - it never reports success without having seen the file.
use_sudoNoUse sudo for the operation
file_pathYesPath to the file to modify
match_lineYesExact line content to match and delete

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: uniqueness constraint, zero/multi-match failure behavior, error returned as a value rather than a raised exception, sudo read semantics, the 50s wait cap with {'status': 'in_progress', 'handle_id'} fallback, the single-concurrent-operation 'busy' error, and the polling tool. This is far beyond what the schema conveys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action and the uniqueness rule, then uses labeled sections for Returns and Long-running calls. It is longer than typical, but the structure is clear and each block (error contract, wait-cap behavior) 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.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with sudo options and long-running support, the description covers failure modes, return shape, concurrency limits, and async polling. Despite an output schema existing, the extra detail on the non-obvious in_progress/busy behavior leaves nothing an agent needs missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 semantics: match_line is 'whitespace-trimmed, literal text - not a pattern' and must match exactly one line. It also explains the deprecated force/use_sudo read behavior. Meaningful value over the schema's one-line parameter descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Delete a line by its exact content') and pins down the matching semantics precisely. It distinguishes itself from ssh_file_replace_line by naming the equivalence and from ssh_file_find_lines_with_pattern by pointing to it as a prerequisite. An agent can select 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to run ssh_file_find_lines_with_pattern first if uniqueness is uncertain, and explains what happens when the match is not unique. It also clarifies this is a shortcut for ssh_file_replace_line_multi(new_lines=[]), giving a clear alternative and the condition that selects each.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_file_find_lines_with_patternA

Search for a pattern in a remote file and return matching lines with their line numbers. Use this to find WHERE a pattern occurs before using ssh_file_get_context_around_line to see surrounding lines, or ssh_file_replace_line/ssh_file_delete_line_by_content to edit (those require an exact, unique line match - this tool helps you find that exact line first).

Regex flavor differs by platform when regex=True: POSIX extended regex (grep -E) on Linux/macOS - avoid PCRE-only syntax like \d, use [0-9] or [[:digit:]] instead; Python's re module on Windows (matched locally after an SFTP read, not via PowerShell - see below). When regex=False (default), the pattern is matched as a literal fixed string on every platform.

On Windows, this reads the whole file via SFTP and matches locally in Python, rather than shelling out to PowerShell/Select-String - matched line content could otherwise come back corrupted for non-ASCII text, since Windows' console encodes stdout in its OEM code page rather than UTF-8 (the same problem ssh_file_read's SFTP approach avoids).

Returns: {'total_matches': int, 'matches': [{'line_number': int, 'content': str}, ...]}. No matches is not an error - total_matches is 0 and matches is []. On failure (e.g. file not found, permission denied), an 'error' key is present instead.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
regexNoWhether to treat pattern as a regular expression
patternYesText or regex pattern to search for
use_sudoNoUse sudo for the operation
file_pathYesPath to the file to search

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does so richly: per-platform regex flavor (POSIX ERE on Linux/macOS vs Python re on Windows), the local-SFTP-read rationale on Windows, error-key semantics, and the long-running in_progress/handle_id polling contract via ssh_cmd_check_status with a 'busy' single-op constraint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and sibling routing, then regex/Windows rationale, then returns, then long-running behavior. It is long, but nearly every sentence carries non-obvious operational value rather than restating structured fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a search tool with an output schema already present, everything an agent needs is covered: return shape, no-match-is-not-an-error semantics, error key, and the async polling path. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 goes further by explaining regex semantics that the schema only gestures at: the exact regex dialect per platform and the PCRE-pitfall example (\d vs [0-9]/[[:digit:]]), plus that regex=False means a literal fixed-string match. use_sudo is left to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (search), resource (a remote file), and scope (return matching lines with line numbers). It is immediately distinguishable from siblings like ssh_file_read (whole file) and ssh_dir_search_files_content (directory-wide).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: use this to find WHERE a pattern occurs, then ssh_file_get_context_around_line for surrounding lines, or ssh_file_replace_line/ssh_file_delete_line_by_content for editing. It even names the prerequisite those edit tools have (exact, unique line match) that this tool helps satisfy.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_file_get_context_around_lineA

Get lines before and after a line, to see it in context before editing. Like the line-editing tools (ssh_file_replace_line and siblings), match_line must match exactly one line in the file (whitespace-trimmed, literal text, not a pattern) - use ssh_file_find_lines_with_pattern first if you're not sure the line is unique.

Reads the file via SFTP and matches locally (same as ssh_file_find_lines_with_pattern) - Unicode/non-ASCII content is safe on all platforms, including Windows.

Returns: On a unique match: {'match_found': True, 'match_line_number': int, 'context_block': [{'line_number': int, 'content': str}, ...]} (the matched line plus context lines before/after). If the line isn't found, or matches more than once: {'match_found': False, 'error': str} - for a multi-match error, also includes 'matches' (every matching line, so you can pick a more specific match_line).

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
contextNoNumber of lines before and after to include
use_sudoNoUse sudo for the operation
file_pathYesPath to the file
match_lineYesExact line content to match

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses the SFTP read + local matching model, Unicode/non-ASCII safety on all platforms, and the long-running async contract (50s wait cap, in_progress handle_id, poll via ssh_cmd_check_status, single-operation concurrency with a 'busy' failure). 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.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded purpose followed by clearly separated guidance and a Returns block; every section earns its place. It is somewhat long, and the return-shape detail is redundant given the output schema, which keeps it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 4-param tool with no annotations, the description covers purpose, uniqueness precondition, alternative tool, platform safety, and the async polling contract. Although an output schema exists (so return values needn't be restated), the added detail does no harm and 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.

Parameters4/5

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 semantics beyond the schema: match_line is 'whitespace-trimmed, literal text, not a pattern', which is not obvious from the schema's 'Exact line content to match'. context and use_sudo are left to the schema, so it stops short of a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Get lines before and after a line ... to see it in context before editing') and explicitly positions itself against the line-editing tools it complements. An agent can distinguish it from ssh_file_replace_line and 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use ('before editing') and a concrete prerequisite path: use ssh_file_find_lines_with_pattern first if the line's uniqueness is uncertain. It also states the hard precondition that match_line must match exactly one line, which routes the agent correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_file_insert_lines_after_matchA

Insert one or more new lines immediately after a matching line. match_line must match EXACTLY ONE line in the file (whitespace-trimmed, literal text - not a pattern); if it matches zero lines or more than one, the operation fails with a descriptive error rather than guessing. Use ssh_file_find_lines_with_pattern first if you're not sure the line is unique.

PARAMETERS:

  • file_path: Path to the file to modify

  • match_line: Exact line content to match (whitespace-trimmed)

  • lines_to_insert: List of lines to insert after the match

    • To insert multiple lines: use ["first line", "second line", ...]

    • To insert a single line: use ["line to insert"]

    • To insert an empty line: use [""]

  • use_sudo: Use sudo for the operation (default: false)

  • force: No longer needed (kept for compatibility) - use_sudo reads root-only files with sudo (default: false)

RETURNS: On success: {'success': True, 'lines_inserted': <len(lines_to_insert)>} (note: the key is lines_inserted here, vs. lines_written on ssh_file_replace_line/ssh_file_replace_line_multi). On failure (match not found, match not unique, file not found/unreadable): {'success': False, 'error': str}

  • not a raised exception. Does NOT return file_path in the response.

EXAMPLES: Example 1: Insert configuration lines after a marker

{
  "file_path": "/etc/nginx/nginx.conf",
  "match_line": "http {",
  "lines_to_insert": ["    server_tokens off;", "    client_max_body_size 20M;"]
}

Example 2: Add a new host entry after localhost

{
  "file_path": "/etc/hosts",
  "match_line": "127.0.0.1 localhost",
  "lines_to_insert": ["192.168.1.10 myserver.local"]
}
Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
forceNoNo longer needed (kept for compatibility): with use_sudo=true the file is read with sudo when the user can't read it. If it can't be read at all, the edit fails - it never reports success without having seen the file.
use_sudoNoUse sudo for the operation
file_pathYesPath to the file to modify
match_lineYesExact line content to match
lines_to_insertYesLine(s) to insert after the match

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and delivers: exact literal (non-pattern) matching, whitespace-trimmed comparison, hard failure on zero or multiple matches rather than guessing, failure returned as a value not a raised exception, deprecated force param, sudo read behavior, and long-running/polling/busy semantics. 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.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core behavior and match constraint, then failure modes, then the async polling caveat. Every section is useful, though the long-running paragraph is somewhat verbose and the RETURNS block partly duplicates the output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers the mutation, its preconditions, its failure contract, and the async completion path, so an agent has everything needed to invoke and interpret the tool. The explicit return-key naming (lines_inserted vs lines_written on siblings) further reduces cross-tool confusion.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, and the description adds genuine meaning: match_line must match exactly one line literally, lines_to_insert format conventions (single, multiple, empty-string), and that force is deprecated. It clarifies rather than merely restates the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Insert one or more new lines immediately after a matching line') with clear scoping. The exact-match semantics and the reference to ssh_file_find_lines_with_pattern distinguish it from replace/delete siblings. An agent can tell what it does without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a concrete prerequisite ('Use ssh_file_find_lines_with_pattern first if you're not sure the line is unique') and implicitly contrasts with replace-by-pattern tools. However, it does not state when to prefer this over, say, ssh_file_write or ssh_file_replace_line for the same edit, so the guidance is strong but not exhaustive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_file_moveA

Move or rename a file or directory (works for both - whichever source is).

If destination already exists: fails cleanly with overwrite=False (default); with overwrite=True, it's replaced (mv -f/Move-Item -Force). If source doesn't exist, also fails cleanly rather than raising.

Returns: {'success': True, 'message': str} on success, or {'success': False, 'message': str} on failure (source not found, destination exists and overwrite=False, permission error) - not a raised exception.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
sourceYesSource file or directory path
use_sudoNoUse sudo for the operation
overwriteNoOverwrite destination if it exists
destinationYesDestination path

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the full burden and does so richly: it discloses error semantics (fails cleanly rather than raising), the exact return shape on success/failure, the async handoff (status in_progress with handle_id), the 50s wait cap, and the single-operation concurrency 'busy' constraint. This is far beyond what any structured field provides.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and overwrite behavior, then return values, then the async caveat. Every block earns its place, though the description is on the longer side for a move tool and the 'Returns:' block partially overlaps the output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations, the description covers the safety-relevant behaviors (overwrite risk, clean failure, permission errors), the async lifecycle, and the concurrency limit. An agent has everything needed to invoke and follow up correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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: it explains that `overwrite` defaults to False and that True maps to `mv -f`/`Move-Item -Force`, and clarifies the move-vs-rename semantics tied to `source`/`destination`. `use_sudo` is left to the schema, keeping it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States specific verbs (move/rename) and resource (file or directory), and clarifies it handles both by inspecting `source`. An agent can immediately distinguish it from ssh_file_copy and ssh_dir_copy 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.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear conditions for the overwrite semantics and source-not-found behavior, and routes the agent to ssh_cmd_check_status for long-running cases while warning 'do not call it again meanwhile'. It doesn't explicitly contrast with ssh_file_copy for the copy-vs-move decision, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_file_readA

Read file contents directly via SFTP.

This tool reads raw bytes from the remote file using SFTP and decodes them on the client side. Unlike command-based file reading (cat, Get-Content), SFTP completely bypasses shell and console encoding issues.

Why use this instead of ssh_cmd_run with cat/Get-Content?

  • Works correctly with Unicode on ALL platforms including Windows

  • Bypasses Windows PowerShell's OEM code page encoding problem

  • More efficient for binary-safe file transfer

  • No shell escaping issues with special characters in content

Returns: Dictionary with: - success: True if file was read successfully - content: The file contents as a string - size: Number of bytes read - encoding: The encoding used to decode the content

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
encodingNoCharacter encoding (default: utf-8)utf-8
max_sizeNoMaximum file size in bytes (default: 10MB, 0 for no limit)
file_pathYesPath to the file to read

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description carries full behavioral burden and meets it: it discloses the return shape, client-side decoding, the server wait cap (~50s), the in_progress/handle_id fallback, the required polling via ssh_cmd_check_status, and the single-concurrency 'busy' failure mode. This is unusually rich operational disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well front-loaded: purpose, then differentiation, then returns, then long-running behavior. Slightly padded by the bullet list where several points (Unicode, OEM code page, binary-safe, shell escaping) overlap, but nothing is wasted enough to harm selection.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists, the description need not restate return values, yet it does so briefly and adds the async/polling contract that the schema cannot express. For a read tool with 3 params, all decidable information is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so encoding, max_size, and file_path are already documented in the schema. The description adds only marginal meaning (client-side decode semantics for encoding), which the schema already covers via defaults. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Read file contents directly via SFTP') and immediately frames the mechanism (SFTP byte-level read with client-side decoding). It distinguishes itself from sibling ssh_cmd_run by naming that alternative explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit when-to-use section ('Why use this instead of ssh_cmd_run with cat/Get-Content?') with concrete selection criteria: Unicode correctness across platforms, Windows code page issues, binary safety, shell escaping. The agent can route correctly without inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_file_replace_lineA

Replace a line in a file with a new line. match_line must match EXACTLY ONE line in the file (whitespace-trimmed, literal text - not a pattern); if it matches zero lines or more than one, the operation fails with a descriptive error rather than guessing which line you meant. Use ssh_file_find_lines_with_pattern first if you're not sure the line is unique.

PARAMETERS:

  • file_path: Path to the file to modify

  • match_line: Exact line content to match and replace (whitespace-trimmed)

  • new_line: New line to insert in place of the match

  • use_sudo: Use sudo for the operation (default: false)

  • force: No longer needed (kept for compatibility) - use_sudo reads root-only files with sudo (default: false)

RETURNS: On success: {'success': True, 'lines_written': 1} (or, in the rare edge case where new_line is identical to the matched line, {'success': True, 'message': 'No changes needed...'} instead - nothing to write). On failure (match not found, match not unique, file not found/unreadable): {'success': False, 'error': str} - not a raised exception. Note: unlike some other file tools, this does NOT return file_path in the response.

EXAMPLES: Example 1: Replace a commented line with an active configuration

{
  "file_path": "/etc/ssh/sshd_config",
  "match_line": "#ClientAliveInterval 0",
  "new_line": "ClientAliveInterval 300"
}

Note: To delete a line entirely, use the dedicated ssh_file_delete_line_by_content tool instead. To replace/insert MULTIPLE lines in one call, use ssh_file_replace_line_multi instead.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
forceNoNo longer needed (kept for compatibility): with use_sudo=true the file is read with sudo when the user can't read it. If it can't be read at all, the edit fails - it never reports success without having seen the file.
new_lineYesNew line to insert in place of the match
use_sudoNoUse sudo for the operation
file_pathYesPath to the file to modify
match_lineYesExact line content to match and replace

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: exact/literal matching semantics, whitespace trimming, failure mode returns a {'success': False, 'error': ...} dict rather than raising, sudo read behavior, the deprecation of force, and the long-running/in_progress handle + polling + single-concurrency 'busy' contract.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core contract and well-sectioned (params, returns, examples), but the force explanation is stated twice (parameter list and schema-adjacent text) and the long-running paragraph is dense. Minor redundancy keeps it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations, the definition covers match semantics, failure behavior, sudo/auth implications, an example, sibling routing, and the async in_progress flow. 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.

Parameters4/5

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 real meaning beyond it: match_line is whitespace-trimmed literal text (not a regex), and force is a compatibility no-op whose semantics have moved to use_sudo. That extra nuance justifies a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource (replace one line in a file) and immediately distinguishes itself from the multi-line and delete-line siblings by name. 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit preconditions (match_line must match exactly one line; use ssh_file_find_lines_with_pattern first if uniqueness is uncertain) and names the alternatives for other cases (ssh_file_delete_line_by_content, ssh_file_replace_line_multi). 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.

ssh_file_replace_line_multiA

Replace a line in a file with one or more new lines (or delete it, with an empty list). Use this instead of ssh_file_replace_line when you need to insert more than one line, or delete a line without using the separate ssh_file_delete_line_by_content tool.

match_line must match EXACTLY ONE line in the file (whitespace-trimmed, literal text - not a pattern); if it matches zero lines or more than one, the operation fails with a descriptive error rather than guessing. Use ssh_file_find_lines_with_pattern first if you're not sure the line is unique.

PARAMETERS:

  • file_path: Path to the file to modify

  • match_line: Exact line content to match and replace (whitespace-trimmed)

  • new_lines: List of new lines to insert in place of the match

    • To replace with multiple lines: use ["first line", "second line", ...]

    • To delete the line entirely: use [] (empty list)

    • To replace with an empty line: use [""]

  • use_sudo: Use sudo for the operation (default: false)

  • force: No longer needed (kept for compatibility) - use_sudo reads root-only files with sudo (default: false)

RETURNS: On success: {'success': True, 'lines_written': <len(new_lines)>} (or, in the rare edge case where the result is byte-identical to the original file, {'success': True, 'message': 'No changes needed...'} instead). On failure (match not found, match not unique, file not found/unreadable): {'success': False, 'error': str} - not a raised exception. Note: does NOT return file_path in the response.

EXAMPLES: Example 1: Replace a line with multiple lines

{
  "file_path": "/etc/hosts",
  "match_line": "127.0.0.1 localhost",
  "new_lines": ["127.0.0.1 localhost", "127.0.0.1 myhost.local"]
}

Example 2: Delete a line entirely

{
  "file_path": "/etc/nginx/nginx.conf",
  "match_line": "# server_tokens off;",
  "new_lines": []
}

Example 3: Replace with an empty line

{
  "file_path": "/etc/ssh/sshd_config",
  "match_line": "PermitRootLogin yes",
  "new_lines": [""]
}
Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
forceNoNo longer needed (kept for compatibility): with use_sudo=true the file is read with sudo when the user can't read it. If it can't be read at all, the edit fails - it never reports success without having seen the file.
use_sudoNoUse sudo for the operation
file_pathYesPath to the file to modify
new_linesYesList of new lines to insert in place of the match
match_lineYesExact line content to match and replace

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the full burden and does: it discloses the uniqueness-match failure mode, that failures return {'success': False, 'error'} rather than raising, the exact success return shape, and the long-running/in_progress handle polling and single-operation 'busy' constraint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads purpose, then constraints, returns, and examples in a scannable order; every section earns its place. Minor redundancy between the description's force/use_sudo note and the schema's own parameter descriptions, which is the only thing keeping it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations, everything an agent needs is present: matching semantics, failure behavior, return shape, sudo/force implications, async fallback, and worked examples. Nothing required for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Goes well beyond the schema by pinning down semantics: match_line is whitespace-trimmed literal text, not a pattern, and must match exactly one line; new_lines encodes delete ([]) vs blank line ([""]); force is deprecated. These distinctions are not derivable from the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Replace a line in a file with one or more new lines') and explicitly differentiates itself from ssh_file_replace_line and ssh_file_delete_line_by_content. An agent can distinguish it from the sibling line-editing 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use this over ssh_file_replace_line ('when you need to insert more than one line, or delete a line'), and routes to ssh_file_find_lines_with_pattern when uniqueness is unverified. Both the alternative and the selecting condition are named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_file_statA

Get status information about a file or directory (via SFTP stat - works the same way on all platforms, no shell command involved).

On Windows, mode/uid/gid come from the SFTP subsystem's own cross-platform attribute reporting, not real Windows ACLs/ownership - Windows has no equivalent concept, so these values (e.g. uid/gid of 0) are not meaningful there and should not be relied on to reason about actual Windows permissions/ownership. type/size/atime/mtime are unaffected and accurate on all platforms.

Returns: {'exists': True, 'path', 'type' ('file'/'directory'/'symlink'/'unknown'), 'mode' (octal string, e.g. "0o40755"), 'uid', 'gid', 'size' (bytes), 'atime', 'mtime'} when the path exists. atime/mtime are raw numeric Unix timestamps (seconds since epoch, as returned by SFTP), not formatted date strings - convert with datetime.fromtimestamp() if you need a readable date. If the path does NOT exist (or stat failed for another reason, e.g. permission denied), returns {'exists': False, 'path', 'error'} instead - this is a normal, non-exceptional return value, not a raised error. If the check itself fails (permission denied, no SFTP on this host, ...), exists is None (unknown), not False, with the reason in error.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesFile or directory path to get information about

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: it discloses cross-platform caveats (Windows mode/uid/gid are not real ACLs and shouldn't be reasoned about), the exists=True/False/None semantics with error strings, the fact that a missing path is a normal non-exceptional return, and the long-running wait cap with the busy constraint and polling target.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Length is substantial but largely earned by the platform caveats, error tri-state, and long-running protocol, and it is front-loaded with the core purpose. The Windows attribute paragraph is arguably over-detailed relative to its decision value, keeping it just short of a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Even though an output schema exists and would relieve the description of explaining return values, the description goes further by covering the non-obvious error tri-state, timestamp format, platform caveats, and the async handle flow. 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.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single path parameter, so the schema already documents it. The description adds no syntax, format, or path-resolution detail beyond 'file or directory path', so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Get status information about a file or directory') and pins down the mechanism ('via SFTP stat'), which differentiates it from shell-based siblings like ssh_cmd_run. An agent knows exactly what it retrieves 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.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies its purpose but never states when to prefer this over adjacent siblings (e.g. ssh_dir_list_advanced, ssh_file_read, ssh_dir_calc_size). It does give one actionable routing instruction - poll ssh_cmd_check_status on in_progress and don't re-call - but no when/when-not guidance for the core stat operation itself.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_file_transferA

Transfer a single FILE between the local machine (running this MCP server) and the remote host, via SFTP. Both local_path and remote_path must be file paths, not directories - for whole-directory transfers, use ssh_dir_transfer instead. For remote-to-remote copies (no local machine involved), use ssh_file_copy instead.

Caveat: use_sudo=True on download/upload stages a copy through /tmp/ using Unix shell commands (mv/chmod/rm) - this only works against Linux/macOS remote hosts. Windows has no per-command sudo concept anyway (see ssh_conn_verify_sudo), so use_sudo=True against a Windows connection raises immediately instead of attempting these Unix commands - connect as Administrator instead.

Returns: {'operation' (human-readable description of what happened), 'success': True, 'local_path', 'remote_path', 'sudo', 'connection'}. Raises an exception on failure rather than returning a success: False dict.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
use_sudoNoUse sudo for transfer
directionYesTransfer direction
local_pathYesLocal file path
remote_pathYesRemote file path

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does so well: it discloses the sudo /tmp staging mechanism and its OS restriction, that Windows raises rather than attempting Unix commands, that failures raise exceptions instead of returning success:False, the exact success response shape, and the async long-running protocol (50s cap, handle_id, poll via ssh_cmd_check_status, don't re-invoke, single-concurrency 'busy' error).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and the routing rules before the caveats, and uses a Returns block plus a long-running paragraph to organize secondary detail. Every sentence earns its place, though the sudo caveat and async paragraph make it longer than typical for a 4-param tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing, the description adds return-shape and exception semantics plus the async polling contract, which the output schema alone would not convey. Nothing needed 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.

Parameters4/5

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: local_path/remote_path must be file paths and not directories, and use_sudo=True is explained behaviorally (staged through /tmp with mv/chmod/rm, Windows raises). It doesn't restate the direction enum, but the constraints it adds are substantive.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource+transport: transfer a single FILE via SFTP between the local machine and remote host. It explicitly differentiates itself from two named siblings (ssh_dir_transfer for directories, ssh_file_copy for remote-to-remote), 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use rules with named alternatives and their selecting conditions: directories -> ssh_dir_transfer, remote-to-remote -> ssh_file_copy. The sudo caveat further scopes usage (Linux/macOS only; Windows raises immediately).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_file_writeA

Create a new file, or overwrite/append to an existing one, with the given content (works the same whether or not the file already exists - append=True on a nonexistent file just creates it). Handles special characters and multi-line content properly.

mode (Unix permission bits) is applied via a chmod command after writing - this only works on Linux/macOS. On Windows there's no equivalent, so mode is silently ignored there (same convention as ssh_dir_mkdir's mode parameter).

Returns: On success: {'success': True, 'file_path', 'bytes_written' (int), 'mode' (octal string, or None if not set OR if the connection is Windows - the response never echoes back a mode value that wasn't actually applied), 'append' (bool, echoes the parameter), 'connection'}. On failure (e.g. parent directory missing and create_dirs=False, write error): {'success': False, 'file_path', 'error'} - not a raised exception.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
modeNoFile permissions to set after writing (octal, e.g. 0o644)
appendNoWhether to append to the file instead of overwriting
contentYesContent to write to the file
use_sudoNoUse sudo for the operation
file_pathYesPath to the file to write to
create_dirsNoCreate parent directories if they don't exist

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and delivers: mode is applied via chmod and silently ignored on Windows, failures return an object rather than raising, and long-running calls return an in_progress handle requiring polling. It even warns about the one-operation-at-a-time busy constraint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action, then layers platform caveats, return shape, and async behavior in a logical order. The Returns block is long but each line carries real signal; minor overhead remains.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter mutation tool with no annotations, the description covers the mutation semantics, platform caveats, failure mode, and async handling. Complete enough that an agent can call and interpret it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 meaning beyond the schema: append=True on a nonexistent file just creates it, and mode only takes effect on Linux/macOS. use_sudo is left to its schema description, which is adequate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('create a new file, or overwrite/append to an existing one') with clear scope, distinguishing it from read/replace-line siblings. The append-vs-overwrite semantics are spelled out so an agent knows exactly what calling it does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives useful operational guidance for the async case (poll ssh_cmd_check_status, don't re-call, busy error). But it never says when to choose this tool over siblings like ssh_file_transfer, ssh_file_replace_line, or ssh_file_copy. Usage is implied through behavior rather than an explicit selection rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_host_disconnectA

Disconnect the current SSH connection if one exists.

Use this when you want to explicitly close the current SSH connection before connecting to a different host or when you're done with SSH operations.

Returns: Dictionary with disconnection status

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description carries the full burden and does so well: it discloses the long-running/wait-cap behavior, the in_progress + handle_id return shape, the polling tool ssh_cmd_check_status, the 'do not call again' rule, and the single-concurrency 'busy' failure mode. The only gap is the no-connection/no-op or error behavior, which 'if one exists' hints at but never states.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose, then usage, then return, then the async caveat in clearly labeled blocks. Every block earns its place, though the long-running boilerplate is somewhat template-heavy for a zero-argument disconnect call.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so the return values need not be spelled out, yet the description still notes the disconnection-status dictionary plus the async envelope. Usage, concurrency, and recovery path are all covered; only the no-op/error case when no connection exists is left implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters (empty object schema, additionalProperties false), so there is nothing for the description to clarify. Baseline of 4 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb (Disconnect) plus resource (the current SSH connection) with the scope qualifier 'if one exists'. It is trivially distinguishable from sibling connectors such as ssh_conn_connect, ssh_conn_is_connected, and ssh_conn_status 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.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use conditions: before connecting to a different host, or when finished with SSH operations. It does not name a when-not case or an alternative tool (e.g. that simply letting the session lapse is an option), so it falls short of a full 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_host_listA

List all configured SSH hosts with their aliases and descriptions. This is the ONLY correct way to see what hosts are configured - never read the host configuration TOML file directly (ssh_conn_add_host's docstring names its path). That file stores every host's password, sudo password, and key passphrase in plaintext; this tool deliberately omits all of that and returns only the fields below. If you need to add, change, or remove a host, use ssh_conn_add_host, ssh_host_update, or ssh_host_remove instead of editing the file - between those and ssh_host_use_config, there is no legitimate reason to open it.

Lists hosts from whichever config file is currently active - the server's default unless ssh_host_use_config was called to switch to an alternate file. The returned config_path always shows which one that is.

Returns: Dictionary with: - hosts: List of host information dictionaries, each containing: - key: The 'user@host' key - alias: Optional short name for the host - description: Optional description of the host - config_path: The host configuration file this list came from

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses that secrets (passwords, sudo passwords, passphrases) are deliberately omitted, that output depends on which config file is active, and that config_path reflects that state. This is exactly the safety/state context annotations would otherwise supply.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and return fields, and the security rationale is well placed. It is slightly repetitive, restating the 'don't open the file' admonition three times, and the return-value block duplicates the output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter list tool with no annotations, the description covers purpose, safety posture, state dependency, and return contents; an agent has everything needed to call it correctly without opening the config file.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero input parameters, so the baseline is 4; the description correctly does not invent parameter semantics and instead documents the returned shape.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource ('List all configured SSH hosts') and enumerates the returned fields (key, alias, description). It is immediately distinguishable from sibling mutation tools like ssh_host_update and ssh_host_remove.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names the alternative paths: use ssh_conn_add_host/ssh_host_update/ssh_host_remove to modify hosts, and never read the TOML file. It also explains the config-file switching behavior tied to ssh_host_use_config, giving full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_host_removeA

Remove a host configuration from the host configuration TOML file (see ssh_conn_add_host's docstring for its exact path and why you should never read it directly - use ssh_host_list to see what's configured instead).

To change a host's password/port/etc. rather than deleting it, use ssh_host_update instead - removing and re-adding loses every field you don't explicitly resupply.

Returns: Dictionary with operation status

ParametersJSON Schema
NameRequiredDescriptionDefault
host_nameYesThe 'user@hostname' identifier of the host to remove

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the destructive consequence (removing and re-adding loses every unsupplied field) and the storage location behavior, but omits permission/auth requirements and whether removal is reversible. Strong disclosure but not complete.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action and the alternative-tool routing. The parenthetical about never reading the file directly and the Returns block add some length, but each sentence largely earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the brief 'Returns: Dictionary with operation status' is sufficient. For a single-param mutation tool the critical caution (data loss on re-add) is covered, though auth/permission context is absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single host_name param, whose 'user@hostname' format is already documented in the schema. The description adds no format or semantic detail beyond what the schema provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Remove a host configuration from the host configuration TOML file') and names the sibling it is not (ssh_host_update for modification). An agent can distinguish it from the update/add/list siblings 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: use ssh_host_update to modify fields, use ssh_host_list to inspect configuration, and remove only for deletion. The when-to-use-vs-alternative conditions are stated directly, not inferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_host_updateA

Update one or more fields of an existing host configuration - this is the safe way to rotate a password, change a port, or adjust other settings without ever needing to read or hand-edit the host configuration TOML file (which stores every host's credentials in plaintext - never read it directly; this tool, ssh_conn_add_host, ssh_host_remove, and ssh_host_list cover everything you should need).

Only the fields you pass are changed - any parameter left at its default (omitted/None) keeps its current value. To clear a field entirely (e.g. drop a password when switching a host to key-only auth), pass an empty string "" rather than omitting it. user/host themselves can't be changed this way (that changes the 'user@host' key identity) - remove and re-add instead if you need that.

Prefer this over ssh_host_remove + ssh_conn_add_host for adjusting an existing host: remove+re-add loses every field you don't explicitly resupply, since ssh_conn_add_host has no knowledge of the entry it just deleted.

host_name may be either the 'user@hostname' key or a configured alias - resolved the same way as ssh_conn_connect.

Warn the user that any new password/passphrase value passed here will be visible to the LLM, the same caveat as ssh_conn_add_host.

Returns: On success: {'status': 'success', 'message', 'key', 'updated_fields' (list of field names that were actually changed)}. On failure (the update would leave neither a password nor a keyfile set, or a duplicate alias): {'status': 'error', 'error': <message>} - not a raised exception.

Raises: SshError: If host_name doesn't resolve to any configured host (tried as both key and alias).

ParametersJSON Schema
NameRequiredDescriptionDefault
portNoNew SSH port. Omit to leave unchanged
aliasNoNew alias. Omit to leave unchanged; pass an empty string to clear it
keyfileNoNew SSH private key path. Omit to leave unchanged; pass an empty string to clear it (e.g. when switching to password-only auth)
passwordNoNew password. Omit to leave unchanged; pass an empty string to clear it (e.g. when switching to key-only auth)
host_nameYesThe 'user@hostname' key or alias of the host to update
descriptionNoNew description. Omit to leave unchanged; pass an empty string to clear it
sudo_passwordNoNew sudo password. Omit to leave unchanged; pass an empty string to clear it
key_passphraseNoNew passphrase for the SSH key. Omit to leave unchanged; pass an empty string to clear it

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: omitted fields retain current value, empty string clears, the update fails if it would leave neither password nor keyfile, duplicate aliases error, and failure returns a status dict rather than raising (with SshError reserved for unresolvable host_name). It also flags the plaintext-TOML sensitivity and the LLM-visibility caveat for secrets.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and the safe-alternative framing, then edge cases and return shape. It is longer than strictly necessary (the plaintext warning overlaps the schema's secret flags, and the omit/empty-string rule is restated across fields), but every paragraph addresses a real decision an agent must make.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An 8-parameter mutation tool with no annotations and an output schema, and the description covers all the load-bearing gaps: mutation semantics, clearing behavior, identity constraints, failure modes, and secret-handling warnings. 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.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so the baseline is 3, and the schema already repeats the omit/empty-string convention per parameter. The description nonetheless adds meaning the schema lacks: host_name resolves as either key or alias (same as ssh_conn_connect), and user/host are deliberately non-updatable. That is genuine value beyond structured fields, though much of the per-field guidance is duplicated.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (update) plus resource (existing host configuration fields) and immediately scopes it against siblings: it names ssh_conn_add_host, ssh_host_remove, and ssh_host_list as the full set covering host config. An agent can distinguish this from ssh_conn_add_host 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to prefer this over ssh_host_remove + ssh_conn_add_host and why (re-add loses unlisted fields). Also states the negative case: user/host cannot be changed here, remove and re-add instead. Both routing conditions are spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_host_use_configA

Switch which host configuration file ssh_host_list, ssh_conn_connect, ssh_conn_add_host, ssh_host_update, and ssh_host_remove all operate against, for the rest of this session (or until you call this again) - not just for one call. This is the same "one active thing at a time" model ssh_conn_connect uses for SSH connections, applied to host configuration files instead; the two are completely independent (switching config files doesn't affect any current SSH connection, and vice versa).

Use this when you want to browse or use hosts from a different TOML file than the server's default - e.g. a separate list of hosts for a different environment/project. The alternate file must already exist and be a valid host configuration TOML file (see ssh_conn_add_host's docstring for the format) - this deliberately does NOT auto-create a missing file the way the server's own default config file is created on first run, since an LLM-supplied path with a typo should fail loudly rather than silently create a stray file somewhere.

Omit config_path (or pass "") to switch back to the server's original default configuration file.

ssh_host_list's response always includes config_path showing whichever file is currently active, so you can check before mutating anything with ssh_conn_add_host/ssh_host_update/ssh_host_remove.

Returns: On success: {'status': 'success', 'message', 'config_path', 'is_default' (bool), 'host_count'}. On failure (path doesn't exist, path is a directory, or the file fails to parse as valid host config TOML): {'status': 'error', 'error': <message>} - not a raised exception.

ParametersJSON Schema
NameRequiredDescriptionDefault
config_pathNoPath to an alternate host configuration TOML file to switch to. Omit or pass an empty string to revert to the server's default configuration file

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden and does so: session-persistent scope, independence from SSH connections, no auto-creation with rationale, boolean is_default and host_count on success, and error responses returned as dicts rather than raised exceptions. Nothing material for correct invocation is left undisclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and scope, then organized into usage guidance and return shape. A few sentences could be tightened, such as the typo rationale, but there is no significant repetition or filler for a session-state tool with no annotations.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter session-state tool with no annotations and an output schema, the definition covers session persistence, revert behavior, prerequisites, failure modes, sibling interactions, and return format. An agent has everything needed to call it correctly and to check active state via ssh_host_list.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already documents omit/empty string to revert. The description adds beyond schema by stating the alternate file must exist and be valid TOML, and that a missing file is deliberately not auto-created, which directly constrains how config_path may be used.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb and resource: switching which host configuration file a named set of host tools operate against, plus session scope. The sibling tools affected are named directly, so an agent can distinguish this from connection-level siblings like ssh_conn_connect 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use it ('browse or use hosts from a different TOML file ... separate environment/project') and how to revert (omit or pass empty config_path). It also states prerequisites: the alternate file must already exist and be valid host config TOML, and the tool deliberately does not auto-create a missing file.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_task_killA

Terminate a background task (launched via ssh_task_launch, or any other real remote PID) by sending a signal to its PID.

If force=True and the process doesn't exit after wait_seconds, it will be forcibly killed with SIGKILL (signal 9).

With use_sudo=True on a 'linux'/'flex' connection with a BusyBox-style ps that doesn't support -o pgid= (check ssh_conn_connect/ ssh_conn_host_info's capabilities), this raises a clear error instead of running - there is no clean fallback, since killing just the captured PID (rather than its whole process group) can leave the sudo'd command's real child process(es) running as orphans, exactly the failure mode this check exists to prevent. Not an issue with use_sudo=False.

Returns: {'pid', 'result', 'signal', 'force_kill_used', 'timestamp'}. result is one of: - 'killed': confirmed terminated (by the initial signal or the force-kill fallback - see force_kill_used to tell which). Terminal - nothing left to check. - 'already_exited': the process was already gone before any signal was sent. Terminal. - 'failed_to_kill': still running after both the signal and force-kill attempt (or after the signal alone, if force=False). Not terminal - the process is still alive; consider retrying or investigating why it won't die. - 'invalid_pid': pid wasn't a valid positive integer - no signal was sent. - 'error': the kill attempt itself failed unexpectedly (e.g. connection issue) - the process's actual state is unknown, not necessarily still running.

`force_kill_used` is True iff the SIGKILL fallback was actually attempted
(the initial signal alone was not enough to end the process), regardless of
whether the fallback itself succeeded - False if the initial signal alone
was sufficient, the process was already gone, `pid` was invalid, or
`force=False` so no fallback was ever attempted.
ParametersJSON Schema
NameRequiredDescriptionDefault
pidYesProcess ID to terminate
forceNoForce kill with SIGKILL if process doesn't exit
signalNoSignal to send (15=TERM, 9=KILL)
use_sudoNoUse sudo for the kill operation
wait_secondsNoSeconds to wait before force kill

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses signal behavior, the SIGKILL fallback gated by force and wait_seconds, the precise sudo/BusyBox failure mode and why no fallback exists, and the meaning of force_kill_used. This is far beyond what a bare mutation tool would convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action is front-loaded, which is good, but the multi-line 'Returns' block is long and largely duplicates the existing output schema, and the sudo/BusyBox paragraph is dense. It is thorough but not tight; several sentences restate information available in structured fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter mutation tool with an output schema, the description covers the operation, the force-kill lifecycle, the environment-specific failure case, and how to interpret results. Nothing an agent needs to invoke or reason about the outcome is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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: force maps to SIGKILL (signal 9) after wait_seconds, use_sudo's BusyBox caveat, and the semantic distinction between force_kill_used and result. It enriches the parameters beyond their schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: terminate a background task by sending a signal to its PID, and ties scope to tasks launched via ssh_task_launch. It does not explicitly differentiate from the sibling ssh_cmd_kill, which also kills a process, leaving the agent to infer which to use.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context (background tasks launched via ssh_task_launch or any real remote PID) and a concrete when-not condition: use_sudo=True on a BusyBox-style ps raises an error rather than running, so the caller must avoid that combination. It does not route to an alternative tool when this one is unsuitable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_task_launchA

Launch a command in the background and return its PID immediately, without waiting for it to complete.

Prefer this over ssh_cmd_run for commands that will take a long time or may be quiet for extended periods: package installs, container/image pulls, large downloads, backups, compilation. It avoids holding a blocking tool call open and the ambiguity of io_timeout - the PID it returns survives reconnects and can be checked anytime with ssh_task_status(pid), and stdout_log/stderr_log can be read with ssh_file_read while the task is still running.

Output is redirected to files (see stdout_log/stderr_log), not captured in memory - read the log files to see progress or final output.

Windows targets: the command runs under cmd.exe (CMD syntax); for PowerShell use powershell -NoProfile -Command "...".

On Linux/macOS the launch FAILS with an error (nothing is started) if a log file can't be created, or, with use_sudo, if sudo itself fails - so a returned PID always means the task was really started. With use_sudo, logs in a directory only root can write are created and written as root.

Returns: {'command', 'pid', 'start_time', 'stdout_log', 'stderr_log'}. Both are the paths the output really goes to on the remote host (read them with ssh_file_read), or None for a stream that's discarded - both are None if log_output=False, and stdout_log is None if you passed only stderr_log. With neither passed, the default is /tmp/task-<pid>.log on Linux/macOS (both streams in one file), and C:\Windows\Temp\task-<pid>.log plus task-<pid>_err.log on Windows.

Long-running calls: if this takes longer than the server's wait cap (default 50s), it
returns {"status": "in_progress", "handle_id": ...} instead of the result - the work keeps
running. Get the result by polling ssh_cmd_check_status(handle_id=...), which returns this
tool's normal response once finished. Do not call it again meanwhile. Only one such
operation runs at a time; another one started meanwhile fails with a 'busy' error.
ParametersJSON Schema
NameRequiredDescriptionDefault
commandYesCommand to execute in the background
use_sudoNoRun command with sudo
log_outputNoWhether to log output to files
stderr_logNoPath to redirect stderr (default: same file as stdout on Linux/macOS; a sibling <name>_err.log on Windows). The response's stderr_log always gives the real path.
stdout_logNoPath to redirect stdout (default: /tmp/task-<pid>.log on Linux/macOS, C:\Windows\Temp\task-<pid>.log on Windows)

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so thoroughly: output goes to files not memory, log files must be readable or nothing starts, sudo log ownership, Windows cmd.exe vs PowerShell semantics, and the wait-cap/in_progress/ssh_cmd_check_status polling flow including the single-operation 'busy' constraint. This is far beyond what structured fields provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is long but front-loaded and segmented into thematic blocks (usage preference, output redirection, Windows, failure semantics, Returns, long-running calls), so each section is scannable. Minor duplication of default log paths already present in the schema keeps it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter background-execution tool with platform divergence, async handle polling, and sudo behavior, the description covers failure modes, return shape, and alternate paths comprehensively. An agent has everything needed to call it correctly and to recover when it returns in_progress.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description still adds meaning: it explains what a None log path means (stream discarded), the interaction between stdout_log and stderr_log, platform-specific defaults, and that with no paths passed both streams go to one file. That is genuine semantics beyond the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a precise verb+resource+behavior: 'Launch a command in the background and return its PID immediately, without waiting for it to complete.' This cleanly separates it from ssh_cmd_run, which the description names explicitly, so an agent can route between the two 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to prefer this tool ('long time or may be quiet') and gives concrete examples (package installs, image pulls, backups, compilation), while naming the alternative and the reason it is avoided (io_timeout ambiguity). It also routes follow-up work to ssh_task_status and ssh_file_read.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ssh_task_statusA

Check the liveness of a background task by PID (from ssh_task_launch, or any other real remote PID - e.g. the pid field from ssh_cmd_run). This does a live check on the remote host every call, not a cached lookup, so it's safe to call repeatedly.

Returns: {'pid', 'status', 'running' (bool, True iff status=='running'), 'timestamp'}. status is one of: - 'running': the process currently exists. - 'exited': the process is gone - it either completed or was killed; there's no way to distinguish which, or recover its exit code, from this tool alone. - 'invalid': the given pid isn't a valid positive integer. - 'error': the liveness check itself failed (e.g. connection issue) - this does NOT mean the process exited, just that its status is unknown.

ParametersJSON Schema
NameRequiredDescriptionDefault
pidYesProcess ID to check status for

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so well: it discloses that every call hits the remote host rather than serving a cache, that repeated calls are safe, and precisely what each status means. It flags the critical ambiguity that 'exited' cannot distinguish completion from a kill or recover an exit code, and that 'error' does not imply the process died.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose, then a clearly delimited Returns block enumerating status values. The parenthetical 'running (bool, True iff status==running)' is mildly redundant, but overall the structure is tight and every section earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Even though an output schema exists, the description enumerates the return fields and every status branch with their caveats, leaving no ambiguity about results. For a one-parameter liveness probe with no annotations, 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.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% for the single pid parameter, so the schema already documents its type. The description adds real meaning by explaining the valid sources of the PID (from ssh_task_launch or any genuine remote PID), which helps the agent supply a correct value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (check liveness/status) and resource (a background task identified by PID), and grounds the PID in the sibling tools ssh_task_launch and ssh_cmd_run. It is distinct from a generic command-status check, though it never explicitly names ssh_cmd_check_status as the near-neighbor it is not.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description usefully says where the PID comes from and that it is a live check safe to call repeatedly, which implies usage context. However, it gives no explicit when-not or alternative selection versus ssh_cmd_check_status / ssh_cmd_output, so the routing guidance is only implied.

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. 16 tool updatesv1.6.1
    • Changedssh_cmd_check_status2 fields changed
      • changedInput schema / properties / handle_id / description
        Previous value: -"Command handle ID to check status for"New value: +"Command handle ID to check status for - the 'id' returned by ssh_cmd_run, including in its io_timeout/wait_timeout response"
      • changedInput schema / properties / wait_seconds / description
        Previous value: -"Seconds to wait before checking"New value: +"Seconds to wait before checking. Clamped to the server's per-call wait cap (default 50s, since most MCP clients abort tool calls at ~60s) - the response's waited_seconds shows the wait actually applied. Short waits (1-10s) with repeated polling work best."
    • Changedssh_cmd_history1 field changed
      • addedInput schema / properties / include_internal
        Added value: +{
        +  "default": true,
        +  "description": "Include internal/plumbing commands issued by other tools (e.g. ssh_file_write's sudo mv/chown/chmod dance, ssh_conn_connect's OS-detection probe, ssh_conn_verify_sudo's sudo check, ssh_dir_transfer's temp-archive handling). Set False to see only commands the user directly asked for via ssh_cmd_run/ssh_task_launch.",
        +  "type": "boolean"
        +}
    • Changedssh_cmd_kill1 field changed
      • changedInput schema / properties / handle_id / description
        Previous value: -"Command handle ID to kill"New value: +"Command handle ID to kill - the 'id' field from ssh_cmd_run's response"
    • Changedssh_cmd_output4 fields changed
      • changedInput schema / properties / handle_id / description
        Previous value: -"Command handle ID to retrieve output for"New value: +"Command handle ID - the 'id' field from ssh_cmd_run's response"
      • changedInput schema / properties / lines / description
        Previous value: -"Number of lines to retrieve (None for all)"New value: +"How many lines to return. Without start_line: the most recent N lines (default 50). With start_line: N lines from there (default 50)."
      • addedInput schema / properties / start_line
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Page through the output: return lines starting at this line number (1 = the command's first line). Use it to read what a truncated ssh_cmd_run response didn't include (see its output_note)."
        +}
      • addedInput schema / properties / stream
        Added value: +{
        +  "default": "stdout",
        +  "description": "Which captured stream to retrieve - stdout (default) or stderr. These are NOT interleaved into one combined stream - call this twice (once per stream) if you need both",
        +  "enum": [
        +    "stdout",
        +    "stderr"
        +  ],
        +  "type": "string"
        +}
    • Changedssh_cmd_run5 fields changed
      • addedInput schema / properties / cwd
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Run the command in this directory, for this call only (Linux/macOS only - not yet supported on Windows). Nothing is remembered between calls: each ssh_cmd_run is an independent process, so pass cwd again on every call where it matters, or chain 'cd dir && command' yourself. Fails closed - if the directory doesn't exist, the command is never executed at all (status='cwd_not_found'), so there's no ambiguity about where anything ran."
        +}
      • changedInput schema / properties / io_timeout / description
        Previous value: -"I/O timeout in seconds"New value: +"Max seconds of SILENCE (no output) before giving up on waiting. Does NOT kill the remote command - hands off to background monitoring and returns control to you. Note a single call never blocks longer than the server's wait cap (default 50s, since most MCP clients abort tool calls at ~60s) - raising this above that only matters for how long silence is tolerated within the cap. For package installs, Docker pulls, large downloads or compilation, prefer ssh_task_launch. If hit, call ssh_cmd_check_status or ssh_cmd_output to check back rather than rerunning."
      • removedInput schema / properties / io_timeout / exclusiveMinimum
        Removed value: -0
      • changedInput schema / properties / runtime_timeout / description
        Previous value: -"Total runtime timeout in seconds"New value: +"Total wall-clock cap in seconds, regardless of output activity. Unlike io_timeout/wait_timeout, hitting this DOES attempt to kill the remote command - it's the only hard ceiling. Set generously for long operations (installs/downloads can need 10-60+ minutes) - this should be a safety net, not a UX mechanism."
      • addedInput schema / properties / wait_timeout
        Added value: +{
        +  "anyOf": [
        +    {
        +      "exclusiveMinimum": 0,
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Max seconds to wait in THIS call, regardless of output activity - unlike io_timeout, fires even if the command is actively producing output. Does NOT kill the remote command, same non-destructive handoff as io_timeout. Use this when you want to check in periodically on a command that's chatty but long-running (e.g. a verbose Docker pull), rather than being blocked until it finishes or goes quiet. Values above the server's wait cap (default 50s) are clamped to it - the response then has wait_capped=true."
        +}
    • Changedssh_dir_list_advanced3 fields changed
      • addedOutput schema / properties / result / anyOf
        Added value: +[
        +  {
        +    "items": {},
        +    "type": "array"
        +  },
        +  {
        +    "additionalProperties": true,
        +    "type": "object"
        +  }
        +]
      • removedOutput schema / properties / result / items
        Removed value: -{}
      • removedOutput schema / properties / result / type
        Removed value: -"array"
    • Changedssh_dir_list_files_basic3 fields changed
      • addedOutput schema / properties / result / anyOf
        Added value: +[
        +  {
        +    "items": {},
        +    "type": "array"
        +  },
        +  {
        +    "additionalProperties": true,
        +    "type": "object"
        +  }
        +]
      • removedOutput schema / properties / result / items
        Removed value: -{}
      • removedOutput schema / properties / result / type
        Removed value: -"array"
    • Changedssh_dir_search_files_content3 fields changed
      • addedOutput schema / properties / result / anyOf
        Added value: +[
        +  {
        +    "items": {},
        +    "type": "array"
        +  },
        +  {
        +    "additionalProperties": true,
        +    "type": "object"
        +  }
        +]
      • removedOutput schema / properties / result / items
        Removed value: -{}
      • removedOutput schema / properties / result / type
        Removed value: -"array"
    • Changedssh_dir_search_glob3 fields changed
      • addedOutput schema / properties / result / anyOf
        Added value: +[
        +  {
        +    "items": {},
        +    "type": "array"
        +  },
        +  {
        +    "additionalProperties": true,
        +    "type": "object"
        +  }
        +]
      • removedOutput schema / properties / result / items
        Removed value: -{}
      • removedOutput schema / properties / result / type
        Removed value: -"array"
    • Changedssh_file_delete_line_by_content1 field changed
      • changedInput schema / properties / force / description
        Previous value: -"Force operation even if file can't be read (sudo only)"New value: +"No longer needed (kept for compatibility): with use_sudo=true the file is read with sudo when the user can't read it. If it can't be read at all, the edit fails - it never reports success without having seen the file."
    • Changedssh_file_insert_lines_after_match1 field changed
      • changedInput schema / properties / force / description
        Previous value: -"Force operation even if file can't be read (sudo only)"New value: +"No longer needed (kept for compatibility): with use_sudo=true the file is read with sudo when the user can't read it. If it can't be read at all, the edit fails - it never reports success without having seen the file."
    • Changedssh_file_replace_line1 field changed
      • changedInput schema / properties / force / description
        Previous value: -"Force operation even if file can't be read (sudo only)"New value: +"No longer needed (kept for compatibility): with use_sudo=true the file is read with sudo when the user can't read it. If it can't be read at all, the edit fails - it never reports success without having seen the file."
    • Changedssh_file_replace_line_multi1 field changed
      • changedInput schema / properties / force / description
        Previous value: -"Force operation even if file can't be read (sudo only)"New value: +"No longer needed (kept for compatibility): with use_sudo=true the file is read with sudo when the user can't read it. If it can't be read at all, the edit fails - it never reports success without having seen the file."
    • Addedssh_host_update
    • Addedssh_host_use_config
    • Changedssh_task_launch2 fields changed
      • changedInput schema / properties / stderr_log / description
        Previous value: -"Path to redirect stderr (default: same as stdout)"New value: +"Path to redirect stderr (default: same file as stdout on Linux/macOS; a sibling <name>_err.log on Windows). The response's stderr_log always gives the real path."
      • changedInput schema / properties / stdout_log / description
        Previous value: -"Path to redirect stdout (default: /tmp/task-<pid>.log)"New value: +"Path to redirect stdout (default: /tmp/task-<pid>.log on Linux/macOS, C:\\Windows\\Temp\\task-<pid>.log on Windows)"
  2. 44 tool updatesv1.3.0
    • First observedlist_tools
    • First observedssh_archive_create
    • First observedssh_archive_extract
    • First observedssh_cmd_check_status
    • First observedssh_cmd_clear_history
    • First observedssh_cmd_history
    • First observedssh_cmd_kill
    • First observedssh_cmd_output
    • First observedssh_cmd_run
    • First observedssh_conn_add_host
    • First observedssh_conn_connect
    • First observedssh_conn_host_info
    • First observedssh_conn_is_connected
    • First observedssh_conn_status
    • First observedssh_conn_verify_sudo
    • First observedssh_dir_batch_delete_files
    • First observedssh_dir_calc_size
    • First observedssh_dir_copy
    • First observedssh_dir_delete
    • First observedssh_dir_list_advanced
    • First observedssh_dir_list_files_basic
    • First observedssh_dir_mkdir
    • First observedssh_dir_remove
    • First observedssh_dir_search_files_content
    • First observedssh_dir_search_glob
    • First observedssh_dir_transfer
    • First observedssh_file_copy
    • First observedssh_file_delete_line_by_content
    • First observedssh_file_find_lines_with_pattern
    • First observedssh_file_get_context_around_line
    • First observedssh_file_insert_lines_after_match
    • First observedssh_file_move
    • First observedssh_file_read
    • First observedssh_file_replace_line
    • First observedssh_file_replace_line_multi
    • First observedssh_file_stat
    • First observedssh_file_transfer
    • First observedssh_file_write
    • First observedssh_host_disconnect
    • First observedssh_host_list
    • First observedssh_host_remove
    • First observedssh_task_kill
    • First observedssh_task_launch
    • First observedssh_task_status

TDQS

A4.1/5.0

Scored across 46 tools

Disambiguation4/5

Most tools target clearly distinct resource+action pairs across well-separated namespaces (conn, host, file, dir, cmd, task, archive). However, a few clusters overlap: ssh_dir_remove vs ssh_dir_delete vs ssh_dir_batch_delete_files all remove directories/files, and ssh_file_replace_line_multi vs ssh_file_delete_line_by_content are near-subsets of each other. Descriptions do disambiguate these, but boundaries require careful reading.

Naming Consistency4/5

The ssh_<namespace>_<verb>_<noun> pattern is broadly consistent across file/dir/cmd/task/archive tools. Deviations exist: host management is split between the ssh_conn_ prefix (ssh_conn_add_host) and the ssh_host_ prefix (ssh_host_update, ssh_host_remove, ssh_host_list), and ssh_file_delete_line_by_content doesn't mirror the ssh_file_replace_line structure. Still readable and mostly predictable.

Tool Count3/5

46 tools is well above the comfortable range and pushes into heavy territory. For a full-featured remote-shell server spanning connection, host, file, directory, command, task, and archive domains most tools earn their place, but the surface could be consolidated (e.g. three directory-deletion tools, two line-replacement tools).

Completeness5/5

Lifecycle coverage is exemplary: connection and host CRUD, file read/write/move/copy/stat plus line-level editing, directory list/mkdir/remove/delete/copy/search/size/transfer, command run/kill/status/output/history, background task launch/status/kill, and archive create/extract. Almost no obvious gaps for an SSH automation server.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers