mcpField
S
SSH MCP Server

SSH MCP Server

本地服务
yaw.sh云与基础设施61 天前更新

关于 SSH MCP Server

SSH MCP Server 为 AI Agent 提供 SSH 环境管理、故障诊断和远程操作工具,适用于需要通过 SSH 访问代码库或服务器的工作。它会在远程操作失败时附带诊断信息,并支持连接复用。

主要功能

  1. 01启动 SSH Agent 并加载密钥
  2. 02诊断连接问题并提供修复命令
  3. 03执行远程命令和文件操作
  4. 04并行对多台主机执行命令
  5. 05自动复用 SSH 连接

适用场景

  1. 01排查 Git over SSH 认证失败
  2. 02在远程服务器执行命令
  3. 03通过 SFTP 上传或读取文件
  4. 04对多台主机运行同一命令

MCP 相关

作为 MCP 服务,它向 MCP 客户端提供 SSH 环境诊断、远程命令执行及 SFTP 文件操作等工具。远程操作失败时会自动运行诊断,并将结果加入错误响应。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"yawlabs-ssh": {
"command": "npx",
"args": [
"-y",
"@yawlabs/ssh-mcp"
]
}
}
}
启动命令npx -y @yawlabs/ssh-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@yawlabs/ssh-mcp0.18.0

工具

21

收录的工具列表 · 更新于 2 周前

参数类型必填说明
envobject否为此命令设置的环境变量。以 `KEY='value' ...` 前缀注入;无论 AcceptEnv 配置如何,均适用于任何 sshd。VALUES 使用 POSIX 单引号引用,因此值中的任何字节都安全。KEYS 不能加引号(shell 赋值前缀要求使用裸名称),因此每个键都必须匹配 /^[A-Za-z_][A-Za-z0-9_]*$/(POSIX 名称语法);不符合此语法的键会被拒绝,且调用会在向主机发送任何内容之前失败。命令策略会针对带前缀的命令进行检查,因此设置此项后,`^` 锚定的白名单模式将不再匹配。
hoststring是SSH 主机名或 IP 地址
portinteger否SSH 端口(默认值:22)
commandstring是要在远程主机上执行的 shell 命令(由远程登录 shell 解释)
timeoutinteger否命令超时时间,单位为毫秒(默认值:30000)。命令启动前,等待可用连接池槽位的最长时间也为此值(SSH_MCP_MAX_POOL_SIZE,默认值 100);等待时间和命令执行时间分别受限。
passwordstring否SSH 密码。强烈建议优先使用基于密钥的身份验证(privateKeyPath 或 ssh-agent)。密码会以明文形式通过 MCP 协议帧传输,并可能被传输层或主机进程记录。
usernamestring否SSH 用户名(默认值:当前用户)
privateKeyPathstring否SSH 私钥路径

详细介绍

@yawlabs/ssh-mcp

添加到 Yaw MCP

单击即可将其添加到本地 Yaw MCP 配置中,以便在每个 Yaw Terminal 会话中使用。也可以按下方说明手动安装。

npm 版本 许可证:MIT

让 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 未运行”错误;只有运行诊断工具后才能看到后者。

身份验证

所有远程操作都接受连接参数:

参数描述默认值
hostSSH 主机名或 IP(必填)—
portSSH 端口来自 SSH 配置或 22
usernameSSH 用户名来自 SSH 配置或当前用户
privateKeyPathSSH 私钥路径自动检测
passwordSSH 密码(建议使用密钥)—

身份验证解析。 显式提供的凭据会直接胜出,不会再提供其他凭据。如果两者都未提供,ssh-mcp 会同时提供 ssh-agent 和一个磁盘上的密钥——与 OpenSSH 客户端的做法相同——由服务器在身份验证交换期间选择。第 2 步之后并非严格的逐项匹配链。

  1. 显式设置 privateKeyPath——仅使用该密钥。不会提供 agent,也不会读取其他密钥。
  2. 显式设置 password——仅使用该密码,与上面的情况相同。
  3. 两者都未提供——在同一连接上配置以下两项:
    • 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 客户端时。

关于第 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 形式。

要求

  • Node.js 18+
  • 已安装 SSH 客户端(用于诊断和环境管理)
  • 可选:oam 0.18.0+ — 参见运行时选择

License

MIT

Follow @YawLabs on X

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。