Logo Craft Homelab Docs Нейросети Хостинг Контакты
linux-mcp-daemon: доступ ИИ-агента к Linux-серверу через инструменты и точечный root Трендовые github проекты в нашем телеграм канале. Подпишись →
26 сентября 2026 г.

Как дать ИИ-агенту разбирать инциденты на сервере без SSH и sudo

Когда ночью заканчивается место на диске или тормозит сайт, ИИ-агент умеет быстро собрать картину: нагрузка, память, диски, процессы, журналы. Дальше ему часто нужно что-то поменять — перезапустить сервис, почистить файл, поправить конфиг. Самый простой способ дать ему такие возможности — SSH-ключ с sudo, и это же самый опасный способ: агент получает всё, что может аккаунт, плюс root.

linux-mcp-daemon (демон mcpd и клиент linuxctl) решает задачу через MCP: агент видит сервер как набор именованных инструментов, root получает только на явно разрешённые операции в заданных путях, а каждый вызов попадает в лог.

Чем плохи существующие MCP-серверы для Linux

Готовые решения делятся на три группы:

  • Shell с белым списком (ssh-mcp и его форки). Инструмент «выполнить команду» проверяет обычно только первое слово, а сама команда уходит в sh -c. Строка ls; rm -rf ~ проходит проверку. Даже продвинутые форки с классификацией команд и подтверждением человеком опираются на разбор текста команды.
  • Только чтение (например, linux-mcp-server от Red Hat). Безопасно для диагностики, но исправить ничего нельзя, а доступ к удалённому хосту всё равно выдаётся SSH-ключом на весь аккаунт.
  • Голый SSH. Все права аккаунта, с sudo — root.

Для разбора инцидентов, в которых участвуют несколько машин, нужен сетевой доступ с аутентификацией, разделение пользователей и выдача root по одному инструменту. Этого набора ни у кого из перечисленных нет.

Устройство mcpd

Демон написан на Go и собирается в один статический бинарник. Агент подключается к нему по HTTPS и получает 38 инструментов с именами вида группа/команда: processes/top, disks/usage, logs/journal-control, services/manage, files/read. У каждого есть описание и JSON-схема аргументов. Кроме инструментов, mcpd отдаёт 11 постоянных ресурсов (os://release, network://routes, devices://pci) и 6 шаблонов вроде service://{name}/status и process://{pid}/{target}.

Сетевой транспорт выбран сознательно. При stdio-транспорте клиент сам запускает сервер командой из своего конфига — и выполнит любую команду, если конфиг подменить. Эта проблема есть во всех официальных SDK, а у mcpd её нет: клиент у себя ничего не запускает.

Данные из ядра

Большую часть информации mcpd читает напрямую из /proc, /sys и у systemd по D-Bus, без вызова ps, df или systemctl с последующим парсингом вывода. Внешние программы запускаются там, где собственная реализация вышла бы хуже: smartctl, traceroute, journalctl, dmesg, last, find. Например, журнал systemd хранится в бинарном сжатом формате, а подключение libsystemd потребовало бы cgo и лишило бы проект статической сборки. Все внешние утилиты вызываются без shell, с отдельными аргументами.

Инструмент processes/top выдаёт вывод в формате top, но собирает его из /proc, а %CPU считает по двум замерам с интервалом. Размеры по умолчанию в байтах, чтобы агенту не пришлось разбирать строки вида 1.8G; для людей есть флаг human_readable.

Worker на каждый вызов

Главный процесс только принимает запрос, проверяет токен и права. Для каждого вызова стартует короткоживущий worker от имени Linux-пользователя с тем же именем, что у пользователя mcpd. Пользователь alice в mcpd — это аккаунт alice в системе, и всё, что ядро запрещает этому аккаунту, агент тоже сделать не сможет.

Root по списку

Привилегированные вызовы описываются в mcp-sudo.yaml:

users:
  logs:
    privileged:
      tools:
        files/read:
          allowed: true
          paths: [/var/log]      # root только внутри /var/log
        logs/journal-control:
          allowed: true
        network/curl:
          network:
            deny_private: true   # никаких localhost, 10/8, 169.254.169.254

Для инструментов, работающих с путями, paths обязателен: без него конфиг не загрузится. Доступ ко всему диску придётся прописать явно как paths: ["/"], чтобы он бросался в глаза при ревью. Попытка выйти за границы заканчивается понятной ошибкой:

$ linuxctl tool files/read --path /root/.bashrc --privileged true
user mcp is not authorized to run files/read on path /root/.bashrc as root

TLS включён по умолчанию: при первом запуске генерируется самоподписанный сертификат, клиенты проверяют его по отпечатку. Каждый вызов пишется в journald или docker logs с пользователем, инструментом, аргументами (токены вырезаются) и результатом. Изменяющие систему вызовы помечаются audit и логируются на любом уровне логирования.

Установка и подключение

На хосте с systemd:

curl -fsSL https://raw.githubusercontent.com/nucleusv/linux-mcp-daemon/main/scripts/install.sh | sudo bash

Скрипт проверяет sha256 релиза, создаёт первого пользователя mcp и один раз печатает его токен (в конфиге хранится только солёный хеш) и отпечаток сертификата. Есть также пакеты .deb/.rpm и образ ghcr.io/nucleusv/linux-mcp-daemon.

Клиент linuxctl работает в стиле kubectl, есть сборка под macOS:

export MCP_SERVER=https://my-server:9091
export MCP_TLS_FINGERPRINT=sha256:...
export MCP_TOKEN=...
linuxctl get processes --sort_by mem --limit 3 --output table
linuxctl explain disks

Список команд клиент каждый раз запрашивает у демона, поэтому новый инструмент на сервере сразу появляется в linuxctl, а автодополнение в bash и zsh показывает пользователю только разрешённое ему.

Подключение к Claude Code:

export NODE_EXTRA_CA_CERTS=~/.config/mcpd/my-server.crt
claude mcp add --transport sse my-server https://my-server:9091/sse \
  --header "Authorization: Bearer <token>"

Проверка на учебном инциденте

На VPS с Ubuntu 24.04 (1 CPU, 2 ГБ) сервис my-service писал отладочный лог без ротации. Агенту завели отдельного пользователя agent с root ровно на одно действие: files/update для /var/log/my-service.log.

За пару минут агент сделал 20 вызовов: свободное место, размеры каталогов, список логов, начало и хвост растущего файла, настройки журнала, процессы, код сервиса. На disks_usage с privileged: true mcpd отказал, и агент досчитал без root. Журнал systemd ему не отдало ядро: agent не состоит в группе systemd-journal. В итоге агент нашёл файл, посчитал скорость роста и предложил очистить лог через усечение. Удаление через rm здесь не помогло бы: сервис держит файл открытым, и место осталось бы занятым.

Узкие на вид права, которые равны root

Эти разрешения легко выдать по ошибке:

  • Запись в /etc через files/update: агент может добавить файл в /etc/sudoers.d/, задачу в cron или systemd-юнит.
  • services/manage действует на любой юнит, включая ssh и сам mcpd.
  • kernel/system-control без write_keys: через kernel.core_pattern можно указать программу, которую ядро запустит от root при падении любого процесса.
  • files/read с paths: ["/"] открывает /etc/shadow и приватный ключ сертификата mcpd.
  • Группа docker у аккаунта агента даёт root без всяких грантов: достаточно запустить контейнер с примонтированным /.
  • network/curl без блока network ходит на внутренние адреса и на 169.254.169.254, где облако отдаёт временные ключи. Если в логе окажется подброшенная инструкция, агент может сходить туда и пересказать ответ. Закрывается это через deny_private: true.

Баги, найденные при разработке

  • Пользователь mcpd с именем root получал root на каждый вызов в обход mcp-sudo.yaml. Сейчас такой конфиг не загружается.
  • Симлинки обходили проверку paths: /var/www/x → /etc/shadow. При ограниченных путях файлы теперь открываются покомпонентно с O_NOFOLLOW, и демон отвечает refusing to follow a symbolic link.
  • Контейнер без --pid host видел собственный PID 1, и вызов с privileged: true молча выполнялся от root внутри контейнера. Агент считал, что работает с хостом, хотя видел образ. С v0.3.4 такой вызов падает с ошибкой cannot switch to the host's filesystem - is the mcpd container running with --privileged --pid host?.

В планах — read-only инструменты для Docker, сводка состояния системы одним вызовом и аудит безопасности: SUID-файлы, каталоги с открытой записью, настройки sshd. Лицензия Apache 2.0, документация со страницей о правах и рисках лежит на nucleusv.github.io/linux-mcp-daemon.