ssh-mcp
一个纯 Rust 的 SSH MCP 服务器,可以从命令行安全地管理身份验证凭据,并允许对多个 Linux 主机执行远程命令、交互式 shell 和 SFTP 文件传输。
MCP 服务配置
复制以下 JSON 到 OPClaw 或其他 MCP 客户端的配置文件中即可使用
{
"mcpServers": {
"ssh-mcp": {
"command": "\u003cyour-path\u003e\\ssh-mcp.exe",
"env": {
"SSH_MCP_MASTER_PASSWORD": "${SSH_MCP_MASTER_PASSWORD}"
},
"type": "stdio"
}
}
}
该服务需要配置环境变量:SSH_MCP_MASTER_PASSWORD
服务介绍
ssh-mcp
使用 Rust 编写的 SSH MCP 服务器:通过命令行安全地加密管理认证凭据,再通过 MCP 工具对多台 Linux 主机执行远程命令、交互式 Shell 与 SFTP 文件传输。SSH 敏感信息(账号、密码、主密码)不会传给 MCP 客户端/agent。
English docs: README.md。
下载
每个版本都会附带 Windows 与 Linux(x86_64)预编译二进制。直接到最新 Release 下载:
ssh-mcp-windows-x86_64.exe— Windowsssh-mcp-linux-x86_64— Linux(在 Linux 上编译)
# Windows
ssh-mcp-windows-x86_64.exe --version
# Linux
chmod +x ssh-mcp-linux-x86_64
./ssh-mcp-linux-x86_64 --version
每个 Release 说明里都附有 SHA-256 校验和。需要其他平台或架构请从源码构建。
功能
- 认证凭据使用 AES-256-GCM 加密保存(密钥由主密码经 Argon2id 派生),凭据只能通过 CLI 添加,MCP 接口无法添加
- SSH 敏感信息(密码/主密码)与 agent 完全隔离:凭据加密保存在本地 vault,仅能通过 CLI 管理;MCP 客户端/agent 只能看到 alias、session_id 和非敏感元数据(用户名/主机/端口),既不能读取也不能修改任何凭据
- 每台主机可同时建立多个会话,每个会话有唯一
session_id - MCP 双传输:stdio(默认)与 Streamable HTTP(actix-web),可同时运行
- 远程命令执行、交互式 PTY Shell、SFTP 上传/下载
- 主机密钥 TOFU 校验(首次连接记录指纹,之后指纹不符拒绝连接)
- 内置命令安全闸门:灾难性命令(如
rm -rf /)硬拦截,高风险命令需 CLI 人工审批(ssh-mcp pending/approve/deny) - 所有操作写入日志文件,带进程 ID,超过 10MB 自动轮转
- HTTP 请求头鉴权(
SSH_MCP_HTTP_TOKEN,Bearer Token) - 内置 Codex / Claude Code / Cursor / VS Code / Claude Desktop / Cherry Studio 客户端接入配置
构建
cargo build --release
产物位于 target/release/ssh-mcp(.exe)。
主密码
凭据库由主密码加密。主密码通过环境变量 SSH_MCP_MASTER_PASSWORD 提供;未设置时仅当 stdin 是终端才会交互式输入,否则报错退出(MCP stdio 模式下必须使用环境变量)。空值视为错误。
CLI 参考
ssh-mcp 是单一二进制。运行 ssh-mcp --help 与 ssh-mcp <命令> --help 可查看内置帮助。
全局选项
| 选项 | 说明 |
|---|---|
-h, --help |
打印帮助 |
-V, --version |
打印版本 |
--data-dir <path> |
数据目录(默认 ~/.ssh-mcp,Windows 为 %USERPROFILE%\.ssh-mcp)。对每个子命令都有效,可放在子命令前或后。pending / approve / deny 需要与运行中的服务器使用相同的数据目录。 |
命令
| 命令 | 参数 | 说明 |
|---|---|---|
add |
<alias> <user@host> <password> [--port <port>] |
添加凭据。<alias> 是后续 MCP 使用的唯一名称;<user@host> 必须严格是 user@host 形式;--port 默认 22。 |
list |
— | 列出已保存凭据(alias user@host:port),不显示密码。 |
remove |
<alias> |
删除凭据。 |
pending |
— | 列出等待人工审批的命令(ID、alias、创建时间、剩余有效期),并打印当前策略。 |
approve |
<id> |
批准一条待审批命令,使下一次相同命令的重试被放行。需要主密码;审批人记录为 USERNAME。 |
deny |
<id> |
删除一条待审批命令,不批准。 |
serve |
[--http <addr:port>] |
启动 MCP 服务器(不写子命令时默认执行此命令)。不带 --http:仅 stdio;带 --http:在 http://<addr>/mcp 提供 Streamable HTTP 并且同时保留 stdio;stdin 关闭时 stdio 侧退出,HTTP 继续服务。 |
示例
# 添加凭据(密码只进入加密 vault)
ssh-mcp add web root@192.168.1.10 'password'
ssh-mcp add db root@10.0.0.5 'password' --port 2222
# 查看与删除
ssh-mcp list
ssh-mcp remove web
# 审批流程
ssh-mcp pending
ssh-mcp approve <id>
ssh-mcp deny <id>
# 仅 stdio 的服务器(由 MCP 客户端拉起进程)
SSH_MCP_MASTER_PASSWORD='...' ssh-mcp
# 在 127.0.0.1:8787 提供 Streamable HTTP
SSH_MCP_MASTER_PASSWORD='...' ssh-mcp serve --http 127.0.0.1:8787
# --data-dir 是全局参数,两种写法都可以
ssh-mcp --data-dir /srv/ssh-mcp serve --http 0.0.0.0:8787
ssh-mcp serve --data-dir /srv/ssh-mcp --http 0.0.0.0:8787
成功退出码为 0,出错为 1(错误信息输出到 stderr)。
数据目录内容
vault.bin— AES-256-GCM 加密的凭据库known_hosts— 已信任主机指纹pending/— 待审批队列(每条待审批命令一个文件)approved/— 已消费的审批记录ssh-mcp.log— 操作日志(见「日志」)
环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
SSH_MCP_MASTER_PASSWORD |
交互式输入(仅终端) | 解锁凭据库的主密码。只要 stdin 不是终端就必须设置(MCP stdio 模式必然如此)。空值视为错误。永不写入日志。 |
SSH_MCP_HTTP_TOKEN |
未设置(不鉴权) | 设置后,每个 HTTP 请求必须携带 Authorization: Bearer <token> 或 X-SSH-MCP-Token: <token>,否则返回 401。仅对 serve --http 生效。永不写入日志。 |
SSH_MCP_COMMAND_POLICY |
block |
block:硬拦截灾难命令 + 高风险命令需审批;warn:仅硬拦截,高风险命令放行并记录警告;allow:关闭过滤(不推荐)。未知值回退为 block。 |
SSH_MCP_APPROVAL_TTL |
300 |
审批有效期(秒)。超过该时间审批失效;审批只对同一 alias 的同一命令生效,且使用一次后即失效。 |
SSH_MCP_LOG_FILE |
<data_dir>/ssh-mcp.log |
覆盖日志文件路径;父目录会自动创建。 |
SSH_MCP_LOG_LEVEL |
info |
trace / debug / info / warn / error。未知值回退为 info。 |
USERNAME |
cli |
执行 ssh-mcp approve 时记录的审批人(Windows 通常自动设置;未设置时回退为 cli)。 |
所有变量都在进程启动时读取一次。
MCP 服务
stdio(默认)
本地 MCP 客户端(Claude Desktop、Cursor 等)直接拉起进程:
SSH_MCP_MASTER_PASSWORD='...' ssh-mcp
Streamable HTTP(actix-web)
SSH_MCP_MASTER_PASSWORD='...' ssh-mcp serve --http 127.0.0.1:8787
端点为 http://127.0.0.1:8787/mcp(MCP Streamable HTTP 规范,stateful 会话)。带 --http 时 stdio 传输仍会保留;stdin 关闭后 stdio 侧退出,HTTP 继续服务。
设置 SSH_MCP_HTTP_TOKEN 后,每个 HTTP 请求都必须携带 Authorization: Bearer <token>(或 X-SSH-MCP-Token: <token>):
SSH_MCP_MASTER_PASSWORD='...' SSH_MCP_HTTP_TOKEN='你的token' ssh-mcp serve --http 0.0.0.0:8787
绑定 0.0.0.0 会把服务暴露到网络——此时务必设置 SSH_MCP_HTTP_TOKEN,并让防火墙只放行可信客户端。
工具
| 工具 | 说明 |
|---|---|
ssh_connect |
按 alias 建立 SSH 会话,返回 session_id |
ssh_disconnect |
关闭会话 |
ssh_exec |
执行命令,返回 stdout/stderr/退出码(可设超时) |
ssh_shell_start |
打开交互式 PTY Shell |
ssh_shell_write |
向 Shell 发送输入 |
ssh_shell_read |
读取 Shell 输出(可设等待毫秒数) |
ssh_shell_close |
关闭 Shell |
ssh_upload |
SFTP 上传本地文件到远程 |
ssh_download |
SFTP 下载远程文件到本地 |
ssh_list_sessions |
列出当前所有会话 |
ssh_list_credentials |
列出已保存凭据(alias、用户名、主机、端口);绝不返回密码 |
凭据只能通过 CLI 添加/删除;MCP 无法修改凭据,也永远读不到任何密码。ssh_list_credentials 只返回非敏感元数据。
命令安全防护(内置安全闸门)
服务器内置命令安全闸门(src/guard.rs):无论哪个 MCP 客户端调用,ssh_exec、ssh_shell_start(带命令)、ssh_shell_write 都会先经过检查,命令在发往远端之前就会被放行或拦截。
分级规则
- 硬拦截(永远禁止,无法审批绕过):对系统根目录的递归强制删除(
rm -rf /、rm -rf /*、rm -rf /etc、rm -rf /boot等);向磁盘设备写入(dd ... of=/dev/sdX、mkfs ... /dev/sdX、> /dev/sdX等);fork bomb(:(){ :|:& };:);对系统根目录的递归chmod/chown。 - 需人工审批(默认):
rm -rf删除任意路径、rm -r删除系统目录、mkfs、dd、关机/重启(shutdown/reboot/halt/poweroff/init 0|6)、kill -9 1、移动系统根目录、curl|wget ... | sh|bash、递归chmod/chown。
审批流程
高风险命令首次执行时,MCP 调用会返回错误并附带审批 ID:
command requires approval: run `ssh-mcp approve <id>` (or `ssh-mcp deny <id>`), then retry the same command
- 查看待审批队列:
ssh-mcp pending - 批准:
ssh-mcp approve <id>(会要求主密码,且需与服务器使用相同的--data-dir) - 让 MCP 客户端重试完全相同的命令,即可放行
- 审批默认 5 分钟内有效(
SSH_MCP_APPROVAL_TTL可调),仅对同一 alias 的同一命令生效,放行一次后即失效
拒绝:ssh-mcp deny <id>。
策略与审批有效期通过 SSH_MCP_COMMAND_POLICY 和 SSH_MCP_APPROVAL_TTL 配置(见环境变量)。
日志
所有操作都会写入日志文件,默认位置为 <data_dir>/ssh-mcp.log(默认 ~/.ssh-mcp/ssh-mcp.log),包括:
- CLI 操作:添加/删除凭据(不记录密码)、查询凭据、审批/拒绝/查看待审批命令
- MCP 工具调用:每个工具的入参(会话 ID、命令、路径等)与成功/失败结果
- 安全闸门:硬拦截、审批生成/批准/放行执行
- HTTP 请求:方法、路径、状态码、耗时
日志路径与级别通过 SSH_MCP_LOG_FILE 和 SSH_MCP_LOG_LEVEL 配置(见环境变量)。
日志文件超过 10MB 会自动轮转为 ssh-mcp.log.1。日志中不包含任何密码或主密码;时间戳为 UTC。日志初始化失败(如文件不可写)只输出警告,不会阻断正常操作。每一行都带进程 ID([pid=12345]),多个 Codex 实例各拉起一个 ssh-mcp 时,可以区分是哪条进程写的。
接入主流 MCP 客户端
以下配置均以 Windows 上的 ssh-mcp.exe 为例。请把 <你的路径> 替换为你实际的绝对路径:
<你的路径>\ssh-mcp.exe
两种接入方式:
- stdio(推荐):由 MCP 客户端拉起进程。客户端需要给子进程设置环境变量
SSH_MCP_MASTER_PASSWORD(解锁加密凭据库)。 - HTTP:先手动启动服务(
ssh-mcp serve --http 127.0.0.1:8787),客户端只填 URL。此方式客户端配置中不需要主密码。
Codex
命令行添加(stdio):
codex mcp add ssh-mcp --env SSH_MCP_MASTER_PASSWORD=你的主密码 -- <你的路径>\ssh-mcp.exe
或直接编辑 ~/.codex/config.toml:
[mcp_servers.ssh-mcp]
command = "<你的路径>\\ssh-mcp.exe"
enabled = true
[mcp_servers.ssh-mcp.env]
SSH_MCP_MASTER_PASSWORD = "${SSH_MCP_MASTER_PASSWORD}"
使用 ${SSH_MCP_MASTER_PASSWORD} 时,需先在系统中设置该环境变量(如 Windows 的「系统属性 → 环境变量」),再启动 Codex;否则会按字面值传递导致解锁失败。
HTTP 方式(token 以请求头形式发送;部分 Codex 版本不接受直接写 bearer token,可以用字面请求头或引用环境变量两种方式):
codex mcp add ssh-mcp --url http://127.0.0.1:8787/mcp --bearer-token-env-var SSH_MCP_HTTP_TOKEN
[mcp_servers.ssh-mcp]
url = "http://127.0.0.1:8787/mcp"
enabled = true
startup_timeout_sec = 3600
tool_timeout_sec = 3600
http_headers = { Authorization = "Bearer 你的token" } # 字面请求头,或:
# bearer_token_env_var = "SSH_MCP_HTTP_TOKEN"
配置后可运行 codex mcp list 确认,重启 Codex 后生效。参考官方文档:https://developers.openai.com/codex/mcp。
让 Codex 在调用 ssh-mcp 工具前询问(codex mcp add 暂无审批参数,需手动编辑 ~/.codex/config.toml):
[mcp_servers.ssh-mcp]
command = "<你的路径>\\ssh-mcp.exe"
enabled = true
default_tools_approval_mode = "prompt" # auto | prompt | approve
# 也可以只对个别高风险工具强制询问
[mcp_servers.ssh-mcp.tools.ssh_exec]
approval_mode = "prompt"
[mcp_servers.ssh-mcp.tools.ssh_shell_write]
approval_mode = "prompt"
Claude Code
命令行添加(stdio):
claude mcp add --transport stdio --scope user ssh-mcp --env SSH_MCP_MASTER_PASSWORD=你的主密码 -- <你的路径>\ssh-mcp.exe
或项目级 .mcp.json(放在项目根目录,跟随仓库共享):
{
"mcpServers": {
"ssh-mcp": {
"type": "stdio",
"command": "<你的路径>\\ssh-mcp.exe",
"env": {
"SSH_MCP_MASTER_PASSWORD": "${SSH_MCP_MASTER_PASSWORD}"
}
}
}
}
同样,${SSH_MCP_MASTER_PASSWORD} 需要先在本机设置好环境变量再启动 Claude Code,否则会原样传字面值导致解锁失败。
HTTP 方式:
claude mcp add --transport http ssh-mcp http://127.0.0.1:8787/mcp
在 Claude Code 中运行 /mcp 查看连接状态。参考官方文档:https://code.claude.com/docs/en/mcp。
让 Claude Code 在调用 ssh-mcp 工具前询问(项目级 .claude/settings.json):
{
"permissions": {
"ask": [
"MCPTool(ssh-mcp:*)"
]
}
}
也可以只针对指定工具询问,如 "MCPTool(ssh-mcp:ssh_exec)"、"MCPTool(ssh-mcp:ssh_shell_write)";放到 deny 列表则直接禁止。
Cursor
项目级 .cursor/mcp.json(或全局 ~/.cursor/mcp.json):
{
"mcpServers": {
"ssh-mcp": {
"type": "stdio",
"command": "<你的路径>\\ssh-mcp.exe",
"env": {
"SSH_MCP_MASTER_PASSWORD": "你的主密码"
}
}
}
}
也可以走界面:Settings → MCP → Add new MCP server → 填入命令、参数与环境变量。参考官方文档:https://cursor.com/help/customization/mcp。
VS Code(GitHub Copilot / Agent 模式)
工作区 .vscode/mcp.json:
{
"servers": {
"ssh-mcp": {
"type": "stdio",
"command": "<你的路径>\\ssh-mcp.exe",
"env": {
"SSH_MCP_MASTER_PASSWORD": "${input:ssh-mcp-master-password}"
}
}
},
"inputs": [
{
"type": "promptString",
"id": "ssh-mcp-master-password",
"description": "ssh-mcp 主密码",
"password": true
}
]
}
使用 ${input:...} 变量时 VS Code 会在首次启动时安全提示输入主密码,避免明文写入配置。HTTP 方式改为:
{
"servers": {
"ssh-mcp": {
"type": "http",
"url": "http://127.0.0.1:8787/mcp"
}
}
}
参考官方文档:https://code.visualstudio.com/docs/copilot/customization/mcp-servers。
Claude Desktop
编辑 %APPDATA%\Claude\claude_desktop_config.json(Windows):
{
"mcpServers": {
"ssh-mcp": {
"command": "<你的路径>\\ssh-mcp.exe",
"env": {
"SSH_MCP_MASTER_PASSWORD": "你的主密码"
}
}
}
}
修改后完全退出并重启 Claude Desktop。
Cherry Studio
设置 → MCP 服务器 → 添加服务器:
- 名称:
ssh-mcp - 命令:
<你的路径>\ssh-mcp.exe - 环境变量:
SSH_MCP_MASTER_PASSWORD=你的主密码
也可以选择 Streamable HTTP 类型并填写 http://127.0.0.1:8787/mcp(无需主密码)。
通用注意事项
- 修改配置后需要重启客户端或重新打开会话,工具列表才会加载。
- stdio 模式下客户端配置中的主密码为明文(或引用环境变量),请勿把含密码的配置提交到公开仓库;
.mcp.json若提交建议用${VAR}形式。 - Windows 路径在 JSON/TOML 中反斜杠需写成
\\,也可以统一使用正斜杠<你的路径>/ssh-mcp.exe。 - 客户端审批(如 Codex 的
approval_mode = "prompt"、Claude Code 的permissions.ask)只约束单个客户端;服务器内置的命令安全闸门对所有客户端生效,是最终的防线。
测试
cargo test
包含凭据库加解密单元测试,以及 stdio 与 HTTP 两种传输的 MCP 握手集成测试。