🔐 SSH MCP Server
Give AI agents secure access to your VPS servers via SSH
Execute commands, transfer files, manage processes — all through Model Context Protocol
Quick Start • Features • IDE Integration • Tools • Security
🚀 Quick Start
Install
# Via pip
pip install mcp-ssh-vps
# Via uvx (recommended for MCP)
uvx mcp-ssh-vps
Add Your First Server
# Interactive setup
uvx mcp-ssh-vps --help
# Or use the CLI
sshmcp-cli server add --name prod --host 192.168.1.100 --user deploy
sshmcp-cli server test prod
Connect to Your AI Agent
Add to your AI IDE config and start managing servers with natural language!
"Deploy my app to the production server"
"Check disk space on all servers"
"Restart nginx on web1 and web2"
✨ Features
| Feature | Description |
|---|---|
| 🖥️ Execute Commands | Run any shell command on remote servers |
| 📁 File Operations | Read, write, and list files via SFTP |
| 📂 Directory Transfer | rsync-like upload/download/sync directories |
| 🔗 SSH Tunnels | Local and remote port forwarding |
| 💻 Interactive Shell | PTY-based shell sessions for interactive work |
| ⚙️ Process Management | Control systemd, pm2, supervisor services |
| 📊 Command History | Track and search executed commands |
| 🚨 Monitoring Alerts | CPU/memory/disk usage alerts |
| 🏷️ Server Tags | Group servers with tags for batch operations |
| 🔄 Batch Execution | Run commands on multiple servers in parallel |
| 🔒 Security Profiles | Strict, moderate, or full access levels |
| 📝 Audit Logging | Track all operations for compliance |
| 🔑 SSH Keys & Passwords | Key, password, and SSH-agent authentication |
🔌 IDE Integration
Note: Config is auto-loaded from
~/.sshmcp/machines.jsonby default. No env variables required!
Claude Code
claude mcp add ssh-vps -- uvx mcp-ssh-vps
Or add to ~/.claude.json:
{
"mcpServers": {
"ssh-vps": {
"command": "uvx",
"args": ["mcp-ssh-vps"]
}
}
}
Factory Droid
droid mcp add ssh-vps "uvx mcp-ssh-vps"
Or add to ~/.factory/mcp.json:
{
"mcpServers": {
"ssh-vps": {
"command": "uvx",
"args": ["mcp-ssh-vps"]
}
}
}
Cursor
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"ssh-vps": {
"command": "uvx",
"args": ["mcp-ssh-vps"]
}
}
}
Qwen Code
qwen mcp add ssh-vps uvx mcp-ssh-vps
Or add to ~/.qwen/settings.json:
{
"mcpServers": {
"ssh-vps": {
"command": "uvx",
"args": ["mcp-ssh-vps"]
}
}
}
Claude Desktop
Add to Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"ssh-vps": {
"command": "uvx",
"args": ["mcp-ssh-vps"]
}
}
}
VS Code + Continue
Add to .continue/config.json:
{
"experimental": {
"modelContextProtocolServers": [
{
"transport": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-ssh-vps"]
}
}
]
}
}
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"ssh-vps": {
"command": "uvx",
"args": ["mcp-ssh-vps"]
}
}
}
OpenAI Codex CLI
codex --mcp-config '{"ssh-vps": {"command": "uvx", "args": ["mcp-ssh-vps"]}}'
Any MCP-Compatible Client
Generic stdio configuration:
{
"command": "uvx",
"args": ["mcp-ssh-vps"]
}
Custom config path? Add
"env": {"SSHMCP_CONFIG_PATH": "/custom/path.json"}
🛠️ Tools Reference
Command Execution
| Tool | Description | Example |
|---|---|---|
execute_command |
Run command on server | execute_command("prod", "docker ps") |
execute_command_streaming |
Run with progress updates | execute_command_streaming("prod", "apt update") |
execute_on_multiple |
Run on multiple servers | execute_on_multiple(["*"], "uptime") |
Server Management
| Tool | Description | Example |
|---|---|---|
list_servers |
List all servers | list_servers() or list_servers(tag="web") |
add_server |
Add new server | add_server("web1", "1.2.3.4", "root") |
remove_server |
Remove server | remove_server("old-server") |
test_connection |
Test SSH connection | test_connection("prod") |
File Operations
| Tool | Description | Example |
|---|---|---|
read_file |
Read remote file | read_file("prod", "/var/log/app.log") |
upload_file |
Upload file | upload_file("prod", "/tmp/script.sh", "#!/bin/bash\n...") |
list_files |
List directory | list_files("prod", "/var/log") |
Process Management
| Tool | Description | Example |
|---|---|---|
manage_process |
Control services | manage_process("prod", "restart", "nginx") |
Help & Info
| Tool | Description | Example |
|---|---|---|
get_help |
Get documentation | get_help("examples") |
get_allowed_commands |
View security config | get_allowed_commands("prod") |
get_server_info |
Server details | get_server_info("prod") |
Interactive Shell Sessions
| Tool | Description | Example |
|---|---|---|
shell_start |
Start PTY shell | shell_start("prod") |
shell_send |
Send to shell | shell_send(session_id, "ls -la") |
shell_recv |
Receive output | shell_recv(session_id) |
shell_close |
Close session | shell_close(session_id) |
shell_list |
List sessions | shell_list() |
Command History
| Tool | Description | Example |
|---|---|---|
get_command_history |
View history | get_command_history(host="prod", limit=50) |
search_command_history |
Search | search_command_history("docker") |
get_command_stats |
Statistics | get_command_stats() |
Directory Transfer (rsync-like)
| Tool | Description | Example |
|---|---|---|
upload_directory |
Upload dir to remote | upload_directory("prod", "./dist", "/var/www") |
download_directory |
Download dir | download_directory("prod", "/var/log", "./logs") |
sync_directory |
Sync with delete | sync_directory("prod", "./app", "/opt/app", "upload") |
Port Forwarding (SSH Tunnels)
| Tool | Description | Example |
|---|---|---|
forward_local |
Local tunnel | forward_local("prod", 5433, "localhost", 5432) |
forward_remote |
Reverse tunnel | forward_remote("prod", 8080, "localhost", 3000) |
list_forwards |
List tunnels | list_forwards() |
close_forward |
Close tunnel | close_forward("local-1") |
Monitoring & Alerts
| Tool | Description | Example |
|---|---|---|
get_alerts |
View alerts | get_alerts(host="prod") |
get_active_alerts |
Active only | get_active_alerts() |
clear_alert |
Clear alert | clear_alert("prod", "cpu") |
🏷️ Server Tags & Batch Operations
Add servers with tags
add_server("web1", "192.168.1.10", "deploy", tags=["production", "web"])
add_server("web2", "192.168.1.11", "deploy", tags=["production", "web"])
add_server("db1", "192.168.1.20", "deploy", tags=["production", "database"])
Filter by tag
list_servers(tag="web") # Only web servers
list_servers(tag="production") # All production servers
Execute on tagged servers
execute_on_multiple(["tag:web"], "nginx -t") # All web servers
execute_on_multiple(["tag:production"], "uptime") # All production
execute_on_multiple(["*"], "df -h") # ALL servers
🔒 Security
Security Profiles
| Profile | Allowed Commands | Use Case |
|---|---|---|
strict |
git, ls, cat, df, uptime |
Read-only monitoring |
moderate |
+ docker, npm, systemctl, pm2 |
Standard DevOps |
full |
All commands (except rm -rf /) |
Full access |
Set security level
add_server("prod", "1.2.3.4", "root", security_level="full")
Audit Logging
All commands are logged with timestamps, user, and results:
2024-01-15T10:30:00Z | prod | root | docker ps | exit_code=0 | 150ms
📁 Configuration
Config Location
~/.sshmcp/machines.json
Example Config
{
"machines": [
{
"name": "production",
"host": "192.168.1.100",
"port": 22,
"user": "deploy",
"auth": {
"type": "key",
"key_path": "~/.ssh/id_rsa"
},
"security": {
"allowed_commands": [".*"],
"forbidden_commands": [".*rm\\s+-rf\\s+/$"],
"timeout_seconds": 120
},
"tags": ["production", "web"],
"description": "Main production server"
}
]
}
Environment Variable
export SSHMCP_CONFIG_PATH=/custom/path/machines.json
📖 Usage Examples
Check status of all servers
User: Check the status of all my servers
AI: I'll run uptime on all configured servers...
execute_on_multiple(["*"], "uptime && df -h | head -5")
Deploy application
User: Deploy the latest code to production
AI: I'll pull the latest changes and restart the service...
execute_command("prod", "cd /app && git pull origin main")
execute_command("prod", "npm install --production")
execute_command("prod", "pm2 restart all")
Debug server issues
User: Why is the web server slow?
AI: Let me check system resources and logs...
execute_command("web1", "top -bn1 | head -20")
execute_command("web1", "tail -50 /var/log/nginx/error.log")
execute_command("web1", "free -m && df -h")
🚀 Advanced Features
Transport Modes
# Default stdio (for MCP clients like Claude Code)
uvx mcp-ssh-vps
# SSE transport for web integration
uvx mcp-ssh-vps --transport sse
# Streamable HTTP for production
uvx mcp-ssh-vps --transport streamable-http
WebSocket Shell (Real-time)
For real-time interactive shells, integrate with your web app:
from fastapi import FastAPI, WebSocket
from sshmcp.ws import ShellWebSocketHandler
app = FastAPI()
handler = ShellWebSocketHandler()
@app.websocket("/ws/shell/{host}")
async def shell(websocket: WebSocket, host: str):
await handler.handle(websocket, host)
Client protocol:
// Connect
const ws = new WebSocket("ws://localhost:8000/ws/shell/prod");
// Send command
ws.send(JSON.stringify({type: "input", data: "ls -la\n"}));
// Resize terminal
ws.send(JSON.stringify({type: "resize", width: 120, height: 40}));
// Receive output
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg.type === "output") terminal.write(msg.data);
};
Streaming Commands
For long-running commands with progress updates:
# Regular (waits for completion)
execute_command("prod", "apt update")
# Streaming (reports progress)
execute_command_streaming("prod", "apt update")
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
git clone https://github.com/LuxVTZ/sshmcp.git
cd sshmcp
pip install -e ".[dev]"
pytest
📄 License
MIT License - see LICENSE for details.
Made with ❤️ for the AI agent ecosystem
PyPI •
GitHub •
Issues
Metadata
Release files for mcp-ssh-vps 0.7.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| mcp_ssh_vps-0.7.1.tar.gz | 101.4 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_ssh_vps-0.7.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 192.9 kB
Release files / mcp_ssh_vps-0.7.1.tar.gz
| Download URL | mcp_ssh_vps-0.7.1.tar.gz |
|---|---|
| Size | 101.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2c4d92a21c6ba1cdb5faedd22466060696769261e658f6da4985f940413afc33
|
|
BLAKE2b-256 checksum How to use checksums |
c8d56ded8edb7819cb995f59993fa80e5601e24fc2d1666f5a92595ea9c48bb7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 22, 2026.
Transparency logRelease files / mcp_ssh_vps-0.7.1-py3-none-any.whl
| Download URL | mcp_ssh_vps-0.7.1-py3-none-any.whl |
|---|---|
| Size | 91.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
467aff3677568300eaf7baf663a0fd621b03dc4a084bac147d3cebfdef3dc60f
|
|
BLAKE2b-256 checksum How to use checksums |
dc6437afc31a20a295b49967b39ff7a430681ef67b15199aa385dd3ff297d1f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 22, 2026.
Transparency logSecurity for mcp-ssh-vps 0.7.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for mcp_ssh_vps-0.7.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.