ssh-mcp
一个本地运行的 MCP 工具,把 AI 接入真实运维环境,同时把目标、凭据和执行边界留在本机。
前言
最近我整理并开源了 ssh-mcp。如果你使用支持 MCP 的 AI Agent(例如 Codex),应该会遇到同一个问题:AI 可以很快读懂日志、分析报错并给出修复建议,但到了线上排障阶段,很多工作仍然要人工完成:登录服务器、查看服务状态、读取配置、查询数据库,再把结果复制回对话框。
直接把生产环境的 SSH 密码交给 AI,风险太高;完全不让 AI 接触真实环境,又只能停留在"告诉我应该执行什么命令"。
ssh-mcp 想解决的就是这一步。它是一个面向支持 MCP 的 AI Agent/客户端的本地 MCP server,允许客户端在用户明确登记的范围内执行 SSH 排障、查看远端文件、查询 MySQL/MariaDB/PostgreSQL,并进行带校验和备份信息的文件部署。本文用 Codex CLI 作为示例,其他能启动本地 stdio MCP server 的客户端也可以接入。
项目地址:https://github.com/lswzw/ssh-mcp
ssh-mcp 是什么
ssh-mcp 通过 MCP over stdio 与 MCP 客户端通信。它在客户端所在的本机运行一个 bridge,并按需连接或启动单实例 daemon;不监听 HTTP/TCP 公网端口,也不是云端代理。bridge、daemon、目标配置和凭据由本机管理;在目标已登记且启用、凭据库已解锁并通过本地策略检查的前提下,命令、SQL 和文件操作才会发往远端目标。
使用前,先在本地 TUI 中登记目标、填写凭据、验证连接并确认 SSH 主机指纹。之后远程操作只能发往这些已经登记且启用的目标;MCP 客户端不能在对话中新增、修改或删除目标,不能读取密码、主密码、私钥或凭据明文,也不能访问未登记目标或扫描网络。
简单来说,它提供的是一条"有范围的本地运维通道":AI 负责理解任务、串联信息和解释结果,人负责在 TUI 中登记目标并决定可用范围。

支持哪些功能
当前版本通过 stdio MCP 提供 11 个工具,覆盖目标发现、SSH、SFTP 文件操作、工作会话和数据库访问。
| 功能 | 用途 |
|---|---|
| SSH 命令执行 | 通过 run_ssh 执行已登记 Linux 主机上的非交互命令,查看服务、磁盘、内存、端口和日志。 |
| 远端文件读取 | 通过 read_ssh_file 使用受限 SFTP 读取单个普通文件,不把路径拼接进 Shell 命令。 |
| 数据库 SQL | 通过 run_sql 访问已登记的 MySQL、MariaDB 或 PostgreSQL,执行查询或明确配置的写操作;只读账号和可写账号可以分开配置。 |
| SSH 工作会话 | 使用 open_ssh_session、set_ssh_session_context、execute_ssh_session 和 close_ssh_session 连续执行共享工作目录的命令。 |
| 文件部署 | 通过 deploy_ssh_binary 将本机普通文件部署到远端已存在的普通文件,校验大小和 SHA-256,备份旧文件后再激活。 |
| 目标发现 | 通过 list_targets、describe_target_capability 和 list_databases 先确认目标及其能力。 |
执行类工具返回结构化 MCP 数据。例如 run_ssh 会返回标准输出、标准错误、退出码、超时和截断信息;远程操作还会给出 execution_outcome,帮助 Agent 区分"没有派发""执行失败"和"结果暂时无法确认"。目标列表和能力查询等本地结果不一定包含这些字段,audit_outcome 也独立于远端执行结果。
SSH 工作会话保存的是 daemon 内存中的声明式工作目录和非机密环境变量,不是持久化的交互式 Shell;它不提供别名、函数、后台任务、交互输入或 TTY。会话默认空闲 5 分钟后失效,bridge 关闭、目标配置变化、凭据库锁定或 daemon 退出时也会失效。
实际使用示例
1. 排查服务器状态
在支持 MCP 的客户端中直接说明任务即可。以 Codex 为例:
text
使用 ssh-mcp 检查已登记生产主机的磁盘空间,找出占用最高的目录,并判断是否有服务因为磁盘不足而异常。
比较稳妥的调用顺序是:
- 调用
list_targets,确认目标已经登记并启用。 - 调用
describe_target_capability,查看当前目标允许的操作。 - 使用
run_ssh执行df -h、du、systemctl status等非交互命令。 - 让 Agent 根据结构化结果给出判断和下一步建议。
需要 root 权限时,可以显式使用非交互 sudo -n。对于 daemon 能识别为需要密码输入、编辑器或交互式 TTY 的常见命令,服务会在派发前拒绝;任意自定义程序的提示不保证都能被静态识别。
2. 查看远端配置
查看配置文件时,不必让 AI 拼接一条 Shell 命令:
json
{
"target": "203.0.113.10",
"path": "/srv/example/config/application.yaml",
"offset": 0,
"max_bytes": 16384
}
read_ssh_file 只允许规范化绝对路径对应的普通文件,拒绝目录、符号链接、设备、FIFO 和 socket。文件能力需要先在 TUI 中启用,单次读取最多 64 KiB;有效 UTF-8 按文本返回,其他字节按 Base64 返回,并标记为不可信远端输出。
3. 查询数据库
例如,查询最近的任务状态:
json
{
"target": "203.0.113.20:5432",
"database": "example",
"statement": "SELECT id, status FROM jobs ORDER BY id DESC LIMIT 20",
"timeout_seconds": 30,
"max_rows": 1000,
"max_bytes": 16384
}
只读 SQL 使用只读账号;可能写入数据的 SQL 必须配置明确的可写账号。没有可写凭据时,工具返回 write_credential_not_configured,请求会在连接远端之前停止,不会自动降级到只读账号。过程调用、动态 SQL、文件或主机副作用 SQL,以及 DROP/TRUNCATE/ALTER ... DROP 和无条件 UPDATE/DELETE 等可识别高危类别也不会派发。数据库传输可配置为经 CA 校验的 tls_verified,该模式需要填写本机绝对 CA 文件路径,验证失败不会降级为明文;legacy_plaintext 仅作为兼容选项,生产环境建议优先使用验证 TLS。
4. 部署文件并重启服务
需要把本机的普通文件部署到远端已有文件时,可以让 MCP 客户端调用 deploy_ssh_binary。以 Codex 为例:
json
{
"target": "203.0.113.10",
"source_path": "/srv/builds/example",
"remote_path": "/srv/example/example",
"start_action": "systemctl restart example.service",
"max_bytes": 67108864,
"timeout_seconds": 600
}
源文件必须是 daemon 所在本机上的普通非符号链接文件,remote_path 必须是规范化绝对路径,且远端目标必须是已存在的普通文件,工具不会创建新的 live 文件;单个文件默认最多 64 MiB、上限 256 MiB,start_action 是可选的非交互命令。部署过程不是直接覆盖线上文件,而是:
- 在远端目标目录创建临时文件。
- 上传文件并校验大小和 SHA-256。
- 将原文件移动到排他备份。
- 重命名临时文件并激活。
- 按请求执行受限的启动动作;该动作仍要经过 SSH 固定拦截和目标黑名单检查。
如果上传、激活或启动过程中发生超时、连接中断或协议错误,导致结果无法确认,结果会标记为 outcome_unknown。这表示"可能已经执行,但客户端无法确认",不能直接重复部署,应该先核验线上文件、备份文件和服务状态。
安全设计
ssh-mcp 的重点不是承诺绝对安全,而是把能明确验证的边界放到远端连接之前。
- 只有本地 TUI 登记且启用的目标才能进行远程访问;MCP 客户端不能新增、修改或删除目标,也不能扫描未登记主机。黑名单和文件操作开关也只能由本地 TUI 修改。
- 凭据由本地凭据库管理,主密码解锁后才在 daemon 内存中使用;AI 和 MCP 客户端拿不到密码明文。敏感字段采用加密封装,但
state.db中的普通元数据不是完整加密数据库。 - SSH 目标保存前会测试连接并确认主机指纹,连接时继续校验已保存的指纹。
- 每个 SSH 目标都可以配置英文逗号分隔的 Go RE2 命令黑名单;黑名单只作用于 SSH,不作用于数据库。
- daemon 内置 11 类可识别的高危拦截,包括格式化或分区、直接写块设备、破坏基础系统目录、无条件批量更新或删除、动态脚本效果和未登记远端跳转。
- 远端输出始终视为不可信输入。远程操作的
execution_outcome会区分completed、failed_known、not_dispatched和outcome_unknown;另一个status字段还可能是failed、rejected或unlock_required等本地状态。
这些设计适合日常排障和受控变更,但不要把它当成主机沙箱、堡垒机或防篡改审计系统。固定规则是有限的本地静态识别,未命中规则不代表操作一定安全;工具约束也不能阻止本机其他程序直接使用 Shell、系统 ssh 或数据库客户端。生产环境仍应配合最小权限账号、网络策略和人工复核。
安装和接入 MCP 客户端
当前本地主机支持 Linux、macOS 和 Windows;远端 SSH 按 Linux 命令语义执行。客户端需要能够启动本地 stdio MCP server,并且本地需要一个可以打开交互终端的桌面环境。程序本身不需要云端或特定模型提供商的 API key。
1. 优先下载预编译版本
发布页有对应资产时,建议直接从 GitHub Releases 下载:
| 平台 | 文件名 |
|---|---|
| Linux amd64 | ssh-mcp-linux-amd64(发布后下载) |
| macOS arm64 | ssh-mcp-darwin-arm64(发布后下载) |
| Windows amd64 | ssh-mcp-windows-amd64.exe(发布后下载) |
Linux/macOS 下载后需要设置执行权限;其他 CPU 架构目前请从源码构建。下载版不需要另外安装 Go。注册 MCP 前,请确认文件来自项目发布页并能正常启动。
如果你的 Agent 具备终端和文件操作权限,也可以把下面这段话发给它,让它协助下载和注册:
text
请从 https://github.com/lswzw/ssh-mcp/releases/latest 下载适合当前系统和架构的 ssh-mcp 预编译版本,放到稳定路径并注册为当前 MCP 客户端的 stdio server(启动参数为 serve),完成后验证工具列表;如果客户端不支持本地 stdio,或需要主密码、目标登记、主机指纹确认,请提示我手动完成。
无论是否自动安装,首次使用仍需在本地 TUI 中设置主密码、登记目标并确认 SSH 主机指纹。
2. 没有匹配版本时从源码构建
下面命令以 Linux/macOS 为例;Windows 请使用对应的 .exe 文件路径。源码构建要求 Go 1.26.5:
bash
git clone https://github.com/lswzw/ssh-mcp.git
cd ssh-mcp
make build
构建完成后,Linux 和 macOS 的程序位于 bin/ssh-mcp,Windows 对应 bin/ssh-mcp.exe。
3. 打开本地控制台并登记目标
以下示例假设程序位于 bin/ssh-mcp;如果使用下载的预编译文件,请替换成实际路径:
bash
./bin/ssh-mcp manage
第一次打开 TUI 时设置主密码,然后按提示添加 SSH 或数据库目标。保存前程序会测试连接;SSH 首次连接或指纹变化时,需要人工核对指纹并确认。如果 TUI 无法自动打开终端,可以设置 SSH_MCP_TERMINAL;修改后先停止 daemon,再重新加载客户端配置。
4. 接入 MCP server
serve 使用 stdio MCP。任何能启动本地 stdio MCP server 的 Agent/客户端都可以接入,通用配置契约如下(字段名可能因客户端而异):
text
transport: stdio
command: /absolute/path/to/bin/ssh-mcp
args: ["serve"]
其中 command 必须是可执行文件的绝对路径,args 只需传入 serve。
Codex CLI 示例
如果使用 Codex CLI,可以执行(下载预编译文件时请把程序路径替换成实际的绝对路径):
bash
codex mcp add ssh-mcp -- "$PWD/bin/ssh-mcp" serve
codex mcp get ssh-mcp
其他客户端请使用自己的 MCP server 配置或注册命令。serve 会在需要时连接或启动本地 daemon,不需要手动启动网络服务。
5. 发起第一次请求
在所用 MCP 客户端的任务中明确要求使用 ssh-mcp。以 Codex 为例:
text
使用 ssh-mcp 查看已登记 SSH 主机的内存和磁盘使用情况。
日常可以使用下面两个命令查看服务状态或停止 daemon。存在活动 bridge 会话时,普通 stop 会拒绝停止;需要强制停止时,必须在交互终端执行 stop --force 并连续两次输入 yes,这可能让正在进行的远程操作变成 outcome_unknown:
bash
./bin/ssh-mcp status
./bin/ssh-mcp stop
需要强制停止时执行:
bash
./bin/ssh-mcp stop --force
当前支持范围
为了避免误解,当前版本有几项明确限制:
- 远端 SSH 只支持已登记的 IP、端口、账号密码直连和 Linux 命令语义;不支持主机名、远端 Windows/macOS 命令语义、SSH 私钥或 agent。
- MCP 不提供交互式 TTY;需要交互输入的常见命令会返回
interactive_input_required,任意自定义程序的提示不保证能被静态识别。 - 不支持独立或持久端口转发;命令中的静态 SSH 转发仍须指向已登记目标并通过策略检查,动态转发会被拒绝。
- 数据库目标使用
IP:端口,支持 MySQL/MariaDB 和 PostgreSQL。 - 普通 SSH 命令和 SQL 默认直接执行,不存在日常审批队列;高风险操作由固定拦截和目标黑名单增加限制。
audit.log是本地尽力而为的运行记录,不是防篡改证据。
把能力边界写清楚,反而更容易判断它是否适合自己的环境。
总结
ssh-mcp 适合希望让 Codex 或其他 MCP 客户端参与真实运维、但又不愿把生产凭据交给云端代理的开发者、后端工程师和 SRE。它把 SSH、文件、数据库和部署集中到一个 MCP 入口,同时把目标登记、凭据保管和高风险边界留在本地用户手里。
如果你正在使用 Codex CLI 或其他支持 stdio 的 MCP 客户端,可以从一个测试环境开始登记目标,先尝试服务状态检查和只读 SQL 查询,再逐步启用文件读取或部署能力。
项目地址:https://github.com/lswzw/ssh-mcp
项目采用 GPL-3.0 开源,欢迎 Star、提交 Issue 和贡献代码。
本文关键词: Codex、MCP、ssh-mcp、SSH、AI 运维、MySQL、PostgreSQL、DevOps、Go