Skip to main content
Glama
termau
by termau
README.md
# SSH MCP Server

A Model Context Protocol (MCP) server for executing commands and managing files on remote servers via SSH.

Optionally auto-discovers [BinaryLane](https://www.binarylane.com.au/) VPS servers so they're available immediately.

## Features

- Execute shell commands on remote servers
- Read files and list directories remotely
- Upload and download files via SFTP
- Persistent connections saved to config file across restarts
- BinaryLane auto-discovery of active servers
- Per-connection SSH key configuration
- Multiple connection sources with clear priority

## Installation

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

## Configuration

### Claude Desktop / Claude Code

Add to your Claude configuration:

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

The `BINARYLANE_API_TOKEN` is optional — only needed for auto-discovery of BinaryLane servers.

### Config File

On first run, a config file is created at `~/.config/ssh-mcp/connections.json`:

```json
{
  "defaultPrivateKeyPath": "~/.ssh/id_ed25519",
  "binarylane": {
    "enabled": true,
    "apiToken": "your-token-here",
    "defaultUsername": "root",
    "defaultPrivateKeyPath": "~/.ssh/id_ed25519"
  },
  "connections": [
    {
      "name": "my-server",
      "host": "10.0.0.5",
      "port": 22,
      "username": "deploy",
      "privateKeyPath": "~/.ssh/deploy_key"
    }
  ]
}
```

The BinaryLane API token can be set here or as an environment variable.

### Environment Variable (Legacy)

Still supported for backward compatibility:

```bash
export SSH_CONNECTIONS='[
  {"name": "web1", "host": "192.168.1.10", "port": 22, "username": "root", "privateKeyPath": "~/.ssh/id_rsa"}
]'
```

### Connection Options

| Option | Required | Default | Description |
|--------|----------|---------|-------------|
| `name` | Yes | - | Unique identifier for the connection |
| `host` | Yes | - | Server hostname or IP address |
| `port` | No | 22 | SSH port |
| `username` | Yes | - | SSH username |
| `privateKeyPath` | No | - | Path to SSH private key (supports `~` expansion) |
| `password` | No | - | SSH password (if not using key auth) |

If neither `privateKeyPath` nor `password` is provided, the server will try default SSH key locations (`~/.ssh/id_ed25519`, `~/.ssh/id_rsa`).

### Connection Priority

When multiple sources define the same connection name:

1. **Config file** (highest) — manual connections from `~/.config/ssh-mcp/connections.json`
2. **Environment variable** — `SSH_CONNECTIONS`
3. **BinaryLane auto-discovery** (lowest) — active servers from the API

## Available Tools

### Connection Management

- `list_connections` — List all available SSH connections with source info
- `test_connection` — Test connectivity with latency reporting
- `add_connection` — Add a connection (persisted to config file)
- `remove_connection` — Remove a manual connection from config
- `refresh_connections` — Re-discover BinaryLane servers and reload all connections
- `get_config` — Show current configuration (tokens redacted)

### Command Execution

- `run_command` — Execute a shell command with configurable timeout

### File Operations

- `read_remote_file` — Read file contents via SFTP
- `list_remote_directory` — List directory contents with metadata
- `upload_file` — Upload a local file to remote server
- `download_file` — Download a remote file to local machine

## Example Usage

```
# List all connections (shows source: config, env, or binarylane)
list_connections

# Test connection
test_connection connection="web1"

# Run a command
run_command connection="web1" command="uptime"

# Add a new persistent connection
add_connection name="staging" host="10.0.0.5" username="deploy" privateKeyPath="~/.ssh/deploy_key"

# Refresh after creating new BinaryLane servers
refresh_connections
```

## Security Notes

- SSH keys are read from your local filesystem and never transmitted or stored by the MCP
- Passwords in config are only held in memory during operation
- The config file should be protected with appropriate filesystem permissions
- Commands are executed with the privileges of the SSH user
- Consider using dedicated SSH keys with limited permissions for automation

## Development

```bash
npm run dev    # Watch mode
npm run build  # Compile TypeScript
npm start      # Run compiled server
```

## Project Structure

```
ssh-mcp/
├── src/
│   ├── index.ts        # Server entry point
│   ├── ssh-client.ts   # SSH connection manager
│   ├── config.ts       # Persistent config file management
│   ├── binarylane.ts   # BinaryLane auto-discovery
│   ├── tools.ts        # MCP tool definitions
│   └── handlers.ts     # Tool handler implementations
├── dist/               # Compiled JavaScript
├── package.json
└── tsconfig.json
```

## License

MIT