Skip to main content
Glama

SSH Read-Only MCP Server

by kunwarmahen
README.md8.98 kB
# SSH Read-Only MCP Server A secure Model Context Protocol (MCP) server that enables remote SSH command execution with strict read-only enforcement. Perfect for safely delegating SSH access to Claude while preventing accidental or malicious write operations. ## Features ✅ **Read-Only Command Enforcement** – Only allows safe, read-only commands ✅ **SSH Connection Pooling** – Support multiple simultaneous connections ✅ **Command Validation** – Blocks dangerous patterns and write operations ✅ **Multicast Discovery** – Auto-announces on network for easy discovery ✅ **Flexible Transport** – Stdio, HTTP, or Streamable-HTTP modes ✅ **Comprehensive Logging** – Full audit trail in `ssh_mcp.log` ✅ **Environment Configuration** – Fully configurable via .env ## Installation ### Prerequisites - Python 3.8+ - `uv` package manager ### Setup ```bash # Clone or create project directory mkdir ssh-mcp-server cd ssh-mcp-server # Initialize uv project (if needed) uv init # Install dependencies uv pip install fastmcp paramiko python-dotenv ``` Or use `pyproject.toml`: ```toml [project] name = "ssh-mcp-server" version = "0.1.0" dependencies = [ "fastmcp>=0.1.0", "paramiko>=3.0.0", "python-dotenv>=1.0.0", ] ``` Then install: ```bash uv sync ``` ## Configuration Create a `.env` file in the project root: ```env # Transport mode: stdio (default), http, or streamable-http MCP_TRANSPORT=stdio # Server identification MCP_SERVER_NAME=SSH Read-Only MCP Server # HTTP mode settings (if using http/streamable-http) MCP_HOST=0.0.0.0 MCP_PORT=3000 # Multicast discovery MCP_ENABLE_BROADCAST=true MCP_BROADCAST_INTERVAL=30 ``` ### Environment Variables | Variable | Default | Description | | ------------------------ | -------------------------- | -------------------------------------------------------------- | | `MCP_TRANSPORT` | `stdio` | Communication transport: `stdio`, `http`, or `streamable-http` | | `MCP_SERVER_NAME` | `SSH Read-Only MCP Server` | Display name for the server | | `MCP_HOST` | `0.0.0.0` | Bind address for HTTP mode | | `MCP_PORT` | `3000` | Port for HTTP mode | | `MCP_ENABLE_BROADCAST` | `true` | Enable multicast discovery announcements | | `MCP_BROADCAST_INTERVAL` | `30` | Seconds between broadcast announcements | ## Usage ### Start the Server **Stdio mode (default):** ```bash uv run ssh_readonly_fastmcp_mcast.py ``` **HTTP mode with multicast discovery:** ```bash MCP_TRANSPORT=http MCP_PORT=3000 uv run ssh_readonly_fastmcp_mcast.py ``` **HTTP mode without broadcasting:** ```bash MCP_ENABLE_BROADCAST=false MCP_TRANSPORT=http MCP_PORT=3000 uv run ssh_readonly_fastmcp_mcast.py ``` ### Available Tools #### 1. `ssh_connect` Establish an SSH connection to a remote machine. **Parameters:** - `host` (required) – Remote host IP or hostname - `username` (required) – SSH username - `port` (optional, default: 22) – SSH port - `key_filename` (optional) – Path to private key file (recommended) - `password` (optional) – SSH password (fallback) **Example:** ``` Connect to 192.168.1.100 as user 'admin' with private key host: 192.168.1.100 username: admin key_filename: /home/user/.ssh/id_rsa ``` #### 2. `ssh_execute` Execute a read-only command on the connected remote machine. **Parameters:** - `host` (required) – Remote host (must be connected first) - `username` (required) – SSH username - `command` (required) – Read-only command to execute - `port` (optional, default: 22) – SSH port **Example:** ``` Run 'ls -la /home' on connected server host: 192.168.1.100 username: admin command: ls -la /home ``` #### 3. `ssh_disconnect` Close an SSH connection. **Parameters:** - `host` (required) – Remote host - `username` (required) – SSH username - `port` (optional, default: 22) – SSH port #### 4. `ssh_list_connections` View all active SSH connections. **Parameters:** None #### 5. `ssh_get_allowed_commands` Retrieve the list of allowed read-only commands. **Parameters:** None ## Allowed Commands The server permits the following read-only operations: - **File operations:** `cat`, `ls`, `file`, `head`, `tail`, `find`, `locate` - **System info:** `ps`, `top`, `df`, `du`, `free`, `uname`, `hostname`, `uptime` - **Network:** `netstat`, `ss`, `ifconfig`, `ip`, `curl`, `wget`, `dig`, `nslookup`, `ping`, `traceroute` - **Process management:** `lsof`, `systemctl`, `service` - **Text processing:** `grep`, `awk`, `sed`, `wc` - And many more read-only utilities **Blocked operations:** `rm`, `mv`, `cp`, `chmod`, `chown`, `mkdir`, `touch`, `kill`, `shutdown`, `reboot`, `sudo`, and any write/modify commands. ## Multicast Discovery When running in HTTP mode with broadcasting enabled, the server announces itself on the multicast group: - **Address:** `239.255.255.250` - **Port:** `5353` - **Interval:** Configurable (default: 30 seconds) Discovery announcement includes: - Server UUID - Server name - Local IP and port - Transport type - Protocol version ## Logging All activity is logged to `ssh_mcp.log`: ``` 2025-10-17 10:30:45,123 [INFO] ssh_mcp - Starting MCP server with transport=http 2025-10-17 10:30:46,456 [INFO] ssh_mcp - Starting multicast broadcaster on 239.255.255.250:5353 2025-10-17 10:30:47,789 [INFO] ssh_mcp - Successfully connected to admin@192.168.1.100:22 ``` ## Security Considerations 🔒 **Read-Only Enforcement:** - Only whitelisted commands are allowed - Dangerous patterns (pipes, redirects, subshells) are blocked - Write operations are prevented at the command level ⏱️ **Timeouts:** - 30-second execution timeout per command - Prevents hanging commands from blocking the server 🔐 **Authentication:** - SSH key authentication recommended over passwords - Passwords stored in memory only, never persisted 📋 **Audit Trail:** - All connections and commands are logged - Review `ssh_mcp.log` for security audits ## Troubleshooting ### Connection Refused ``` Error: Connection failed: [Errno 111] Connection refused ``` - Verify the remote host is reachable: `ping <host>` - Check SSH is running on the remote machine - Verify port number (default 22) ### Authentication Failed ``` Error: Connection failed: Authentication failed ``` - Verify username is correct - For key auth: check key file path and permissions (`chmod 600`) - For password auth: verify credentials - Ensure SSH public key is authorized on remote (`~/.ssh/authorized_keys`) ### Command Not Allowed ``` Error: Command not allowed for security reasons ``` - The command contains a blocked pattern or is not in the allowed list - Use `ssh_get_allowed_commands` to see permitted commands - For write operations, use SSH directly instead ### Broadcast Not Working - Verify `MCP_ENABLE_BROADCAST=true` - Check network supports multicast (most corporate networks block it) - Verify firewall allows UDP on port 5353 - Check `ssh_mcp.log` for broadcast errors ## Development ### Running in Debug Mode ```bash DEBUG=true uv run ssh_readonly_fastmcp_mcast.py ``` ### Testing ```bash # Test connection uv run -c "from ssh_readonly_fastmcp_mcast import is_command_safe; print(is_command_safe('ls -la'))" # Should print: True # Test blocked command uv run -c "from ssh_readonly_fastmcp_mcast import is_command_safe; print(is_command_safe('rm -rf /'))" # Should print: False ``` ## Project Structure ``` ssh-mcp-server/ ├── ssh_readonly_fastmcp_mcast.py # Main server implementation ├── .env # Configuration file ├── .env.example # Configuration template ├── ssh_mcp.log # Server logs (auto-generated) ├── pyproject.toml # Project metadata └── README.md # This file ``` ## API Response Format All tools return consistent JSON responses: **Success:** ```json { "status": "success", "host": "192.168.1.100", "command": "ls -la /home", "exit_code": 0, "output": "total 24\ndrwxr-xr-x 3 root root 4096...", "error": null } ``` **Error:** ```json { "status": "error", "message": "Command not allowed for security reasons", "reason": "Only read-only commands are permitted" } ``` ## License MIT ## Contributing Contributions welcome! Please ensure: - All changes maintain read-only enforcement - Code is logged appropriately - Tests pass for security validations ## Support For issues or questions: 1. Check `ssh_mcp.log` for error details 2. Review the Troubleshooting section 3. Verify environment configuration 4. Check network connectivity to remote hosts

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/kunwarmahen/ssh-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server