ssh-hosts-mcp
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-hosts-mcprun df -h on my-host"
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-hosts-mcp
Unified SSH MCP server with a host registry — one host_id per call instead of IPs, users and key paths.
Overview
ssh-hosts-mcp is a Model Context Protocol server that gives LLM clients access to SSH hosts through a named registry. The agent calls ssh_exec with host_id — addresses, users, ports and private keys stay in a local config file and never enter the model context.
Three transports are supported:
Transport | Implementation | Tools |
|
| exec, read, SFTP write (base64-exec fallback) |
| spawns the | exec, read, base64-exec write (≤48 KB) |
| WSL | exec only |
Related MCP server: MCP SSH Server
Features
Host registry —
host_idabstraction; the agent never guesses IP/user/keyThree transports — direct
ssh2,ssh3(QUIC over UDP), WSL-proxied SSHFile transfer — SFTP with automatic base64-exec fallback for hosts without sftp-server (OpenWrt/dropbear), written bytes verified
RouterOS-aware — MikroTik hosts flagged with
"shell": "routeros"Server instructions —
docs/INSTRUCTIONS.mdis served to the MCP client automaticallyAgent Skills — a ready SKILL.md for skill-aware clients (copy to the client's
skills/directory)Safety rails — rejects literal
undefined/nullfile paths, propagates remote exit codes (incl. win32 unsigned 32-bit fixup)Local-first config — real addresses live in a gitignored
hosts.local.json; the repository ships an anonymized template
Tools
Tool | Purpose |
| List configured hosts and metadata |
| Run a remote command |
| Read a remote file ( |
| Write a remote file (SFTP on direct hosts, base64-exec on ssh3; ≤48 KB) |
Installation
git clone https://github.com/nagual2/ssh-hosts-mcp.git
cd ssh-hosts-mcp
npm install
npm testMCP configuration
Generic mcpServers entry (Claude Desktop, Cursor, ZCode, …):
{
"mcpServers": {
"ssh": {
"command": "node",
"args": ["/path/to/ssh-hosts-mcp/index.mjs"],
"env": {
"SSH_HOSTS_CONFIG": "/path/to/hosts.local.json"
}
}
}
}Config precedence: SSH_HOSTS_CONFIG env override → hosts.local.json (real addresses, gitignored) → hosts.json (anonymized template, safe to publish).
Host configuration
{
"version": 1,
"hosts": {
"my-host": {
"label": "Linux box",
"transport": "direct",
"host": "192.0.2.10",
"user": "root",
"port": 22,
"privateKeyPath": "~/.ssh/id_ed25519"
},
"my-ssh3-host": {
"label": "Same box over ssh3",
"transport": "ssh3",
"host": "server.example.lan",
"port": 443,
"urlPath": "/ssh3-term",
"user": "user",
"privateKeyPath": "~/.ssh/id_ed25519",
"clientPath": "ssh3-client"
},
"my-proxy-host": {
"label": "Reachable only through a proxy",
"transport": "wsl",
"wslHost": "alias-from-ssh-config",
"user": "coder"
}
}
}Transports in detail
direct— Nodessh2from the MCP host machine;~inprivateKeyPathis expanded to the home directory.ssh3— spawns the ssh3 client (clientPath, defaultssh3-clienton PATH); all flags go before the positionaluser@host:port/urlPathtarget. The server certificate must be pinned in~/.ssh3/known_hosts(TOFU) or"insecure": trueset (dev only). Requires ssh3 server ≥ 0.1.8 — use thenagual2/ssh3fork, which adds the-privkeyflag.wsl— runswsl bash -lc 'ssh -o BatchMode=yes <wslHost> <command>'; onlyssh_execis supported (usecat/tar|sshfor files).
Full field reference: hosts.json and docs/INSTRUCTIONS.md.
Design notes
48 KB base64-exec limit — remote writes are embedded as
echo <base64> | base64 -d > file; an ARG_MAX-safe ceiling, with the written size verified viawc -c.Exit codes — Go clients surface unsigned 32-bit codes on win32;
normalizeExitCodemaps them back to signed values.filePath, notpath— the write schema usesfilePath; a literal"undefined"/"null"path is rejected before touching the remote host.
Testing
npm test # node --test test/lib.test.mjs — pure helpers, no networkLicense
MIT © 2026 nagual2
Available Tools
4 toolsssh_execB
Execute a command on a configured host by host_id
| Name | Required | Description | Default |
|---|---|---|---|
| command | Yes | Remote command (bash on Linux; RouterOS on MikroTik hosts) | |
| host_id | Yes | Host id from ssh_list_hosts (e.g. prod-openwrt, dslab-ml) | |
| timeoutMs | No | Timeout in milliseconds (default 120000) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full disclosure burden. It only states that a command is executed; it does not warn that command execution can have side effects, or clarify output behavior, exit codes, stderr handling, or privileges on the remote host.
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 filler. It states the action and the key routing parameter immediately.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema and no annotations, yet the description does not explain what the tool returns, whether it streams output, how errors/timeouts surface, or that it is capable of mutating remote state. An agent invoking ssh_exec would lack critical execution-context details.
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%, with useful parameter descriptions: command specifies bash on Linux vs RouterOS on MikroTik, host_id references ssh_list_hosts, and timeoutMs has a default. The tool description adds little beyond mentioning host_id, but the schema already handles parameter semantics adequately.
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 uses a specific verb ('Execute') and a specific resource ('a command on a configured host by host_id'). This clearly distinguishes it from siblings like ssh_list_hosts, ssh_read_file, and ssh_write_file, which handle listing and file operations rather than command execution.
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 the obvious use case: run a command on a host instead of reading/writing files or listing hosts. However, it gives no explicit guidance on when to prefer this tool over alternatives, nor any exclusions or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_list_hostsA
List configured SSH hosts (use host_id with ssh_exec)
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the operation is a list (read-only), which is clear, but it does not mention any side effects, permissions, or output format. For a simple listing operation this is likely safe, but the lack of detail about what is returned (e.g., host names, IDs, connection details) leaves some ambiguity. The description is not misleading, but it is minimal.
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, efficient sentence that states the purpose and provides a usage hint. There is no fluff or redundant information. It is front-loaded with the main action and follows with the relevant cross-tool reference. Every word 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 list tool with no parameters, no output schema, and no annotations, the description is fairly complete. It tells the agent what the tool does and how the result connects to a sibling tool. However, it does not specify the exact format of the returned hosts (e.g., whether it returns host names, IDs, or full connection strings), which could be a minor gap. Given the simplicity and the cross-reference to ssh_exec, it is adequate for a basic 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?
The tool has zero parameters, and schema description coverage is 100% (trivially, since there are none). Per the rules, the baseline for 0 params is 4. The description does not need to add parameter details because there are none. It adds a hint about the output being used as host_id, which indirectly explains the semantic meaning of what is returned, but no parameter explanation is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists configured SSH hosts, using a specific verb ('List') and a specific resource ('configured SSH hosts'). It also hints at a follow-up action ('use host_id with ssh_exec'), which distinguishes it from the sibling tools (ssh_exec, ssh_read_file, ssh_write_file) that operate on files or execute commands. The purpose is unambiguous.
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 explicitly mentions 'use host_id with ssh_exec', which tells the agent that the output of this tool is intended as input for ssh_exec. This implies when to use this tool (to discover available hosts before executing commands). It does not explicitly state when not to use it or alternatives, but for a simple listing tool this is adequate guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_read_fileB
Read a remote file (direct hosts only; uses cat)
| Name | Required | Description | Default |
|---|---|---|---|
| host_id | Yes | ||
| filePath | Yes | ||
| timeoutMs | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden for behavioral disclosure. It only reveals that the tool 'uses cat', which hints at output behavior but does not state whether SSH credentials are required, what happens on missing files, error behavior, or that the operation is read-only.
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 very short, front-loaded with the core action, and contains no filler. Every element ('Read a remote file', 'direct hosts only', 'uses cat') adds value and fits in a single compact sentence.
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?
This is a simple 3-parameter read operation with no output schema and no annotations. The description is minimally viable: 'cat' implies the file content is returned, and host/file parameters are reasonably self-explanatory. However, it does not explain return format, failure behavior, timeout handling, or permissions.
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 0%, so the description must compensate for parameter meaning. It marginally helps by indicating host_id refers to a direct host and filePath is the remote file, but timeoutMs is completely undocumented, and no parameter-specific details such as formats or constraints are provided.
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: 'Read a remote file'. It adds a useful qualifier ('direct hosts only') and an implementation hint ('uses cat'), making the tool's function clear. However, it does not explicitly differentiate itself from siblings like ssh_exec, which could also read files by executing 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?
The phrase 'direct hosts only' provides an implicit scope limitation and some usage context, suggesting it is not for indirect/proxied hosts. Yet the description offers no explicit when-to-use versus alternatives guidance, such as 'use ssh_write_file to write' or 'use ssh_exec for arbitrary commands'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ssh_write_fileA
Write remote file via SFTP (base64-exec fallback). Param is filePath (not path). direct hosts only.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | rewrite | |
| content | Yes | File content (UTF-8) | |
| host_id | Yes | ||
| filePath | Yes | Absolute remote path (required name: filePath, not path) | |
| timeoutMs | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description bears full responsibility. It discloses a fallback mechanism (base64-exec) and a host restriction, which adds value beyond the obvious write operation. However, it does not explicitly state overwrite behavior, permissions, or failure handling – significant gaps for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, tightly packed sentence conveys the method, fallback, parameter trap, and a constraint. Every element earns its place; the most important info is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with five parameters, no annotations, and no output schema, this description is far too thin. It lacks usage guidance, behavioral safety disclosures, and parameter semantics beyond a single naming caveat. An agent would need to rely heavily on the incomplete schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 40%, yet the description only clarifies the filePath naming. It provides no elaboration on mode, timeoutMs, or host_id, leaving those parameters ambiguous. The description does not compensate for the low schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action (write remote file), the method (SFTP), and a naming gotcha (filePath). This distinguishes it from siblings like ssh_read_file and ssh_exec, and even pre-empts a common parameter mistake.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It establishes the purpose (writing files) implicitly, which indicates when to use it, but does not explicitly contrast with alternatives. The 'direct hosts only' constraint adds context but does not mention exclusions or alternative tool selection.
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.
4 tool updates
v1.1.0- First observed
ssh_exec - First observed
ssh_list_hosts - First observed
ssh_read_file - First observed
ssh_write_file
TDQS
Scored across 4 tools
Each tool has a clear, unique purpose: listing hosts, executing commands, reading files, and writing files. There is no overlap or ambiguity between the tools, and the descriptions clarify any caveats like 'direct hosts only'.
All tools follow a consistent 'ssh_' prefix followed by a verb_noun pattern: list_hosts, exec, read_file, write_file. The naming is predictable and uniform, making it easy for an agent to infer functionality.
Four tools is a well-scoped number for an SSH host management server. It covers the essential operations without unnecessary bloat, and each tool clearly earns its place.
The tool set covers the core lifecycle of SSH host interaction: listing, executing, reading, and writing. While operations like deleting files or managing host configurations are missing, the common workflows are fully supported, leaving only minor gaps.
Maintenance
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Provides capabilities that let LLM agents perform a range of infrastructure management tasks.
Scoped, audited SSH exec, sessions, and SFTP on your saved servers without exposing credentials
Develop, manage, and debug Railway projects, services, and deployments from within agents.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables LLMs to interact with remote servers via SSH, supporting command execution, file upload/download, and directory listing.7MIT
- AlicenseNot gradedqualityFmaintenanceEnables AI assistants to execute commands and transfer files on remote servers over SSH connections.1MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to securely execute commands, transfer files, and manage port forwarding on remote servers via SSH.132 npm37Apache 2.0
- FlicenseAqualityCmaintenanceEnables LLMs to securely SSH into remote servers, execute commands, and manage files via SFTP including listing, reading, writing, deleting, and renaming files.11-