npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mcp-ssh-server-tool

v2.2.2

Published

MCP Server for SSH connections and remote command execution

Readme

SSH MCP Server

一个用于 SSH 连接和远程命令执行的 MCP (Model Context Protocol) 服务器。

功能

  • 🔐 密码认证 - 使用用户名和密码连接到 SSH 服务器
  • 🔑 公钥认证 - 使用私钥文件连接到 SSH 服务器
  • 💻 远程命令执行 - 在连接的服务器上执行命令并获取输出
  • 📊 会话管理 - 管理多个 SSH 连接会话
  • 🛡️ 按需留痕 - 只读命令走轻量通道,变更命令走可审计通道(见下)

安装

npx -y mcp-ssh-server-tool

MCP 工具

ssh_connect

建立 SSH 连接

参数:

  • host: 服务器地址 (必需)
  • port: 端口号 (默认: 22)
  • username: 用户名 (必需)
  • auth_type: 认证方式 - "password" | "public_key" (必需)
  • password: 密码 (auth_type 为 password 时必需)
  • private_key_path: 私钥路径 (auth_type 为 public_key 时必需)
  • passphrase: 私钥密码 (可选)
  • timeout: 连接超时 (默认: 10秒)

ssh_exec

在 SSH 会话中执行命令

参数:

  • host / username / password 等:单次执行时传入,自动连接→执行→断开
  • session_id: 会话 ID(连续执行多命令时使用,先调 ssh_connect 获取)
  • command: 要执行的命令(单条)
  • commands: 命令数组(按顺序执行)
  • audit: 留痕控制,取值 "force"(可选,见下节)

返回:

  • stdout: 标准输出
  • stderr: 标准错误
  • exitCode: 退出码
  • channel: 实际使用的通道(exec | shell)
  • channelReason: 选择该通道的原因

ssh_disconnect

断开 SSH 连接

参数:

  • session_id: SSH 会话 ID (必需)

ssh_list_sessions

列出所有活动的 SSH 会话

按需留痕(audit)

背景

在堡垒机(JumpServer / KoKo 等)场景下,SSH 通道类型决定了会话是否被录像:

| SSH 通道 | 堡垒机归类 | 是否录像 | |---|---|---| | exec(client.exec()) | 命令执行 | ❌ 不支持录像 | | shell(client.shell()) | 正常会话 | ✅ 完整录像 |

注意:是否分配 PTY 不影响这个判定。exec 即使带 pty: true,仍归为「命令执行」、不录像。

这意味着:如果所有命令都走 exec,变更操作在堡垒机侧没有操作级审计;如果都走 shell,日常只读巡检又会灌满审计记录。

行为

ssh_exec 会按命令性质自动选择通道:

ssh_exec(command)
  ├─ audit === 'force'   → shell 通道(强制留痕)
  ├─ 命中只读白名单       → exec 通道(不留痕,快且输出干净)
  └─ 其余一律            → shell 通道(留痕)

默认留痕,且不提供「关闭留痕」的选项。

这样判错的失败方向是单向的:

  • 只读命令被误判为需留痕 → 多一条审计记录(无害)
  • 变更命令被误判为只读 → 静默执行且不留痕(最坏情况,已在设计上避免)

只读判定

判定逻辑在 readonly_policy.js,采用「默认拒绝 + 显式约束」:

  • 不在白名单里的命令 → 一律留痕
  • 能读也能写的命令(ip / docker / kubectl / find / sed …)必须显式约束写形态
  • 无法静态分析的形态(> 重定向、$(...) 命令替换、管道进 shell)直接否决
  • 语义级写操作由 denyPattern 拦截(如 awk 的 system()、sysctl 的 key=value、mysql 的 INTO OUTFILE)

可通过 loadPolicy(jsonPath) 传入 JSON 覆盖内置白名单:

{
  "ls": {},
  "tail":      { "denyArgs": ["-f", "--follow"] },
  "sed":       { "denyArgs": ["-i", "--in-place"] },
  "systemctl": { "sub": ["status", "is-active", "list-units"] },
  "mysql":     { "requirePattern": "\\b(SELECT|SHOW)\\b" }
}

字段说明:

| 字段 | 含义 | |---|---| | sub | 允许出现的子命令/位置参数,命中任一即通过;省略 = 不限制 | | denyArgs | 禁止出现的参数,命中任一即否决 | | denyPattern | 正则,匹配到即否决(语义级写操作) | | requirePattern | 正则,必须匹配才通过(如 SQL 必须是查询语句) |

键名规则:命令名中的 - 换成 _(如 redis-cli → redis_cli)。

环境变量

| 变量 | 默认 | 说明 | |---|---|---| | SSH_SHELL_TIMEOUT_MS | 30000 | shell 通道单条命令的超时上限(毫秒) |

使用示例

1. 密码认证连接

{
  "host": "192.168.1.100",
  "port": 22,
  "username": "admin",
  "auth_type": "password",
  "password": "your_password"
}

2. 公钥认证连接

{
  "host": "192.168.1.100",
  "port": 22,
  "username": "admin",
  "auth_type": "public_key",
  "private_key_path": "/home/user/.ssh/id_rsa"
}

3. 执行命令

{
  "session_id": "<从 ssh_connect 返回的 session_id>",
  "command": "ls -la /home"
}

4. 强制留痕执行(变更操作)

{
  "session_id": "<session_id>",
  "command": "systemctl restart nginx",
  "audit": "force"
}

5. 断开连接

{
  "session_id": "<session_id>"
}

命令复核自动应答(auto_confirm_review)

背景

堡垒机(JumpServer)若开了命令过滤 ACL 且动作是「审批」,命中其命令组正则的命令会被 koko 拦下, 在终端弹出交互提示:

需要复核,是否继续?[Y/N]

exec 通道没有 stdin,应答不了这个提示 —— 命令会一直卡住直到超时。 本工具的非只读命令走的是 PTY shell 通道,所以有能力把 y 写回去。

⚠️ 应答字符必须是「单字节 y」(2026-09-23 实测定论)

这是踩过的坑,写错会刷屏死循环:

| 写什么 | 结果 | |---|---| | 'y'(单字节,不带回车换行) | ✅ koko 立刻提交工单 + 发邮件通知审核人 + 进入倒计时等审批 | | 'y\n' | ❌ \n 被当成额外的输入行吞掉,koko 无限重放同一条提示 | | 'y\r' | ❌ 同 'y\n',死循环 | | 'Y'(大写) | ❌ 不被接受,同样重放提示 |

实测数据:写 'y\n' 时 45 秒内重放 3195 次、刷出 15983 行输出,且不提交任何申请。 原因:PTY 行规程下 koko 读的是单个按键,不是「一行输入」。

应答成功后 koko 会回一段(含 ANSI 色):

需要工单命令执行复核,已发邮件通知审核人
工单审核人:<某人>(<工号>)
可复制审核地址,通知审核人:https://.../tickets/<uuid>?type=command_confirm
请等待审核人复核命令 `...`,取消按 CTRL+C 或 CTRL+D。

随后进入每秒刷新的倒计时(0s → 1s → …),直到审批人处理或超时。

语义澄清(重要)

写 y 只是「提交审批申请」,命令不会立刻执行 —— 仍需审批人在 JumpServer 侧批准。 所以本功能不绕过任何管控,只是把「人工在终端按 y」这一步自动化了。

⚠️ 代价:工单的「申请人」会显示为当前堡垒机用户,但实际是工具自动发起的。 审批人无法从工单上区分「本人按的」与「工具自动按的」。启用前请确认这符合你们的管控要求。

行为

| auto_confirm_review | 检测到复核提示时 | |---|---| | false(默认) | 立刻返回 errorType: "ReviewRequired",不再白等到超时;stdout 里带上提示原文 | | true | 自动写单字节 y 提交申请,然后把看门狗放宽到 review_wait(默认 10 分钟)等审批 |

返回值里新增这些字段,便于调用方判断:

  • reviewPrompted —— 是否检测到复核提示
  • autoConfirmed —— 是否已自动应答 y
  • reviewSubmitted —— 工单是否已确认提交(koko 回了「已发邮件通知审核人」)
  • ticketUrl —— 从应答文本里抽出的审核链接,可直接转给审批人

审批通过后,shell 会继续执行原命令并回显结束哨兵 —— 也就是说 现有解析逻辑无需改动,命令正常执行、exitCode 正常返回。 超时未获批则返回 errorType: "ReviewPending"。

开关

  • 每次调用传参:auto_confirm_review: true
  • 全局默认开启:环境变量 SSH_AUTO_CONFIRM_REVIEW=1
  • 等待时长:review_wait(秒)或环境变量 SSH_REVIEW_WAIT_MS(毫秒)

已知限制

  • 命令以 exit / exec 结尾会终止 shell:哨兵无法回显,命令会走到超时。此时仍会返回已捕获的输出,但 exitCode 为 null。
  • exitCode 取的是最后一条命令的退出码:a; b; c 形式的复合命令,返回的是 c 的退出码。
  • shell 通道有固定开销:每次都要走一次 shell 初始化(MOTD 等),比 exec 慢约 1~2 秒。
  • 只读判定是安全网,不是证明:它做静态字符串分析,绕过方式是存在的。真正的强约束应放在服务端(如堡垒机的命令过滤 ACL)。
  • 复核提示的识别靠关键词匹配(需要复核 / 是否继续 / 是否提交申请 / 命令需要审批)。 若目标环境的提示文案不同,需同步调整 ssh_manager.js 里的 REVIEW_PROMPT_RE; 文案不匹配时表现为「没识别到提示,走普通超时」。
  • 自动应答只在 shell 通道生效:只读命令走 exec 通道,本来也不会被拦(除非 ACL 覆盖了只读命令名)。
  • 工单上显示的命令文本不完全可控:koko 记录复核工单时,提取的是「一次写入的整行」。 实测同样用单行拼装写法,有时工单上只显示 rm -f /tmp/x(干净), 有时显示 N=xxx; echo "..."; rm -f /tmp/x; echo "...$?" 全串(含哨兵)。 推测与 SSH 通道的数据分包时机有关,不做保证。 如果工单命令的可读性很重要,建议先确认目标环境的实际表现。

依赖

  • Node.js >= 18.0.0
  • ssh2 >= 1.15.0

License

MIT