A Model Context Protocol (MCP) SSH client server that provides autonomous SSH operations for GitHub Copilot and VS Code. Enable natural language SSH automation without manual prompts or GUI interactions.
Official MCP Registry entry: io.github.oaslananka/mcp-ssh-tool
Registry metadata: https://registry.modelcontextprotocol.io/v0.1/servers/io.github.oaslananka%2Fmcp-ssh-tool/versions/latest
- Global install (recommended):
npm install -g mcp-ssh-tool - One-off run:
npx mcp-ssh-tool
Add to your MCP configuration (mcp.json, .vscode/mcp.json, or the Claude Desktop MCP config):
{
"servers": {
"ssh-mcp": {
"type": "stdio",
"command": "mcp-ssh-tool",
"args": []
}
}
}Once configured, you can use natural language with your MCP client:
- SSH Connection: "Connect to server 192.168.1.100 as admin using SSH key"
- File Operations: "Read the content of /etc/nginx/nginx.conf on the server"
- Command Execution: "Run 'systemctl status nginx' on the remote server"
- Package Management: "Install htop package on Ubuntu server"
- Service Control: "Restart the nginx service"
- Claude Desktop: "connect to my server and check disk usage"
- Install a package/service stack: "install nginx on my remote server"
- Read a config file: "read the file /etc/nginx/nginx.conf"
- Restart a service: "restart the nginx service"
- Browse logs: "list files in /var/log"
ssh_open_session- Establish SSH connection with various auth methodsssh_close_session- Close SSH sessionssh_list_sessions- List all active SSH sessionsssh_ping- Check if a session is alive and responsivessh_list_configured_hosts- List hosts from ~/.ssh/configssh_resolve_host- Resolve host alias from SSH configproc_exec- Execute commands remotely (with optional timeout)proc_sudo- Execute commands with sudo privilegesfs_read,fs_write,fs_list,fs_stat,fs_mkdirp,fs_rmrf,fs_rename- File system operationsensure_package- Package management withpresentandabsentstatesensure_service- Service control includingrestartedensure_lines_in_file- File line management withpresentandabsentstatespatch_apply- Apply patches to filesos_detect- System information detectionget_metrics- Server metrics in JSON or Prometheus format
The SSH MCP Server acts as a bridge between GitHub Copilot and remote systems via SSH. It supports:
- Non-interactive SSH operations - No prompts or GUI interactions
- Multiple authentication methods - Password, SSH keys, or SSH agent
- Session management - Automatic connection pooling with TTL and LRU eviction
- File system operations - Read, write, list, and manage remote files via SFTP, with SSH-shell fallbacks for hosts that do not expose an SFTP subsystem
- Process execution - Run commands and sudo operations remotely
- High-level automation - Package management, service control, and configuration management
- Security - Automatic redaction of sensitive data in logs
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ GitHub Copilot │────│ SSH MCP Server │────│ Remote Systems │
│ / VS Code │ │ │ │ (via SSH) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
│ MCP stdio protocol │ Session management │ SSH + optional SFTP
│ │ LRU cache + TTL │
│ │ Auth strategies │
Some embedded targets expose SSH command execution but do not ship an SFTP
subsystem, which is common with Dropbear- or BusyBox-based systems. In that
case ssh_open_session still succeeds and reports sftpAvailable: false.
Core file tools such as fs_read, fs_write, fs_stat, fs_list,
fs_mkdirp, fs_rmrf, and fs_rename automatically fall back to shell-based
implementations.
- Node.js ≥ 20 (LTS)
- SSH access to target systems
- SSH keys or credentials for authentication
npm install -g mcp-ssh-toolgit clone https://github.com/oaslananka/mcp-ssh-tool.git
cd mcp-ssh-tool
npm install
npm run build
npm link--help/-h: Show usage and examples.--version/-v: Print version.--stdio: Force stdio mode (default).
Note: This is an MCP stdio server. The terminal is not an interactive shell; use an MCP client (Claude Desktop, VS Code MCP, etc.) or send JSON-RPC over stdio.
- Linux / macOS: Uses POSIX shell wrappers with safe quoting. Default temp directory:
/tmp. - Windows targets: Requires OpenSSH server/agent; key discovery checks
C:\\Users\\<you>\\.ssh\\. Commands are wrapped for PowerShell-safe execution. Package/service helpers are intentionally disabled on Windows targets. - Host keys: Host key checking is relaxed by default. Set
STRICT_HOST_KEY_CHECKING=trueand optionallyKNOWN_HOSTS_PATHto enforce verification.
npm run setup:chatgptThis command automatically configures ChatGPT Desktop to use mcp-ssh-tool.
Add to your ChatGPT Desktop MCP config:
- macOS:
~/Library/Application Support/ChatGPT/mcp.json - Windows:
%APPDATA%\ChatGPT\mcp.json - Linux:
~/.config/chatgpt/mcp.json
{
"mcpServers": {
"ssh-mcp-server": {
"name": "ssh-mcp-server",
"command": "npx",
"args": ["-y", "mcp-ssh-tool"]
}
}
}For detailed usage, see docs/chatgpt-usage.md.
Open VS Code and press Ctrl+Shift+P, then run "MCP: Open User Configuration".
Add to your mcp.json:
{
"servers": {
"ssh-mcp": {
"type": "stdio",
"command": "mcp-ssh-tool",
"args": []
}
}
}Create .vscode/mcp.json in your workspace:
{
"servers": {
"ssh-mcp": {
"type": "stdio",
"command": "mcp-ssh-tool",
"args": []
}
}
}- Restart VS Code
- Open Copilot Chat
- The SSH MCP tools should appear in the available tools list
- Test with: "Connect to 192.168.1.100 as admin and run 'uname -a'"
"Connect to 10.11.12.13 as deployer with password 'mypass' and run 'df -h'"
"Connect to server.example.com as admin, read /etc/nginx/nginx.conf and show me the server blocks"
"Connect to 192.168.1.50 as root, install htop package, start nginx service, and list /var/www contents"
"Connect to web-server as admin, add these lines to /etc/hosts:
192.168.1.10 db-server
192.168.1.20 cache-server
Then restart networking service"
"connect to my server and check disk usage"
"install nginx on my remote server"
"read the file /etc/nginx/nginx.conf"
"restart the nginx service"
"list files in /var/log"
- Multiple sessions: Open one session per host or environment and keep them alive with
ssh_list_sessionsandssh_pingwhen you are switching between production, staging, and development machines. - SFTP fallback for BusyBox/Dropbear: On embedded systems that do not expose an SFTP subsystem,
ssh_open_sessioncan still succeed withsftpAvailable: false, and the corefs_*tools automatically fall back to shell-based implementations. - Host key verification: Set
STRICT_HOST_KEY_CHECKING=truein the MCP server environment and optionallyKNOWN_HOSTS_PATHfor stricter production-grade SSH verification.
{
"host": "example.com",
"username": "admin",
"port": 22,
"auth": "auto",
"password": "optional",
"privateKey": "optional-inline-key",
"privateKeyPath": "optional-path",
"passphrase": "optional",
"useAgent": false,
"readyTimeoutMs": 20000,
"ttlMs": 900000
}Returns:
{
"sessionId": "ssh-1645123456789-1",
"host": "example.com",
"username": "admin",
"expiresInMs": 900000
}{
"sessionId": "ssh-1645123456789-1"
}ssh_list_sessionsreturns active sessions with remaining TTL.ssh_pingchecks liveness and latency for a session.ssh_list_configured_hostsreads~/.ssh/config.ssh_resolve_hostexpands an SSH host alias into connection parameters.
{
"sessionId": "ssh-1645123456789-1",
"command": "ls -la /home",
"cwd": "/tmp",
"env": {
"DEBUG": "1"
},
"timeoutMs": 30000
}{
"sessionId": "ssh-1645123456789-1",
"command": "systemctl restart nginx",
"password": "sudo-password",
"cwd": "/etc",
"timeoutMs": 30000
}Both return:
{
"code": 0,
"stdout": "command output",
"stderr": "",
"durationMs": 245
}fs_read
{
"sessionId": "ssh-1645123456789-1",
"path": "/etc/hosts",
"encoding": "utf8"
}fs_write
{
"sessionId": "ssh-1645123456789-1",
"path": "/tmp/config.txt",
"data": "server_name example.com;\nlisten 80;",
"mode": 420
}fs_statreturnssize,mtime,mode, andtype.fs_listreturns{ "entries": [...], "nextToken": "optional" }.fs_mkdirpcreates directories recursively.fs_rmrfremoves files or directories recursively.fs_renamerenames or moves a path.
{
"sessionId": "ssh-1645123456789-1",
"name": "nginx",
"state": "present",
"sudoPassword": "optional"
}state supports present and absent.
{
"sessionId": "ssh-1645123456789-1",
"name": "nginx",
"state": "restarted",
"sudoPassword": "optional"
}state supports started, stopped, restarted, enabled, and disabled.
{
"sessionId": "ssh-1645123456789-1",
"path": "/etc/hosts",
"lines": [
"192.168.1.10 db-server",
"192.168.1.20 cache-server"
],
"state": "present",
"createIfMissing": true,
"sudoPassword": "optional"
}state supports present and absent.
{
"sessionId": "ssh-1645123456789-1",
"path": "/etc/hosts",
"diff": "@@ -1 +1 @@\n-old\n+new"
}Returns remote platform, distro, version, package manager, init system, shell, and temp directory.
Returns server metrics. Default output is JSON; optional { "format": "prometheus" } emits Prometheus text format.
The server supports multiple authentication methods with automatic fallback:
- Password (if provided)
- SSH Key (inline → path → auto-discovery)
- SSH Agent (if available)
The server automatically searches for SSH keys in:
~/.ssh/id_ed25519~/.ssh/id_rsa~/.ssh/id_ecdsa
Note: DSA keys (
id_dsa) are no longer supported due to security concerns.
Custom key directory: Set SSH_DEFAULT_KEY_DIR environment variable.
Password Authentication:
{
"host": "server.com",
"username": "admin",
"auth": "password",
"password": "secret"
}SSH Key (inline):
{
"host": "server.com",
"username": "admin",
"auth": "key",
"privateKey": "-----BEGIN PRIVATE KEY-----\n...",
"passphrase": "optional"
}SSH Key (file path):
{
"host": "server.com",
"username": "admin",
"auth": "key",
"privateKeyPath": "/home/user/.ssh/id_rsa"
}SSH Agent:
{
"host": "server.com",
"username": "admin",
"auth": "agent"
}| Variable | Description | Default |
|---|---|---|
LOG_LEVEL |
Logging level (error, warn, info, debug) |
info |
STRICT_HOST_KEY_CHECKING |
Enable strict SSH host key verification | false |
KNOWN_HOSTS_PATH |
Custom known_hosts file path |
~/.ssh/known_hosts |
SSH_DEFAULT_KEY_DIR |
SSH key search directory | ~/.ssh |
SSH_MCP_MAX_SESSIONS |
Maximum concurrent sessions | 20 |
SSH_MCP_SESSION_TTL |
Session TTL in milliseconds | 900000 |
SSH_MCP_COMMAND_TIMEOUT |
Default command timeout in milliseconds | 30000 |
SSH_MCP_DEBUG |
Enable debug logging | false |
SSH_MCP_RATE_LIMIT |
Enable rate limiting (true / false) |
true |
- Connection timeout: 20 seconds
- Session TTL: 15 minutes
- Max concurrent sessions: 20
- Host key checking: Relaxed (disabled by default)
The server returns structured error codes for machine-readable error handling:
- EAUTH - Authentication failed
- ECONN - Connection error
- ETIMEOUT - Operation timeout
- ENOSUDO - Sudo operation failed
- EPMGR - Package manager not found
- EFS - File system operation failed
- EPATCH - Patch application failed
- EBADREQ - Invalid request parameters
Each error includes:
name: Error class namecode: Machine-readable error codemessage: Human-readable error messagehint: Optional suggestion for resolution
Sensitive data is automatically redacted from logs:
- Passwords
- Private keys
- Passphrases
- Sudo passwords
- SSH agent socket paths
- Configurable host key verification
- Support for known_hosts files
- Connection timeout enforcement
- Automatic session cleanup
- TTL-based session expiration
- LRU cache eviction
- Graceful connection cleanup
- No persistent credential storage
git clone https://github.com/oaslananka/mcp-ssh-tool.git
cd mcp-ssh-tool
npm installnpm run build # Compile TypeScript
npm run dev # Watch mode compilation
npm run test # Run unit tests
npm run test:e2e # Run E2E tests (requires RUN_SSH_E2E=1)
npm run lint # Type-check (no emit)
npm run format # Run Prettier
npm run test:coverage
npm run docsUnit Tests:
npm testE2E Tests (optional):
RUN_SSH_E2E=1 npm run test:e2eMIT License
Copyright (c) 2025 Osman Aslan (oaslananka)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
E2E tests require a local Docker container or SSH server for testing.
- Follow TypeScript and ESLint rules
- Add tests for new features
- Update documentation
- Ensure all tests pass
- Use conventional commit messages
MIT License - see LICENSE file for details.
- Model Context Protocol
- Anthropic MCP on GitHub
- Glama MCP Server Listing
- LobeHub MCP Listing
- VS Code MCP Guide - VS Code Copilot extensibility
- GitHub Copilot - GitHub Copilot documentation