MCP-шлюз через полгода: как агент читает прод-базу и не может её сломать
29 сентября 2026 г. 7 мин Читать

MCP-шлюз через полгода: как агент читает прод-базу и не может её сломать

В сентябре мы опубликовали пост «Корпоративные MCP» — про то, как устроен доступ наших агентов к продакшн-данным: отдельный шлюз, только чтение, никаких ssh-сессий на прод. Это была архитектурная статья: схема, обоснования, почему мы выбрали MCP единым способом подключения агентов к данным и что из этого получилось на старте.

Сейчас — про эксплуатацию. К этому моменту шлюз отработал полгода в реальном бою: с живой прод-базой, живыми логами и агентами, которые читают данные каждый рабочий день. Такого срока как раз хватает, чтобы отделить «работает» от «красиво выглядело на схеме»: часть решений подтвердилась, кое-что пришлось дописать, а пара мест честно мешает до сих пор.

Ниже — что мы добавили за эти полгода, какие наблюдения накопились, почему узкие инструменты обошли универсальный SQL и три правила доступа агента к прод-данным, которые мы теперь считаем обязательными.

Table Of Contents

Архитектура в пяти строках

Короткое напоминание, чтобы читать дальше можно было без первого поста:

  • MCP (Model Context Protocol) — открытый стандарт от Anthropic, который описывает подключение инструментов и данных к агентам. Для нас это единственная дверь от агента к прод-окружению: что не через шлюз — то не через ничего.
  • База — Postgres в Kubernetes под управлением CrunchyData. Агент ходит в неё только через шлюз и только на чтение.
  • Авторизация — OAuth2 через Authentik, транспорт закрыт TLS от letsencrypt. Изоляция по базам: учётка агента видит ровно свою базу и ничего вокруг.
  • Логи агент читает через MCP к VictoriaLogs, историю кода — через MCP к нашему Gitea.
  • Чего у агента нет: ssh-доступа к проду и прав записи в него. Изменения в код — только через PR, и мержит человек.

Почему именно так, а не «выдали агенту консоль и надеемся», разобрано в посте «Корпоративные MCP». Дальше — что с этой схемой стало после полугода работы.

Что пришлось добавить за полгода

Главная мысль эксплуатации: схема «поставили шлюз — и живём» не выживает. Не потому, что она неверная, а потому, что живые агенты сразу задают вопросы, которых нет в документации протокола. Вот пять доделок, без которых шлюз к концу этого срока уже не обходится.

OAuth-авторизация клиентов. Через шлюз хотят ходить разные потребители: постоянные агенты, разовые скрипты, новые задачи. Каждому — собственный клиент OAuth2 в Authentik, никакой «общей служебной учётки на всех». Отсюда растёт всё остальное: клиента видно в журнале по имени, и его можно отрезать, не трогая остальных.

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

Лимиты на тяжёлые запросы. Самая болезненная доделка. Агент не оценивает стоимость запроса: «посчитай по всей таблице» выглядит для него как обычное чтение, а для прод-базы это долгий скан, который роняет latency для людей. Лимиты на стороне шлюза превратили это из регулярной боли в штатное ограничение: слишком тяжёлый запрос просто не доходит до базы.

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

Отзыв токена без перезапуска. Отозвать доступ должно быть так же просто, как выдать. У нас отзыв токена срабатывает без перезапуска шлюза — пока такой механики нет, отзыв превращается в дело, которое «сделаем потом». А «потом» — это ровно тот момент, когда отрезать доступ нужно срочно.

Warning

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

Он роняет latency прод-базы для всех, кто работает с ней в тот же момент, — и сам агент даже не узнает, что виноват.

Что показала эксплуатация

Сразу оговорка: это качественные наблюдения, а не замеры. Честных цифр вида «сколько строк прочитал агент» у нас нет, а выдумывать проценты мы не будем — не тот жанр.

Агент почти никогда не читает «всю базу». Типичный сценарий выглядит скромно: посмотреть структуру таблиц и последние записи. Что за объекты есть, как называются поля, что появилось за последние часы. Запрос «дай всё» — редкость и почти всегда признак плохо сформулированной задачи. Страшная картинка «агент сливает базу» на практике выглядит как «агент посмотрел схему и несколько свежих строк».

Самые полезные инструменты — узкие. Не «выполнить SQL», а вопросы вида «покажи ошибки за сутки» или «покажи коммиты по файлу». Они отвечают в том виде, в котором ответ сразу можно использовать, и не требуют от агента знания нашей схемы наизусть. Универсальный SQL остаётся для редких случаев, когда узких инструментов не хватает, но в повседневной работе он проигрывает по всем статьям.

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

И вся эта активность — не развлечение, а рутина: через шлюз агенты разбирают очередь поддержки. Экономика такого саппорта — отдельная история, мы посвятили ей отдельный разбор.

Почему узкие инструменты лучше универсального SQL

На первый взгляд «выполнить SQL» — идеальный инструмент: один вместо двадцати, умеет всё. На практике «умеет всё» — это ровно «слишком много».

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

Цена ошибки. Агент иногда путается в формулировках — это нормально, он текстовая машина. В узком инструменте ошибка стоит дёшево: «не тот фильтр в готовом запросе». В универсальном SQL та же ошибка превращается в тяжёлый запрос к прод-базе — знакомую нам историю из предыдущего раздела.

Читаемость журнала. «Показать ошибки за сутки» в журнале вызовов — понятная запись, которую можно прочесть и через месяц. Произвольный SQL — строка, которую надо разбирать глазами. Журнал по-настоящему полезен, когда вызовы семантические.

Поэтому мы продолжаем дробить: каждый вопрос, который агенты задают прод-данным часто, — кандидат в отдельный узкий инструмент.

Матрица доступа: что агент может, а что нет

Собрали текущее состояние прав в одну таблицу.

ИнструментЧто можетЧто не может
Postgres (через шлюз)читать структуру таблиц и данные своей базы, смотреть последние записиписать и менять схему, видеть чужие базы, уходить в тяжёлые запросы без ограничений
VictoriaLogs (через MCP)искать по логам — «покажи ошибки за сутки», читать свежие записименять и удалять логи, трогать конфигурацию
git (Gitea через MCP)читать историю, диффы, коммиты по файлумержить PR — это делает человек, доставлять изменения в прод напрямую
Файлычитать файлы проектаизменять файлы и конфигурацию прода

Главное про эту таблицу: каждое «не может» — не обещание агента вести себя хорошо, а отсутствие технической возможности. Разница между «нельзя по правилам» и «нельзя по правам» — это разница между регламентом и архитектурой.

Где read-only не хватает

Самое заметное ограничение: агент не может воспроизвести баг, для которого нужна запись. Если проблема проявляется только при создании заявки, агент не соберёт её целиком из данных и логов — до момента, когда запись уже сделана человеком. И это правильно: read-only делает цену ошибки агента предсказуемой. Половинный диагноз лучше сломанного прода.

Как обходим: агент собирает из чтения всё, что можно, — данные, логи, историю кода, — формулирует гипотезу и готовит патч; изменения уходят через PR, а применяет и проверяет человек, у которого права записи есть. Да, это медленнее, чем «дать агенту консоль», — зато не требует верить агенту на слово.

Второе честное место — лимиты мешают большим аналитическим выборкам. Иногда агент упирается в ограничение и вместо одного большого ответа собирает ответ из нескольких маленьких. Мы пока считаем эту цену справедливой: latency для людей дороже удобства агента.

Info

Изменения в код — только через PR, и мержит человек. Это не процессный ритуал, а та же модель доверия, что и read-only у шлюза: агент предлагает, человек решает.

Итог: три правила доступа к прод-данным

Полгода эксплуатации сжались в три правила, которые мы теперь применяем к каждому новому контуру с агентами:

  1. Записи у агента не существует. Не «запрещено регламентом», а физически нет прав — read-only на уровне шлюза и учётки. Правило, которое держится на дисциплине, рано или поздно нарушается; правило, встроенное в доступ, — никогда.
  2. Узкие инструменты вместо универсального SQL. Каждый частый вопрос к прод-данным — отдельный инструмент с предсказуемой нагрузкой и читаемой записью в журнале.
  3. Каждое действие — под именем. Своя учётка и свой токен на задачу, журнал вызовов, отзыв без перезапуска. Тогда «разобраться, что произошло» — это минута, а не расследование.

Если хотите такую же схему у себя — доступ агентов к прод-данным без риска для прода и без ssh — это часть наших ИИ-работ: мы строим такие контуры под задачи клиента. Соседние части конвейера — изоляция агентов и экономика агентного саппорта — разобраны в статьях цикла, ссылки выше.