docs: rewrite README for dynamic mode in Russian
This commit is contained in:
@@ -2,85 +2,103 @@
|
||||
|
||||
<img src="images/ssh-mcp-server-logo-v2.png" alt="ssh-mcp-server logo" width="220">
|
||||
|
||||
# ssh-mcp-server
|
||||
# ssh-dynamic-mcp
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
基于 SSH 的 MCP (Model Context Protocol) 服务器,允许通过 MCP 协议远程执行 SSH 命令。
|
||||
|
||||
[English Document](README_EN.md) | 中文文档
|
||||
MCP-сервер для управления удалёнными серверами по SSH с **динамическими подключениями на лету** и встроенной **маскировкой секретов** в логах и ошибках.
|
||||
|
||||
</div>
|
||||
|
||||
## 📝 项目介绍
|
||||
## 📝 О проекте
|
||||
|
||||
ssh-mcp-server 是一个桥接工具,可以让 AI 助手等支持 MCP 协议的应用通过标准化接口执行远程 SSH 命令。这使得 AI 助手能够安全地操作远程服务器,执行命令并获取结果,而无需直接暴露 SSH 凭据给 AI 模型。
|
||||
`ssh-dynamic-mcp` — это форк [classfang/ssh-mcp-server](https://github.com/classfang/ssh-mcp-server) (v1.9.0), расширенный поддержкой **динамического режима**: теперь сервер можно запустить **без какой-либо конфигурации** и подключаться к произвольному хосту прямо в каждом вызове инструмента, передавая `host`, `username` и пароль (или приватный ключ) в параметрах вызова.
|
||||
|
||||
💬 如有任何问题,欢迎加入微信群交流:
|
||||
Ключевые отличия от исходной версии:
|
||||
|
||||
<img src="images/wechat.jpg" alt="wechat" width="220">
|
||||
- 🔌 **Динамический режим** — запуск без аргументов и подключение «на лету» к любому хосту
|
||||
- 🛡️ **Маскировка секретов** — пароли, фразы-пароли и ключи автоматически заменяются на `[REDACTED]` в логах и сообщениях об ошибках
|
||||
- 🔑 **`--password-from-env`** — чтение пароля из переменной окружения вместо аргументов командной строки
|
||||
- 🚫 Новые стабильные коды ошибок, в том числе `SSH_CONFIG_MISSING` при неполных параметрах подключения
|
||||
|
||||
## ✨ 功能亮点
|
||||
Остальной функционал исходной версии (статическая конфигурация, несколько серверов, прокси, shell-транспорт, команды-шаблоны, whitelist/blacklist, 2FA) сохранён и работает как раньше.
|
||||
|
||||
- **🔒 安全连接**:支持多种安全的 SSH 连接方式,包括密码认证和私钥认证(支持带密码的私钥)
|
||||
- **🛡️ 命令安全控制**:通过灵活的黑白名单机制,精确控制允许执行的命令范围,防止危险操作
|
||||
- **🔄 标准化接口**:符合 MCP 协议规范,与支持该协议的 AI 助手无缝集成
|
||||
- **🚇 双传输模式**:同时支持 `exec` 和 `shell` 两种 transport,兼容直连主机与堡垒机或跳板机场景
|
||||
- **📂 文件传输**:支持双向文件传输功能,可上传本地文件到服务器或从服务器下载文件
|
||||
- **🔑 凭据隔离**:SSH 凭据完全在本地管理,不会暴露给 AI 模型,增强安全性
|
||||
- **🚀 即用即走**:使用 NPX 可直接运行,无需全局安装,方便快捷
|
||||
## 🛠️ Инструменты
|
||||
|
||||
## 📦 开源仓库
|
||||
| Инструмент | Назначение |
|
||||
|------------|------------|
|
||||
| `execute-command` | Выполнить команду на удалённом сервере |
|
||||
| `upload` | Загрузить локальный файл на сервер |
|
||||
| `download` | Скачать файл с сервера |
|
||||
| `list-servers` | Показать список доступных SSH-подключений |
|
||||
|
||||
GitHub:[https://github.com/classfang/ssh-mcp-server](https://github.com/classfang/ssh-mcp-server)
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
NPM: [https://www.npmjs.com/package/@fangjunjie/ssh-mcp-server](https://www.npmjs.com/package/@fangjunjie/ssh-mcp-server)
|
||||
### Динамический режим (новое)
|
||||
|
||||
## 🛠️ 工具列表
|
||||
Запустите сервер вообще **без аргументов** — и подключайтесь к любому хосту прямо при вызове инструмента.
|
||||
|
||||
| 工具 | 名称 | 描述 |
|
||||
|---------|-----------|----------|
|
||||
| execute-command | 命令执行工具 | 在远程服务器上执行 SSH 命令并获取执行结果 |
|
||||
| upload | 文件上传工具 | 将本地文件上传到远程服务器指定位置 |
|
||||
| download | 文件下载工具 | 从远程服务器下载文件到本地指定位置 |
|
||||
| list-servers | 服务器列表工具 | 列出所有可用SSH服务器配置 |
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-dynamic": {
|
||||
"command": "node",
|
||||
"args": ["C:/path/to/ssh-dynamic-mcp/build/index.js"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📚 使用方法
|
||||
Теперь в каждом вызове можно задать целевой хост и учётные данные:
|
||||
|
||||
### 0. 🤖 通过 AI Skill 快速配置(推荐)
|
||||
```json
|
||||
{
|
||||
"tool": "execute-command",
|
||||
"params": {
|
||||
"cmdString": "df -h",
|
||||
"host": "10.101.33.243",
|
||||
"port": 22,
|
||||
"username": "max",
|
||||
"password": "пароль"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果你使用支持 skill 的 AI 编程助手(如 Claude Code),可以直接使用内置的 **ssh-mcp-helper** skill 通过交互式问答完成安装和配置,无需手动编辑 JSON 文件。
|
||||
То же относится к `upload` и `download` — передавайте `host`/`username` (+ `password` или `privateKey`) прямо в параметрах вызова, и для операции создастся одноразовое эфемерное подключение, которое будет закрыто после выполнения.
|
||||
|
||||
**使用方式:**
|
||||
> **Как это устроено**: когда в вызове присутствуют `host` и `username`, сервер открывает отдельное соединение только для этой операции (динамический режим). Если их нет — используется `connectionName` для подключения к предварительно настроенному (статическому) серверу.
|
||||
|
||||
1. 从本仓库 `skills/` 目录安装该 skill
|
||||
2. 告诉你的 AI 助手:"帮我配置 ssh-mcp-server" 或 "给 Cursor 加一个 SSH MCP 连接"
|
||||
3. skill 会逐步引导你:检查 Node.js 环境 → 选择 MCP 客户端 → 选择认证方式 → 收集连接参数 → 生成并写入配置
|
||||
### Безопасность паролей
|
||||
|
||||
该 skill 支持下文所有场景(账号密码、私钥、SSH config 复用、SOCKS 代理、堡垒机、多连接、2FA、命令限制等),并自动生成格式正确的配置。
|
||||
Пароли в аргументах командной строки видны в списке процессов и командной истории. Чтобы этого избежать, используйте `--password-from-env`:
|
||||
|
||||
---
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-dynamic": {
|
||||
"command": "node",
|
||||
"args": [
|
||||
"C:/path/to/ssh-dynamic-mcp/build/index.js",
|
||||
"--password-from-env", "SSH_MCP_PASSWORD"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
下面的章节按从简单到复杂的顺序排列,最简单的入门方式就是用账号密码连接服务器。直接复制对应场景下的 `mcp.json` 配置到你的 MCP 客户端即可使用。
|
||||
Пароль будет прочитан из переменной окружения `SSH_MCP_PASSWORD`, заданной в среде, где запущен сервер.
|
||||
|
||||
> **⚠️ 重要提示**:在 MCP 配置文件中,每个命令行参数和其值必须是 `args` 数组中的独立元素。不要用空格将它们连接在一起。例如,使用 `"--host", "192.168.1.1"` 而不是 `"--host 192.168.1.1"`。
|
||||
Секреты (пароль, фраза-пароль приватного ключа) автоматически маскируются знаком `[REDACTED]` в любом логе и сообщении об ошибке, возвращаемом модели, — они **не** попадут в вывод сервера.
|
||||
|
||||
### 1. 🔑 账号密码(最简单)
|
||||
## 🔐 Статическая конфигурация (как в оригинале)
|
||||
|
||||
Весь функционал исходной версии поддерживается. Например, парольная аутентификация:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"command": "node",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"C:/path/to/ssh-dynamic-mcp/build/index.js",
|
||||
"--host", "192.168.1.1",
|
||||
"--port", "22",
|
||||
"--username", "root",
|
||||
@@ -91,290 +109,23 @@ NPM: [https://www.npmjs.com/package/@fangjunjie/ssh-mcp-server](https://www.npmj
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 🔐 账号 + 私钥
|
||||
### Несколько серверов
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"command": "node",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--host", "192.168.1.1",
|
||||
"--port", "22",
|
||||
"--username", "root",
|
||||
"--privateKey", "~/.ssh/id_rsa"
|
||||
"C:/path/to/ssh-dynamic-mcp/build/index.js",
|
||||
"--config-file", "ssh-config.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 🔏 带密码的私钥
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--host", "192.168.1.1",
|
||||
"--port", "22",
|
||||
"--username", "root",
|
||||
"--privateKey", "~/.ssh/id_rsa",
|
||||
"--passphrase", "pwd123456"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 📋 复用 `~/.ssh/config`
|
||||
|
||||
如果你已经在 `~/.ssh/config` 配置了主机别名,服务器会自动从中读取连接参数,`mcp.json` 里就不用再写一遍。
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--host", "myserver"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
假设你的 `~/.ssh/config` 包含:
|
||||
|
||||
```
|
||||
Host myserver
|
||||
HostName 192.168.1.1
|
||||
Port 22
|
||||
User root
|
||||
IdentityFile ~/.ssh/id_rsa
|
||||
```
|
||||
|
||||
你也可以指定自定义的 SSH 配置文件路径:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--host", "myserver",
|
||||
"--ssh-config-file", "/path/to/custom/ssh_config"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**注意**:命令行参数优先级高于 SSH 配置值。例如,如果你指定了 `--port 2222`,它会覆盖 SSH 配置中的端口。
|
||||
|
||||
### 5. 🌐 通过代理连接
|
||||
|
||||
当目标主机只能通过代理访问时,可使用 `--proxy` 配置 SOCKS5、HTTP 或 HTTPS 代理。
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--host", "192.168.1.1",
|
||||
"--port", "22",
|
||||
"--username", "root",
|
||||
"--password", "pwd123456",
|
||||
"--proxy", "http://username:password@proxy-host:proxy-port"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
支持的 URL 格式:
|
||||
|
||||
```text
|
||||
socks://username:password@proxy-host:1080
|
||||
socks5://username:password@proxy-host:1080
|
||||
http://username:password@proxy-host:8080
|
||||
https://username:password@proxy-host:8443
|
||||
```
|
||||
|
||||
HTTP 和 HTTPS 代理通过 `CONNECT` 方法建立到 SSH 服务的隧道,用户名和密码使用 Basic 代理认证。HTTP、HTTPS 未填写端口时分别默认使用 `80`、`443`;SOCKS5 必须填写端口。HTTPS 代理证书使用 Node.js 默认信任链进行验证。
|
||||
|
||||
原有 `socksProxy` 配置和 `--socksProxy` 参数继续兼容,但只接受 `socks://` 和 `socks5://`。不要同时配置 `proxy` 和 `socksProxy`。
|
||||
|
||||
### 6. 📝 使用命令白名单 / 黑名单
|
||||
|
||||
通过 `--whitelist` 和 `--blacklist` 限制服务器允许执行的命令范围。多个模式之间用逗号分隔,每个模式都是一个正则表达式。**生产环境强烈建议配置**。
|
||||
|
||||
白名单示例(仅允许只读型查看命令):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--host", "192.168.1.1",
|
||||
"--port", "22",
|
||||
"--username", "root",
|
||||
"--password", "pwd123456",
|
||||
"--whitelist", "^ls( .*)?,^cat .*,^df.*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
黑名单示例(屏蔽危险命令):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--host", "192.168.1.1",
|
||||
"--port", "22",
|
||||
"--username", "root",
|
||||
"--password", "pwd123456",
|
||||
"--blacklist", "^rm .*,^shutdown.*,^reboot.*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 注意:如果同时指定了白名单和黑名单,系统会先检查命令是否在白名单中,再检查是否在黑名单中,命令必须同时通过两项检查才能被执行。
|
||||
|
||||
### 7. 🧩 使用命令模板包裹命令
|
||||
|
||||
`commandTemplate` 会把每条执行的命令套进一个模板里,适合切换用户(`su`)、放进容器、或经过跳板机的场景。当命令会作为 shell 参数传入时使用 `<quotedCommand>`,需要原样插入时使用 `<command>`;模板会**在目录 `cd` 拼接之后**应用,因此整个 `cd ... && <实际命令>` 都会被包裹起来。
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--host", "10.0.0.1",
|
||||
"--port", "22",
|
||||
"--username", "deploy",
|
||||
"--password", "xxx",
|
||||
"--command-template", "su root -c <quotedCommand>"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
当指定目录为 `/data` 执行 `ls /app` 时,实际发送的命令是:
|
||||
|
||||
```
|
||||
su root -c 'cd -- '\''/data'\'' && ls /app'
|
||||
```
|
||||
|
||||
其他常见模板:
|
||||
|
||||
```text
|
||||
sudo bash -c <quotedCommand>
|
||||
docker exec -i mycontainer sh -c <quotedCommand>
|
||||
ssh jumphost <quotedCommand>
|
||||
```
|
||||
|
||||
### 8. 🚇 堡垒机 / 跳板机(`transportMode: shell`)
|
||||
|
||||
`transportMode` 默认是 `exec`。出现下面这些情况时,应该切换到 `shell`:
|
||||
|
||||
- SSH 登录成功,但 `exec` 执行命令失败
|
||||
- 远端必须等登录 banner、profile、环境初始化完成后才能正常执行命令
|
||||
- 连接目标本质上是堡垒机或只暴露交互式 shell 的设备
|
||||
|
||||
两者差异:
|
||||
|
||||
- `exec`:支持 `execute-command`、`upload`、`download`
|
||||
- `shell`:命令通过持久 shell 会话串行执行,内部带命令队列;但**不支持** `upload` / `download`,因为该模式下禁用了 SFTP
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--host", "bastion.example.com",
|
||||
"--port", "22",
|
||||
"--username", "ops",
|
||||
"--password", "pwd123456",
|
||||
"--transport-mode", "shell",
|
||||
"--shell-ready-timeout", "15000"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
JSON 配置文件中还可以通过 `shellCommandTimeoutMs` 覆盖 shell 模式下单条命令的默认超时。
|
||||
|
||||
### 9. 🔐 多因素认证(2FA / MFA)
|
||||
|
||||
当 SSH 服务器要求多因素认证(密码 + 私钥 + 2FA 验证码)时启用 `tryKeyboard`。密码和私钥会自动提供;对于非密码提示,请在连接前通过服务端环境变量 `SSH_MCP_2FA_CODE` 提供验证码。
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--host", "example.com",
|
||||
"--port", "22",
|
||||
"--username", "user",
|
||||
"--password", "your_password",
|
||||
"--privateKey", "/path/to/key",
|
||||
"--try-keyboard"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**认证流程:**
|
||||
1. 私钥认证(如果提供)
|
||||
2. 密码认证(如果提供)
|
||||
3. 键盘交互式认证通过 `SSH_MCP_2FA_CODE` 提供 2FA 验证码
|
||||
|
||||
### 10. 🧩 多 SSH 连接配置
|
||||
|
||||
需要在同一个 MCP server 里同时管理多个 SSH 目标时,给每个连接命名,调用时通过 `connectionName` 选择。共有三种配置方式:
|
||||
|
||||
#### 📄 方式一:使用配置文件(推荐)
|
||||
|
||||
创建 JSON 配置文件(例如 `ssh-config.json`):
|
||||
|
||||
**数组格式:**
|
||||
Файл `ssh-config.json` (массив или объект):
|
||||
|
||||
```json
|
||||
[
|
||||
@@ -383,10 +134,7 @@ JSON 配置文件中还可以通过 `shellCommandTimeoutMs` 覆盖 shell 模式
|
||||
"host": "1.2.3.4",
|
||||
"port": 22,
|
||||
"username": "alice",
|
||||
"password": "{abc=P100s0}",
|
||||
"socksProxy": "socks://127.0.0.1:10808",
|
||||
"commandTimeoutMs": 120000,
|
||||
"maxOutputBytes": 10485760
|
||||
"password": "secret"
|
||||
},
|
||||
{
|
||||
"name": "bastion",
|
||||
@@ -394,231 +142,107 @@ JSON 配置文件中还可以通过 `shellCommandTimeoutMs` 覆盖 shell 模式
|
||||
"port": 22,
|
||||
"username": "ops",
|
||||
"password": "pwd123456",
|
||||
"transportMode": "shell",
|
||||
"shellReadyTimeoutMs": 15000,
|
||||
"shellCommandTimeoutMs": 45000,
|
||||
"connectionTimeoutMs": 30000,
|
||||
"keepaliveIntervalMs": 10000,
|
||||
"keepaliveCountMax": 3
|
||||
},
|
||||
{
|
||||
"name": "prod",
|
||||
"host": "5.6.7.8",
|
||||
"port": 22,
|
||||
"username": "bob",
|
||||
"password": "yyy",
|
||||
"socksProxy": "socks://127.0.0.1:10808"
|
||||
},
|
||||
{
|
||||
"name": "secure-server",
|
||||
"host": "secure.example.com",
|
||||
"port": 22,
|
||||
"username": "admin",
|
||||
"password": "your_password",
|
||||
"privateKey": "/path/to/private/key",
|
||||
"tryKeyboard": true
|
||||
"transportMode": "shell"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**对象格式:**
|
||||
|
||||
```json
|
||||
{
|
||||
"dev": {
|
||||
"host": "1.2.3.4",
|
||||
"port": 22,
|
||||
"username": "alice",
|
||||
"password": "{abc=P100s0}",
|
||||
"socksProxy": "socks://127.0.0.1:10808",
|
||||
"commandTimeoutMs": 120000,
|
||||
"maxOutputBytes": 10485760
|
||||
},
|
||||
"bastion": {
|
||||
"host": "9.9.9.9",
|
||||
"port": 22,
|
||||
"username": "ops",
|
||||
"password": "pwd123456",
|
||||
"transportMode": "shell",
|
||||
"shellReadyTimeoutMs": 15000,
|
||||
"shellCommandTimeoutMs": 45000
|
||||
},
|
||||
"prod": {
|
||||
"host": "5.6.7.8",
|
||||
"port": 22,
|
||||
"username": "bob",
|
||||
"password": "yyy",
|
||||
"socksProxy": "socks://127.0.0.1:10808"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
然后使用 `--config-file` 参数:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--config-file", "ssh-config.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 🔧 方式二:使用 JSON 格式的 --ssh 参数
|
||||
|
||||
可以直接传递 JSON 格式的配置字符串:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ssh-mcp-server": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@fangjunjie/ssh-mcp-server",
|
||||
"--ssh", "{\"name\":\"dev\",\"host\":\"1.2.3.4\",\"port\":22,\"username\":\"alice\",\"password\":\"{abc=P100s0}\",\"socksProxy\":\"socks://127.0.0.1:10808\"}",
|
||||
"--ssh", "{\"name\":\"bastion\",\"host\":\"9.9.9.9\",\"port\":22,\"username\":\"ops\",\"password\":\"pwd123456\",\"transportMode\":\"shell\",\"shellReadyTimeoutMs\":15000}",
|
||||
"--ssh", "{\"name\":\"prod\",\"host\":\"5.6.7.8\",\"port\":22,\"username\":\"bob\",\"password\":\"yyy\",\"socksProxy\":\"socks://127.0.0.1:10808\"}"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 📝 方式三:旧格式逗号分隔(向后兼容)
|
||||
|
||||
对于密码中不包含特殊字符的简单情况,仍可使用旧格式:
|
||||
|
||||
```bash
|
||||
npx @fangjunjie/ssh-mcp-server \
|
||||
--ssh "name=dev,host=1.2.3.4,port=22,user=alice,password=xxx" \
|
||||
--ssh "name=prod,host=5.6.7.8,port=22,user=bob,password=yyy"
|
||||
```
|
||||
|
||||
> **⚠️ 注意**:旧格式在处理包含特殊字符(如 `=`、`,`、`{`、`}`)的密码时可能会有问题。如果密码包含特殊字符,请使用方式一或方式二。
|
||||
|
||||
在MCP工具调用时,通过 `connectionName` 参数指定目标连接名称,未指定时使用默认连接。
|
||||
|
||||
示例(在prod连接上执行命令):
|
||||
Выбор подключения при вызове — через `connectionName`:
|
||||
|
||||
```json
|
||||
{
|
||||
"tool": "execute-command",
|
||||
"params": {
|
||||
"cmdString": "ls -al",
|
||||
"connectionName": "prod"
|
||||
"connectionName": "dev"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
示例(带超时选项的命令执行):
|
||||
## ⚙️ Динамические параметры инструментов
|
||||
|
||||
```json
|
||||
{
|
||||
"tool": "execute-command",
|
||||
"params": {
|
||||
"cmdString": "ping -c 10 127.0.0.1",
|
||||
"connectionName": "prod",
|
||||
"timeout": 5000
|
||||
}
|
||||
}
|
||||
```
|
||||
Для `execute-command`, `upload` и `download` в динамическом режиме доступны:
|
||||
|
||||
### ⏱️ 命令执行超时
|
||||
| Параметр | Тип | Описание |
|
||||
|----------|-----|----------|
|
||||
| `host` | string | Целевой хост (IP или hostname) |
|
||||
| `port` | number | SSH-порт (по умолчанию `22`) |
|
||||
| `username` | string | SSH-пользователь |
|
||||
| `password` | string | Пароль |
|
||||
| `privateKey` | string | Путь к приватному ключу или его содержимое |
|
||||
| `passphrase` | string | Фраза-пароль для зашифрованного ключа |
|
||||
|
||||
`execute-command` 工具支持超时选项,防止命令无限期挂起:
|
||||
> `host` и `username` обязательны для запуска динамического подключения. Если их не передать — будет использован `connectionName` (статический сервер).
|
||||
|
||||
- **timeout**: 单次调用的命令执行超时时间(毫秒,可选);传入时会覆盖连接配置,未传入时使用对应连接配置或其 30000ms 默认值
|
||||
- 在 JSON 配置文件里为单个连接设置 `commandTimeoutMs`,可以改掉这个默认值,避免每次调用都手动传 `timeout`(`exec` 模式)
|
||||
- `shell` 模式对应的配置项是 `shellCommandTimeoutMs`
|
||||
- 调用参数里的 `timeout` 始终优先于上面两个配置项
|
||||
- 连接默认启用 SSH keepalive(`keepaliveIntervalMs`: 10000,`keepaliveCountMax`: 3),并使用 `connectionTimeoutMs` 限制连接建立时间
|
||||
- SFTP 打开和传输操作使用 `sftpTimeoutMs` 控制超时(默认 300000ms)
|
||||
- 错误响应现在包含稳定的 `code`、`message`、`retriable` 字段,便于上层 Agent 处理
|
||||
## ⏱️ Тайм-ауты и лимиты
|
||||
|
||||
这对于像 `ping`、`tail -f` 或其他可能阻塞执行的长时间运行进程特别有用。
|
||||
- `timeout` — тайм-аут одной команды (мс, опционально; по умолчанию 30000 мс)
|
||||
- `commandTimeoutMs` / `shellCommandTimeoutMs` — настраиваемые значения по умолчанию в конфигурации
|
||||
- `connectionTimeoutMs` — лимит установления SSH-соединения (по умолчанию 30000 мс)
|
||||
- `sftpTimeoutMs` — тайм-аут SFTP-операций (по умолчанию 300000 мс)
|
||||
- `maxOutputBytes` — ограничение общего объёма `stdout`+`stderr` одной команды (по умолчанию 10 MiB; `0` отключает)
|
||||
|
||||
### 📦 命令输出限制
|
||||
## 🛡️ Продвинутые возможности (из оригинала)
|
||||
|
||||
会限制单条命令捕获的 `stdout` 和 `stderr` 总量,避免大文件或无限输出耗尽 MCP server 内存:
|
||||
- **Прокси**: `--proxy` поддерживает SOCKS5, HTTP и HTTPS
|
||||
- **Whitelist / blacklist**: `--whitelist`, `--blacklist` ограничивают допустимые команды
|
||||
- **Shell-транспорт**: `--transport-mode shell` для 堡垒机/跳板机 и интерактивных оболочек
|
||||
- **Командные шаблоны**: `--command-template` с `<quotedCommand>` / `<command>`
|
||||
- **SSH config**: переиспользование `~/.ssh/config` через `--host <alias>`
|
||||
- **2FA / MFA**: `--try-keyboard` + переменная `SSH_MCP_2FA_CODE` для одноразовых кодов
|
||||
- **Ограничение путей**: `--allowed-local-paths` и `--allowed-remote-paths`
|
||||
|
||||
- 在 JSON 连接配置中使用 `maxOutputBytes` 设置上限,默认值为 `10485760`(10 MiB)
|
||||
- `maxOutputBytes` 必须是非负整数;设置为 `0` 可禁用限制,但不建议对不受信任的命令禁用
|
||||
- 输出超过限制时,远端命令会被中止,工具返回 `OUTPUT_LIMIT_EXCEEDED` 错误和已经捕获的截断输出,不会把中止的命令误报为成功
|
||||
- 当 `pty` 为 `false` 时,成功命令写入 `stderr` 的警告或进度信息会保留在 `[stderr]` 区段中
|
||||
- `exec` 与 `shell` 两种模式都会应用该限制。区别在于 `exec` 模式只关闭该命令的通道,而 `shell` 模式的通道由该连接上的所有命令共用、远端在中止后仍会继续写入,因此会断开连接(与 shell 模式命令超时的处理一致)
|
||||
|
||||
### 🗂️ 列出所有SSH服务器
|
||||
|
||||
可以通过MCP工具 `list-servers` 获取所有可用的SSH服务器配置:
|
||||
|
||||
调用示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"tool": "list-servers",
|
||||
"params": {}
|
||||
}
|
||||
```
|
||||
|
||||
返回示例:
|
||||
|
||||
```json
|
||||
[
|
||||
{ "name": "dev", "host": "1.2.3.4", "port": 22, "username": "alice" },
|
||||
{ "name": "prod", "host": "5.6.7.8", "port": 22, "username": "bob" }
|
||||
]
|
||||
```
|
||||
|
||||
### ⚙️ 命令行选项参考
|
||||
## ⚙️ Справка по командной строке
|
||||
|
||||
```text
|
||||
选项:
|
||||
--config-file JSON 配置文件路径(推荐用于多服务器配置)
|
||||
--ssh-config-file SSH 配置文件路径(默认: ~/.ssh/config)
|
||||
--ssh SSH 连接配置(可以是 JSON 字符串或旧格式)
|
||||
-h, --host SSH 服务器主机地址或 SSH 配置中的别名
|
||||
-p, --port SSH 服务器端口
|
||||
-u, --username SSH 用户名
|
||||
-w, --password SSH 密码
|
||||
-k, --privateKey SSH 私钥文件路径
|
||||
-P, --passphrase 私钥密码(如果有的话)
|
||||
-a, --agent SSH agent socket 路径
|
||||
--try-keyboard 启用键盘交互式认证以支持 2FA/MFA(默认: false)
|
||||
-W, --whitelist 命令白名单,以逗号分隔的正则表达式
|
||||
-B, --blacklist 命令黑名单,以逗号分隔的正则表达式
|
||||
--proxy 代理地址,支持 SOCKS5、HTTP 和 HTTPS
|
||||
-s, --socksProxy 旧版 SOCKS5 代理地址(兼容参数)
|
||||
--allowed-local-paths upload/download 允许访问的额外本地路径,逗号分隔
|
||||
--allowed-remote-paths SFTP upload/download 允许访问的远端路径(POSIX 绝对路径),逗号分隔
|
||||
--transport-mode SSH transport 模式: exec 或 shell(默认: exec)
|
||||
--shell-ready-timeout shell 就绪探测超时,单位毫秒(默认: 10000)
|
||||
--command-template 命令模板;shell 参数用 <quotedCommand>,原样插入用 <command>
|
||||
--pty 为命令执行分配伪终端(默认: true)
|
||||
--pre-connect 启动时预连接所有配置的 SSH 服务器
|
||||
--version, -v 打印包版本
|
||||
--help 打印帮助信息
|
||||
Опции:
|
||||
--config-file <path> Загрузить конфигурации из JSON-файла
|
||||
--ssh-config-file <path> SSH-конфиг (по умолчанию: ~/.ssh/config)
|
||||
--ssh <config> Добавить конфигурацию (JSON или key=value)
|
||||
-h, --host <host> Хост или алиас из SSH config
|
||||
-p, --port <port> Порт (по умолчанию: 22)
|
||||
-u, --username <name> SSH-пользователь
|
||||
-w, --password <pw> SSH-пароль
|
||||
--password-from-env <name> Читать пароль из переменной окружения (безопаснее, чем -w)
|
||||
-k, --privateKey <path> Приватный ключ
|
||||
-P, --passphrase <pass> Фраза-пароль ключа
|
||||
-a, --agent <path> SSH agent socket
|
||||
-W, --whitelist <patterns> Белый список команд (регэкспы через запятую)
|
||||
-B, --blacklist <patterns> Чёрный список команд
|
||||
--proxy <url> Прокси (SOCKS5 / HTTP / HTTPS)
|
||||
-s, --socksProxy <url> Старая SOCKS5-прокси
|
||||
--allowed-local-paths <paths> Доп. локальные пути для upload/download
|
||||
--allowed-remote-paths <paths> Разрешённые удалённые пути (POSIX абсолютные)
|
||||
--transport-mode <mode> exec | shell (по умолчанию: exec)
|
||||
--shell-ready-timeout <ms> Тайм-аут готовности shell (по умолчанию: 10000)
|
||||
--command-template <tpl> Шаблон обёртки команд
|
||||
--pty Выделять псевдо-TTY (по умолчанию: включено)
|
||||
--pre-connect Предподключение ко всем серверам при старте
|
||||
--version, -v Версия
|
||||
--help Справка
|
||||
```
|
||||
|
||||
## 🛡️ 安全注意事项
|
||||
## 🛡️ Безопасность
|
||||
|
||||
该服务器提供了在远程服务器上执行命令和传输文件的强大功能。为确保安全使用,请注意以下几点:
|
||||
- **Динамический режим не имеет белого списка команд** — при подключении к произвольным хостам следите за тем, какой команды вы позволяете модели выполнять.
|
||||
- **Редокция активна всегда**: значения паролей и фраз-паролей, переданные в инструменты, автоматически заменяются на `[REDACTED]` в логах и сообщениях об ошибках.
|
||||
- **`--password-from-env`** рекомендован везде, где пароль задаётся через CLI, чтобы он не мелькал в списке процессов и истории команд.
|
||||
- **Приватные ключи** загружаются в память процесса — запускайте сервер в защищённой среде.
|
||||
- **Ограничивайте команды** через `--whitelist` / черный список для статических серверов.
|
||||
- **Пути** `upload`/`download` ограничивайте через `--allowed-local-paths` и `--allowed-remote-paths`, чтобы модель (или отправленный в неё prompt-injection) не читала и не писала чувствительные файлы.
|
||||
|
||||
- **命令白名单**:*强烈建议* 使用 `--whitelist` 选项来限制可执行的命令集合。如果没有白名单,任何命令都可以在远程服务器上执行,这可能带来重大的安全风险。
|
||||
- **私钥安全**:服务器会将 SSH 私钥读入内存。请确保运行 `ssh-mcp-server` 的机器是安全的。不要将服务器暴露给不受信任的网络。
|
||||
- **拒绝服务攻击 (DoS)**:服务器没有内置的速率限制。攻击者可能通过向服务器发送大量连接请求或大文件传输来发起 DoS 攻击。建议在具有速率限制功能的防火墙或反向代理后面运行服务器。
|
||||
- **路径遍历**:服务器内置了对本地文件系统路径遍历攻击的保护。但是,仍然需要注意在 `upload` 和 `download` 命令中使用的路径。
|
||||
- **本地传输范围**:默认仅允许访问当前工作目录。只有在明确可信时,才建议通过 `--allowed-local-paths` 或配置文件中的 `allowedLocalPaths` 放宽范围。
|
||||
- **远端传输范围**:SFTP upload/download 仅接受绝对 POSIX 路径。未配置 `allowedRemotePaths`(或 `--allowed-remote-paths`)时,任意远端路径都允许,但启动时会打印警告。强烈建议显式配置 `allowedRemotePaths` 白名单,避免模型被 prompt 注入后读写 `~/.ssh/authorized_keys`、`/etc/sshd_config` 之类敏感文件。
|
||||
## 📦 Сборка и тесты
|
||||
|
||||
## 🌟 Star 历史
|
||||
```bash
|
||||
npm install
|
||||
npm run build # компиляция TypeScript → build/
|
||||
npm test # запуск тестов
|
||||
```
|
||||
|
||||
## Star History
|
||||
Код: [gitea.wtnet.ru/mshcheglov/ssh-dynamic-mcp](https://gitea.wtnet.ru/mshcheglov/ssh-dynamic-mcp)
|
||||
|
||||
[](https://www.star-history.com/?type=date&legend=top-left&repos=classfang%2Fssh-mcp-server)
|
||||
Оригинал: [github.com/classfang/ssh-mcp-server](https://github.com/classfang/ssh-mcp-server)
|
||||
|
||||
## 📄 Лицензия
|
||||
|
||||
ISC — см. файл [LICENSE](LICENSE).
|
||||
|
||||
Reference in New Issue
Block a user