249 lines
13 KiB
Markdown
249 lines
13 KiB
Markdown
<div align="center">
|
||
|
||
<img src="images/ssh-mcp-server-logo-v2.png" alt="ssh-mcp-server logo" width="220">
|
||
|
||
# ssh-dynamic-mcp
|
||
|
||
MCP-сервер для управления удалёнными серверами по SSH с **динамическими подключениями на лету** и встроенной **маскировкой секретов** в логах и ошибках.
|
||
|
||
</div>
|
||
|
||
## 📝 О проекте
|
||
|
||
`ssh-dynamic-mcp` — это форк [classfang/ssh-mcp-server](https://github.com/classfang/ssh-mcp-server) (v1.9.0), расширенный поддержкой **динамического режима**: теперь сервер можно запустить **без какой-либо конфигурации** и подключаться к произвольному хосту прямо в каждом вызове инструмента, передавая `host`, `username` и пароль (или приватный ключ) в параметрах вызова.
|
||
|
||
Ключевые отличия от исходной версии:
|
||
|
||
- 🔌 **Динамический режим** — запуск без аргументов и подключение «на лету» к любому хосту
|
||
- 🛡️ **Маскировка секретов** — пароли, фразы-пароли и ключи автоматически заменяются на `[REDACTED]` в логах и сообщениях об ошибках
|
||
- 🔑 **`--password-from-env`** — чтение пароля из переменной окружения вместо аргументов командной строки
|
||
- 🚫 Новые стабильные коды ошибок, в том числе `SSH_CONFIG_MISSING` при неполных параметрах подключения
|
||
|
||
Остальной функционал исходной версии (статическая конфигурация, несколько серверов, прокси, shell-транспорт, команды-шаблоны, whitelist/blacklist, 2FA) сохранён и работает как раньше.
|
||
|
||
## 🛠️ Инструменты
|
||
|
||
| Инструмент | Назначение |
|
||
|------------|------------|
|
||
| `execute-command` | Выполнить команду на удалённом сервере |
|
||
| `upload` | Загрузить локальный файл на сервер |
|
||
| `download` | Скачать файл с сервера |
|
||
| `list-servers` | Показать список доступных SSH-подключений |
|
||
|
||
## 🚀 Быстрый старт
|
||
|
||
### Динамический режим (новое)
|
||
|
||
Запустите сервер вообще **без аргументов** — и подключайтесь к любому хосту прямо при вызове инструмента.
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"ssh-dynamic": {
|
||
"command": "node",
|
||
"args": ["C:/path/to/ssh-dynamic-mcp/build/index.js"]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
Теперь в каждом вызове можно задать целевой хост и учётные данные:
|
||
|
||
```json
|
||
{
|
||
"tool": "execute-command",
|
||
"params": {
|
||
"cmdString": "df -h",
|
||
"host": "192.168.1.10",
|
||
"port": 22,
|
||
"username": "max",
|
||
"password": "пароль"
|
||
}
|
||
}
|
||
```
|
||
|
||
То же относится к `upload` и `download` — передавайте `host`/`username` (+ `password` или `privateKey`) прямо в параметрах вызова, и для операции создастся одноразовое эфемерное подключение, которое будет закрыто после выполнения.
|
||
|
||
> **Как это устроено**: когда в вызове присутствуют `host` и `username`, сервер открывает отдельное соединение только для этой операции (динамический режим). Если их нет — используется `connectionName` для подключения к предварительно настроенному (статическому) серверу.
|
||
|
||
### Безопасность паролей
|
||
|
||
Пароли в аргументах командной строки видны в списке процессов и командной истории. Чтобы этого избежать, используйте `--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"
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
Пароль будет прочитан из переменной окружения `SSH_MCP_PASSWORD`, заданной в среде, где запущен сервер.
|
||
|
||
Секреты (пароль, фраза-пароль приватного ключа) автоматически маскируются знаком `[REDACTED]` в любом логе и сообщении об ошибке, возвращаемом модели, — они **не** попадут в вывод сервера.
|
||
|
||
## 🔐 Статическая конфигурация (как в оригинале)
|
||
|
||
Весь функционал исходной версии поддерживается. Например, парольная аутентификация:
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"ssh-mcp-server": {
|
||
"command": "node",
|
||
"args": [
|
||
"C:/path/to/ssh-dynamic-mcp/build/index.js",
|
||
"--host", "192.168.1.1",
|
||
"--port", "22",
|
||
"--username", "root",
|
||
"--password", "pwd123456"
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Несколько серверов
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"ssh-mcp-server": {
|
||
"command": "node",
|
||
"args": [
|
||
"C:/path/to/ssh-dynamic-mcp/build/index.js",
|
||
"--config-file", "ssh-config.json"
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
Файл `ssh-config.json` (массив или объект):
|
||
|
||
```json
|
||
[
|
||
{
|
||
"name": "dev",
|
||
"host": "1.2.3.4",
|
||
"port": 22,
|
||
"username": "alice",
|
||
"password": "secret"
|
||
},
|
||
{
|
||
"name": "bastion",
|
||
"host": "9.9.9.9",
|
||
"port": 22,
|
||
"username": "ops",
|
||
"password": "pwd123456",
|
||
"transportMode": "shell"
|
||
}
|
||
]
|
||
```
|
||
|
||
Выбор подключения при вызове — через `connectionName`:
|
||
|
||
```json
|
||
{
|
||
"tool": "execute-command",
|
||
"params": {
|
||
"cmdString": "ls -al",
|
||
"connectionName": "dev"
|
||
}
|
||
}
|
||
```
|
||
|
||
## ⚙️ Динамические параметры инструментов
|
||
|
||
Для `execute-command`, `upload` и `download` в динамическом режиме доступны:
|
||
|
||
| Параметр | Тип | Описание |
|
||
|----------|-----|----------|
|
||
| `host` | string | Целевой хост (IP или hostname) |
|
||
| `port` | number | SSH-порт (по умолчанию `22`) |
|
||
| `username` | string | SSH-пользователь |
|
||
| `password` | string | Пароль |
|
||
| `privateKey` | string | Путь к приватному ключу или его содержимое |
|
||
| `passphrase` | string | Фраза-пароль для зашифрованного ключа |
|
||
|
||
> `host` и `username` обязательны для запуска динамического подключения. Если их не передать — будет использован `connectionName` (статический сервер).
|
||
|
||
## ⏱️ Тайм-ауты и лимиты
|
||
|
||
- `timeout` — тайм-аут одной команды (мс, опционально; по умолчанию 30000 мс)
|
||
- `commandTimeoutMs` / `shellCommandTimeoutMs` — настраиваемые значения по умолчанию в конфигурации
|
||
- `connectionTimeoutMs` — лимит установления SSH-соединения (по умолчанию 30000 мс)
|
||
- `sftpTimeoutMs` — тайм-аут SFTP-операций (по умолчанию 300000 мс)
|
||
- `maxOutputBytes` — ограничение общего объёма `stdout`+`stderr` одной команды (по умолчанию 10 MiB; `0` отключает)
|
||
|
||
## 🛡️ Продвинутые возможности (из оригинала)
|
||
|
||
- **Прокси**: `--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`
|
||
|
||
## ⚙️ Справка по командной строке
|
||
|
||
```text
|
||
Опции:
|
||
--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) не читала и не писала чувствительные файлы.
|
||
|
||
## 📦 Сборка и тесты
|
||
|
||
```bash
|
||
npm install
|
||
npm run build # компиляция TypeScript → build/
|
||
npm test # запуск тестов
|
||
```
|
||
|
||
Код: [gitea.wtnet.ru/mshcheglov/ssh-dynamic-mcp](https://gitea.wtnet.ru/mshcheglov/ssh-dynamic-mcp)
|
||
|
||
Оригинал: [github.com/classfang/ssh-mcp-server](https://github.com/classfang/ssh-mcp-server)
|
||
|
||
## 📄 Лицензия
|
||
|
||
ISC — см. файл [LICENSE](LICENSE).
|