关于 SSH MCP Server
SSH MCP Server 为 AI Agent 提供 SSH 环境管理、故障诊断和远程操作工具,适用于需要通过 SSH 访问代码库或服务器的工作。它会在远程操作失败时附带诊断信息,并支持连接复用。
主要功能
- 01启动 SSH Agent 并加载密钥
- 02诊断连接问题并提供修复命令
- 03执行远程命令和文件操作
- 04并行对多台主机执行命令
- 05自动复用 SSH 连接
适用场景
- 01排查 Git over SSH 认证失败
- 02在远程服务器执行命令
- 03通过 SFTP 上传或读取文件
- 04对多台主机运行同一命令
MCP 相关
作为 MCP 服务,它向 MCP 客户端提供 SSH 环境诊断、远程命令执行及 SFTP 文件操作等工具。远程操作失败时会自动运行诊断,并将结果加入错误响应。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
21收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| env | object | 否 | 为此命令设置的环境变量。以 `KEY='value' ...` 前缀注入;无论 AcceptEnv 配置如何,均适用于任何 sshd。VALUES 使用 POSIX 单引号引用,因此值中的任何字节都安全。KEYS 不能加引号(shell 赋值前缀要求使用裸名称),因此每个键都必须匹配 /^[A-Za-z_][A-Za-z0-9_]*$/(POSIX 名称语法);不符合此语法的键会被拒绝,且调用会在向主机发送任何内容之前失败。命令策略会针对带前缀的命令进行检查,因此设置此项后,`^` 锚定的白名单模式将不再匹配。 |
| host | string | 是 | SSH 主机名或 IP 地址 |
| port | integer | 否 | SSH 端口(默认值:22) |
| command | string | 是 | 要在远程主机上执行的 shell 命令(由远程登录 shell 解释) |
| timeout | integer | 否 | 命令超时时间,单位为毫秒(默认值:30000)。命令启动前,等待可用连接池槽位的最长时间也为此值(SSH_MCP_MAX_POOL_SIZE,默认值 100);等待时间和命令执行时间分别受限。 |
| password | string | 否 | SSH 密码。强烈建议优先使用基于密钥的身份验证(privateKeyPath 或 ssh-agent)。密码会以明文形式通过 MCP 协议帧传输,并可能被传输层或主机进程记录。 |
| username | string | 否 | SSH 用户名(默认值:当前用户) |
| privateKeyPath | string | 否 | SSH 私钥路径 |
详细介绍
@yawlabs/ssh-mcp
单击即可将其添加到本地 Yaw MCP 配置中,以便在每个 Yaw Terminal 会话中使用。也可以按下方说明手动安装。
让 AI 工具能够使用 SSH。 一个 MCP 服务,用于管理 SSH 环境、诊断并修复故障,并为 Agent 提供对任意内容的远程访问能力。
由 Yaw Labs 构建并维护。
问题
AI 命令行工具在子进程中运行,而其中的 SSH 总是出问题。Agent 尝试执行 git pull,却遇到 Permission denied (publickey)。它尝试 SSH 连接服务器,却发现 Agent 套接字已失效。它尝试部署,却发现主机密钥已更改,因为实例被重新创建了。每次遇到这些问题,AI 都不知道原因,继而陷入混乱。
所有需要 SSH 密钥的场景都会遇到这类问题:
- Git — 克隆、拉取、推送、获取、子模块、LFS
- 包管理器 — 从私有仓库执行
npm install、pip install、go get、cargo、composer - 服务器访问 — SSH、SCP、SFTP、rsync
- 隧道 — 数据库端口转发、SOCKS 代理
- 部署 — Ansible、Terraform、Capistrano、部署脚本
- 云服务 — AWS EC2、GCP、Azure、DigitalOcean、任意 VPS
ssh-mcp 可解决这些问题。它会管理 SSH Agent、加载密钥、诊断故障并提供可执行的修复命令,还能提供远程操作功能——所有功能都以 MCP 工具的形式提供,供 AI Agent 调用。
快速开始
添加到 MCP 客户端配置中:
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": ["-y", "@yawlabs/ssh-mcp@latest"]
}
}
}
在 Windows 上,请使用 cmd /c 包装命令,因为 Node 20+ 无法直接启动 .cmd 文件:
{
"mcpServers": {
"ssh": {
"command": "cmd",
"args": ["/c", "npx", "-y", "@yawlabs/ssh-mcp@latest"]
}
}
}
@latest 标签会让 npx 每次启动时都从注册表重新解析版本,因此每个 MCP 会话都能使用最新发布的版本。也可以选择全局安装并固定版本(不会自动更新):
npm install -g @yawlabs/ssh-mcp
# then in client config: "command": "ssh-mcp"
工具
SSH 环境管理
用于修复本地 SSH 设置的工具,让其他功能(例如 Git、部署、隧道)不再出问题。
| 工具 | 描述 |
|---|---|
ssh_agent_ensure | 确保 ssh-agent 正在运行。如果需要,会启动它并为会话设置环境变量。 |
ssh_key_list | 列出 ~/.ssh/ 中的所有 SSH 密钥,包括类型、指纹和 Agent 状态。 |
ssh_key_load | 将密钥加载到正在运行的 Agent 中。会先确保 Agent 已启动。 |
ssh_config_lookup | 解析主机的有效 SSH 配置(主机名、用户、端口、代理、身份文件)。 |
ssh_known_hosts_fix | 移除过期的主机密钥并重新扫描。修复“主机密钥验证失败”错误。 |
ssh_git_check | 测试通过 SSH 连接 GitHub、GitLab、Bitbucket 等平台的 Git 身份验证。 |
ssh_test | 快速测试连接,并提供耗时信息和可执行的错误详情。 |
诊断
| 工具 | 描述 |
|---|---|
ssh_diagnose | 全面诊断 SSH 环境。检查 Agent、密钥、配置、known_hosts 和连接情况。针对每项故障返回确切的修复命令。 |
远程操作
| 工具 | 描述 |
|---|---|
ssh_exec | 在远程主机上执行命令。最多返回三个内容块,状态信息在前:[exit code: N](当通道仅因信号关闭时,若 code: -1,还会附带 [signal: NAME];如果流达到 10 MB 上限,也会附带相应标记),然后是 [stderr],最后是 [stdout]。状态信息置于开头,因此即使代理截断较长的结果(Yaw MCP 默认保留约 100 KB),也不会丢失退出代码。可选参数 env 用于设置每次调用的环境变量(使用 POSIX 安全前缀,无论 sshd 的 AcceptEnv 设置如何都有效)。如果配置了命令策略,则受其限制。 |
ssh_read_file | 通过 SFTP 读取远程主机上的文件(整个文件最多 10 MB)。可选参数 offset 和 length(字节数)用于读取一页;工具会在文本前返回 [bytes A-B of SIZE; next offset: N] 状态块。大文件或结果受代理限制时可使用这些参数。 |
ssh_write_file | 通过 SFTP 将内容写入远程主机上的文件。 |
ssh_upload | 通过 SFTP 将本地文件上传到远程主机。 |
ssh_download | 将文件从远程主机下载到本地文件系统。 |
ssh_ls | 列出远程主机上目录中的文件。 |
ssh_stat | 获取文件或目录的元数据(大小、八进制格式的权限、uid/gid、mtime/atime、isFile/isDirectory/isSymbolicLink)。请使用此工具,而不要解析 ls -la 的输出。 |
ssh_mkdir | 通过 SFTP 创建目录。设置 recursive: true 可实现 mkdir -p 的行为。与其他 SFTP 工具不同,路径可以是相对路径,会根据 SFTP 工作目录解析(通常是远程用户的主目录)。~ 不会展开;SFTP 没有 Shell。 |
ssh_delete | 通过 SFTP 删除文件或空目录。根据路径本身的类型(lstat)自动选择 unlink 或 rmdir,因此符号链接总是会被解除链接,不会跟随链接;即使链接悬空或指向目录也是如此。此工具有意不支持递归删除目录——如有需要,请使用 ssh_exec rm -rf。 |
更高级的操作
这些工具封装了 Agent 使用 ssh_exec 实现的常见模式,速度更快,也更不容易出错。
| 工具 | 描述 |
|---|---|
ssh_multi_exec | 在多台主机上并行运行命令。按主机返回结果。可选参数 env 用于设置每次调用的环境变量(与 ssh_exec 使用相同的 POSIX 安全前缀,并应用一次后发送给每台主机)。如果配置了命令策略,则受其限制(策略会在分发到各主机前,针对带环境变量前缀的命令检查一次)。 |
ssh_find | 使用结构化参数(name、type、size、depth、newer——匹配修改时间晚于参考路径的文件)在远程搜索文件。 |
ssh_tail | 读取文件末尾 N 行,可选择使用 grep 模式进行筛选。 |
ssh_service_status | 检查 systemd 服务状态(active、PID、运行时间、描述)。仅当找不到或无法查询单元时,才会将 isError 标记为 true;已有单元处于主动停止状态时不会标记。 |
自动诊断
任何远程操作失败时,ssh-mcp 都会自动运行诊断,并在错误响应中附上结果。你的 Agent 无需单独调用 ssh_diagnose——错误消息会直接说明问题所在及解决方法。
连接池
远程操作会自动复用 SSH 连接。当 Agent 多次调用同一主机时,首次调用会打开连接,后续调用则复用该连接。连接在最后一次使用后会保持活动状态 60 秒,然后自动关闭。
连接池默认最多容纳 100 个连接,仍在建立中的连接也计入上限。达到上限时,连接池会关闭一个空闲连接腾出空间。如果所有连接槽都在使用中或正在建立,工具调用会等待,而不是失败:
- 单主机远程工具(
ssh_exec、SFTP 工具、ssh_find、ssh_tail、ssh_service_status)最多等待其timeout指定的时长(没有timeout参数的 SFTP 工具为 30 秒),并在首个释放的连接槽可用时优先获得该槽。因此,在一场范围较大的ssh_multi_exec执行过程中到来的ssh_exec,会在它执行的两台主机之间运行,而不会因为整场执行而遭拒。只有在这段时间内始终未能获得连接槽时,才会报告Connection pool is full。 ssh_multi_exec同时最多运行SSH_MCP_MAX_POOL_SIZE台主机(默认 100 台),并会随着连接槽释放继续处理更长的主机列表,因此提高上限也会提高其并行度;timeout按每台主机计算,不限制整个调用的总时长。连接池已满时,它会等待;只有当它自己的主机都未占用连接槽,且整整一个timeout时长内都没有主机开始或完成时,才会放弃。此时正在等待的主机(每个并行槽最多一台)以及所有仍在队列中的主机都会报告Connection pool is full;队列中的主机不会尝试连接。
只有当其他调用(例如长时间运行的 ssh_exec 或并发的 ssh_multi_exec)连续一个 timeout 时长占用所有连接槽时,调用才会遇到 Connection pool is full。如果一个扇出任务独占连接池,即使运行时间再长,只要主机数超过上限,也不会遇到此错误。如果看到此错误,请等这些调用完成后重新运行(对于 ssh_multi_exec,请仅重新运行报告错误的主机),或者在服务的环境中通过 SSH_MCP_MAX_POOL_SIZE=<n> 提高上限。错误信息中会指出该变量名。
默认情况下,库的 acquire() / withConnection() 不会等待:除非传入 { waitForCapacityMs },否则会立即以 PoolFullError(code: "ERR_SSH_MCP_POOL_FULL"、isPoolFullError())拒绝请求;请参阅编程用法。
SSH 配置支持
所有连接都会遵循你的 ~/.ssh/config。主机别名、自定义端口、用户名、身份文件和 ProxyJump 设置都会自动使用。如果你在 SSH 配置中配置了 Host myserver,只需传入 host: "myserver",ssh-mcp 就会解析所有配置。
ProxyJump / 堡垒主机会自动获得支持。如果你的 SSH 配置为某台主机设置了 ProxyJump bastion,ssh-mcp 就会透明地通过堡垒主机连接。也支持代理链。
主机密钥验证
所有远程操作都会根据 ~/.ssh/known_hosts 验证服务端的主机密钥:
- 主机已知,密钥匹配 — 接受。
- 主机已知,密钥已更改 — 拒绝(防范中间人攻击)。拒绝消息会区分真正的密钥不匹配与“服务端提供的密钥类型未包含在
known_hosts条目中”,因此缺少 ed25519 行不会被误认为是攻击。 - 主机未知 — 接受,除非启用了严格模式(
SSH_MCP_STRICT_HOSTKEYS=1)。
最后一种情况是始终信任,而不是 TOFU。 真正的首次使用时信任会固定首次看到的密钥,并在之后密钥发生更改时拒绝连接。连接路径从不写入 known_hosts — 没有任何工具会在连接时顺带添加条目 — 因此连接不会固定任何密钥:每次连接到 known_hosts 中不存在的主机,都是一次“首次”使用,都会被接受,包括攻击者在你上次调用后替换了密钥的情况。只有通过其他方式放入 known_hosts 的主机才会受到密钥不匹配保护 — 可以由你、ssh-keyscan 或这里唯一会写入该文件的工具 ssh_known_hosts_fix 添加。请显式调用它来添加条目,以便检测之后的密钥更改。
在安全要求更严格的环境中,设置 SSH_MCP_STRICT_HOSTKEYS=1(或不区分大小写的 true)以拒绝未知主机。请先使用 ssh_known_hosts_fix 显式添加主机。旧名称 SSH_MCP_STRICT_HOST_KEY 仍然有效,并接受相同的值,但建议使用新名称:Yaw MCP 等凭据扫描器会将任何包含 _KEY 片段的名称视为机密,并将旧名称标记为明文凭据。
诊断工具(ssh_test、ssh_diagnose)会在探测命令中使用 StrictHostKeyChecking=no。这些探测只会运行 echo SSH_OK — 不会传输凭据或数据 — 因此,宽松设置可安全用于连接测试。实际操作始终通过 hostVerifier 执行。
命令策略
ssh_exec 和 ssh_multi_exec 接受 Agent 提供的任意 Shell 命令。对于注重安全的部署,可以通过两个环境变量限制允许运行的命令;每个变量都接受以逗号分隔的正则表达式列表:
SSH_MCP_COMMAND_WHITELIST— 如果已设置,命令必须匹配至少一个模式,否则将被阻止。SSH_MCP_COMMAND_BLACKLIST— 如果已设置,命令不得匹配任何模式,否则将被阻止。
如果同时设置了两个变量,命令必须通过两项检查(先检查白名单,再检查黑名单)。如果两个变量都未设置(默认情况),则允许所有命令。
模式为 JavaScript 正则表达式。使用 ^ 和 $ 进行完全匹配;否则,模式将按子串匹配处理。逗号是分隔符,因此模式中的字面逗号需要写成 \x2c 或放入字符类中。
# Read-only allowlist: only ls / df / cat / find / tail
SSH_MCP_COMMAND_WHITELIST="^ls( .*)?,^df( .*)?,^cat ,^find ,^tail "
# Block destructive ops even if your agent goes off-script
SSH_MCP_COMMAND_BLACKLIST="^rm ,^shutdown,^reboot,^mkfs,^dd if=,>\s*/dev/"
命令被阻止时,会显示清晰的错误信息,指出拒绝此次调用的模式(或环境变量),以便 Agent 调整命令,而不是猜测。策略会在 SSH 连接打开前执行 — 被阻止的命令不会启动任何远程进程。
范围:策略仅涵盖 ssh_exec 和 ssh_multi_exec
所有其他工具都不受检查。这分为两种截然不同的情况。
结构化的读取工具全部豁免,但豁免的原因有两种——它们访问远程端的方式不同。
ssh_find、ssh_tail 和 ssh_service_status 确实会构建 shell 命令(find、tail、systemctl),但这些命令由类型化参数生成,所有插入的值都经过 shell 引号处理,绝不会来自 Agent 的自由输入。豁免它们是为了使用方便:否则,严格的 ^ls 白名单会迫使你额外允许 ^find 、^tail 、^systemctl ,才能让这些工具正常工作——这就失去了严格白名单的意义。
ssh_ls、ssh_stat、ssh_read_file 和 ssh_download 完全不会构建命令。它们是纯 SFTP 操作(readdir、stat、readFile、fastGet),因此——和下面会修改状态的 SFTP 工具完全一样——没有可供正则表达式匹配的命令字符串;即使你想限制它们,这些环境变量也无法做到。它们与读取工具归为一类,而不是被标记为策略漏洞,因为它们不会修改远程状态。有一点需要注意:ssh_download 只是不修改远程端——它会写入传入的任意本地路径,而这些环境变量同样不会限制这一点。
会修改远程状态的 SFTP 工具也不受检查,这是一个真实的漏洞,并非出于使用便利的考虑。 ssh_write_file、ssh_upload、ssh_mkdir 和 ssh_delete 从不构建 shell 命令字符串,因此命令形式的正则表达式无从匹配。具体来说:SSH_MCP_COMMAND_BLACKLIST="^rm " 无法阻止 ssh_delete,而 SSH_MCP_COMMAND_WHITELIST="^ls " 无法阻止 ssh_write_file。要解决这一问题,需要单独的路径策略机制,而本服务有意不提供这种机制。如果你必须阻止远程端的状态修改,请从 MCP 客户端的工具允许列表中移除这四个工具(或使用会限制它们的客户端)——这两个环境变量做不到这一点。
策略与 env 参数的交互(ssh_exec、ssh_multi_exec)
调用 ssh_exec 或 ssh_multi_exec 并传入 env: { KEY: "value" } 时,这些值会以 KEY='value' ... 的 shell 前缀形式插入命令之前(见工具说明)。策略检查的是添加此前缀后的完整命令,而不是单独的 command 参数——在 ssh_multi_exec 的情况下,检查只会在扇出前进行一次。这是在协议层更安全的执行顺序,但这意味着白名单模式必须考虑此前缀,且必须使用锚定匹配,不能使用子串匹配:
# WRONG -- blocks any ssh_exec call that uses `env`, because the final command
# starts with `KEY='value' ` and never matches `^ls`.
SSH_MCP_COMMAND_WHITELIST="^ls "
# RIGHT -- allow zero or more `KEY='value' ` prefixes before the real command.
SSH_MCP_COMMAND_WHITELIST="^([A-Za-z_][A-Za-z0-9_]*='[^']*' )*ls( |$)"
你不必从单纯的拒绝结果中自行判断原因:如果白名单阻止了一个使用 env 的调用,错误信息会附加说明,解释前缀为何导致 ^ 锚定无法匹配,并建议使用上面的兼容模式。
如果你担心有恶意 Agent,请避免使用 ls 这类子串匹配模式。Agent 可以传入 env: { ATTACK: " ls " },使最终命令变成 ATTACK=' ls ' rm -rf /,从而匹配子串 ls 并绕过白名单。上面的锚定模式没有这个弱点,因为它要求真正的命令名称出现在环境变量前缀之后,而不是出现在带引号的环境变量值中。
黑名单也需要同样谨慎。^rm 会阻止不带前缀的 rm 调用,但无法阻止 FOO='bar' rm。请使用同样兼容环境变量前缀的锚定模式:
SSH_MCP_COMMAND_BLACKLIST="^([A-Za-z_][A-Za-z0-9_]*='[^']*' )*rm( |$)"
如果你完全不信任 Agent 传入的 env 值,最简单的缓解措施就是在客户端配置中不使用 env,并通过 command 字符串自行传入所有内容。
Windows 支持
在 Windows 上,当未设置 SSH_AUTH_SOCK 时,ssh-mcp 会自动使用 OpenSSH Authentication Agent 的 \\.\pipe\openssh-ssh-agent 命名管道。无需设置 SSH_AUTH_SOCK——只需确保 OpenSSH agent 服务正在运行。
在 oam 运行时上,agent 身份验证需要 oam 0.18.0 或更高版本:这是首个 net 能够拨号连接命名管道或 Unix 套接字的 oam,ssh2 正是通过这种方式连接 agent(而且启动器不会在更旧的版本上启动)。目前,基于 agent 的远程操作仅在 Node 上完成了端到端验证;在 oam 上验证了握手和 ssh_config_lookup,但未验证仅使用 agent 的 ssh_exec。如果在 oam 上 agent 身份验证失败,请设置 SSH_MCP_RUNTIME=node,以排除运行时的影响。
ssh_agent_ensure 和 ssh_diagnose 会探测该管道,并告知你服务是否已停止。远程操作不会这样做:它们假设管道存在,如果 agent 不在,就让连接自行失败。因此,agent 服务停止时会显示为身份验证失败,而不是“agent 未运行”错误;只有运行诊断工具后才能看到后者。
身份验证
所有远程操作都接受连接参数:
| 参数 | 描述 | 默认值 |
|---|---|---|
host | SSH 主机名或 IP(必填) | — |
port | SSH 端口 | 来自 SSH 配置或 22 |
username | SSH 用户名 | 来自 SSH 配置或当前用户 |
privateKeyPath | SSH 私钥路径 | 自动检测 |
password | SSH 密码(建议使用密钥) | — |
身份验证解析。 显式提供的凭据会直接胜出,不会再提供其他凭据。如果两者都未提供,ssh-mcp 会同时提供 ssh-agent 和一个磁盘上的密钥——与 OpenSSH 客户端的做法相同——由服务器在身份验证交换期间选择。第 2 步之后并非严格的逐项匹配链。
- 显式设置
privateKeyPath——仅使用该密钥。不会提供 agent,也不会读取其他密钥。 - 显式设置
password——仅使用该密码,与上面的情况相同。 - 两者都未提供——在同一连接上配置以下两项:
- ssh-agent——
SSH_AUTH_SOCK,或在 Windows 上使用\\.\pipe\openssh-ssh-agent命名管道。Windows 管道会被无条件视为可用;ssh-mcp 不会检查 OpenSSH Authentication Agent 服务是否实际正在运行。 - 一个磁盘上的密钥——
ssh -G <host>的identityfile列表中第一个可读路径。OpenSSH 会为每个主机输出该列表,包括没有IdentityFile行的主机(默认值为~/.ssh/id_rsa、id_ecdsa、id_ecdsa_sk、id_ed25519、id_ed25519_sk),因此这是常规路径,并非仅供你配置了身份的主机使用的路径。ssh-mcp 自带的列表(~/.ssh/id_ed25519、id_rsa、id_ecdsa)仅在ssh -G完全无法运行时作为回退方案使用,例如未安装 SSH 客户端时。
- ssh-agent——
关于第 3 步,有两点需要注意:
- 最多只会提供一个磁盘上的密钥——第一个存在的候选密钥。ssh-mcp 不会像
ssh那样遍历整个身份列表,因此如果第一个可读密钥不正确,身份验证将依赖 agent 中的密钥。传入privateKeyPath可强制使用指定密钥。 - 配置了 agent 时,会跳过磁盘上经过加密的密钥,并继续检查下一个候选项。底层 ssh2 库会立即解析
privateKey,并在遇到加密密钥时因“未提供密码短语”而报错,这会破坏一种常见配置:磁盘上存放加密密钥,而解密后的副本已加载到 agent 中。未配置 agent 时,无论是否加密,都会加载第一个存在的密钥,并由 ssh2 自行报告密码短语错误。由于上述 Windows 管道会被无条件视为可用,因此在 Windows 上始终会跳过加密密钥。
示例工作流
Agent 无法执行 git pull
Agent calls ssh_git_check → "Permission denied. Your SSH key is not registered with github.com."
Agent calls ssh_key_list → finds id_ed25519 exists but is not loaded
Agent calls ssh_key_load("~/.ssh/id_ed25519") → "Key loaded"
Agent calls ssh_git_check → "Git SSH authentication to github.com succeeded as username"
Agent runs git pull → works
重建实例后主机密钥发生变化
Agent calls ssh_exec on server → error: "Host key verification failed"
(auto-diagnostics included in error: "Fix with ssh_known_hosts_fix")
Agent calls ssh_known_hosts_fix("my-server") → "Host key refreshed"
Agent calls ssh_exec → works
首次连接到新服务器
Agent calls ssh_test("new-server") → "Connection refused at new-server:22"
Agent calls ssh_diagnose("new-server") → full report showing agent running, keys loaded, but host unreachable
Agent reports: "SSH server isn't running on new-server or port 22 is blocked"
编程用法
import { connect, exec, diagnose, ensureAgent, listSshKeys, checkGitSsh, ConnectionPool, isPoolFullError } from '@yawlabs/ssh-mcp';
// Fix SSH environment
const agent = ensureAgent();
console.log(agent.message);
// Check git access
const git = checkGitSsh('github.com');
console.log(git.message);
// List available keys
const keys = listSshKeys();
for (const key of keys) {
console.log(`${key.name} (${key.type}) - ${key.loadedInAgent ? 'loaded' : 'not loaded'}`);
}
// Run a remote command (one-off)
const client = await connect({ host: 'my-server', username: 'deploy' });
const result = await exec(client, 'uptime');
console.log(result.stdout);
client.end();
// Run multiple commands with connection pooling
const pool = new ConnectionPool();
await pool.withConnection({ host: 'my-server' }, async (client) => {
const r1 = await exec(client, 'uptime');
console.log(r1.stdout);
});
// Connection stays open for 60s — next call reuses it
await pool.withConnection({ host: 'my-server' }, async (client) => {
const r2 = await exec(client, 'df -h');
console.log(r2.stdout);
});
// A full pool rejects at once with a PoolFullError; pass a budget to wait for a slot
// instead, the way the tools do, and match the rejection on its code, not its text
try {
await pool.withConnection(
{ host: 'other-server' },
async (client) => {
const r3 = await exec(client, 'uptime');
console.log(r3.stdout);
},
{ waitForCapacityMs: 30_000 },
);
} catch (err) {
if (!isPoolFullError(err)) throw err;
console.log('no slot within 30s:', err.message);
}
pool.drain(); // close all connections when done
// Diagnose issues
const report = diagnose('my-server');
console.log(report.overall); // "ok" | "warning" | "error"
for (const check of report.checks) {
console.log(`[${check.status}] ${check.name}: ${check.message}`);
}
运行时选择
ssh-mcp 命令(即 npx @yawlabs/ssh-mcp 运行的命令)是一个小型启动器。它优先使用 oam 运行时,否则会在 Node 上运行服务,因此 oam 是可选的。最低要求是最新的 oam 版本,目前为 0.18.0,并且绝不会在更旧的 oam 上运行服务。
两个环境变量控制运行时选择;在 MCP 客户端的 env 块中设置:
SSH_MCP_RUNTIME— 要使用的运行时。不区分大小写;除oam或node以外的任何值都按auto处理。auto(默认)— 使用能找到的最新 oam,且版本为 0.18.0 或更高;否则在 Node 上运行。oam— 必须使用 oam。如果找不到可用的 oam,则会明确报错:启动器会在 stderr 中打印找到的内容,以及跳过每个版本的原因,并以状态码 1 退出,而不是启动服务。node— 始终使用 Node。启动器不会查找 oam,并会忽略OAM_BIN。
OAM_BIN— 优先于自动发现使用的 oam 二进制文件路径,版本必须为 0.18.0 或更高。如果该文件不存在、版本过旧、无法运行,或使用 oam 自身的oam x.y.z横幅格式响应--version(其他程序的版本,例如 Node 的v22.x.y,不算),启动器会在 stderr 中说明情况,然后继续自动发现。
自动发现会依次检查 $OAM_INSTALL_DIR(如果已设置,即 oam 安装器的安装目标)、%LOCALAPPDATA%\oam\bin(仅限 Windows)、~/.oam/bin,然后检查 PATH 中的每个目录;启动器会查询找到的每个 oam 二进制文件的版本,只将带有 oam 自身 oam x.y.z 横幅的响应计为有效,并使用版本为 0.18.0 或更高的最新版本。如果版本相同,则优先使用先找到的版本,因此已安装的副本优先于 PATH 中的版本。仅 Windows 上的 oam.exe 有效:PATH 中的 oam.cmd/oam.bat 垫片不会被运行;如果找不到可用的 oam,stderr 中会列出这些垫片。
默认情况下,不可用的 oam 不会导致错误。当 Node 启动启动器时(由 npx 或全局安装启动,或由 MCP 客户端直接运行),auto 模式会回退到 Node:如果什么都没找到,则不输出提示;否则会在 stderr 中提示,并列出每个被跳过的 oam(以及 OAM_BIN)及其原因:版本低于 0.18.0、无法运行或是垫片。如果选中的 oam 随后无法启动,也会在 stderr 中列出。当较旧的 oam 启动启动器时,切换到 Node 始终会在 stderr 中提示(见下文)。使用 SSH_MCP_RUNTIME=oam 时,上述每种情况都会以状态码 1 退出。
当启动器本身由 oam 启动时(oam run <path>/bin/ssh-mcp.mjs,这是安装了较新 oam 时 Yaw MCP 启动 npx @yawlabs/ssh-mcp 条目的方式):
- 如果 oam 版本为 0.18.0 或更高,服务会在该 oam 上、同一进程中运行。不会执行自动发现或启动子进程,也不会读取
OAM_BIN;SSH_MCP_RUNTIME=oam会将其视为所需的 oam。 - 如果 oam 版本较旧,则绝不会在该版本上运行服务。启动器会将服务交给能找到的最新可用 oam;如果没有,则交给
PATH中的 Node;两者都没有时,以状态码 1 退出(SSH_MCP_RUNTIME=oam会以状态码 1 退出,而不会交给 Node)。 - 设置
SSH_MCP_RUNTIME=node时,无论 oam 版本如何,启动器都会将服务交给PATH中的 Node。
只要 oam 宿主启动子进程(即上述交接情况),启动器就会从子进程继承的 NODE_OPTIONS 中移除 --permission 和 --allow-* 标志。oam 0.18.0 会将自己的权限标志添加到每个子进程的 NODE_OPTIONS 中,而 Node 不允许其中的一些标志(--allow-net is not allowed in NODE_OPTIONS,退出码为 9);此服务不处于沙盒中,因此无需传递这些标志。若 oam 本身是通过 --permission 启动的,它会在 spawn() 内重新添加这些标志,启动器无法撤销,因此不要以这种方式启动 oam。
例如,要始终在 Node 上运行:
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": ["-y", "@yawlabs/ssh-mcp@latest"],
"env": { "SSH_MCP_RUNTIME": "node" }
}
}
}
在 Windows 上,将相同的 env 块添加到 快速开始 中的 cmd /c 形式。
要求
License
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。