内容
# 远程 SSH MCP
**English** | [简体中文](./README.zh-CN.md)
一个本地的 MCP 服务器,为 AI 代理提供持久的、有状态的远程 Bash 会话。重用相同的会话 ID 可以保留工作目录、环境变量和 shell 副作用。需要干净的环境时,可以打开新的会话。
远程 SSH MCP 使用系统 OpenSSH 客户端,而不是重新实现 SSH。现有的 `~/.ssh/config`、已知主机、SSH 代理、ProxyJump 路由和硬件密钥策略继续有效。
## 为什么
每次远程操作都运行 `ssh host "command"` 会反复连接、丢失 shell 状态、重复横幅和环境探测,浪费模型上下文。远程 SSH MCP 在小型、显式工具接口后面保持一个远程 shell:
```text
ssh_open(host) → 会话 ID
ssh_run(id, 命令) → 相同的工作目录和环境
ssh_peek(id) / ssh_interrupt(id) → 观察或恢复卡住的命令
ssh_close(id) → 释放 shell 和连接
```
## 功能
- 持久的远程 Bash 会话,带有稳定的 ID
- 每个会话内的工作目录和环境持久性
- 工具结果中的单独 `stdout` 和 `stderr`
- 非阻塞的长命令观察,带有单独的硬超时
- 当 shell 恢复无法确认时,安全地失败关闭
- 带有效 UTF-8 边界的头部和尾部输出截断
- 来自 `ssh_config` 和显式配置的精确 SSH 主机别名允许列表
- 会话限制、空闲回收、命令审计和最小安全拒绝列表
- MCP stdio 支持旧版和当前协议握手
- 无密码、私钥文本或任意 SSH 选项参数
## MCP 工具
| 工具 | 用途 |
|---|---|
| `ssh_open` | 为允许的 SSH 主机别名打开干净的持久 shell |
| `ssh_run` | 在现有会话中运行非交互式命令 |
| `ssh_peek` | 检查状态和最新的 N 输出行(默认为 50) |
| `ssh_interrupt` | 发送 Ctrl-C 并等待确认 shell 恢复 |
| `ssh_list` | 列出会话、工作目录、状态、空闲倒计时和容量 |
| `ssh_close` | 清理并关闭会话 |
## 要求
- Node.js 20 或更高版本
- OpenSSH 客户端
- 带有 Bash、 `base64`、`stty`、`mkdir`、`cat` 和 `rm` 的远程主机
- 配置的 SSH 主机别名和已知的 hosts 密钥
服务器强制执行 `BatchMode=yes` 和 `StrictHostKeyChecking=yes`。在正常终端中完成首次连接的主机密钥确认和身份验证设置,然后再使用 MCP 服务器。它永远不会打开密码或确认提示。
## 安装
```bash
git clone https://github.com/the-nine-nation/remote-ssh-mcp.git
cd remote-ssh-mcp
npm install
npm run build
npm test
```
直接运行服务器:
```bash
node /绝对路径/to/remote-ssh-mcp/dist/index.js
```
或者,在将其安装为包后,使用 `remote-ssh-mcp` 可执行文件。
## MCP 主机配置
大多数 stdio MCP 主机接受以下形状的配置;外部密钥可能因主机而异:
```json
{
"mcpServers": {
"remote-ssh": {
"command": "node",
"args": [
"/绝对路径/to/remote-ssh-mcp/dist/index.js"
],
"env": {
"SSH_MCP_ALLOWED_HOSTS": "prod,staging"
}
}
}
}
```
`SSH_MCP_ALLOWED_HOSTS` 将显式别名添加到允许列表中。默认情况下,服务器还会从 `~/.ssh/config` 及其 `Include` 文件中发现确切的 `Host` 别名。包含 `*`、`?` 或 `!` 的模式将被忽略。工具输入仅接受安全的别名,不接受 `user@host`、端口或额外的 SSH 选项。
## 配置
可选的配置文件默认为:
```text
~/.config/remote-ssh-mcp/config.json
```
示例:
```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` | 以逗号分隔的额外主机别名 |
| `SSH_MCP_SSH_CONFIG` | SSH 配置路径 |
| `SSH_MCP_SSH_PATH` | OpenSSH 可执行文件 |
| `SSH_MCP_MAX_TIMEOUT_SEC` | 最大显式请求命令超时 |
| `SSH_MCP_DEFAULT_WAIT_SEC` | `ssh_run` 等待多长时间后返回 `running` |
| `SSH_MCP_MAX_WAIT_SEC` | 允许的最大 `wait_sec` |
| `SSH_MCP_OPEN_TIMEOUT_SEC` | 连接和握手超时 |
| `SSH_MCP_IDLE_TIMEOUT_SEC` | 空闲会话生命周期 |
| `SSH_MCP_INTERRUPT_GRACE_SEC` | Ctrl-C 后标记恢复宽限期 |
| `SSH_MCP_MAX_SESSIONS` | 最大活动会话数 |
| `SSH_MCP_OUTPUT_MAX_BYTES` | 每流保留的输出限制 |
| `SSH_MCP_OUTPUT_HEAD_BYTES` | 截断时保留的头部字节 |
| `SSH_MCP_AUDIT_LOG` | JSONL 审计日志路径 |
审计日志以 `0600` 模式创建。它记录会话、主机、结果、持续时间、命令长度、命令名称和 SHA-256 哈希。故意省略完整命令参数以减少记录机密的机会。
## 执行语义
- 一个会话一次只接受一个前台命令。并发 `ssh_run` 调用返回 `busy` 而不是排队。
- `wait_sec` 仅限制 MCP 调用等待的时间。如果超时,`ssh_run` 返回 `status: "running"`,而远程命令继续运行。不要重新启动命令。轮询 `ssh_peek`,使用 `ssh_interrupt` 停止,或打开另一个会话进行并行工作。
- 默认情况下,命令没有自动执行超时。模型拥有它们的生命周期。只有显式提供的 `timeout_sec` 才创建发送 Ctrl-C 的硬截止日期。
- `ssh_peek` 默认返回 stdout 和 stderr 的最新 50 行。传递 `lines`(最大 1,000)以获取不同的尾部长度。字节限制仍然适用,因此非常长的单个行仍然有界限。
- 用户命令的 stdin 为 `/dev/null`。不要运行 `vim`、`top`、交互式安装程序或其他 TUI 输入驱动程序。
- 超时发送 Ctrl-C。如果在宽限期内到达完整的协议标记,会话返回到空闲状态。否则,会话关闭以防止未知前台进程破坏下一个命令。
- `stdout` 和 `stderr` 独立保留其开头和结尾。响应始终在有效的 UTF-8 边界结束。
- 内置拒绝列表仅阻止几个明显破坏性的模式。它不是一个完整的策略引擎。
- 该项目针对受信任的本地开发环境。它不是多租户远程执行服务。
- 如果 MCP 主机退出或其 stdio/父连接消失,服务器关闭每个跟踪的 SSH 连接,包括仍在打开的连接。
正常的前台进程使用 PTY 结束;故意分离的进程(如 `nohup`、`setsid`、服务和容器)可能会继续运行。
例如,使用 `wait_sec: 10` 启动 `docker pull`,省略 `timeout_sec`。`running` 结果意味着原始拉取仍然活动 — 而不是应该重试。 使用相同的会话 ID 调用 `ssh_peek`,直到它变为 `idle`,显式中断它,或打开另一个会话进行并行工作。
## 开发
```bash
npm run typecheck
npm test
npm run build
npm audit --omit=dev
```
测试套件涵盖了 MCP stdio 发现和调用、持久 cwd/环境状态、流分离、跨任意块边界的帧、超时失败关闭行为、shell 死亡、允许列表发现、输出截断和安全拒绝列表。
## 安全
请不要通过公共 GitHub 问题报告安全漏洞。在配置了私有安全咨询工作流程之前,请通过其 GitHub 个人资料中列出的电子邮件联系维护人员。
远程命令可以具有不可逆的副作用,即使 MCP 传输正确工作。审查主机权限、使用最小特权帐户并保持允许列表范围窄。
## 许可证
[MIT](./LICENSE)
线协议和详细设计决策在 [远程SSH-MCP设计.md](./远程SSH-MCP设计.md) 中记录。