13 KiB
ssh-dynamic-mcp
MCP-сервер для управления удалёнными серверами по SSH с динамическими подключениями на лету и встроенной маскировкой секретов в логах и ошибках.
📝 О проекте
ssh-dynamic-mcp — это форк 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-подключений |
🚀 Быстрый старт
Динамический режим (новое)
Запустите сервер вообще без аргументов — и подключайтесь к любому хосту прямо при вызове инструмента.
{
"mcpServers": {
"ssh-dynamic": {
"command": "node",
"args": ["C:/path/to/ssh-dynamic-mcp/build/index.js"]
}
}
}
Теперь в каждом вызове можно задать целевой хост и учётные данные:
{
"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:
{
"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] в любом логе и сообщении об ошибке, возвращаемом модели, — они не попадут в вывод сервера.
🔐 Статическая конфигурация (как в оригинале)
Весь функционал исходной версии поддерживается. Например, парольная аутентификация:
{
"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"
]
}
}
}
Несколько серверов
{
"mcpServers": {
"ssh-mcp-server": {
"command": "node",
"args": [
"C:/path/to/ssh-dynamic-mcp/build/index.js",
"--config-file", "ssh-config.json"
]
}
}
}
Файл ssh-config.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:
{
"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
⚙️ Справка по командной строке
Опции:
--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) не читала и не писала чувствительные файлы.
📦 Сборка и тесты
npm install
npm run build # компиляция TypeScript → build/
npm test # запуск тестов
Код: gitea.wtnet.ru/mshcheglov/ssh-dynamic-mcp
Оригинал: github.com/classfang/ssh-mcp-server
📄 Лицензия
ISC — см. файл LICENSE.