SSH MCP Server
一个基于 Model Context Protocol (MCP) 的 SSH 服务器,提供通过 SSH 连接到远程服务器并执行命令的功能。
功能特性
- 🔐 支持密码和SSH密钥认证
- 🌐 支持多个命名SSH连接
- 🚀 执行远程shell命令
- 📊 获取命令执行结果(成功/失败状态、退出码)
- 📝 获取命令输出内容(stdout、stderr)
- 🔄 支持交互式命令执行
- 📤 支持文件上传(SFTP)
- ⚡ 基于环境变量的灵活配置
- 🛡️ 完善的错误处理和日志记录
- ♻️ 向后兼容传统单连接配置
快速开始
方式一:使用 uvx(推荐,无需克隆)
直接在 MCP 客户端配置中使用 uvx,无需手动安装:
Claude Desktop
编辑配置文件(Windows: %APPDATA%\Claude\claude_desktop_config.json,macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"ssh": {
"command": "uvx",
"args": ["mcp-ssh-server"],
"env": {
"SSH_PROD_HOST": "your-server.com",
"SSH_PROD_USERNAME": "admin",
"SSH_PROD_PASSWORD": "your-password"
}
}
}
}
VS Code / Cursor
在项目根目录创建 .mcp.json 文件:
{
"mcpServers": {
"ssh": {
"command": "uvx",
"args": ["mcp-ssh-server"],
"env": {
"SSH_PROD_HOST": "your-server.com",
"SSH_PROD_USERNAME": "admin",
"SSH_PROD_PASSWORD": "your-password"
}
}
}
}
方式二:从源码安装
# 克隆仓库
git clone https://github.com/liang04/ssh-mcp.git
cd ssh-mcp
# 使用 uv 安装
pip install uv
uv sync
# 或使用 pip 安装
pip install -e .
配置 MCP 客户端使用本地安装:
{
"mcpServers": {
"ssh": {
"command": "uv",
"args": ["--directory", "/path/to/ssh-mcp", "run", "mcp-ssh-server"],
"env": {
"SSH_PROD_HOST": "your-server.com",
"SSH_PROD_USERNAME": "admin",
"SSH_PROD_PASSWORD": "your-password"
}
}
}
}
提示:将 SSH 连接信息替换为您的实际配置。支持通过环境变量配置多个连接,详见下方配置说明。
配置
多连接配置(推荐)
通过环境变量配置多个命名SSH连接,格式为 SSH_{连接名}_{参数名}:
# 生产环境连接
SSH_PROD_HOST=prod.example.com
SSH_PROD_USERNAME=admin
SSH_PROD_PASSWORD=prod_password
SSH_PROD_PORT=22
# 测试环境连接
SSH_TEST_HOST=test.example.com
SSH_TEST_USERNAME=tester
SSH_TEST_KEY_PATH=/path/to/test_key
SSH_TEST_PORT=2222
# 开发环境连接
SSH_DEV_HOST=dev.example.com
SSH_DEV_USERNAME=developer
SSH_DEV_PASSWORD=dev_password
# 设置默认连接(可选)
SSH_DEFAULT_CONNECTION=prod
连接命名规则:
- 连接名使用大写字母和下划线,如
PROD、TEST、DEV_SERVER - 在工具调用时使用小写形式,如
connection_name="prod"
支持的参数:
HOST: 目标服务器的IP地址或主机名(必需)USERNAME: SSH登录用户名(必需)PASSWORD: SSH登录密码(与 KEY_PATH 二选一)KEY_PATH: SSH私钥文件路径(与 PASSWORD 二选一)PORT: SSH端口号,默认为22(可选)
单连接配置(向后兼容)
传统的单连接配置方式仍然支持,会被自动注册为 default 连接:
SSH_HOST=your-server-ip-or-hostname
SSH_USERNAME=your-username
SSH_PASSWORD=your-password
# 或使用SSH密钥(推荐)
SSH_KEY_PATH=/path/to/your/private/key
SSH_PORT=22 # 可选,默认为22
日志配置(可选)
日志路径默认基于当前工作目录,支持相对路径和绝对路径。
# 命令执行日志
SAVE_EXEC_LOG=true # 是否保存命令执行日志
EXEC_LOG_FILE=logs/exec_log.json # 相对路径(基于 CWD)
# 或使用绝对路径
EXEC_LOG_FILE=/var/log/ssh-mcp/exec_log.json
# 调试日志(可选,默认不写入文件)
SSH_MCP_LOG_FILE=logs/debug.log # 设置后才会写入文件
注意:通过
uvx运行时,相对路径基于 MCP 客户端的启动目录。建议使用绝对路径以确保日志位置可预测。
可用工具
1. list_ssh_connections
列出所有可用的SSH连接配置。
返回:
{
"connections": {
"prod": {
"name": "prod",
"host": "prod.example.com",
"port": 22,
"username": "admin",
"auth_method": "password"
},
"test": {
"name": "test",
"host": "test.example.com",
"port": 2222,
"username": "tester",
"auth_method": "key"
}
},
"default_connection": "prod",
"total_count": 2
}
2. execute_command
执行shell命令并返回完整结果。
参数:
command(str): 要执行的shell命令timeout(int, 可选): 超时时间,默认30秒connection_name(str, 可选): 连接名称,不指定则使用默认连接
返回:
{
"success": true/false,
"exit_code": 0,
"stdout": "命令输出",
"stderr": "错误输出",
"error": null,
"connection": "prod"
}
4. check_ssh_connection
检查SSH连接状态。
参数:
connection_name(str, 可选): 连接名称,不指定则使用默认连接
返回:
{
"connected": true/false,
"connection_name": "prod",
"host": "prod.example.com",
"port": 22,
"username": "admin",
"test_output": "连接测试成功",
"error": null
}
5. execute_interactive_command
执行交互式命令(可以发送输入数据)。
参数:
command(str): 要执行的shell命令input_data(str, 可选): 要发送给命令的输入数据timeout(int, 可选): 超时时间,默认30秒connection_name(str, 可选): 连接名称,不指定则使用默认连接
返回:同 execute_command
6. upload_file
使用SFTP协议上传文件到远程服务器。
参数:
local_path(str): 本地文件路径remote_path(str): 远程服务器文件路径timeout(int, 可选): 传输超时时间,默认60秒connection_name(str, 可选): 连接名称,不指定则使用默认连接
返回:
{
"success": true/false,
"local_path": "/path/to/local/file",
"remote_path": "/path/to/remote/file",
"file_size": 1024,
"connection": "prod",
"error": null
}
7. download_file
使用SFTP协议从远程服务器下载文件到本地。
参数:
remote_path(str): 远程服务器文件路径(绝对路径)local_path(str): 本地文件保存路径timeout(int, 可选): 传输超时时间,默认60秒connection_name(str, 可选): 连接名称,不指定则使用默认连接
返回:
{
"success": true/false,
"remote_path": "/path/to/remote/file",
"local_path": "/path/to/local/file",
"file_size": 1024,
"connection": "prod",
"error": null
}
8. list_directory
获取远程目录的结构化文件列表。
参数:
remote_path(str, 可选): 远程目录路径,默认为当前目录 "."timeout(int, 可选): 操作超时时间,默认30秒connection_name(str, 可选): 连接名称,不指定则使用默认连接
返回:
{
"success": true/false,
"path": "/path/to/directory",
"files": [
{
"name": "example.txt",
"type": "file",
"size": 1024,
"permissions": "rw-r--r--",
"modified_time": 1701234567,
"owner_uid": 1000,
"group_gid": 1000
},
{
"name": "subdir",
"type": "directory",
"size": null,
"permissions": "rwxr-xr-x",
"modified_time": 1701234567,
"owner_uid": 1000,
"group_gid": 1000
}
],
"total_count": 2,
"connection": "prod",
"error": null
}
使用示例
列出所有连接
# 查看所有可用连接
connections = list_ssh_connections()
print(f"共有 {connections['total_count']} 个连接")
print(f"默认连接: {connections['default_connection']}")
文件下载
# 从生产环境下载文件
result = download_file(
remote_path="/path/to/remote/file.txt",
local_path="/path/to/local/file.txt",
connection_name="prod"
)
if result["success"]:
print(f"文件下载成功: {result['file_size']} 字节")
目录列表
# 列出生产环境的目录内容
result = list_directory(
remote_path="/var/log",
connection_name="prod"
)
if result["success"]:
print(f"目录包含 {result['total_count']} 项:")
for file in result["files"]:
file_type = file["type"]
name = file["name"]
if file_type == "file":
size = file["size"]
print(f" [文件] {name} ({size} 字节)")
elif file_type == "directory":
print(f" [目录] {name}/")
使用默认连接
# 不指定连接名,使用默认连接
result = execute_command("ls -la")
print(result["stdout"])
使用指定连接
# 在生产环境执行命令
result = execute_command("df -h", connection_name="prod")
print(result["stdout"])
# 在测试环境执行命令
result = execute_command("ps aux", connection_name="test")
print(result["stdout"])
检查连接状态
# 检查默认连接
status = check_ssh_connection()
if status["connected"]:
print(f"已连接到 {status['host']}")
# 检查特定连接
status = check_ssh_connection(connection_name="prod")
if status["connected"]:
print(f"生产环境连接正常")
交互式命令
# 在指定连接上执行需要输入的命令
result = execute_interactive_command(
command="sudo apt update",
input_data="your-password\n",
connection_name="dev"
)
文件上传
# 上传文件到生产环境
result = upload_file(
local_path="/path/to/local/file.txt",
remote_path="/path/to/remote/file.txt",
connection_name="prod"
)
if result["success"]:
print(f"文件上传成功: {result['file_size']} 字节")
安全注意事项
- 密钥认证优于密码认证:推荐使用SSH密钥而不是密码
- 环境变量安全:不要在代码中硬编码敏感信息,使用
.env文件并加入.gitignore - 网络安全:确保SSH连接在安全的网络环境中
- 权限控制:使用具有适当权限的用户账户
- 连接隔离:为不同环境(生产、测试、开发)配置独立的连接
错误处理
服务器会处理以下常见错误:
- SSH认证失败
- 网络连接问题
- 命令执行超时
- 权限不足
- 连接不存在
所有错误都会记录到日志中,并返回详细的错误信息。
项目结构
ssh-mcp/
├── ssh_server.py # 主服务器文件
├── .env.example # 环境变量配置示例
├── pyproject.toml # 项目配置
├── LICENSE # MIT 许可证
└── README.md # 项目文档
更新日志
v2.0.0 - 多连接支持
- ✨ 新增多个命名SSH连接支持
- ✨ 新增
list_ssh_connections工具 - ✨ 所有工具函数支持
connection_name参数 - ✨ 自动发现和加载环境变量中的连接配置
- ♻️ 保持向后兼容传统单连接配置
许可证
MIT License