Skip to main content
Glama
avranju

SSH MCP Server

by avranju
README.md
# SSH MCP Server

An MCP (Model Context Protocol) server that gives AI agents SSH capabilities — execute commands, transfer files, and inspect remote systems.

## Setup

```bash
npm install
npm run build
```

## Configuration

Create an SSH config file (see `ssh-config.example.json`):

```json
{
  "hosts": {
    "production-server": {
      "host": "prod.example.com",
      "port": 22,
      "username": "deploy",
      "privateKeyPath": "/path/to/ssh/keys/prod_key",
      "passphrase": null
    }
  }
}
```

Point the server at it with the `SSH_CONFIG_PATH` environment variable.

## Tools

| Tool | Description |
|------|-------------|
| `ssh_execute_command` | Run a shell command on a remote host |
| `ssh_upload_file` | Upload a local file to a remote host via SFTP |
| `ssh_download_file` | Download a remote file to the local filesystem via SFTP |
| `ssh_get_system_info` | Get OS info, uptime, memory, and disk usage |

All tools accept a `host` parameter that must match a key in the config file's `hosts` object.

## Integration with Nanoclaw

Add to your `.mcp.json`:

```json
{
  "mcpServers": {
    "ssh": {
      "command": "node",
      "args": ["/path/to/ssh-mcp/dist/index.js"],
      "env": {
        "SSH_CONFIG_PATH": "/path/to/ssh-config.json"
      }
    }
  }
}
```

## Example usage

```
User: "Check disk usage on production-server"
Agent: calls ssh_execute_command { host: "production-server", command: "df -h /" }
Agent: "Production server: 67% used on /"

User: "Upload the config file to staging"
Agent: calls ssh_upload_file { host: "staging-server", local_path: "/tmp/app.conf", remote_path: "/etc/app/app.conf" }
```

## Security

- Only key-based authentication is supported (no passwords).
- Hosts must be pre-registered in the config file; the agent cannot connect to arbitrary hosts.
- Private key files are read at connection time and never logged.
- Commands run non-interactively with a configurable timeout (default 30 s).
- All diagnostic output goes to **stderr** and does not interfere with the MCP stdio transport.