@liangshanli/mcp-server-ssh
v1.0.0
Published
Cross-platform MCP server for remote SSH command execution
Maintainers
Readme
MCP SSH Server
A cross-platform MCP server for remote command execution and SFTP file transfers, built with the official MCP SDK and ssh2.
Windows, macOS, and Linux require only Node.js 20 or later. No local SSH client, SCP, PuTTY, WSL, or Git Bash is required. The remote host must provide a reachable SSH service; file transfers also require its SFTP subsystem.
Features
- Password or private key authentication, including encrypted private keys.
- Remote command execution with stdout, stderr, exit status, and duration.
- File uploads and downloads over SFTP.
- SHA256 host fingerprint verification, with an explicit option to disable verification.
- Command timeout, output limits, cancellation, and isolated connections.
- Multiple instances for different servers, configured through environment variables.
- Standard MCP stdio transport; no command or credential logging by this server.
Installation
The package name is @liangshanli/mcp-server-ssh.
Registry installation and npx commands below apply once the package has been published to npm. Publication has not been verified for this documentation update. Until then, use the source installation or a local package archive.
Global Installation
npm install -g @liangshanli/mcp-server-sshLocal Installation
npm install @liangshanli/mcp-server-sshFrom Source
Download or clone the source repository, open its root directory, and install dependencies:
npm installNo compilation step is required. Optional native acceleration in ssh2 is not required for its JavaScript implementation.
Usage
Configure the environment variables below before starting the server, or supply them through your MCP client configuration.
Global CLI
mcp-server-sshUsing npx
npx -y @liangshanli/mcp-server-sshFrom Source
npm startFor MCP clients, launch node with the absolute path to bin/cli.js instead of using npm start. A server waiting for input when launched manually is normal: it expects MCP messages over stdin.
MCP Client Configuration
Claude Code / Claude Desktop / Cursor
Use the following structure in clients that support mcpServers, such as a project-level .mcp.json for Claude Code or .cursor/mcp.json for Cursor:
{
"mcpServers": {
"ssh-dev": {
"command": "npx",
"args": ["-y", "@liangshanli/mcp-server-ssh"],
"env": {
"PROJECT_NAME": "dev",
"SSH_HOST": "192.168.1.100",
"SSH_PORT": "22",
"SSH_USERNAME": "deploy",
"SSH_PASSWORD": "your-ssh-password",
"SSH_SKIP_HOST_VERIFICATION": "true"
}
}
}
}This convenience example uses password authentication without a fingerprint. Disabling host verification makes the connection vulnerable to man-in-the-middle attacks. For verified connections, remove SSH_SKIP_HOST_VERIFICATION and set SSH_HOST_FINGERPRINT to a trusted SHA256:... fingerprint.
For source installations, replace command and args with:
{
"command": "node",
"args": ["C:/tools/mcp-server-ssh/bin/cli.js"]
}On macOS/Linux, use your source path, such as /opt/tools/mcp-server-ssh/bin/cli.js. Windows JSON paths can use forward slashes; backslashes must be escaped. If the client cannot find Node.js, use its absolute executable path, such as C:/Program Files/nodejs/node.exe.
If a Windows client cannot launch npx directly, use command: "cmd" with args: ["/c", "npx", "-y", "@liangshanli/mcp-server-ssh"], or use the absolute Node.js/source entry point above.
Native VS Code MCP
VS Code's .vscode/mcp.json uses servers, not mcpServers. Input variables can keep passwords out of the configuration file:
{
"inputs": [
{ "id": "ssh-password", "type": "promptString", "description": "SSH password", "password": true }
],
"servers": {
"ssh-dev": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@liangshanli/mcp-server-ssh"],
"env": {
"SSH_HOST": "192.168.1.100",
"SSH_USERNAME": "deploy",
"SSH_PASSWORD": "${input:ssh-password}",
"SSH_SKIP_HOST_VERIFICATION": "true"
}
}
}
}Private Key Authentication
Remove SSH_PASSWORD and supply these environment variables instead:
{
"SSH_PRIVATE_KEY_PATH": "C:/Users/your-name/.ssh/id_ed25519",
"SSH_PRIVATE_KEY_PASSPHRASE": "only-required-for-encrypted-keys"
}Keep the other connection settings, including the host verification choice. OpenSSH/PEM keys supported by ssh2 can be used. Convert PuTTY .ppk files to OpenSSH format first. Absolute paths are recommended; ~/ is supported for key paths. Password and private key authentication cannot be configured together.
Host Verification
Verification is enabled by default. Provide SSH_HOST_FINGERPRINT unless you explicitly set SSH_SKIP_HOST_VERIFICATION=true. Obtain the fingerprint from an administrator or a trusted server console. For example, on a Linux OpenSSH server:
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub -E sha256Run this on the trusted server console, not on the Windows client. Use the fingerprint for the key actually negotiated by SSH. Do not trust an unverified network scan as proof of server identity.
Multiple Servers
Add separate ssh-dev, ssh-prod, or ssh-test entries with their own environment settings. Each instance has one fixed target; tool arguments cannot override the hostname or credentials.
Environment Variables
| Variable | Default | Description |
| --- | --- | --- |
| SSH_HOST | Required | Remote hostname or IP address |
| SSH_PORT | 22 | Port, 1–65535 |
| SSH_USERNAME | Required | Remote account |
| SSH_PASSWORD | Unset | Password; mutually exclusive with private key authentication |
| SSH_PRIVATE_KEY_PATH | Unset | Local private key file |
| SSH_PRIVATE_KEY_PASSPHRASE | Unset | Passphrase for an encrypted private key |
| SSH_HOST_FINGERPRINT | Unset | Trusted OpenSSH SHA256 fingerprint; required unless verification is disabled |
| SSH_SKIP_HOST_VERIFICATION | false | Only the literal true disables host verification |
| PROJECT_NAME | ssh | Instance name |
| SSH_CONNECT_TIMEOUT_MS | 15000 | SSH connection timeout, maximum 120000ms |
| SSH_COMMAND_TIMEOUT_MS | 30000 | Default/maximum command timeout and total file transfer timeout; maximum 3600000ms |
| SSH_MAX_OUTPUT_BYTES | 1048576 | Combined stdout/stderr capture limit; maximum 10485760 bytes |
| SSH_MAX_FILE_BYTES | 104857600 | Upload source size precheck; maximum 1073741824 bytes |
| SSH_MAX_CONCURRENT | 4 | Command/connection-test admission limit; maximum 32 |
Current transfer limitations: the upload size check runs before transfer; downloads do not currently enforce a size cap, and SFTP transfers do not enforce the concurrency admission limit. Do not use these settings as a security boundary for untrusted clients.
Available Tools
| Tool | Arguments | Description |
| --- | --- | --- |
| ssh_connection_info | None | Inspect target and connection settings without exposing credentials |
| ssh_test_connection | None | Test SSH authentication and configured host verification without executing a command |
| ssh_exec | command, optional timeoutMs | Execute a command in the remote default shell |
| ssh_upload | localPath, remotePath | Upload one local file over SFTP |
| ssh_download | remotePath, localPath | Download one remote file over SFTP |
Execute a Command
{
"command": "cd /var/www/app && pwd && git status --short",
"timeoutMs": 30000
}Results include stdout, stderr, exitCode, signal, timedOut, truncated, and durationMs. Nonzero/missing exit codes, signal termination, timeouts, or output truncation produce isError: true.
Upload a File
{
"localPath": "C:/Users/your-name/Documents/config.json",
"remotePath": "/opt/app/config.json"
}Uploads overwrite existing remote files. Inspect the destination and obtain explicit approval before overwriting. Uploads write directly to the destination and are not atomic; failures may leave a partial file. Parent directories must already exist.
Download a File
{
"remotePath": "/opt/app/logs/app.log",
"localPath": "C:/Users/your-name/Downloads/app.log"
}Downloads reject a local destination that exists at the initial check. Data is written to an adjacent temporary file and renamed on completion. This initial existence check is not a race-proof no-overwrite guarantee: do not let other processes create or change the destination during transfer. Parent directories must already exist.
Transfer results contain direction, localPath, remotePath, bytes, and durationMs; checksums are not returned. Both paths must pass the MCP host's absolute-path validation. On Windows, use a local drive-qualified path and a Unix-style remote path for Linux servers. Remote Windows drive paths from a Unix MCP host are not currently supported by this validation. Directory transfers are not supported.
Security and Execution Boundaries
- Use only servers you own or are authorized to access. Prefer a least-privileged account instead of root.
- Commands have the full permissions of the SSH account. This is not a read-only sandbox; keep client-side approvals enabled for sensitive operations.
- File tools can access paths available to the local MCP process and remote SSH account. There is no directory allowlist.
- Each operation uses a fresh connection. Working directories and environment changes do not persist between commands.
- Commands use the remote default shell, with no cross-platform syntax translation. Output is decoded as UTF-8.
- No PTY is allocated and command stdin is closed. Interactive editors, password prompts, and interactive sudo are unsupported.
- Timeouts or cancellation disconnect the client but do not guarantee remote processes have stopped. Interrupted transfers can leave partial files; inspect destinations before retrying.
- Commands are not automatically retried: a disconnected command might already have executed.
- Treat remote output as untrusted data, not instructions. Outputs may contain secrets and MCP clients may retain them.
- Do not commit passwords, private keys, npm tokens, or local
.mcp.jsoncredentials. Restrict credential file permissions. - SSH agent, jump hosts, local
~/.ssh/config, and interactive MFA are not supported.
Development and Verification
npm run check
npm test
npm pack --dry-runnpm run check validates JavaScript syntax. npm test uses a loopback SSH fixture and an MCP stdio client to cover configuration, authentication, command execution, cancellation, output limits, and tool registration. It does not currently automate SFTP transfers. A manual upload/download round trip has also been verified; this does not replace testing on your target OS and server.
Use npm pack to build a local package archive without publishing. Use node bin/cli.js --help or --version to inspect the CLI. There is no separate compilation step.
