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

@zyluo/remote-ssh-mcp

v0.2.2

Published

Persistent, stateful remote SSH sessions for AI agents via Model Context Protocol (MCP)

Readme


为什么需要 Remote SSH MCP?

多数 Agent 访问远程机器的方式是:

bash → ssh host "cmd" → 断开 → 再来一次

每次调用都在交同样的税:

| 痛点 | 表现 | |------|------| | 🔁 Token 浪费 | banner、MOTD、登录噪声、pwd / whoami 探测反复灌进上下文 | | 🧊 状态丢失 | cwdexport、虚拟环境、shell 副作用无法延续 | | 🔌 不稳定 | 每次新建连接:超时、host key、ProxyJump、鉴权抖动 | | 🌀 错误放大 | 模型用更长探测命令补偿不确定性 → 更费 token |

Remote SSH MCP 把一条长生命周期的远程 Bash 做成一等 MCP 工具。相同 session id 会保留工作目录、环境变量和 shell 副作用;需要干净环境时关闭旧 session,再新开一个。

为什么选我们,而不是在 bash 里拼 ssh

面向 Agent 多步远程任务(部署、排障、构建、看日志)的收益对照:

| 维度 | 一次性 ssh host "…" | Remote SSH MCP | |------|----------------------|---------------------| | 💰 Token | 每一步都重交连接噪声 + 状态探测;模型常反复 cd / pwd | ssh_open 只付一次;后续 ssh_run 主要返回命令本身输出。结构化工具 + 头尾截断压住结果体积。多步会话里,相对「每次重连」通常可 少约 50–80% 的远程工具上下文噪声(取决于 MOTD 大小与模型是否爱探测)。 | | ✅ 成功率 | N 步 ≈ N 次握手 → N 次失败机会(超时、跳板、agent、host key) | 每个 session 只握手一次;后续命令走已存活 shell。长任务用 running + ssh_peek,不必因工具调用超时就整段重来。重连变少 → 任务中途「SSH 又挂了」的假失败环显著减少。 | | 🧳 便携性 | 远端本身也无需装东西——但每台跑 Agent 的机器都要重复同一套脆弱的 ssh … 拼装 | 只在跑 Claude / Cursor / Grok 等的本机装一次远端机器零安装(不要 Node、不要 MCP 守护进程、不要常驻 agent)。只要普通 shell 账号 + SSH 本就会用的工具(bashbase64stty 等)。密钥与跳板仍在本机 ~/.ssh/config。 | | 🧠 模型心智 | 模型自己编 ssh 字符串、转义与恢复逻辑 | 稳定工具面:open → run → peek → close,session id 是唯一句柄 | | 🔐 信任边界 | 容易把密钥读进上下文,或在带内要密码 | 只走本机 OpenSSH;工具绝不接收密码 / 私钥内容 |

便携性一句话:MCP 装在你的开发机 / AI 宿主上;ssh_config 里已有的机器都能管——服务器机群不用装任何包。

┌─────────────────────────┐         SSH(OpenSSH)        ┌──────────────────┐
│  笔记本 / CI Agent 机    │  ───────────────────────────► │  prod / staging  │
│  Claude · Cursor · Grok │     ~/.ssh/config · agent     │  无需安装 MCP    │
│  + remote-ssh-mcp       │                               │  普通 Bash 即可  │
└─────────────────────────┘                               └──────────────────┘

Token 示意(多步远程排障,示意而非基准测试):

一次性路径(每步 × 8):
  ssh 包装 + banner/MOTD + pwd/whoami + 重新 cd + 命令输出
  → 噪声占主导,上下文被重连垃圾填满

会话路径:
  ssh_open  → 一次(握手 + READY)
  ssh_run × 8 → 主要是真实 stdout/stderr(头尾截断)
  → 上下文留给工作产物,而不是传输层

实现不重写 SSH,而是复用本机 OpenSSH client,因此 ~/.ssh/config、known_hosts、SSH agent、ProxyJump 和硬件密钥策略仍然生效。

ssh_hosts()              → 发现允许的 Host 别名
ssh_open(host)           → session id
ssh_run(id, command)     → 同一 cwd + 环境
ssh_peek / ssh_interrupt → 观察或恢复长任务 / 卡住的命令
ssh_close(id)            → 释放 shell 与连接

功能特性

🧠 持久远程会话

  • 一个稳定 session ID 对应一条长生命周期远程 Bash
  • cwd 与环境变量 在多次 ssh_run 之间保留
  • 需要干净环境时新开 session 即可
  • 可对同一或不同 host 开多个 session(受 maxSessions 限制)

🔧 原生 OpenSSH 集成

  • 调用真实的 ssh 可执行文件,不自造加密栈
  • 完整尊重 ~/.ssh/configInclude、agent socket 与 ProxyJump
  • 强制 BatchMode=yesStrictHostKeyChecking=yes
  • 绝不从模型侧接收密码、私钥文本或任意 SSH 参数

📡 友好支持长任务

  • ssh_run 最多同步等待 wait_sec(默认 10 秒),到期返回 status: "running",远端命令继续
  • ssh_peek(wait_sec=...) 做长轮询,而不是空转
  • 可选硬超时 timeout_sec 才会发 Ctrl-C;默认不自动杀进程
  • 适合 docker pull、构建、下载、部署等不应占死工具调用的任务

🛡️ 安全与控制面

  • 来自 ssh_config + 配置 / 环境变量的精确 Host 别名 allowlist
  • *?! 的模式不会进入 allowlist
  • Fail-closed 中断:Ctrl-C 后若无法确认 shell 恢复,则关闭 session
  • 内置少量明显高风险命令的 denylist(不是完整策略引擎)
  • 空闲回收、session 上限,以及权限 0600JSONL 审计日志(命令哈希)

📦 面向模型的干净输出

  • stdout / stderr 分离
  • 头尾 字节截断,并保证 UTF-8 边界完整
  • 展示前剥离 ANSI / PTY 噪声(颜色、CSI、bracketed-paste 标记、纯控制空行)
  • 安静 open-frameTERM=dumbNO_COLOR、关闭 bracketed-paste,从源头少产生垃圾输出
  • 精简 JSON 载荷:省略空 stderrfalse 截断标志与请求回显字段,双通道 content + structuredContent 更省 token
  • ssh_hosts 只返回安全元数据:aliashostnameuserportproxy_jump
  • 永不泄露 IdentityFile、证书、agent socket 或 ProxyCommand

🔌 原生 MCP

  • stdio 传输,适配 Claude Desktop、Cursor 等 MCP 宿主
  • 兼容新旧 MCP 握手
  • 宿主 / stdio 退出时回收全部已建立及正在建立的 SSH 连接

工作原理

flowchart LR
  A[AI Agent] -->|MCP 工具| B[Remote SSH MCP]
  B -->|spawn| C[OpenSSH client]
  C -->|SSH + PTY| D[远程 Bash]
  D --> E[(cwd / env / 副作用)]

  subgraph 本机
    B
    C
    F[~/.ssh/config<br/>agent / keys]
    C -.-> F
  end

  subgraph 远程主机
    D
    E
  end

推荐 Agent 流程

1. ssh_hosts()                 # 从 allowlist 选别名
2. ssh_open(host="prod")       # 得到 session id "s_…"
3. ssh_run(id, "cd app && …")  # 状态绑定在此 id
4. ssh_run(id, "npm test")     # 仍在 app/,环境保留
5. ssh_peek(id, wait_sec=20)   # 长轮询慢任务
6. ssh_close(id)               # 用完清理

MCP 工具

| 工具 | 作用 | |------|------| | 🗂️ ssh_hosts | 列出允许的 Host 别名(仅安全元数据)。改完 ~/.ssh/config 后传 reload=true | | 🔓 ssh_open | 为允许的 Host 别名新建持久 shell → 返回 session id | | ▶️ ssh_run | 在已有 session 中执行非交互命令 | | 👀 ssh_peek | 查看状态与最新 N 行输出;可选 wait_sec 在运行中长轮询 | | ⛔ ssh_interrupt | 发送 Ctrl-C,并等待确认 shell 已恢复 | | 📋 ssh_list | 列出 session、cwd、状态、idle 回收倒计时与容量 | | 🔒 ssh_close | 清理远程临时状态并关闭连接 |

主要参数

| 工具 | 关键参数 | |------|----------| | ssh_open | host(必填 Host 别名),可选 name 标签 | | ssh_run | idcommand,可选 wait_sec、可选 timeout_sec | | ssh_peek | id,可选 lines(默认 50,最大 1000),可选 wait_sec | | ssh_interrupt / ssh_close | id | | ssh_hosts | 可选布尔 reload |


快速开始

环境要求

| 要求 | 说明 | |------|------| | Node.js | 20 或更新 | | OpenSSH client | 系统 ssh 在 PATH 上(或配置 sshPath) | | 远程主机 | Bash 以及 base64sttymkdircatrm | | SSH 配置 | Host 别名已写入 ~/.ssh/config,host key 已信任 |

⚠️ 首次连接的 host key 确认与鉴权请在普通终端完成。MCP 服务不会弹出密码或信任提示。

安装

git clone https://github.com/the-nine-nation/remote-ssh-mcp.git
cd remote-ssh-mcp
npm install
npm run build
npm test

启动:

node /absolute/path/to/remote-ssh-mcp/dist/index.js

或从 npm 安装(发布后):

npx @zyluo/remote-ssh-mcp
# 或
npm install -g @zyluo/remote-ssh-mcp
remote-ssh-mcp

本地从本仓库安装为包之后,也可使用 remote-ssh-mcp 可执行文件。

MCP 宿主配置

使用 stdio 的宿主通常类似下面(外层键名因产品而异):

{
  "mcpServers": {
    "remote-ssh": {
      "command": "node",
      "args": [
        "/absolute/path/to/remote-ssh-mcp/dist/index.js"
      ],
      "env": {
        "SSH_MCP_ALLOWED_HOSTS": "prod,staging"
      }
    }
  }
}

Cursor · Claude Desktop · Claude Code 等:把 command / args 指到构建好的 dist/index.js,并设置 SSH_MCP_ALLOWED_HOSTS(或依赖从 ~/.ssh/config 自动发现)。

SSH_MCP_ALLOWED_HOSTS附加 allowlist。默认还会读取 ~/.ssh/config 及其 Include 中的精确 Host 别名。工具参数只接受安全别名,不接受 user@host、端口或额外 SSH 选项。

修改 ~/.ssh/config 后调用 ssh_hosts(reload=true) 即可,无需重启 MCP。

凭证边界

认证只发生在本机 OpenSSH client 内部:

  • 工具不接受密码 / 私钥参数
  • ssh_hosts 不返回密钥路径、证书、agent socket 或 ProxyCommand
  • Agent 用 Host 别名调用 ssh_open 即可,不要用本地文件工具去读 ~/.ssh 私钥

配置

可选配置文件默认路径:

~/.config/remote-ssh-mcp/config.json
{
  "allowedHosts": ["prod", "staging"],
  "sshConfigPath": "~/.ssh/config",
  "sshPath": "ssh",
  "maxTimeoutSec": 1800,
  "defaultWaitSec": 10,
  "maxWaitSec": 30,
  "openTimeoutSec": 20,
  "idleTimeoutSec": 1800,
  "interruptGraceSec": 5,
  "maxSessions": 8,
  "outputMaxBytes": 32768,
  "outputHeadBytes": 4096,
  "auditLogPath": "~/.local/state/remote-ssh-mcp/audit.jsonl"
}

环境变量

| 环境变量 | 作用 | |----------|------| | SSH_MCP_CONFIG | 配置文件路径 | | SSH_MCP_ALLOWED_HOSTS | 逗号分隔的附加 Host allowlist | | SSH_MCP_SSH_CONFIG | SSH config 路径 | | SSH_MCP_SSH_PATH | OpenSSH 可执行文件 | | SSH_MCP_MAX_TIMEOUT_SEC | 显式 timeout_sec 的允许上限 | | SSH_MCP_DEFAULT_WAIT_SEC | ssh_run 返回 running 前的默认等待 | | SSH_MCP_MAX_WAIT_SEC | ssh_run / ssh_peekwait_sec 上限 | | SSH_MCP_OPEN_TIMEOUT_SEC | 建连 / 握手超时 | | SSH_MCP_IDLE_TIMEOUT_SEC | idle 自动回收时间 | | SSH_MCP_INTERRUPT_GRACE_SEC | Ctrl-C 后等待 marker 的宽限期 | | SSH_MCP_MAX_SESSIONS | 最大并发 session 数 | | SSH_MCP_OUTPUT_MAX_BYTES | stdout、stderr 各自保留上限 | | SSH_MCP_OUTPUT_HEAD_BYTES | 截断时保留的头部字节数 | | SSH_MCP_AUDIT_LOG | JSONL 审计日志路径 |

环境变量覆盖配置文件。审计日志权限固定为 0600,记录 session、host、状态、时长、命令长度、命令名和 SHA-256;记录完整命令参数,降低凭证入日志的风险。


执行语义

| 主题 | 行为 | |------|------| | 并发 | 同一 id 同时只跑一个前台命令;再次 ssh_run 返回 busy | | wait_sec | 只限制 MCP 调用 等待时长;到期返回 running,远端继续 | | 不要重试 | 收到 running 后不要重发同一长命令 — 用 ssh_peek 轮询 | | 硬超时 | 只有显式 timeout_sec 才会在到期后 Ctrl-C | | ssh_peek | 默认最新 50 行(最大 1000);字节上限仍生效;可长轮询 | | stdin | 用户命令 stdin 为 /dev/null — 不要跑 vimtop、交互安装器 | | 中断恢复 | Ctrl-C + 宽限期等协议 marker;恢复失败则关闭 session(fail-closed) | | 输出 | stdout / stderr 独立保留头尾,始终在合法 UTF-8 边界截断 | | Denylist | 只拦少量高风险模式,不是完整策略引擎 | | 信任模型 | 面向本机可信开发者 — 不是多租户远程执行服务 | | 宿主退出 | MCP 宿主 / stdio 断开会回收 SSH;nohup / setsid 进程可能继续 |

示例:wait_sec: 10 启动 docker pull,不设 timeout_sec。返回 running 表示原 pull 仍在进行 — 不要再启一次。用带正 wait_secssh_peek 等到 idle,或 ssh_interrupt,或另开 session 做并行工作。


开发

npm run typecheck
npm test
npm run build
npm audit --omit=dev

测试覆盖 MCP stdio 发现与调用、cwd / 环境持久化、流分离、任意分片边界上的帧解析、超时 fail-closed、shell 死亡、allowlist 发现、输出截断与 denylist。

协议与设计决策见 远程SSH-MCP设计.md


安全

不要通过公开 GitHub Issue 报告安全漏洞。在配置私有安全公告流程之前,请通过维护者 GitHub 主页 上的邮箱联系。

即使 MCP 传输正常,远程命令也可能产生不可逆副作用。请使用最小权限账号、收紧 allowlist,并仔细审查目标主机权限。


项目状态

| 项 | 状态 | |----|------| | 版本 | 0.2.2 | | 许可证 | MIT | | 语言 | TypeScript(Node ≥ 20) | | 协议 | MCP over stdio | | 到主机的传输 | 系统 OpenSSH |


更新日志

0.2.2 — 更安静的远端输出,更少 token

PTY + 交互式 bash 常注入转义序列;经 JSON 转义后像「二进制」(\u001b[?2004h、颜色 CSI、光标码等),每次 ssh_peek / ssh_run 都在浪费上下文。

| 改动 | 作用 | |------|------| | 展示时净化 | 剥离 ANSI/OSC/CSI,按 CR 覆盖(进度条),丢掉纯控制空行,再应用 lines 窗口 | | 安静会话打开 | 导出 TERM=dumb / NO_COLOR / CLICOLOR=0,关闭 bracketed-paste,open 时发送一次 \033[?2004l | | 精简工具载荷 | 省略空 stderrfalse 标志(truncatedinterrupted 等)与回显的 lines;保留空 stdout 以明确「无输出」 | | 测试 | 覆盖 sanitize、open-frame 安静化、session 展示路径与 slim JSON |

升级:npm i -g @zyluo/[email protected](或在 MCP 配置中 bump 版本),然后重启 MCP 进程以加载新服务端。

0.2.1

  • 修复 open frame 被 PTY 回显时 READY 标记解析失败

0.2.0

  • 首次公开发布(npm / GitHub)

Star History

如果这个项目帮你省了 token、少踩了断线坑,点个 ⭐ 能让更多人发现它。