mcp-ssh
Allows running commands on Cisco IOS/NX-OS devices via a stateful PTY shell, supporting proprietary CLI interactions.
Allows running stateless commands on Linux servers via SSH exec, with safety and audit logging.
Allows running commands on MikroTik RouterOS devices via a stateful PTY shell, supporting proprietary CLI.
Allows running commands on OpenWRT/DD-WRT devices via SSH exec (POSIX shell).
Allows running commands on Raspberry Pi (Linux-based) via SSH exec.
Click on "Install 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., "@mcp-sshrun 'df -h' on home-server"
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.
mcp-ssh
MCP server for running commands over persistent SSH sessions. Connects AI assistants (Claude, Cursor, etc.) to remote hosts — Linux servers, routers, switches, and any SSH-accessible device.
Built with the help of Claude AI (Anthropic).
Features
Persistent SSH sessions — connections are pooled and reused; no reconnect overhead per command
Two execution modes — stateless
execfor POSIX hosts, stateful PTY shell for interactive CLIs (Cisco, MikroTik, etc.)Safety layer — configurable regex deny-list blocks destructive commands (
rm -rf /,mkfs,reboot, etc.)Append-only audit log — every command, decision, and exit code recorded to JSONL
Two transports —
stdiofor local use,SSEwith Bearer token auth for remote/Docker deploymentNo secrets in config — passwords and passphrases are referenced by environment variable name, not stored
Related MCP server: MCP ShellKeeper
MCP Tools
Tool | Description |
| List configured hosts (no secrets exposed) |
| Open or reuse a persistent session |
| Run a stateless command via exec (POSIX) |
| Run a command in the interactive PTY shell (stateful, required for CLI devices) |
| Show active sessions and idle times |
| Close a session |
All tools accept confirm_dangerous=true to override a safety block when the command is intentional.
Quick Start
Install
git clone https://github.com/your-username/mcp-ssh
cd mcp-ssh
poetry config virtualenvs.in-project true --local
poetry installConfigure hosts
Use the interactive manager to add, edit, or remove hosts without touching YAML by hand:
python manage_hosts.py
# or with an explicit config path:
MCP_SSH_CONFIG=/path/to/hosts.yaml python manage_hosts.pyThe script provides a menu-driven terminal UI: list hosts, add, edit (current values shown as defaults), and delete with confirmation. Validates IP/hostname, port range, regex syntax, and warns if a referenced env var is not exported.
Alternatively, copy hosts.example.yaml and edit manually:
hosts:
home-server:
host: 192.168.1.10
user: admin
auth:
method: key
key_path: ~/.ssh/id_ed25519
shell: posix
cisco-switch:
host: 192.168.1.1
user: cisco
auth:
method: password
password_env: CISCO_PASS # name of env var, not the password itself
shell: cli
prompt_regex: '[\w.-]+[>#]\s*$'
settings:
idle_timeout: 600
command_timeout: 60
audit_log: ~/.mcp_ssh/audit.logExport secrets before starting:
export MCP_SSH_CONFIG=/path/to/hosts.yaml
export CISCO_PASS='my-password'Run (stdio — local use)
poetry run mcp-sshRegister poetry run mcp-ssh (with env vars set) as a stdio MCP server in your AI assistant.
Run (SSE — remote / Docker)
export MCP_TRANSPORT=sse
export MCP_AUTH_TOKEN=$(python -c "import secrets; print(secrets.token_hex(32))")
export MCP_PORT=8000
poetry run mcp-sshMCP_HOST defaults to 127.0.0.1. Set MCP_HOST=0.0.0.0 only when a reverse proxy handles TLS and auth in front.
Shell Types
Device |
| Reason |
Linux / Raspberry Pi |
| Standard POSIX shell, has |
OpenWRT / DD-WRT |
| BusyBox ash — POSIX compatible |
Cisco IOS / NX-OS |
| Proprietary CLI, no |
MikroTik RouterOS |
| Proprietary CLI |
Managed switches |
| Proprietary CLI |
cli hosts require prompt_regex — a regex matching the device prompt (e.g. [\w.-]+[>#]\s*$).
Safety
Default deny patterns block:
rm -rf / mkfs reboot shutdown
dd of=/dev/* write erase erase startup-configExtend or override in hosts.yaml:
settings:
deny_patterns:
- "rm\\s+-rf\\s+/"
- "your-custom-pattern"Pass confirm_dangerous=true to any tool to override a block when you know it is intentional.
Docker / Portainer
See docs/portainer-deployment.md for a full guide including nginx reverse proxy setup.
docker compose up -dKey environment variables for the container:
Variable | Required | Default | Description |
| yes | — | Path to |
| no |
| Set to |
| yes (SSE) | — | Bearer token; required in SSE mode |
| no |
| Bind address |
| no |
| Bind port |
Tests
# Unit tests (no Docker required)
poetry run pytest -m "not integration"
# Full suite (requires docker-compose SSH server)
docker compose up -d
poetry run pytest
docker compose downArchitecture
AI Agent (Claude / Cursor)
│ stdio or HTTP SSE + Bearer token
▼
mcp-ssh server
├── safety.classify_command() ← regex deny-list
├── audit.log() ← append-only JSONL
└── SessionManager.get() ← pooled SSH connections
├── SSHConnection.run_exec() ← POSIX stateless
└── SSHConnection.run_in_shell() ← PTY stateful (ShellSession)Key modules: mcp_ssh/server.py · mcp_ssh/session_manager.py · mcp_ssh/connection.py · mcp_ssh/safety.py · mcp_ssh/audit.py
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/seraved/mcp_ssh'
If you have feedback or need assistance with the MCP directory API, please join our Discord server