npm package: @frah/ssh-mcp
Description: MCP server for SSH control of Linux and Windows servers
Author: frah
Latest version: 1.0.0

# SSH MCP Server

A Model Context Protocol (MCP) server that provides secure SSH control for Linux and Windows servers. Execute remote shell commands, transfer files, and manage multiple server connections through a standardized MCP interface.

## Features

- **Multiple Authentication Methods**: Password and SSH key authentication
- **Multi-hop SSH Support**: Connect through multiple jump hosts/bastions
- **File Operations**: Upload and download files via SFTP
- **Security Controls**: Command whitelist/blacklist configuration
- **Connection Pooling**: Efficient connection management and reuse
- **TypeScript**: Full type safety and modern JavaScript features
- **Bun Runtime**: Fast execution and built-in TypeScript support

## Installation

### Prerequisites

- [Bun](https://bun.sh/) runtime installed
- Node.js 18+ (for compatibility)

### Quick Start (using bunx)

Run directly without installation:
```bash
# Generate example config file
bunx @frah/ssh-mcp --example-config > config.json

# Run with default config (./config.json)
bunx @frah/ssh-mcp

# Run with custom config file
bunx @frah/ssh-mcp --config /path/to/your/config.json

# Show help
bunx @frah/ssh-mcp --help
```

### Local Setup

1. Clone the repository:
```bash
git clone https://github.com/frah/ssh-mcp.git
cd ssh-mcp
```

2. Install dependencies:
```bash
bun install
```

3. Copy and configure the example config:
```bash
cp config.example.json config.json
# Edit config.json with your server details
```

## Configuration

Create a `config.json` file based on the provided example:

```json
{
  "connections": [
    {
      "id": "dev-server",
      "host": "192.168.1.100",
      "port": 22,
      "username": "developer",
      "password": "your-password",
      "description": "Development environment server",
      "commandWhitelist": ["^ls", "^cat", "^grep"],
      "timeout": 30000
    },
    {
      "id": "prod-server",
      "host": "prod.example.com",
      "username": "admin",
      "privateKeyPath": "/path/to/key",
      "commandBlacklist": ["^rm", "^dd"]
    }
  ],
  "globalSettings": {
    "maxConnections": 10,
    "defaultTimeout": 30000,
    "idleTimeout": 60000
  }
}
```

### Connection Configuration Options

- `id`: Unique identifier for the connection
- `host`: Server hostname or IP address
- `port`: SSH port (default: 22)
- `username`: SSH username
- `password`: Password authentication (optional)
- `privateKey`: Private key content as string (optional)
- `privateKeyPath`: Path to private key file (optional)
- `passphrase`: Private key passphrase (optional)
- `description`: Human-readable description of the connection (optional)
- `proxy`: Array of proxy configurations for multi-hop connections
- `commandWhitelist`: Regex patterns for allowed commands
- `commandBlacklist`: Regex patterns for blocked commands
- `timeout`: Command execution timeout in milliseconds

### Global Settings Options

- `defaultTimeout`: Default command execution timeout in milliseconds
- `maxConnections`: Maximum number of concurrent SSH connections
- `idleTimeout`: SSH connection idle timeout in milliseconds (default: 60000)
- `commandWhitelist`: Global regex patterns for allowed commands
- `commandBlacklist`: Global regex patterns for blocked commands

### Multi-hop SSH Configuration

For connections through bastion hosts:

```json
{
  "id": "internal-server",
  "host": "10.0.1.50",
  "username": "app-user",
  "privateKeyPath": "/path/to/key",
  "proxy": [
    {
      "host": "bastion.example.com",
      "username": "bastion-user",
      "privateKeyPath": "/path/to/bastion/key"
    }
  ]
}
```

## Usage

### Running the Server

#### Using bunx (No Installation Required)

```bash
# Run with default config (./config.json)
bunx @frah/ssh-mcp

# Run with custom config file
bunx @frah/ssh-mcp --config /path/to/your/config.json
```

#### From Source

Start the MCP server (Bun natively supports TypeScript):

```bash
bun run dev
# or directly
bun src/index.ts
```

#### Production Build

For production deployment with Node.js:

```bash
bun run build
node dist/index.js
```

### Command Line Options

- `-c, --config <path>`: Specify path to configuration file (default: `./config.json`)
- `-h, --help`: Show help message
- `-v, --version`: Show version number
- `--example-config`: Output example configuration JSON to stdout

**Examples:**
```bash
ssh-mcp                                    # Start with default config
ssh-mcp --config /etc/ssh-mcp/config.json # Use custom config path
ssh-mcp --example-config > config.json    # Generate config file
ssh-mcp --help                            # Show help information
ssh-mcp --version                         # Show version
```

### Available MCP Tools

#### 1. ssh_execute
Execute commands on remote servers.

**Parameters:**
- `connectionId` (string): Connection ID from config
- `command` (string): Command to execute
- `timeout` (number, optional): Timeout in milliseconds

**Example:**
```json
{
  "tool": "ssh_execute",
  "arguments": {
    "connectionId": "dev-server",
    "command": "ls -la /var/log",
    "timeout": 5000
  }
}
```

#### 2. ssh_upload
Upload files to remote server via SFTP.

**Parameters:**
- `connectionId` (string): Connection ID from config
- `localPath` (string): Local file path
- `remotePath` (string): Remote destination path

**Example:**
```json
{
  "tool": "ssh_upload",
  "arguments": {
    "connectionId": "dev-server",
    "localPath": "/local/file.txt",
    "remotePath": "/remote/file.txt"
  }
}
```

#### 3. ssh_download
Download files from remote server via SFTP.

**Parameters:**
- `connectionId` (string): Connection ID from config
- `remotePath` (string): Remote file path
- `localPath` (string): Local destination path

**Example:**
```json
{
  "tool": "ssh_download",
  "arguments": {
    "connectionId": "dev-server",
    "remotePath": "/remote/log.txt",
    "localPath": "/local/log.txt"
  }
}
```

#### 4. ssh_list_servers
List all configured SSH server definitions.

**Parameters:**
None

**Returns:**
Array of server configurations with:
- `id`: Connection identifier
- `host`: Server hostname
- `port`: SSH port number
- `username`: SSH username
- `description`: Human-readable description (if configured)

**Example:**
```json
{
  "tool": "ssh_list_servers",
  "arguments": {}
}
```

**Response Example:**
```json
[
  {
    "id": "dev-server",
    "host": "192.168.1.100",
    "port": 22,
    "username": "developer",
    "description": "Development environment server"
  },
  {
    "id": "prod-server",
    "host": "prod.example.com",
    "port": 22,
    "username": "admin",
    "description": ""
  }
]
```

## Security Features

### Command Filtering

The server supports both whitelist and blacklist patterns for commands:

- **Whitelist**: Only commands matching these patterns are allowed
- **Blacklist**: Commands matching these patterns are blocked
- Patterns are evaluated as regular expressions
- Connection-specific rules override global rules

### Built-in Dangerous Command Protection

The following dangerous commands are always blocked:
- `rm -rf /` and variants
- Disk formatting commands
- Fork bombs
- Direct disk write operations

### Path Sanitization

All file paths are automatically sanitized to prevent directory traversal attacks.

## Claude Code Integration

To use this MCP server with Claude Code, follow these steps:

### 1. Configure Claude Code

Add the MCP server to your Claude Code configuration file:

**Configuration File Location:**

**Option A: Global Configuration**
- **Linux/macOS**: `~/.claude.json`
- **Windows**: `%USERPROFILE%\.claude.json`

**Option B: Project-Specific Configuration**
Create `.claude/settings.local.json` in your project directory.

**Configuration Example:**

**Using bunx (Recommended - No Installation Required):**
```json
{
  "mcpServers": {
    "ssh-mcp": {
      "command": "bunx",
      "args": ["@frah/ssh-mcp", "--config", "/absolute/path/to/your/config.json"]
    }
  }
}
```

**Using Local Installation:**
```json
{
  "mcpServers": {
    "ssh-mcp": {
      "command": "bun",
      "args": ["run", "/absolute/path/to/ssh-mcp/src/index.ts", "--config", "/absolute/path/to/your/config.json"]
    }
  }
}
```

**Example for Windows:**
```json
{
  "mcpServers": {
    "ssh-mcp": {
      "command": "bunx",
      "args": ["@frah/ssh-mcp", "--config", "C:\\Users\\YourName\\ssh-mcp-config.json"]
    }
  }
}
```

**Important Notes:**
- When using `bunx`, you only need to specify the config file path
- The config file path in `--config` must be absolute, not relative
- bunx will automatically download and run the latest version of ssh-mcp

### 2. Create Configuration File

Ensure you have a `config.json` file in the ssh-mcp directory:

```bash
cd /absolute/path/to/ssh-mcp
cp config.example.json config.json
# Edit config.json with your server details
```

### 3. Verify Configuration

You can verify the MCP server is properly configured by running:

```bash
# Test the server directly
bun run /absolute/path/to/ssh-mcp/src/index.ts

# Or inside Claude Code, use the slash command
/mcp
```

If the server starts successfully, you should see log messages indicating the server is running.

### 4. Restart Claude Code

After configuring the MCP server, restart Claude Code to load the new configuration.

### 5. Usage in Claude Code

Once configured, you can use the SSH tools in Claude Code conversations:

**Example commands:**
- "Show me the list of available SSH servers"
- "Execute `ls -la` on my development server"
- "Upload the local file `app.log` to `/var/log/app.log` on production"  
- "Download `/etc/nginx/nginx.conf` from the web server to my local machine"

With the `ssh_list_servers` tool, Claude can automatically discover available connections and select the appropriate server based on your natural language description.

### Alternative: Using Node.js

If you prefer to use Node.js instead of Bun, you need to first build the project:

```bash
bun run build
```

Then configure it as:

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

**Notes:**
- Replace `/absolute/path/to/ssh-mcp` with the **full absolute path** to your ssh-mcp directory
- Make sure Node.js 18+ is installed and run `bun install` to install dependencies
- The `--config` parameter is optional if your config.json is in the ssh-mcp directory

## Environment Variables

- `LOG_LEVEL`: Set logging level (debug, info, warn, error)
- `LOG_FILE`: Path to log file (optional)

Example:
```bash
LOG_LEVEL=debug LOG_FILE=ssh-mcp.log bun run dev
```

## Development

### Project Structure

```
ssh-mcp/
├── src/
│   ├── index.ts           # MCP server entry point
│   ├── ssh/
│   │   └── connection.ts  # SSH connection management
│   ├── tools/
│   │   ├── execute.ts     # Command execution
│   │   └── file.ts        # File operations
│   ├── security/
│   │   └── validator.ts   # Security validation
│   ├── config/
│   │   └── manager.ts     # Configuration management
│   └── utils/
│       └── logger.ts      # Logging utilities
├── tests/                 # Test files
├── config.example.json    # Example configuration
└── package.json
```

### Running Tests

```bash
bun test
```

### Type Checking

```bash
bun run lint
```

## Troubleshooting

### MCP Configuration Issues

1. **"No MCP servers configured"**: 
   - Check file path in configuration is absolute, not relative
   - Verify `.claude.json` file location and JSON syntax
   - Make sure Bun is installed and in PATH

2. **Server not starting**:
   - Test the command manually: `bun run /full/path/to/ssh-mcp/src/index.ts`
   - Check for TypeScript compilation errors
   - Verify all dependencies are installed: `bun install`

### Connection Issues

1. **Authentication Failed**: Check username/password or key file permissions
2. **Connection Timeout**: Verify network connectivity and firewall rules
3. **Key Permission Error**: Ensure private key has 600 permissions

### Command Execution Issues

1. **Command Blocked**: Check whitelist/blacklist configuration
2. **Timeout Error**: Increase timeout value in config or command
3. **Permission Denied**: Verify user has necessary permissions on remote server

### Debug Mode

Enable debug logging for troubleshooting:

```bash
LOG_LEVEL=debug bun run dev
```

## License

MIT