SSH MCP Server

SSH MCP Server

Enables AI assistants to securely execute commands, transfer files, and manage port forwarding on remote servers via SSH.

Category
访问服务器

README

SSH MCP Server for AI Assistants - Secure Remote Server Management

A secure, production-ready Model Context Protocol (MCP) server that empowers AI assistants to manage remote infrastructure via SSH.

npm version npm downloads CI License Node.js Version TypeScript GitHub stars

The SSH MCP Server bridges the gap between Large Language Models (LLMs) and your infrastructure. It enables AI assistants like Claude Desktop, Cursor, and GitHub Copilot to securely execute commands, transfer files via SFTP, and manage port forwarding tunnels. Turn your AI into a capable DevOps assistant that can troubleshoot, deploy, and monitor your servers with strict security boundaries.

Table of Contents

Why use SSH MCP Server?

  • DevOps Automation: Let your AI assistant check Docker container status, read Kubernetes pod logs, or restart systemd services.
  • Infrastructure Debugging: Quickly analyze log files, check disk usage, and investigate network issues using natural language.
  • Secure File Management: Safely read configuration files, update scripts, or retrieve logs via SFTP without leaving your chat interface.
  • Complex Workflows: Chain multiple commands and tools to perform complex maintenance tasks with a single prompt.

Compatibility

This MCP server is designed to work with any client supporting the Model Context Protocol, including:

  • Anthropic Claude Desktop
  • Cursor Editor
  • GitHub Copilot

Features

  • 🔐 Secure SSH Command Execution - Run shell commands on remote servers with strict validation and timeouts.
  • 🛡️ Granular Access Control - Whitelist specific commands and arguments to prevent unauthorized actions (e.g., allow docker ps but block docker stop).
  • 📁 SFTP Integration - Full support for reading, writing, and listing files on remote filesystems.
  • 🌉 Smart Port Forwarding - Automatically manage SSH tunnels to access internal services like databases or dashboards.
  • 🔄 Robust Connection Pooling - Efficiently manages multiple persistent SSH connections for high performance.
  • 🔑 Key-Based Authentication - Supports standard SSH keys (Ed25519, RSA) for secure, password-less authentication.
  • ⚙️ SSH Config Import - Seamlessly imports hosts from your existing ~/.ssh/config file.
  • 🎯 Parameterized Templates - Define safe, reusable command templates (macros) for common tasks.
  • 📝 Audit Logging - Complete JSONL audit trails of all executed commands for compliance and security reviews.

Installation

As an MCP Server

The recommended way to use this package is as an MCP server with AI assistants like GitHub Copilot.

Prerequisites:

  • Node.js 18.0.0 or higher
  • SSH access to target servers
  • SSH private keys configured

Using npx (recommended):

No installation required! Add to your MCP client configuration:

{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": [
        "@uarlouski/ssh-mcp-server@latest",
        "--configPath=/path/to/your/ssh-mcp-config.json"
      ]
    }
  }
}

Global installation:

npm install -g @uarlouski/ssh-mcp-server

Then configure with:

{
  "mcpServers": {
    "ssh": {
      "command": "ssh-mcp-server",
      "args": ["--configPath=/path/to/your/ssh-mcp-config.json"]
    }
  }
}

Quick Start

1. Create SSH Keys

If you don't already have SSH keys for your servers:

ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -C "deploy@example.com"
ssh-copy-id -i ~/.ssh/deploy_key.pub user@your-server.com

2. Create Configuration File

Create a ssh-mcp-config.json file:

{
  "allowedCommands": ["ls", "cat", "grep", "docker", "kubectl"],
  "servers": {
    "my-server": {
      "host": "example.com",
      "username": "deploy",
      "privateKeyPath": "~/.ssh/deploy_key"
    }
  }
}

3. Configure Your MCP Client

Add the server to your MCP client (e.g., GitHub Copilot):

{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": [
        "@uarlouski/ssh-mcp-server@latest",
        "--configPath=/Users/yourname/ssh-mcp-config.json"
      ]
    }
  }
}

4. Restart Your MCP Client

Restart your AI assistant to load the new server configuration.

Configuration

Basic Configuration

The configuration file supports the following options:

{
  "allowedCommands": ["ls", "pwd", "cat", "grep", "docker", "kubectl"],
  "servers": {
    "server-name": {
      "host": "hostname-or-ip",
      "port": 22,
      "username": "username",
      "privateKeyPath": "~/.ssh/private_key"
    }
  },
  "portForwardingServices": {
    "service-name": {
      "connectionName": "server-name",
      "localPort": 8080,
      "remoteHost": "localhost",
      "remotePort": 80,
      "description": "Optional description"
    }
  },
  "commandTemplates": {
    "k8s-pod-logs": {
      "command": "kubectl logs -n {{namespace}} {{pod}} --tail={{lines:100}}",
      "description": "Fetch Kubernetes pod logs with configurable tail size"
    },
    "app-deploy": {
      "command": "cd /var/www/{{app}} && git pull origin {{branch:main}} && npm install && pm2 restart {{app}}",
      "description": "Deploy application with git pull, npm install, and pm2 restart"
    },
    "docker-stats": "docker stats {{container:--all}} --no-stream --format 'table {{.Name}}\\t{{.CPUPerc}}'"
  },
  "commandTimeout": 30000,
  "maxConnections": 10
}

Configuration Options

allowedCommands (optional)

Array of base command names that are permitted for execution.

  • If specified (non-empty): Enables strict validation
    • Only listed commands can be executed
    • Validates complex commands including pipes (|), chains (&&, ||, ;), and substitutions ($())
    • Blocks bypass attempts like ls | rm -rf /
  • If omitted or empty: Disables validation (all commands allowed - use with caution!)

Example:

"allowedCommands": ["ls", "cat", "grep", "docker", "kubectl", "systemctl"]

servers (required)

Named SSH server configurations. Each server must have:

  • host (required): Hostname or IP address
  • username (required): SSH username
  • privateKeyPath (required): Path to SSH private key (supports ~ expansion)
  • port (optional): SSH port (default: 22)

Example:

"servers": {
  "staging-api": {
    "host": "api-staging-01.example.com",
    "username": "deploy",
    "privateKeyPath": "~/.ssh/staging_deploy_key"
  },
  "staging-db": {
    "host": "db-staging-master.example.com",
    "port": 2222,
    "username": "dbadmin",
    "privateKeyPath": "~/.ssh/db_admin_key"
  }
}

sshConfigImport (optional)

Import server configurations from your existing SSH config file (e.g. ~/.ssh/config). This feature allows you to reuse your existing SSH configurations without duplicating them in the MCP config file.

Benefits:

  • 🔄 Reuse existing SSH configurations
  • 🎯 Import specific hosts using pattern matching
  • 🔒 Works cross-platform (macOS, Linux, Windows)

Configuration:

  • path (string, optional): Path to SSH config file (default: ~/.ssh/config)
  • hosts (array of strings, optional): Host patterns to import (e.g., ["prod-*", "staging-*"])
    • Supports wildcards: * (matches any characters), ? (matches single character)
    • If omitted, imports all valid hosts (excluding wildcard-only hosts like *)

Note: Simply defining sshConfigImport in your config enables SSH config import. To disable it, remove the sshConfigImport field entirely.

Example - Import specific hosts with pattern matching:

{
  "sshConfigImport": {
    "path": "/custom/path/to/ssh_config",
    "hosts": ["prod-*", "staging-*"]
  }
}

Notes:

  • Only hosts with all required fields (HostName, User, IdentityFile) are imported
  • Wildcard SSH config entries (Host *) apply their settings to specific hosts but aren't imported as standalone servers
  • If the SSH config file doesn't exist, the server continues with manually defined servers
  • Important: If a server name exists in both manual configuration and SSH config import, the server will fail to start with a clear error message. Use the hosts pattern filter to avoid conflicts, or rename servers in one of the configurations.

portForwardingServices (optional)

Pre-configured named port forwarding services for common use cases.

  • connectionName (required): Name of the server from servers config
  • remoteHost (required): Remote host to forward to
  • remotePort (required): Remote port to forward to
  • localPort (optional): Local port to bind to (random if omitted)
  • description (optional): Human-readable description

Example:

"portForwardingServices": {
  "pg-staging-database": {
    "connectionName": "staging-db",
    "remoteHost": "db-internal-01.example.com",
    "remotePort": 5432,
    "description": "PostgreSQL database access"
  }
}

commandTemplates (optional)

Reusable parameterized command templates with variable substitution.

Templates can be defined in two formats:

  • String format: "template-name": "command with {{variables}}"
  • Object format: "template-name": { "command": "...", "description": "..." }

Variable syntax:

  • {{variable}} - Required variable
  • {{variable:default}} - Optional variable with default value
  • {{.field}} - Preserved for Docker/Go templates (not substituted)

Example:

"commandTemplates": {
  "k8s-pod-logs": {
    "command": "kubectl logs -n {{namespace}} {{pod}} --tail={{lines:100}}",
    "description": "Fetch Kubernetes pod logs with configurable tail size"
  },
  "app-deploy": {
    "command": "cd /var/www/{{app}} && git pull origin {{branch:main}} && npm install && pm2 restart {{app}}",
    "description": "Deploy application"
  },
  "docker-stats": "docker stats {{container:--all}} --no-stream --format 'table {{.Name}}\\t{{.CPUPerc}}'",
  "nginx-reload": "sudo nginx -t && sudo systemctl reload nginx"
}

Usage with AI:

"Get logs from the api-7d8f9 pod in the staging namespace"

The AI will recognize this matches the k8s-pod-logs template and execute it with the appropriate variables.

commandTimeout (optional)

Command execution timeout in milliseconds. Default: 30000 (30 seconds).

maxConnections (optional)

Maximum number of concurrent SSH connections. Default: 5.

auditLog (optional)

Configure audit logging for SSH sessions.

  • enabled (boolean, optional): Enable audit logging (default: false)
  • folder (string, optional): Path to store audit logs (defaults to current directory)

Example:

"auditLog": {
  "enabled": true,
  "folder": "~/ssh-audit-logs"
}

Complete Example

See config.example.json for a complete configuration example.

Available Tools

ssh_execute_command

Execute commands on remote servers.

Parameters:

  • connectionName (string, required): Name of the server from your config
  • command (string, required): Command to execute
  • commandTimeout (number, optional): Command execution timeout in milliseconds (overrides global commandTimeout)

Example:

{
  "connectionName": "staging-api",
  "command": "docker ps -a"
}

Response:

{
  "stdout": "CONTAINER ID   IMAGE     COMMAND   ...",
  "stderr": "",
  "exitCode": 0,
  "timedOut": false
}

ssh_list_servers

List all available SSH servers configured in your config file.

Parameters: None

Example:

{}

Response:

{
  "success": true,
  "servers": [
    {
      "name": "production-api",
      "host": "api-prod-01.example.com",
      "port": 22,
      "username": "deploy"
    },
    {
      "name": "staging-db",
      "host": "db-staging.example.com",
      "port": 2222,
      "username": "admin"
    }
  ],
  "count": 2
}

This tool helps AI assistants discover what servers are available for SSH operations without needing to see the full configuration file.

ssh_port_forward

Set up SSH port forwarding to access remote services.

Parameters:

  • connectionName (string, required): Name of the server from your config
  • remoteHost (string, required): Remote host to forward to
  • remotePort (number, required): Remote port to forward to
  • localPort (number, optional): Local port to bind to (random if omitted)

Example with specific local port:

{
  "connectionName": "staging-db",
  "localPort": 8080,
  "remoteHost": "internal-db.cluster.local",
  "remotePort": 5432
}

Example with automatic port assignment:

{
  "connectionName": "staging-db",
  "remoteHost": "internal-db.cluster.local",
  "remotePort": 5432
}

Response:

{
  "localPort": 8080,
  "remoteHost": "internal-db.cluster.local",
  "remotePort": 5432,
  "status": "active"
}

ssh_close_port_forward

Close an active port forward.

Parameters:

  • connectionName (string, required): Name of the server
  • localPort (number, required): Local port to close

Example:

{
  "connectionName": "staging-db",
  "localPort": 8080
}

ssh_list_port_forwards

List all active port forwards across all connections.

Parameters: None

Response:

{
  "forwards": [
    {
      "connectionName": "staging-db",
      "localPort": 8080,
      "remoteHost": "internal-db.cluster.local",
      "remotePort": 5432
    }
  ]
}

ssh_port_forward_service

Start a pre-configured named port forwarding service from your config.

Parameters:

  • serviceName (string, required): Name of the service from portForwardingServices config

Example:

{
  "serviceName": "pg-staging-database"
}

This is equivalent to calling ssh_port_forward with the pre-configured parameters.

ssh_upload_file

Upload a file from local system to remote server via SFTP.

Parameters:

  • connectionName (string, required): Name of the server from your config
  • localPath (string, required): Local file path to upload
  • remotePath (string, required): Remote destination path
  • permissions (string, optional): File permissions in octal format (e.g., "0644", "0755")

Example:

{
  "connectionName": "app-server",
  "localPath": "~/configs/app.json",
  "remotePath": "/var/www/app/config.json",
  "permissions": "0644"
}

Response:

{
  "success": true,
  "bytesTransferred": 1024,
  "message": "Successfully uploaded ~/configs/app.json to /var/www/app/config.json",
  "localPath": "~/configs/app.json",
  "remotePath": "/var/www/app/config.json"
}

ssh_download_file

Download a file from remote server to local system via SFTP.

Parameters:

  • connectionName (string, required): Name of the server from your config
  • remotePath (string, required): Remote file path to download
  • localPath (string, required): Local destination path

Example:

{
  "connectionName": "app-server",
  "remotePath": "/var/log/app/error.log",
  "localPath": "~/downloads/error.log"
}

Response:

{
  "success": true,
  "bytesTransferred": 2048,
  "message": "Successfully downloaded /var/log/app/error.log to ~/downloads/error.log",
  "remotePath": "/var/log/app/error.log",
  "localPath": "~/downloads/error.log"
}

ssh_list_remote_files

List files in a remote directory via SFTP.

Parameters:

  • connectionName (string, required): Name of the server from your config
  • remotePath (string, required): Remote directory path to list
  • pattern (string, optional): Glob pattern to filter files (e.g., ".log", ".json")

Example:

{
  "connectionName": "app-server",
  "remotePath": "/var/log/app",
  "pattern": ".*\\.log$"
}

Response:

{
  "remotePath": "/var/log/app",
  "pattern": ".*\\.log$",
  "totalCount": 3,
  "files": [
    {
      "name": "error.log",
      "size": 10485760,
      "modified": "2024-12-04T12:00:00.000Z",
      "permissions": "100644",
      "isDirectory": false,
      "isFile": true
    }
  ]
}

ssh_delete_remote_file

Delete a file on the remote server via SFTP.

Parameters:

  • connectionName (string, required): Name of the server from your config
  • remotePath (string, required): Remote file path to delete

Example:

{
  "connectionName": "app-server",
  "remotePath": "/tmp/old-backup.tar.gz"
}

Response:

{
  "success": true,
  "message": "Successfully deleted /tmp/old-backup.tar.gz",
  "remotePath": "/tmp/old-backup.tar.gz"
}

ssh_execute_template

Execute a pre-configured command template with variable substitution.

Parameters:

  • connectionName (string, required): Name of the server from your config
  • templateName (string, required): Name of the command template
  • variables (object, optional): Key-value pairs for variable substitution
  • commandTimeout (number, optional): Command execution timeout in milliseconds (overrides global commandTimeout)

Example:

{
  "connectionName": "kubernetes-bastion",
  "templateName": "k8s-pod-logs",
  "variables": {
    "namespace": "staging",
    "pod": "api-7d8f9",
    "lines": "50"
  }
}

Response:

{
  "success": true,
  "templateName": "k8s-pod-logs",
  "expandedCommand": "kubectl logs -n production api-7d8f9 --tail=50",
  "variables": {
    "namespace": "staging",
    "pod": "api-7d8f9",
    "lines": "50"
  },
  "result": {
    "stdout": "...",
    "stderr": "",
    "exitCode": 0,
    "timedOut": false
  }
}

ssh_list_templates

List all available command templates with their descriptions and variables.

Parameters: None

Example:

{}

Response:

{
  "success": true,
  "templates": [
    {
      "name": "k8s-pod-logs",
      "command": "kubectl logs -n {{namespace}} {{pod}} --tail={{lines:100}}",
      "description": "Fetch Kubernetes pod logs with configurable tail size",
      "variables": [
        { "name": "namespace", "required": true },
        { "name": "pod", "required": true },
        { "name": "lines", "required": false, "defaultValue": "100" }
      ]
    }
  ],
  "count": 1
}

Security

Built-in Security Features

  1. Command Validation

    • Automatically enabled when allowedCommands is specified
    • Validates all commands including pipes (|), chains (&&, ||, ;), and command substitutions ($(), backticks)
    • Blocks bypass attempts like ls | rm -rf / or cat $(whoami)
    • Uses robust parsing to prevent command injection
  2. Server Allowlist

    • Only pre-configured servers in ssh-mcp-config.json can be accessed
    • No dynamic server connections allowed
    • Prevents unauthorized access to infrastructure
  3. SSH Key Authentication Only

    • Only SSH key-based authentication is supported
    • No password authentication
    • Follows security best practices
  4. Connection Pooling

    • Limits concurrent connections via maxConnections
    • Prevents resource exhaustion
    • Automatic cleanup of idle connections
  5. Template Validation

    • Command templates are validated at config load time
    • Expanded template commands are subject to allowedCommands validation
    • Template syntax prevents conflicts with shell variable substitution
    • Docker/Go template patterns ({{.Field}}) are preserved and not substituted

Security Considerations

⚠️ Warning: This server provides powerful capabilities. Consider the following:

  • AI assistants will have the ability to execute commands and create tunnels on configured servers
  • Ensure you understand the capabilities you're granting
  • Start with restrictive allowedCommands and expand as needed
  • Use separate SSH keys for MCP access
  • Regularly audit command execution logs

Examples

Example 1: Kubernetes Management

Config:

{
  "allowedCommands": ["kubectl", "helm", "docker"],
  "servers": {
    "k8s-bastion": {
      "host": "k8s-bastion.example.com",
      "username": "k8s-operator",
      "privateKeyPath": "~/.ssh/kubernetes_operator_key"
    }
  }
}

Usage: Ask your AI assistant: "Check the status of pods in the staging namespace"

The assistant will execute:

{
  "connectionName": "k8s-bastion",
  "command": "kubectl get pods -n staging"
}

Example 2: Database Access via Port Forwarding

Config:

{
  "servers": {
    "db-bastion": {
      "host": "bastion.example.com",
      "username": "dbadmin",
      "privateKeyPath": "~/.ssh/db_key"
    }
  },
  "portForwardingServices": {
    "staging-db": {
      "connectionName": "db-bastion",
      "localPort": 5432,
      "remoteHost": "db-internal.example.com",
      "remotePort": 5432,
      "description": "Staging PostgreSQL database"
    }
  }
}

Usage: Ask your AI assistant: "Start the staging database tunnel"

The assistant will execute:

{
  "serviceName": "staging-db"
}

Then you can connect locally: psql -h localhost -p 5432 -U dbuser

Example 3: Docker Container Management

Config:

{
  "allowedCommands": ["docker", "docker-compose"],
  "servers": {
    "app-server": {
      "host": "app-01.example.com",
      "username": "deploy",
      "privateKeyPath": "~/.ssh/deploy_key"
    }
  }
}

Usage: Ask your AI assistant: "Restart the nginx container on app-server"

The assistant will execute:

{
  "connectionName": "app-server",
  "command": "docker restart nginx"
}

Example 4: File Management and Log Analysis

Config:

{
  "servers": {
    "app-server": {
      "host": "app-01.example.com",
      "username": "deploy",
      "privateKeyPath": "~/.ssh/deploy_key"
    }
  }
}

Usage:

Upload a configuration file:

Ask your AI assistant: "Upload my local config.json to /var/www/app/config.json on app-server with 644 permissions"

The assistant will execute:

{
  "connectionName": "app-server",
  "localPath": "~/config.json",
  "remotePath": "/var/www/app/config.json",
  "permissions": "0644"
}

Download logs for analysis:

Ask your AI assistant: "Download the error log from /var/log/app/error.log on app-server"

The assistant will execute:

{
  "connectionName": "app-server",
  "remotePath": "/var/log/app/error.log",
  "localPath": "~/downloads/error.log"
}

List and filter log files:

Ask your AI assistant: "Show me all .log files in /var/log/app on app-server"

The assistant will execute:

{
  "connectionName": "app-server",
  "remotePath": "/var/log/app",
  "pattern": ".*\\.log$"
}

Clean up old backups:

Ask your AI assistant: "Delete the old backup at /tmp/backup-2024-01-01.tar.gz on app-server"

The assistant will execute:

{
  "connectionName": "app-server",
  "remotePath": "/tmp/backup-2024-01-01.tar.gz"
}

License

Apache 2.0 - see LICENSE file for details.


Repository: github.com/uarlouski/ssh-mcp-server

Issues: github.com/uarlouski/ssh-mcp-server/issues

npm Package: @uarlouski/ssh-mcp-server

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选