01.08.2027 335 материалов

Как научить ИИ управлять сетевым оборудованием: собираем первый MCP-сервер

Вторая часть цикла о том, как дать ИИ-ассистенту доступ к сетевым устройствам через MCP — на этот раз разбираемся, как устроен минимально полезный сервер: от инвентаризации устройств до безопасного чтения конфигураций.

Как научить ИИ управлять сетевым оборудованием: собираем первый MCP-сервер

Первый MCP-сервер для сетевого оборудования — это не инструмент «из коробки», а семя: минимальный каркас, который растёт по мере реальных запросов инженеров. Задача — не автоматизировать всё сразу, а создать безопасную читающую основу, на которую потом можно наращивать слои.

Это вторая часть семисерийного цикла про то, как связать ИИ-ассистентов с сетевым оборудованием через протокол Model Context Protocol (MCP). Первая часть объясняла, зачем сетевым устройствам вообще нужен MCP-сервер. Теперь автор цикла, Узи Голан, переходит от теории к практике: строит первую рабочую версию.

Что такое MCP и зачем это сетевику

Если совсем коротко: MCP — это протокол, который позволяет ИИ-модели (Claude, Copilot, ChatGPT и т.д.) вызывать внешние инструменты. Не просто генерировать текст, а реально выполнять действия — подключаться к устройствам, запрашивать данные, проверять статус.

Для сетевого инженера это означает: можно написать на естественном языке «покажи активные аварии на устройстве sf-163-187», и ассистент подключится по SSH, выполнит нужные команды, получит результат и вернёт его в удобном виде. Без того, чтобы вручную заходить на консоль, помнить синтаксис команд для каждого типа оборудования и копаться в сыром выводе.

Но прежде чем это заработает, нужно построить сервер, который умеет это делать. И вот тут начинается самое интересное.

Минимально полезная версия: что входит, а что — нет

Автор сразу задаёт рамки. Первый сервер умеет:

  • вести инвентарь устройств (добавлять, удалять, обновлять);
  • подключаться к оборудованию по SSH или telnet;
  • выполнять разрешённые команды чтения (те самые show);
  • проверять «здоровье» устройства (идентификация, активные аварии);
  • сохранять бэкапы конфигураций.

При этом сервер не умеет менять конфигурацию, не содержит базы знаний об оборудовании, не поддерживает SNMP и не распределяется между несколькими пользователями. Всё это — темы следующих статей серии.

Подход честный и прагматичный: не пытаться сделать всё сразу, а выстроить каркас, который потом наращивается. Каждый новый слой появляется тогда, когда инженер задаёт вопрос, на который текущие инструменты не могут ответить.

Инвентарь: знаем, что подключено

Первый инструмент — не команда к оборудованию, а реестр устройств. Прежде чем ИИ обратится к оборудованию, он должен знать, что оно существует.

Добавление устройства требует ровно шести данных: имя, IP-адрес, семейство (тип устройства), группа (например, «lab» или «production»), логин и пароль. Если хоть одно поле пропущено, ассистент спросит всё недостающее за один раз, а не по очереди — важный нюанс для удобства работы.

Разделение паролей и данных — не обсуждается

Самое важное архитектурное решение: учётные данные никогда не хранятся в файле инвентаря. Файл инвентаря содержит только имя, адрес, тип и группу — его можно безопасно сохранять в Git, показывать коллегам, выводить в ответах ассистента. Пароли уходят в отдельный файл .env, который исключён из Git и виден только серверу.

Это не просто «хорошая практика» — это фундаментальная граница безопасности. Данные инвентаря и данные аутентификации живут в разных мирах.

Драйверы: один инструмент — много устройств

Технический центр всей конструкции — это абстракция драйверов. Ключевая идея: транспорт (как подключиться) и диалект команд (что писать в консоли) меняются независимо друг от друга.

Представьте, что вы работаете с разными автомобилями. Транспорт — это то, как вы садитесь в машину (через дверь, через люк, через задний багажник — зависит от модели). Диалект — это то, как вы управляете: рычаг, кнопка, сенсорный экран. Два разных измерения, и они не привязаны друг к другу жёстко.

В сетевом мире: SSH и telnet — это транспорт. А вот формат приглашения, навигация по контексту команд, именование портов, способ сохранения конфигурации — это уже «диалект», который зависит от семейства устройства. SecFlow использует ethernet 3, ETX-2 — ethernet 0/2, а Megaplex-4100 — ethernet 1/1/1. Попытка прописать все эти различия в одном скрипте приводит к тому, что к третьему семейству у вас три копии одного и того же кода, которые постепенно разъезжаются.

Абстракция драйверов решает это элегантно: общий диалект живёт в базовом классе, а различия между семействами — в наследниках, которые переопределяют только то, что реально отличается. Инструменту (например, run_show) всё равно, с каким конкретно оборудованием он работает: он вызывает драйвер, а драйвер уже знает, какую команду выполнить и как распарсить ответ.

Netmiko: транспортный слой

Для управления SSH-сессиями используется библиотека Netmiko — зрелый инструмент для Python, который поддерживают десятки типов оборудования. Если у вас уже есть автоматизация на Netmiko или NAPALM, MCP-сервер просто оборачивает ваши существующие примитивы в типизированные инструменты, которые может вызвать ИИ.

Однако Netmiko — это только транспорт. Политику (какие команды разрешены, что подлежит подтверждению, что логируется) задаёт сам MCP-сервер. Netmiko доставляет вас до устройства, а сервер решает, что там безопасно делать.

Постоянные сессии

Подключение по SSH занимает 5–7 секунд, и многие устройства отказывают в новой сессии, пока не завершится старая. Поэтому сессии кешируются: одна постоянная SSH-сессия на устройство, которая проверяется на «живость» после 60 секунд простоя и прозрачно пересоздаётся при необходимости.

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

Чтение по приглашению, а не по таймеру

Ещё один важный технический момент: каждое чтение завершается не по таймауту тишины, а в момент, когда на экране снова появляется приглашение устройства (prompt). Это кажется мелочью, но на практике решает серьёзную проблему.

Например, SecFlow-1p детерминированно делает паузу больше трёх секунд в середине вывода info. Если ориентироваться на таймер тишины, вывод обрезается — и часть конфигурации просто теряется. Ориентировка на приглашение устройства — детерминированна, а ориентировка на таймер — вероятностна. В сетевых операциях детерминированность побеждает всегда.

Первые инструменты: только чтение

Каждый инструмент следует одной модели: пользователь спрашивает на естественном языке, ассистент вызывает инструмент, инструмент выполняется на устройстве и возвращает результат.

  • add_device — регистрация устройства в инвентаре (шесть обязательных полей, пароли сразу уходят в защищённое хранилище).
  • list_devices — вывод списка устройств (без паролей, с фильтрацией по семейству или группе).
  • test_connectivity — проверка доступности по SSH (только проверяет, что сессия устанавливается, не выполняет команд).
  • run_show — выполнение разрешённых команд чтения. Ассистент сам навигирует по нужному контексту на устройстве и выполняет команду. Важно: принимаются только «белые» команды, а не произвольные строки — защита от инъекции.
  • run_show_in_context — вариант для устройств, где команды нужно выполнять из определённого контекста (например, configure reportingshow active-alarms).
  • cli_help — отправка ? на устройство и получение дерева доступных команд. Ничего не выполняет — только читает встроенную справку.
  • get_config — экспорт полной конфигурации в локальный архив, с диффами относительно предыдущих бэкапов.
  • health_check — проверка «здоровья» устройства: идентификация, активные аварии, базовая проверка связности. Результат возвращается в структурированном виде, а не как сырой текст.

Каждый инструмент защищён: белые списки команд, валидация контекстов, строгая проверка символов, отсутствие паролей в ответах и логах.

Почему важно не возвращать всё подряд

Принципиальный момент в архитектуре: инструменты чтения должны возвращать нужное количество данных в нужной форме, а не всё, что прислало устройство.

Команда show может вернуть 20 строк на одном оборудовании и 2000 — на другом. Экспорт конфигурации может занять 15 тысяч строк. Отправить всё это в контекст модели — значит потратить огромное количество токенов, ухудшить качество рассуждений и получить худший ответ, а не лучший.

Автор описывает три направления фильтрации:

  1. Фильтрация по объёму — не любая команда, а только разрешённые. Белый список формируется для каждого семейства.
  2. Фильтрация по форме — структурированные данные вместо сырого текста CLI. Модель работает с полями быстрее и точнее, чем с потоком символов.
  3. Фильтрация по детализации — разный уровень глубины для разных запросов. «Покажи аварии» — одна детализация, «покажи справочник аварий с описаниями и рекомендациями» — совсем другая.

Для больших наборов данных используется паттерн «сначала поиск, потом чтение»: сначала compact-выдача с отрывками и указателями, и только если ответа нет в отрывке — запрос конкретного фрагмента по стабильному идентификатору.

Чего сервер пока не умеет

Автор честно перечисляет ограничения, и это важная часть материала:

  • Нет записи конфигураций. Изменения на оборудовании требуют модели безопасности: staged commits, предпросмотр диффов, явное одобрение, аудит. Это тема третьей статьи.
  • Нет базы знаний. Сервер может получить вывод команды, но не знает, что она означает, что говорит справочник аварий или какие функции доступны на конкретной прошивке. Слои знаний — тема пятой статьи.
  • Нет SNMP. CLI — единственный путь доступа к устройству. SNMP даёт второе