
# ssh-dynamic-mcp
MCP-сервер для управления удалёнными серверами по SSH с **динамическими подключениями на лету** и встроенной **маскировкой секретов** в логах и ошибках.
## 📝 О проекте
`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` с `