ssh-mcp
Enables reading remote files over SSH, such as Caddy configuration files like /etc/caddy/Caddyfile.
Allows running commands on remote machines over SSH, such as managing Docker containers with 'docker ps' or other Docker CLI operations.
Enables reading and stat-ing remote files over SSH, such as NGINX configuration files like /etc/nginx/nginx.conf.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ssh-mcprun docker ps on my snow host and show me the output"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ssh-mcp
ssh-mcp is a local Model Context Protocol server that gives AI agents safe, structured access to remote machines over SSH. Instead of hand-assembling ssh snow "docker ps" commands, the agent calls typed tools like ssh_exec({host: "snow", command: "docker ps"}) and gets back stdout, stderr, exit code, timeout and truncation information.
AI Agent
│ MCP / stdio
▼
ssh-mcp
│ SSH (connection pool, your OpenSSH config/credentials)
▼
Remote machinesThe MCP server has essentially the same remote privileges as the SSH identity in use. Only connect it to agents you trust, on machines you are comfortable granting shell access to.
Requirements
Node.js >= 20
An SSH configuration you already use (
~/.ssh/config) with working credentials
Related MCP server: SSH MCP Server
Installation
From npm:
npm install -g @callumbicknell/ssh-mcpFrom source:
git clone https://github.com/CallumBicknell/ssh-mcp.git
cd ssh-mcp
pnpm install
pnpm run buildSSH configuration
ssh-mcp discovers hosts from your existing OpenSSH client config — ~/.ssh/config by default, or SSH_CONFIG_PATH if set. Nothing is duplicated: hostnames, users, ports and key paths all come from the file the ssh CLI already uses.
Per host, it resolves: HostName, Port, User, IdentityFile (tried in order), and IdentityAgent/SSH_AUTH_SOCK. Agent auth is preferred when available, then identity files.
MCP client configuration
Local/source usage:
{
"mcpServers": {
"ssh": {
"command": "node",
"args": ["/path/to/ssh-mcp/dist/index.js"]
}
}
}npm usage:
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": ["-y", "@callumbicknell/ssh-mcp"]
}
}
}The server speaks MCP on stdio; all logs go to stderr.
Tools
Tool | Purpose |
| List the concrete host aliases available in your SSH config (no secrets) |
| Run a remote command; returns stdout/stderr/exit code/timeout/truncation |
| Read a remote text file (size-capped) |
| Atomically write a remote file (temp file + rename; never creates parent dirs) |
| Compact directory listing with type, size, mode, mtime |
| File/dir metadata: type, size, permissions, mtime, uid/gid |
| Persistent local port-forwards over the pooled SSH connection |
ssh_exec result shape
exit code: 0
stdout:
...
stderr:
...
[stdout truncated at 65536 bytes] ← only when truncatedNon-zero exit codes and stderr are always surfaced as MCP errors/text; timeouts return partial output plus a clear timeout message. On timeout the remote process is sent KILL and the channel is closed.
Configuration
Variable | Default | Meaning |
|
| Max bytes kept per output stream before truncation |
|
| Default |
|
| SSH connection timeout (ms) |
|
| Per-operation SFTP timeout (ms) |
|
| How long an idle pooled connection is kept (ms) |
|
| Path to the OpenSSH client config |
Timeout semantics: connection timeout bounds establishing the TCP/SSH session; command timeout bounds a single ssh_exec; operation timeout bounds one SFTP read/write/stat/readdir; idle timeout only evicts a connection with no active operations.
SSH compatibility limitations
ssh-mcp uses the ssh2 library plus a parser for ~/.ssh/config. It is not a full OpenSSH client:
Supported | Not supported (or approximate) |
|
|
|
|
|
|
Per-host aliases |
|
Agent and publickey auth | Password prompts (no interactive prompting — use keys/agent) |
For hosts that require jump hosts or proxy commands, either add direct HostName/Port entries you can reach, or front them with a reachable bastion address in your config. Switching to shelling out to the system ssh binary was evaluated and rejected: it would lose connection pooling, structured results, and make timeout/output control and atomic-write SFTP impossible to guarantee portably.
Security model
No command allowlist by design: the server is an administration tool, and a blanket allowlist would make it useless for that purpose. Command-policy/confirmation middleware is a clear extension point.
Private keys/passwords are read by
ssh2during auth only; they are never logged or returned.Host identifiers are validated and never interpolated into a local shell.
All output is byte-capped; all operations are timeout-bounded.
File writes are atomic and do not create parent directories.
Examples
ssh_hosts()
→ snow\nserver01\nfileserver
ssh_exec({host: "snow", command: "docker ps --format '{{.Names}} {{.Status}}'"})
ssh_read_file({host: "snow", path: "/etc/caddy/Caddyfile"})
ssh_write_file({host: "snow", path: "/tmp/deploy.yaml", content: "..."})
ssh_list_directory({host: "snow", path: "~/stacks"})
ssh_stat({host: "snow", path: "/etc/nginx/nginx.conf"})Quick install (one-liner for an AI agent)
Copy this into any agent that can read URLs and follow instructions:
Read https://raw.githubusercontent.com/CallumBicknell/ssh-mcp/main/AGENT_INSTALL.md and follow it exactly.Development
pnpm install # install
pnpm run dev # rebuild on change (tsc --watch)
pnpm run build # emit to dist/
pnpm run typecheck # strict type check
pnpm test # vitest — no real SSH server required
pnpm start # run on stdioTests mock the SSH/SFTP layer; they validate host parsing, validation, truncation (including UTF-8 edge cases), timeout logic, atomic write failure handling, connection-pool behaviour under concurrency, error formatting, and tool registration. CI runs install/typecheck/test/build on Node 22, 24 and 26.
Publishing
Package name on npm: @callumbicknell/ssh-mcp (the unscoped ssh-mcp name is owned by another project).
npm login
npm publish --access publicprepublishOnly runs typecheck + tests + build automatically. npm pack --dry-run shows that only dist/, README.md and LICENSE ship.
Available Tools
9 toolsssh_execA
Run a shell command on a remote machine over SSH. host is an alias from your local ~/.ssh/config (see ssh_hosts). The command runs via a non-interactive remote shell; stdout and stderr are captured, truncated at a configured size limit, and reported together with the exit code. Non-zero exit codes are surfaced, not hidden. Default timeout: 30s (override per call with timeout). For long-running jobs, run them in the background remotely and poll.
| Name | Required | Description | Default |
|---|---|---|---|
| host | Yes | SSH config alias of the target host | |
| command | Yes | Command to execute on the remote host | |
| timeout | No | Timeout in milliseconds (default: 30000) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses non-interactive execution, combined stdout/stderr capture, truncation at a size limit, exit-code surfacing (non-zero codes not hidden), and the 30s default timeout. It omits any warning that arbitrary command execution can mutate or destroy remote state and any auth/permission prerequisites.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences, front-loaded with the core verb and host semantics, then behavior, then the timeout and long-running guidance. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-param tool with no output schema, the description covers what an agent needs on the return side (stdout+stderr+exit code, truncation) and timeout behavior. The remaining gap is the absence of any destructive-capability or permission caveat for arbitrary shell execution.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description adds real meaning: it explains what a `host` alias resolves to, that the timeout is overridable per call, and reconciles units (30s vs the schema's milliseconds).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Run a shell command on a remote machine over SSH') and immediately scopes the host parameter to an alias from local ~/.ssh/config. This clearly separates it from siblings like ssh_read_file and ssh_write_file.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear context for invocation and explicitly routes the agent to `ssh_hosts` for aliases, plus guidance to background long-running jobs rather than block. It stops short of stating when to prefer ssh_read_file/ssh_write_file over a raw shell command, so there is no explicit alternative-selection rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_hostsA
List the SSH host aliases available in the local SSH client configuration (~/.ssh/config). Use these aliases as the host argument to the other ssh tools. Does not expose keys, usernames' credentials, or secrets.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does so reasonably: it discloses that no keys, usernames' credentials, or secrets are exposed, which is the key safety fact for an agent deciding whether to call it. It does not state whether it is strictly read-only or how missing/empty configs are handled, so it is not fully transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core action and source, then the follow-up usage, then the safety note. Every sentence earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read tool with no output schema or annotations, the description covers what it returns (aliases), where they come from, and how to use them. A brief note on behavior when the config is absent or unreadable would make it fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the baseline is 4; there is nothing for the description to disambiguate. The mention of the `host` argument applies to sibling tools rather than this one, so it adds no parameter detail here but also creates no confusion.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the SSH host aliases') and names the exact source ('~/.ssh/config'), which distinguishes it from the sibling ssh_tunnel/ssh_tunnels listing tools. An agent can identify this as the discovery tool without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent what to do with the output: use the aliases as the `host` argument to the other ssh tools. That is strong routing guidance. It lacks a when-not clause (e.g., what to do if no config exists), 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_list_directoryA
List the contents of a directory on a remote SSH host (defaults to the remote user's home directory). Each entry includes type, size, permission bits and modification time.
| Name | Required | Description | Default |
|---|---|---|---|
| host | Yes | SSH config alias of the target host | |
| path | No | Directory path (defaults to the remote user's home directory) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It discloses what each entry includes (type, size, permission bits, modification time), which is useful, but it doesn't mention error behavior (e.g., if the path doesn't exist), permission requirements, or whether it follows symlinks. For a read-only operation, the safety profile is implied but not stated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences that front-load the action and scope. Every clause earns its place by adding either the default path or the entry fields, with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple two-parameter read operation, no output schema, and 100% schema coverage, the description is nearly complete. It covers default and return fields but lacks any mention of error handling or limitations, which would be helpful for an agent in production use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters (host as SSH config alias, path as directory path with default). The description repeats the default for path but adds no syntax, format, or edge-case details beyond the schema. Baseline 3 is appropriate when schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the contents of a directory on a remote SSH host') and clarifies the default scope (remote user's home directory). It is clearly distinguishable from siblings like ssh_stat (single file metadata) and ssh_read_file (file contents) without needing to open schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage context (listing remote directory contents) and defaults, which helps an agent decide to use this over ssh_stat or ssh_read_file. However, it doesn't explicitly state when not to use it or name alternatives for edge cases (e.g., listing a single file's metadata).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_read_fileA
Read the contents of a text file on a remote SSH host. Large files are truncated at a configured size limit; for very large files prefer ssh_exec with head/tail/grep.
| Name | Required | Description | Default |
|---|---|---|---|
| host | Yes | SSH config alias of the target host | |
| path | Yes | Absolute or relative path of the file to read |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It usefully discloses truncation at a configured size limit, a non-obvious trait, but omits permission/auth failure behavior, encoding assumptions, and how partial content is signaled.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core action, and the fallback guidance follows immediately. Every clause earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter read tool with full schema coverage, the description is nearly complete, covering the action and the truncation caveat. With no output schema, a brief note on the return format (e.g., whether truncation is flagged in the response) would close the remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for both parameters (host alias, file path), so the schema already carries the semantics. The description adds no syntax, format, or path-resolution detail beyond what the schema provides, making the baseline 3 correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Read) and resource (contents of a text file on a remote SSH host), including scope (remote host, text file). It implicitly differentiates from ssh_write_file and ssh_exec by naming the exec alternative that handles large-file slicing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to ssh_exec with head/tail/grep for very large files, which is clear conditional guidance with a named alternative. It does not, however, address other edge cases (binary files, error paths) that would justify a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_statA
Get metadata about a file or directory on a remote SSH host: type, size, permissions, modification time, owner/group ids.
| Name | Required | Description | Default |
|---|---|---|---|
| host | Yes | SSH config alias of the target host | |
| path | Yes | Path to inspect |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It establishes that the operation targets a remote SSH host and what data comes back, but says nothing about failure modes (missing path, permission denied), symlink following, or whether the path is interpreted relative to the remote user's home.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that front-loads the verb and resource and then lists return fields. No filler, no redundancy with the title or schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates reasonably by enumerating the returned metadata fields. For a low-risk read tool this is nearly sufficient; only error/edge-case behavior and symlink semantics are unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters are documented there (host as SSH config alias, path as the target). The description adds no syntax, default, or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (get) and resource (metadata about a file or directory on a remote SSH host), then enumerates exactly what is returned: type, size, permissions, mtime, owner/group ids. This field list implicitly separates it from ssh_read_file (contents) and ssh_list_directory (listing), but no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied by the purpose: an agent can infer this is for inspecting a single remote path's metadata. There is no statement of when to prefer it over ssh_list_directory or ssh_read_file, nor any prerequisites such as reachability of the host.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_tunnelA
Start a persistent local port-forward through the pooled SSH connection for host, e.g. forward local port 8080 to snow:80. The tunnel stays open until ssh_tunnel_stop is called. Returns the tunnel id and the local URL to use.
| Name | Required | Description | Default |
|---|---|---|---|
| host | Yes | SSH config alias to tunnel through | |
| localHost | No | Local bind address | 127.0.0.1 |
| localPort | Yes | Local port to listen on (0 = random) | |
| remoteHost | No | Destination host from the SSH server's perspective | 127.0.0.1 |
| remotePort | Yes | Destination port |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It does disclose the key trait of persistence and what the call returns (tunnel id + local URL), but says nothing about prerequisites (existing pooled connection/host alias), auth, port-collision failures, or resource cleanup on error.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, zero filler, with the lifetime constraint and return value front-loaded. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description usefully explains the return (tunnel id, local URL) alongside lifetime semantics. Only gap is failure/error behavior, which leaves it slightly short of fully self-contained for a stateful networking tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the worked example ('forward local port 8080 to snow:80') adds real meaning by showing how host, localPort, and remotePort combine, which is more than the schema's per-field text conveys.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource: 'Start a persistent local port-forward through the pooled SSH connection for `host`', with a concrete example (local 8080 -> snow:80). An agent can distinguish it from siblings ssh_tunnels (listing) and ssh_tunnel_stop (teardown) directly from the description.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly states the lifecycle condition ('stays open until ssh_tunnel_stop is called'), which routes the agent to the teardown sibling. It does not explicitly say when to prefer this over a one-off ssh_exec or when not to open a tunnel, so the guidance is clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_tunnelsB
List currently open SSH port-forward tunnels.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It indicates a read-only listing of currently open tunnels, which is useful, but does not disclose permissions, return format, pagination, or whether it only shows tunnels opened by the current session.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no wasted words. It efficiently communicates the core action and scope.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter list tool with no output schema, the description is minimally adequate. It states what is listed but omits return format, ordering, or scope limitations that could matter for an SSH tunnel inventory.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so parameter semantics are not applicable. The baseline score of 4 is appropriate because there are no parameters to document.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('List') and resource ('SSH port-forward tunnels') with a clear scope modifier ('currently open'). It clearly distinguishes the operation from sibling tools like ssh_tunnel and ssh_tunnel_stop, but does not explicitly name or contrast with them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this tool versus alternatives such as ssh_tunnel or ssh_tunnel_stop. The implied usage is clear from the verb 'List', but no context or exclusions are provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_tunnel_stopA
Stop a port-forward tunnel by id (from ssh_tunnel / ssh_tunnels).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Tunnel id to stop |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It does not say whether the tunnel is killed vs detached, whether the local port is released, whether the call errors on an unknown id, or whether it is idempotent — all things an agent needs before retrying or chaining.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence, front-loaded with the action and resource, with the id provenance tucked into a parenthetical. No filler and nothing to trim.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-param, no-output-schema tool the description covers what is done and where the id comes from, which is the minimum viable. With zero annotations and no output schema, it should still say what happens on an unknown id or whether stopping is idempotent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single 'id' param is documented as 'Tunnel id to stop', so the baseline is 3. The description adds genuine value by telling the agent where that id comes from (ssh_tunnel / ssh_tunnels), which the schema does not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Stop) and resource (a port-forward tunnel) scoped by id. It also names the sibling tools (ssh_tunnel / ssh_tunnels) where the id originates, so an agent can place it in the tunnel lifecycle without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The parenthetical '(from ssh_tunnel / ssh_tunnels)' tells the agent this is the teardown counterpart to tunnel creation, giving clear usage context. It stops short of stating when not to call it (e.g., unknown/already-closed id) or what to do instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_write_fileB
Write text to a file on a remote SSH host. The write is atomic (temporary file, then rename), so a failed or interrupted write never leaves a partially-written destination. Parent directories are NOT created automatically.
| Name | Required | Description | Default |
|---|---|---|---|
| host | Yes | SSH config alias of the target host | |
| path | Yes | Absolute or relative path of the file to write | |
| content | Yes | Text content to write |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It usefully discloses atomicity (temp file then rename) and that parent directories are not created, but omits key behaviors such as whether existing files are overwritten, permission requirements, or error handling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences with zero waste, and the core purpose is front-loaded before the atomicity and directory-creation details. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple three-parameter write tool with no output schema and full schema coverage, the description covers the important non-obvious behaviors (atomic write, parent directory behavior). It is nearly complete, though the omission of overwrite semantics is a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all three parameters. The description adds no parameter-level semantics beyond what the schema provides, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Write text to a file on a remote SSH host.' It clearly distinguishes from read-oriented siblings like ssh_read_file, but does not explicitly differentiate from ssh_exec, which could also write files via shell commands.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance is given, and no alternatives are mentioned. An agent must infer that this tool is for writing files rather than using ssh_exec, with no explicit conditions or exclusions provided.
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.
9 tool updates
v0.2.1- First observed
ssh_exec - First observed
ssh_hosts - First observed
ssh_list_directory - First observed
ssh_read_file - First observed
ssh_stat - First observed
ssh_tunnel - First observed
ssh_tunnel_stop - First observed
ssh_tunnels - First observed
ssh_write_file
TDQS
Scored across 9 tools
Each tool targets a distinct operation: file read/write, command execution, directory listing, metadata stat, host enumeration, and tunnel start/list/stop. The tunnel trio (ssh_tunnel, ssh_tunnels, ssh_tunnel_stop) is clearly differentiated by verb, and file/metadata tools do not overlap. No realistic misselection risk.
All tools use a consistent `ssh_` snake_case prefix, which is strong. Minor deviations exist: some are verb_noun (ssh_read_file, ssh_list_directory), some are bare resource plurals (ssh_hosts, ssh_tunnels), and ssh_tunnel_stop puts the verb last instead of following the verb_noun pattern.
Nine tools is well-scoped for an SSH remote-operations server. Each tool covers a distinct capability (file I/O, exec, directory listing, stat, hosts, tunnel lifecycle) without redundancy or bloat.
The surface covers core SSH workflows: read, write, execute, list, stat, host discovery, and tunnel lifecycle. Gaps exist for dedicated delete, mkdir, move, and binary/SCP-style transfer, but most of these are workable via ssh_exec with shell commands.
Maintenance
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
- emisarOAuthdev.emisar
Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.
Use your Mac, Windows or Linux computer from ChatGPT, Claude or Codex: files, commands, documents.
Scoped, audited SSH exec, sessions, and SFTP on your saved servers without exposing credentials
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI coding agents to securely execute shell commands on remote SSH servers with granular per-host permission controls. Automatically discovers hosts from ~/.ssh/config and exposes dedicated tools for each allowed host to ensure proper authorization before remote execution.11,976 npmApache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to securely execute commands, transfer files, and manage port forwarding on remote servers via SSH.145 npm37Apache 2.0
- AlicenseAqualityDmaintenanceEnables AI agents to execute SSH commands, read files, and list directories on remote hosts with a configurable command-safety policy.5MIT
- FlicenseAqualityCmaintenanceEnables LLMs to securely SSH into remote servers, execute commands, and manage files via SFTP including listing, reading, writing, deleting, and renaming files.11-