228 lines
7.0 KiB
Markdown
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 |