ssh-mcp
ssh-mcp
Централизованный MCP-шлюз, который предоставляет AI-агентам контролируемый доступ к SSH-инфраструктуре через Streamable HTTP.
ssh-mcp работает как единый HTTP-сервис. Несколько AI-клиентов — агенты, CI-пайплайны, дашборды — подключаются к одному шлюзу. SSH-учётные данные остаются на шлюзе. Политики авторизации, аудит-логирование и ограничение частоты запросов применяются централизованно до выполнения любой SSH-команды.
Оглавление
Related MCP server: MCP SSH Orchestrator
Архитектура
Локальный MCP через stdio (распространённый паттерн)
AI client
│
▼
local MCP process ──► SSH targetКаждый агент запускает собственный процесс. SSH-учётные данные находятся на каждой машине. Централизованного контроля нет.
ssh-mcp (централизованный HTTP-шлюз)
AI clients ───────┐
CI agents ────────┼──► ssh-mcp ──► SSH targets
Dashboards ───────┘ │
├─ API-key authentication
├─ per-client authorization
├─ rate limiting
├─ audit logging
└─ connection poolingОдно развёртывание обслуживает всех клиентов. Учётные данные, политики и логи находятся в одном месте.
Зачем нужен ssh-mcp?
Централизованный HTTP-шлюз — Одно развёртывание обслуживает всех AI-агентов, CI-пайплайны и дашборды через Streamable HTTP
Авторизация для каждого клиента — Разные API-ключи предоставляют разные наборы команд на разных серверах
Многоуровневые политики команд — Блокирующие паттерны, обнаружение опасных shell-конструкций и разрешающие списки для каждой цели работают вместе
Централизованный SSH-доступ — SSH-учётные данные находятся на шлюзе, а не на машине каждого агента
Журнал аудита — Каждая команда, каждый клиент, каждый результат — структурированные JSONL-логи с трассировкой запросов
Операционная устойчивость — Пул соединений, автоматические выключатели и повторные попытки с экспоненциальной задержкой
Наблюдаемость — Метрики Prometheus и эндпоинты здоровья для мониторинга
Контроль доступа для нескольких агентов
Разным агентам нужны разные разрешения. ssh-mcp обеспечивает это на шлюзе:
monitoring agent → API key A → read-only commands → all servers
deployment agent → API key B → deploy commands → web servers only
database agent → API key C → db commands → database server only ┌─ monitoring agent (read-only, all servers)
├─ deployment agent (deploy commands, web only)
MCP clients ──────┼─ database agent (db commands, db server only)
└─ ...
│
▼
ssh-mcp
│
centralized policies
│
┌──────────┼──────────┐
▼ ▼ ▼
web db monitoring
servers servers serversМинимальная конфигурация, демонстрирующая эту настройку:
{
"version": 1,
"ssh_targets": {
"web-1": { "host": "10.0.1.10", "username": "deploy" },
"db-1": { "host": "10.0.1.20", "username": "dbadmin" }
},
"allowed_commands": {
"default": {
"web-1": { "allow": ["uptime", "df -h", "free -m"] }
},
"api_keys": {
"deploy-key": {
"web-1": { "allow": ["systemctl restart app", "deploy *"] }
},
"db-key": {
"db-1": { "allow": ["systemctl restart postgres", "pg_dump *"] }
}
}
}
}Проблема
Большинство MCP SSH-серверов запускаются как локальные stdio-процессы — по одному на клиента, без общего состояния, без централизованной авторизации и без журнала аудита. Когда нескольким AI-агентам, CI-пайплайнам или дашбордам нужен SSH-доступ, каждый из них независимо управляет своими SSH-ключами и запускает собственный MCP-процесс. Это приводит к:
Отсутствию централизованного контроля доступа — каждый клиент сам решает, что ему можно запускать
Отсутствию журнала аудита — команды невидимы для команды эксплуатации
Расползанию SSH-ключей — ключи разбросаны по всем машинам, где работают агенты
Отсутствию ограничения частоты запросов — вышедший из-под контроля агент может перегрузить цель
Отсутствию пула соединений — каждый клиент открывает и закрывает SSH-сессии независимо
ssh-mcp решает эту проблему, разворачивая один MCP-сервер как HTTP-шлюз. Все клиенты подключаются к нему; он подключается к вашим SSH-целям. Авторизация, аутентификация, ограничение частоты запросов, пул соединений и аудит-логирование выполняются в одном месте.
Варианты использования
Управление серверами несколькими агентами
Запустите команду AI-агентов с разными уровнями доступа. Агент развёртывания может выполнять systemctl restart nginx на веб-серверах; агент мониторинга может выполнять journalctl где угодно; агент баз данных может запускать только psql на сервере БД. Каждый агент аутентифицируется собственным API-ключом; у каждого ключа свой набор разрешений.
Интеграция с CI/CD-пайплайнами
Направьте ваш CI-пайплайн на ssh-mcp вместо управления SSH-ключами на каждом раннере. Один API-ключ на пайплайн, сетевые правила для вашей CI-подсети и разрешающие списки команд гарантируют, что ваши скрипты развёртывания выполняют ровно то, что должны, — и ничего больше.
Централизованное получение логов и конфигураций
Используйте ssh_download_file, чтобы получать логи, конфигурационные файлы или дампы баз данных с удалённых серверов, не выходя из вашего MCP-клиента. 8-уровневая проверка пути и настройки корня песочницы гарантируют, что передача файлов остаётся в безопасных границах.
Дашборды состояния серверов
Создайте дашборд на базе MCP, который опрашивает uptime, free, df и ps по всему вашему парку серверов. Пул соединений переиспользует SSH-сессии, автоматический выключатель изолирует отказавшие цели, а метрики Prometheus на /metrics питают ваш существующий стек мониторинга.
Комплаенс и аудит
Каждая команда логируется в виде структурированного JSONL: кто что запускал, на каком сервере, с какого IP, было ли это разрешено и сколько времени заняло. Поле matched_via точно показывает, какой именно уровень авторизации принял решение. Изменения конфигурации логируются отдельно с состоянием до и после.
Модель безопасности
ssh-mcp применяет эшелонированную защиту (defense-in-depth) на каждом уровне. Полная модель безопасности описана в docs/SECURITY.md.
Граница безопасности: ssh-mcp добавляет уровень авторизации, аутентификации и аудита перед SSH. Он не заменяет права нижележащих SSH-учётных записей. Если команда разрешена, SSH-пользователь выполняет её с теми привилегиями, которыми обладает эта учётная запись. Сам шлюз следует защищать с помощью TLS и средств контроля сетевого доступа. Логи могут содержать вывод команд, и к ним следует относиться соответствующим образом.
Цепочка авторизации команд
Команды проверяются через упорядоченную многоуровневую цепочку. Если какой-либо уровень отклоняет запрос, обработка останавливается:
Уровень | Что проверяется | ||
1. Проверка цели | Известно ли имя сервера? | ||
2. | Соответствует ли команда заблокированному regex? | ||
3. Опасные паттерны | Содержит ли | ||
4. Защита от перенаправлений | Направлены ли перенаправления shell на | ||
5. Сегментация | После удаления перенаправлений и разбиения по |
| |
6. Правила | Правила разрешения/запрета для всех клиентов | ||
7. Правила | Правила разрешения/запрета для каждого ключа | ||
8. Правила | Правила разрешения/запрета для каждого CIDR | ||
9. Запрет | Неявное правило по умолчанию |
Аутентификация
API-ключи передаются через заголовки X-API-Key или Authorization: Bearer. Ключи хешируются с помощью PBKDF2-HMAC-SHA256 (100 000 итераций, случайная 16-байтовая соль) и проверяются сравнением за константное время. Исходные ключи никогда не хранятся.
Очистка входных данных
Команды, имена целей и строки логов очищаются перед обработкой: удаляются нулевые байты, удаляются управляющие символы, выполняется NFKC-нормализация, и всё прогоняется через защиту от ReDoS для block_patterns.
Предотвращение обхода путей
SFTP-передачи проходят 8-уровневую проверку пути, включая проверку нулевых байтов, удаление управляющих символов, нормализацию dot-сегментов, разрешение символьных ссылок и соблюдение корня песочницы.
Ограничение частоты запросов
Ограничитель частоты запросов со скользящим окном для каждого IP-адреса клиента (60 запросов / 60 секунд, /health исключён). При превышении лимита возвращается HTTP 429 с заголовком Retry-After.
Ограничение частоты запросов настраивается в разделе settings.rate_limit:
"settings": {
"rate_limit": {
"enabled": true, // set false to disable entirely
"max_requests_per_minute": 60, // max requests per client IP in the window
"window_seconds": 60.0, // sliding-window duration
"cleanup_interval_seconds": 300.0 // expired-entry GC interval
}
}Примечание: ограничитель частоты запросов создаётся один раз при запуске контейнера из начальной конфигурации и не пересоздаётся при горячей перезагрузке конфигурации. Чтобы отключить ограничение частоты запросов, необходимо установить
settings.rate_limit.enabledвfalseв конфигурации, которая присутствует при загрузке (например,config/ssh-mcp-config.jsonв смонтированном томе). Это полезно для клиентов с большим объёмом запросов или тестовых наборов, отправляющих много запросов с одного IP.
Быстрый старт
Предварительные требования
Docker с Docker Compose
Пара SSH-ключей (или пароли для каждой цели) для серверов, к которым вы хотите подключаться
1. Создайте каталог
mkdir -p config logs
ssh-keygen -t ed25519 -f ssh_key -N ""
cp default-config.json config/ssh-mcp-config.json2. Добавьте SSH-цель
Откройте config/ssh-mcp-config.json и добавьте одну цель:
{
"version": 1,
"ssh_targets": {
"web-server": {
"host": "192.168.1.10",
"port": 22,
"username": "deploy",
"private_key": "/app/ssh_key"
}
},
"block_patterns": [ "\\brm\\s+-rf\\b", "\\bdd\\s+if=" ],
"allowed_commands": {
"default": [
{ "targets": ["*"], "commands": ["hostname", "uptime", "free", "df", "ps", "ls", "cat"] }
]
},
"settings": {}
}3. Запустите сервер
docker compose up -d --build4. Проверьте, что сервер запущен
curl http://localhost:9080/health
# {"status": "ok", "connection_pool": {...}}5. Подключите MCP-клиент
Любой MCP-клиент, поддерживающий Streamable HTTP, может подключиться. Направьте его на http://localhost:9080/mcp, передавая заголовок с API-ключом. Подробности см. в разделе Конфигурация MCP-клиента.
6. Выведите список серверов и выполните команду
curl -X POST http://localhost:9080/mcp \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "ssh_list_servers",
"arguments": {}
}
}'
curl -X POST http://localhost:9080/mcp \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "ssh_execute_command",
"arguments": {"server_name": "web-server", "command": "uptime"}
}
}'Конфигурация MCP-клиента
Любой MCP-клиент, поддерживающий транспорт Streamable HTTP, может подключиться. Формат конфигурации зависит от клиента — используйте URL и заголовки из таблицы ниже.
Параметр | Значение |
Транспорт | Streamable HTTP |
URL |
|
Аутентификация | заголовок |
Универсальная конфигурация Streamable HTTP
{
"mcpServers": {
"ssh": {
"url": "http://localhost:9080/mcp",
"headers": {
"Authorization": "Bearer <your-api-key>"
}
}
}
}Python-клиент
import requests
MCP_URL = "https://ssh-mcp.example.com/mcp"
API_KEY = "your-api-key"
def call_tool(name: str, arguments: dict) -> dict:
response = requests.post(
MCP_URL,
headers={
"Content-Type": "application/json",
"X-API-Key": API_KEY,
},
json={
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {"name": name, "arguments": arguments},
},
)
response.raise_for_status()
return response.json()
print(call_tool("ssh_list_servers", {}))
print(call_tool("ssh_execute_command", {
"server_name": "web-server",
"command": "uptime",
}))Сырой JSON-RPC
Отправляйте вызовы инструментов как JSON-RPC-запросы tools/call на /mcp:
curl -X POST http://localhost:9080/mcp \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "ssh_execute_command",
"arguments": {"server_name": "web-server", "command": "uptime"}
}
}'Инструменты
Все вызовы инструментов — это JSON-RPC-запросы tools/call на /mcp. Все инструменты возвращают строку (JSON или обычный текст).
Tool | Параметры | Описание |
| (нет) | Перечисляет настроенные SSH-цели (host, port, username — без секретов) |
|
| Перечисляет команды, которые текущий клиент может выполнять на цели (объединение правил default + api_key + network) |
|
| Выполняет команду по SSH; возвращает stdout (stderr добавляется как |
|
| Скачивает файл по SFTP; авторизация эквивалентна |
|
| Загружает файл по SFTP; авторизация эквивалентна |
|
| Проверяет SSH-подключение, выполняя |
Примеры
# List available servers
call_tool("ssh_list_servers", {})
# {"web-server": {"host": "192.168.1.10", "port": 22, "username": "deploy"}}
# List what this client can run on web-server
call_tool("ssh_list_allowed_commands", {"server_name": "web-server"})
# ["cat", "df", "du", "free", "grep", "head", "hostname", ...]
# Execute a command
call_tool("ssh_execute_command", {
"server_name": "web-server",
"command": "uptime",
})
# " 07:12:33 up 10 days, 2:15, 1 user, load average: 0.08, 0.03, 0.01"
# Download a file
call_tool("ssh_download_file", {
"server_name": "web-server",
"remote_path": "/etc/hostname",
})
# "web-server\n"
# Upload a file
call_tool("ssh_upload_file", {
"server_name": "web-server",
"remote_path": "/tmp/backup.sql",
"content": "CREATE TABLE ...;\n",
"permissions": "0640",
})
# "OK: Uploaded 19 bytes to /tmp/backup.sql"
# Check SSH connectivity
call_tool("ssh_check_connection", {"server_name": "web-server"})
# {"success": true, "output": "ping", "error": null, "exit_code": 0, "checkcommand": "echo ping"}
# Check with custom timeout
call_tool("ssh_check_connection", {"server_name": "web-server", "timeout": 5})Примечание о sudo: Параметра
sudo_passwordне существует. Если для sudo требуется пароль, он берётся из поляpasswordцели в конфигурации. Флагsudoоборачивает команду вsudo -S -p ''(пароль из конфигурации) илиsudo -n(без пароля).
Ответы об ошибках
При сбое инструмент возвращает:
{
"error": true,
"error_type": "AuthorizationError",
"message": "Command rejected: target 'foo' not found",
"retryable": false,
"request_id": "abc-123"
}Распространённые значения error_type: AuthorizationError, PathValidationError, FileTransferError, SSHAuthenticationError, SSHTimeoutError, MCPSSHError. Флаг retryable равен true для SSHTimeoutError. Нарушения лимита запросов вместо этого возвращают HTTP 429.
Конфигурация
Расположение файла конфигурации
Сервер читает <config_dir>/ssh-mcp-config.json. Значение config_dir задаётся через CLI-флаг --config или переменную окружения MCP_SSH_CONFIG_PATH (по умолчанию: /config). Если файл не существует, сервер записывает встроенный default-config.json.
Структура верхнего уровня
{
"version": 1,
"ssh_targets": { ... },
"block_patterns": [ ... ],
"allowed_commands": {
"default": [ ... ],
"api_keys": [ ... ],
"networks": [ ... ]
},
"settings": { ... }
}При загрузке конфигурация проверяется по схеме config.schema.json (JSON Schema Draft 2020-12). Неизвестные ключи вызывают жёсткую ошибку.
ssh_targets
Объект, ключами которого являются идентификаторы серверов. Для каждой цели требуются host, port, username и хотя бы одно из значений private_key или password.
"ssh_targets": {
"web-server": {
"host": "192.168.1.10",
"port": 22,
"username": "deploy",
"private_key": "/app/ssh_key",
"checkcommand": "echo ping"
}
}Поле | Обязателен | По умолчанию | Описание |
| Да | — | Имя хоста или IP-адрес |
| Нет |
| SSH-порт |
| Да | — | Имя пользователя SSH |
| * | — | Путь к файлу закрытого SSH-ключа в файловой системе сервера |
| * | — | Пароль SSH (также может быть задан через |
| Нет |
| Команда, выполняемая |
* Требуется хотя бы одно из значений: private_key или password.
private_key— это путь в файловой системе сервера (в Docker — монтируется в контейнер), а не встроенный ключ.
block_patterns
Список regex-шаблонов. Любая команда, соответствующая шаблону, запрещается независимо от других уровней разрешающего списка. Шаблоны при загрузке проверяются на наличие конструкций, вызывающих катастрофический возврат (защита от ReDoS), а во время выполнения компилируются с таймаут-защитой.
allowed_commands
Три подобъекта управляют тем, какие команды может выполнять каждый клиент:
default— правила для всех клиентов (если более специфичный уровень не сработает первым)api_keys— правила для отдельных ключей, сопоставляемые поkey_hashnetworks— правила для отдельных CIDR-подсетей, сопоставляемые по исходному IP-адресу клиента
Каждое правило содержит список targets (идентификаторы серверов или "*" для всех) и список commands (базовые имена команд или "*" для любой команды).
"allowed_commands": {
"default": [
{ "targets": ["*"], "commands": ["hostname", "uptime", "free", "df", "ps"] }
],
"api_keys": [
{
"name": "ci-bot",
"key_hash": "pbkdf2:sha256:100000$<salt>$<hash>",
"rules": [
{ "targets": ["web-server"], "commands": ["systemctl", "journalctl"] }
]
}
],
"networks": [
{
"name": "home-lan",
"range": "192.168.1.0/24",
"rules": [
{ "targets": ["*"], "commands": ["*"] }
]
}
]
}settings
Параметр | По умолчанию | Описание |
|
| Максимальный объём вывода команды, возвращаемый клиенту (целое число или строка размера) |
|
| Жёсткий предел таймаута команды (секунды) |
|
| Количество повторов при временных сбоях SSH |
|
| Базовый экспоненциальный бэкофф (секунды) |
|
| Число сбоев до размыкания circuit breaker для цели |
|
| Таймаут восстановления разомкнутого circuit breaker (секунды) |
|
| Уровень журналирования: DEBUG, INFO, WARNING, ERROR |
|
| Максимальное число символов вывода, сохраняемых в записях журнала |
|
| Сжимать (gzip) ротированные файлы журнала |
|
| Максимум пулированных SSH-подключений на цель |
|
| Таймаут простоя подключения (секунды) |
|
| Интервал очистки пула (секунды) |
|
| Глобальный предел по всем целям; при превышении возвращается HTTP 503 |
|
| Минимальный интервал между перезагрузками конфигурации; |
|
| Доверенные IP-адреса обратных прокси (IPv4/IPv6) |
Настройки SFTP (settings.sftp)
Параметр | По умолчанию | Описание |
|
| Корневой каталог для проверки SFTP-путей |
|
| Максимально допустимая длина SFTP-пути (байты); |
Секреты
Пароли SSH-целей и хеши API-ключей можно вынести из основной конфигурации в <config_dir>/secrets.json или переменные окружения MCP_SSH_SECRET_*. Приоритет:
environment variables > secrets.json > ssh-mcp-config.jsonИсточник секрета | Эффект |
| Переопределения |
| Переопределяет |
| Переопределяет |
<TARGET_ID> и <KEY_NAME> приводятся к верхнему регистру, где - заменяется на _. Значения API-ключей должны быть хеш-строками, а не исходными ключами.
Переменные окружения и CLI-флаги
Переменная окружения | CLI-флаг | По умолчанию | Устаревший аналог |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| — |
| — |
| — |
| — | (обязателен, когда API включён) | — |
— |
|
| — |
— |
| — | — |
CLI-флаги имеют приоритет над переменными окружения. Любой ключ settings можно переопределить во время выполнения с помощью MCP_SSH_SETTING_<KEY> (в верхнем регистре, - → _).
Горячая перезагрузка
Сервер опрашивает файл конфигурации на предмет изменений (интервал — 15 с, антидребезг — 2 с). При обнаружении изменения он перезагружает конфигурацию, проверяет её и атомарно подменяет новой. Обратные вызовы при изменении конфигурации (пересборка правил авторизации, обновление пула подключений) выполняются после успешной подмены. Когда доступно, используется файловый мониторинг на основе watchdog.
Наблюдаемость
Проверка состояния
GET /health возвращает {"status": "ok"} плюс статистику пула подключений. HEALTHCHECK контейнера использует эту конечную точку.
Метрики Prometheus
GET /metrics отдаёт метрики в отдельном реестре, все с префиксом mcpssh_:
Метрика | Тип | Метки |
| Counter |
|
| Counter |
|
| Histogram |
|
| Counter |
|
| Histogram |
|
| Gauge |
|
| Gauge |
|
| Counter |
|
Структурированное журналирование
Сервер mcp-ssh поддерживает подключаемые цели журналирования, настраиваемые через settings.logging.log_targets в файле конфигурации. Каждая цель — независимый драйвер, получающий все записи журнала.
Поведение по умолчанию
По умолчанию записи журнала выводятся в stdout в удобочитаемом текстовом формате. Это подходит для сред Docker, где журналы контейнера собираются средой выполнения.
Типы целей журналирования
Цель | Значение конфигурации | Формат | Описание |
Stdout |
| Text | Записывает в stdout. Цель по умолчанию. |
JSON File |
| JSONL | Записывает по одному JSON-объекту в строку в файл. |
Text File |
| Text | Записывает человекочитаемый текст в файл. |
Конфигурация
{
"settings": {
"log_level": "INFO",
"logging": {
"log_targets": [
{ "target": "stdout" },
{ "target": "jsonfile", "filepath": "logs/ssh-mcp.log" }
],
"max_log_output": 4096,
"compress_rotated": true
}
}
}Уровень логирования
Файл конфигурации: задайте
settings.log_level, чтобы управлять уровнем по умолчанию.Переменная окружения: задайте
MCP_SSH_LOG_LEVEL, чтобы переопределить значение по умолчанию из файла конфигурации (например,MCP_SSH_LOG_LEVEL=DEBUG).Для отдельной цели: каждая цель логирования может иметь собственный
log_level, который переопределяет значение по умолчанию.
Устаревшая конфигурация
Если settings.logging отсутствует, сервер возвращается к одной цели — JSONL-файлу в каталоге журналов (по умолчанию /logs). Это обеспечивает обратную совместимость с существующими конфигурациями.
Текстовый формат
Цели stdout и текстового файла используют формат:
2025-01-15 10:30:00 INFO ssh_execute_command: Command executed on server1Формат JSON
Цели JSON-файла записывают по одному JSON-объекту в строку:
{"timestamp": "2025-01-15T10:30:00+00:00", "event": "ssh_execute_command", "level": "INFO", "message": "Command executed on server1", "request_id": "abc-123", "log_level": "INFO", "log_format_version": 1}Ротация файлов
Файловые цели выполняют ротацию при превышении max_file_size_mb (по умолчанию: 10 МиБ), сохраняя backup_count резервных копий (по умолчанию: 5). Ротированные файлы сжимаются gzip, когда compress_rotated имеет значение true.
События изменения конфигурации
Событие | Значение |
| Начальная конфигурация загружена при запуске |
| Конфигурация перечитана с диска (с |
| Применена миграция схемы ( |
| Скопирована встроенная конфигурация по умолчанию |
| Выполнен откат к значениям по умолчанию в памяти |
| Обратный вызов изменения конфигурации вызвал исключение |
API конфигурации и веб-панель управления
Единый контейнер включает опциональные API конфигурации и веб-панель управления — полный контур управления для вашей SSH-политики, целей, правил команд и резервных копий. Редактирование файла конфигурации не требуется. Эта функция отключена по умолчанию.
Что вы получаете
Веб-панель управления — адаптивное одностраничное приложение с 5 страницами: SSH-цели, шаблоны блокировок, правила команд, настройки и резервные копии. Войдите с помощью своего API-токена и управляйте всем из браузера.
REST API — полный CRUD для каждого раздела конфигурации, а также проверка конфигурации, хеширование API-ключей, управление резервными копиями и встроенная проверка SSH-подключения.
Утилита хеширования API-ключей — преобразует API-ключи в виде открытого текста в строки PBKDF2, готовые для конфигурации. Больше не нужно угадывать формат хеша.
Резервное копирование и восстановление — автоматическое резервное копирование конфигурации при каждой записи; просматривайте, восстанавливайте или удаляйте резервные копии из панели управления или API.
Атомарные и потокобезопасные записи — все записи конфигурации проверяются, сериализуются с помощью блокировки потоков и атомарно записываются на диск.
Swagger UI и ReDoc — автоматически генерируемая интерактивная документация API по адресам
/api/docsи/api/redoc.
Включение API конфигурации
Задайте эти переменные окружения в вашем файле compose.yaml или .env:
Переменная | По умолчанию | Описание |
|
| Установите |
| (обязателен при включении) | Bearer-токен для аутентификации API-запросов |
services:
mcp-ssh:
environment:
CONFIG_API_ENABLED: "true"
CONFIG_API_TOKEN: "your-secret-token-here"API-эндпоинты
Все эндпоинты смонтированы по пути /api в том же приложении Starlette ASGI, что и MCP-сервер.
Состояние и утилиты
Метод | Путь | Описание |
|
| Проверка состояния API конфигурации (аутентификация не требуется) |
|
| Хеширует API-ключ в виде открытого текста в строку PBKDF2-HMAC-SHA256 |
|
| Возвращает JSON Schema конфигурации (аутентификация не требуется) |
|
| Проверяет словарь конфигурации без записи на диск |
Конфигурация
Метод | Путь | Описание |
|
| Получить полную конфигурацию (секреты скрываются) |
|
| Заменить полную конфигурацию |
|
| Получить один раздел конфигурации ( |
|
| Заменить один раздел конфигурации |
SSH-цели
Метод | Путь | Описание |
|
| Получить конкретную SSH-цель (секреты удалены) |
|
| Создать или заменить SSH-цель |
|
| Удалить SSH-цель |
|
| Проверить SSH-подключение с помощью |
Правила команд
Метод | Путь | Описание |
|
| Вывести список разрешённых правил команд (через |
|
| Заменить разрешённые правила команд (через |
Шаблоны блокировок
Метод | Путь | Описание |
|
| Вывести список шаблонов блокировок (через |
|
| Заменить все шаблоны блокировок |
|
| Добавить шаблон блокировки |
|
| Заменить один шаблон блокировки по индексу |
|
| Удалить один шаблон блокировки по индексу |
Резервные копии
Метод | Путь | Описание |
|
| Вывести список резервных копий конфигурации (сначала новые) |
|
| Восстановить конфигурацию из резервной копии |
|
| Удалить файл резервной копии |
Аутентификация
Все API-запросы (кроме /api/health и /api/config/schema) требуют токен Bearer в заголовке Authorization:
curl -H "Authorization: Bearer your-secret-token-here" http://localhost:9080/api/configВеб-панель управления
Когда она включена, адаптивное одностраничное приложение доступно по адресу http://localhost:9080/ui/ — полноценный интерфейс управления, созданный с помощью Tailwind CSS. Никаких перезагрузок страниц: toast-уведомления для каждой операции и модальные диалоги для редактирования.
Страница | Возможности |
SSH-цели | Просмотр, добавление, редактирование, удаление целей; встроенная проверка подключения через |
Шаблоны блокировок | Добавление, редактирование (по индексу), удаление отдельных шаблонов; просмотр полного списка шаблонов |
Правила команд | Редактирование правил по умолчанию, API-ключей и сетевых правил; полноценный редактор правил со списками целей и команд |
Настройки | Редактирование всех параметров сервера: SFTP-песочница, ограничение скорости, журналирование, пул соединений, автоматический выключатель и другое |
Резервные копии | Просмотр, восстановление и удаление резервных копий конфигурации; метка времени и размер для каждой копии |
Дополнительные возможности:
Вход на основе токена с управлением сессией (хранится в
sessionStorage)Проверка конфигурации — изменения проверяются перед записью
Хеширование API-ключей — хешируйте ключи в виде открытого текста прямо из панели управления
Адаптивный дизайн — работает на компьютерах и мобильных устройствах
Toast-уведомления — обратная связь об успехе/ошибке для каждой операции
Swagger / ReDoc
Интерактивная документация API автоматически генерируется FastAPI:
Swagger UI:
http://localhost:9080/api/docsReDoc:
http://localhost:9080/api/redoc
Развертывание
Docker Compose
Файл compose.yaml определяет один сервис mcp-ssh, который содержит как MCP-сервер, так и (опционально) API конфигурации и веб-панель управления. API конфигурации включается через переменную окружения CONFIG_API_ENABLED (по умолчанию: false).
mcp-ssh — MCP SSH Gateway + API конфигурации
Путь на хосте | Путь в контейнере | Режим |
|
| rw |
|
| rw |
|
| ro |
|
| ro |
Порт 9080 на хосте открыт наружу (соответствует порту 8080 в контейнере). В качестве образа выполнения используется python:3.13-alpine с закреплённым по хешу дайджестом. Процесс запускается от непривилегированного пользователя mcpssh. На этапе сборки sbom формируется SBOM в формате CycloneDX.
API конфигурации и веб-панель управления (опционально)
Включите API конфигурации, установив CONFIG_API_ENABLED=true в вашем файле .env или в окружении:
# Generate an auth token
openssl rand -hex 32CONFIG_API_ENABLED=true
CONFIG_API_TOKEN=<your-token>Когда эта функция включена, API конфигурации монтируется по пути /api на том же HTTP-сервере, что и MCP-шлюз. Он предоставляет:
REST API по адресу
http://localhost:9080/api/...— полный CRUD для SSH-целей, шаблонов блокировок, правил команд, резервных копий и настроекВеб-панель управления (GUI) по адресу
http://localhost:9080/ui/— одностраничное приложение для визуального управления политиками (SSH-цели, шаблоны блокировок, правила команд, настройки, резервные копии)Документация API по адресам
http://localhost:9080/api/docs(Swagger UI) иhttp://localhost:9080/api/redoc(ReDoc)
Makefile
Команда | Описание |
| Собрать образ Docker ( |
|
|
|
|
| Запустить модульные тесты |
| Запустить модульные тесты config-api |
| Собрать тестовый образ, запустить интеграционные тесты |
| Удалить тестовые артефакты и контейнеры |
Скачивание из GHCR
Образ Docker автоматически собирается и публикуется в GitHub Container Registry:
docker pull ghcr.io/gelse/ssh-mcp:latestОграничения и модель угроз
Чем ssh-mcp не является
Не оболочка. Вы не можете получить интерактивную терминальную сессию. Всё выполнение — разовые вызовы команд.
Не файловый менеджер. SFTP ограничен загрузкой/скачиванием одного файла с проверкой пути и соблюдением песочницы. Никакого вывода списка каталогов, никаких рекурсивных операций.
Не сетевой брандмауэр. Ограничение частоты запросов применяется по IP-адресу с фиксированными значениями по умолчанию. Оно защищает от неконтролируемых клиентов, а не от целеустремлённых злоумышленников.
Модель угроз
Угроза | Смягчение |
Инъекция команд через объединение в цепочку ( | Сегментация команд — каждый сегмент проходит полную цепочку авторизации |
Перенаправление вывода оболочки в чувствительные пути ( | Механизм проверки цели перенаправления запрещает перенаправление в |
Path traversal в SFTP | 8-уровневая проверка пути: проверка нулевого байта, удаление управляющих символов, нормализация dot-сегментов, разрешение символических ссылок, соблюдение корневой директории песочницы |
ReDoS через | Статическая проверка при загрузке + защитные таймауты во время выполнения |
Перебор API-ключа | PBKDF2-HMAC-SHA256 с проверкой за постоянное время; ограничение частоты запросов по IP |
Инъекция в логи | Очистка символов новой строки во всех полях, контролируемых пользователем, перед записью в журнал |
Секреты в конфигурации | Разделение |
Вне области действия
Завершение TLS (обрабатывается вашим обратным прокси)
Аутентификация пользователей помимо API-ключей (нет OAuth, нет mTLS на уровне приложения)
Мультиплексирование SSH-сессий (нет поддержки tmux/screen)
Защита журнала аудита от подделки (журналы — локальные файлы; используйте собственную доставку логов для обеспечения неизменяемости)
Разработка
Структура проекта
server.py— фабрика приложения FastMCP + точка входа CLIlib/— 30 модулей с единой ответственностью (auth, config, SSH client, file transfer, logging и т. д.)config-api/— Configuration API + Web Dashboard (FastAPI, смонтирована по адресу/api, когдаCONFIG_API_ENABLED=true)tests/— 36 файлов модульных тестов + интеграционные тесты с реальными контейнерами Docker
Технологический стек
Python 3.13, FastMCP 3.4.x, paramiko 5.0, Starlette 1.4, FastAPI 0.115+, Pydantic 2.10+, httpx 0.28+, uvicorn 0.34+
Запуск тестов
# Unit tests (fast inner loop)
source .venv/bin/activate
python -m pytest tests/test_<module>.py -x
# Full unit test suite
make test
# Integration tests (requires Docker)
make integrationtestДобавление нового инструмента
Полный пример в AGENTS.md описывает добавление нового обработчика @mcp.tool() от начала до конца: константы, типы, реэкспорты, обработчик, тесты, коммит.
Нет инструментов линтинга/проверки типов
В проекте нет конфигурации ruff, mypy, pyright или flake8. Форматирование следует настройкам по умолчанию .editorconfig (4 пробела для Python, строки по 88 символов).
Дорожная карта
Графический интерфейс конфигурации для визуального управления политиками
Лицензия
Лицензия MIT — подробности см. в LICENSE.
This server cannot be installed
Maintenance
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables secure remote access operations through SSH, SFTP, rsync, VPN, and tunneling with enterprise-grade policy enforcement and audit logging. Provides AI assistants with secure, policy-driven access to remote systems while maintaining comprehensive audit trails and zero-trust security.1Apache 2.0
- AlicenseBqualityAmaintenanceProvides policy-driven, auditable SSH access to server fleets for AI assistants with zero-trust security controls, command whitelisting, and comprehensive audit logging to safely manage infrastructure.1327Apache 2.0
- AlicenseAqualityCmaintenanceEnables AI assistants to securely execute remote SSH commands, perform file transfers, and monitor system status through a standardized interface. It features robust security controls including command whitelisting, blacklisting, and credential isolation to prevent unauthorized operations.1022MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to securely execute SSH commands on remote servers with connection pooling, session isolation, and a web audit panel.3MIT
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.
Agent payments, API key vaulting, and governed mandates. Agents spend within user-defined limits.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/gelse/ssh-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server