mcpssh/README.md

228 lines
7.0 KiB
Markdown

# MCP SSH Server
An Anthropic Model Context Protocol (MCP) server that provides SSH access to remote systems, enabling full access to remote virtual machines in a sandbox environment.
## Features
- Uses stdio for MCP communication
- Provides SSH connection to remote servers
- Enables command execution on remote systems
- Secure public key authentication
- SCP/SFTP file transfer (upload, download, directory listing, file removal, disk usage)
- Configurable via environment variables or MCP config
- Automatically terminates when the client stops polling for resources/prompts (controlled by `MCP_SSH_POLL_INTERVAL` and `MCP_SSH_MISSED_POLLS_THRESHOLD`)
## Installation
```bash
pip install -e .
```
## Configuration
The SSH server can be configured using environment variables or the MCP JSON configuration:
| Environment Variable | Description | Default |
|----------------------|-------------|---------|
| `MCP_SSH_HOSTNAME` | SSH server hostname or IP address | None |
| `MCP_SSH_PORT` | SSH server port | 22 |
| `MCP_SSH_USERNAME` | SSH username | None |
| `MCP_SSH_KEY_FILENAME` | Path to SSH private key file | None |
| `MCP_SSH_SERVER_NAME` | Custom name for the server instance | "SSH Server" |
| `MCP_SSH_TOOL_PREFIX` | Prefix for tool names (e.g., 'server1_' for 'server1_ssh_connect') | "" |
| `MCP_SSH_POLL_INTERVAL` | Interval in seconds between client polling requests (`resources/list` / `prompts/list`) | 60 |
| `MCP_SSH_MISSED_POLLS_THRESHOLD` | Number of missed polling intervals before the server auto-shuts down | 3 |
### Claude Desktop MCP Configuration
Add the following to your Claude Desktop MCP configuration file:
```json
{
"mcpssh": {
"command": "python",
"args": [
"-m",
"mcpssh"
],
"env": {
"MCP_SSH_HOSTNAME": "example.com",
"MCP_SSH_PORT": "22",
"MCP_SSH_USERNAME": "user",
"MCP_SSH_KEY_FILENAME": "/path/to/private_key"
}
}
}
```
### Multiple SSH Server Configuration
You can configure multiple SSH servers in Claude Desktop by creating multiple entries with different names and using the `MCP_SSH_SERVER_NAME` and `MCP_SSH_TOOL_PREFIX` environment variables to distinguish them:
```json
{
"mcpssh1": {
"command": "python",
"args": [
"-m",
"mcpssh"
],
"env": {
"MCP_SSH_HOSTNAME": "production.example.com",
"MCP_SSH_USERNAME": "prod-user",
"MCP_SSH_KEY_FILENAME": "~/.ssh/prod_key",
"MCP_SSH_SERVER_NAME": "Production Server",
"MCP_SSH_TOOL_PREFIX": "prod_"
}
},
"mcpssh2": {
"command": "python",
"args": [
"-m",
"mcpssh"
],
"env": {
"MCP_SSH_HOSTNAME": "dev.example.com",
"MCP_SSH_USERNAME": "dev-user",
"MCP_SSH_KEY_FILENAME": "~/.ssh/dev_key",
"MCP_SSH_SERVER_NAME": "Development Server",
"MCP_SSH_TOOL_PREFIX": "dev_"
}
}
}
```
With this configuration:
1. Claude will have access to two separate SSH server tools
2. Each server will be identified by its custom name in Claude's UI
3. Each server's tools will have unique prefixes to distinguish them (e.g., `prod_ssh_connect` vs `dev_ssh_connect`)
## Usage
This server implements the Anthropic MCP protocol and provides the following tools (note that when using `MCP_SSH_TOOL_PREFIX`, the tool names will be prefixed with that value):
- `ssh_connect`: Connect to an SSH server using public key authentication (using config or explicit parameters)
- `ssh_execute`: Execute a command on the SSH server
- `ssh_disconnect`: Disconnect from the SSH server
- `scp_upload`: Upload a file to the remote server via SFTP/SCP
- `scp_download`: Download a file from the remote server via SFTP/SCP
- `scp_listdir`: List a remote directory via SFTP
- `scp_remove`: Remove a remote file via SFTP
- `scp_disk_usage`: Get remote disk usage statistics via SFTP
### Example
```python
from mcp import ClientSession, StdioServerParameters
from mcpssh.server import SSHServerMCP, FileTransferParams
# Start the server in a subprocess
server_params = StdioServerParameters(
command="python",
args=["-m", "mcpssh"],
env={
"MCP_SSH_HOSTNAME": "example.com",
"MCP_SSH_PORT": "22",
"MCP_SSH_USERNAME": "user",
"MCP_SSH_KEY_FILENAME": "/path/to/private_key"
}
)
# Use with an MCP client
with ClientSession(server_params) as client:
# Connect to SSH server
client.ssh_connect()
# Execute a command
result = client.ssh_execute(command="ls -la")
print(result["stdout"])
# Upload a file
upload_params = FileTransferParams(
local_path="/path/to/local.txt",
remote_path="/tmp/remote.txt",
max_size=1024*1024*10, # 10MB
on_conflict="RENAME" # Options: FAIL, OVERWRITE, RENAME
)
upload_result = client.scp_upload(upload_params)
print(upload_result)
# Download a file
download_params = FileTransferParams(
local_path="/tmp/downloaded.txt",
remote_path="/tmp/remote.txt",
on_conflict="OVERWRITE"
)
download_result = client.scp_download(download_params)
print(download_result)
# List a remote directory
dir_result = client.scp_listdir("/tmp")
print(dir_result)
# Remove a remote file
rm_result = client.scp_remove("/tmp/remote.txt")
print(rm_result)
# Get remote disk usage
disk_result = client.scp_disk_usage("/tmp")
print(disk_result)
# Disconnect
client.ssh_disconnect()
```
### Direct Server Usage
```python
from mcpssh.server import SSHServerMCP
# Initialize and run the server
server = SSHServerMCP(
hostname="example.com",
port=22,
username="user",
key_filename="/path/to/private_key",
server_name="My Custom Server", # Optional custom server name
tool_prefix="custom_" # Optional tool name prefix
)
# Run the server with stdio transport
server.run(transport="stdio")
```
## File Transfer Parameters
File transfer tools (`scp_upload`, `scp_download`) use the `FileTransferParams` model:
```python
class FileTransferParams(BaseModel):
local_path: str
remote_path: str
max_size: Optional[int] = 1073741824 # bytes (default: 1GB)
on_conflict: Literal["FAIL", "OVERWRITE", "RENAME"] = "FAIL"
```
- `local_path`: Path to the local file (upload: source, download: destination)
- `remote_path`: Path to the remote file (upload: destination, download: source)
- `max_size`: Optional file size limit (in bytes)
- `on_conflict`: What to do if the file exists (`FAIL`, `OVERWRITE`, `RENAME`)
## Conflict Resolution
- `FAIL`: Abort if the file exists
- `OVERWRITE`: Replace the existing file
- `RENAME`: Add a timestamp suffix to avoid overwriting
## Error Handling
- All file operations return a `success` boolean and detailed error messages if applicable.
- Partial transfers are automatically cleaned up unless configured otherwise.
- Disk space and file size are checked before transfer.
## Security Note
This tool provides full access to a remote system. It should only be used with virtual machines in sandbox environments where security implications are well understood.
## License
MIT