MCP встроили в монолит. 200 строк - и готово
MCP встроили в монолит. 200 строк - и готово

Российская команда разработки внедрила поддержку Model Context Protocol прямо в существующий Go-монолит - без отдельного сервиса, без новых зависимостей, за один вечер. Результат: ИИ-ассистент теперь напрямую отвечает на вопросы о статусе клиентских сайтов, не требуя от пользователя ни одного лишнего клика.

Зачем это вообще нужно

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

Ассистент теперь не просто отвечает. Он сам компонует готовый абзац для письма клиенту: какой был аптайм за месяц, что падало и когда восстановилось. Это уже не «посмотреть данные», а полноценная автоматизация рутины.

Почему MCP, а не очередной кастомный формат

До появления Model Context Protocol каждый вендор ИИ-инструментов тащил свой формат: свой function calling, свои плагины, свои манифесты. MCP - попытка унифицировать этот зоопарк. Сервер один раз декларирует инструменты, а дальше любой совместимый клиент их подхватывает автоматически.

Список уже внушительный: Claude Code, Claude Desktop, Cursor, VS Code - все умеют быть MCP-клиентами. Один эндпоинт даёт доступ сразу ко всем окружениям. Не нужно писать отдельную интеграцию для каждого.

Как сделали: минимум кода, ноль лишнего

Официальный Go SDK для MCP тянет за собой сессии, SSE-стриминг, resumability. Всё это имеет смысл, когда инструменты работают долго или сервер хочет пушить события. Здесь инструменты - обычные SELECT-запросы к Postgres, которые отвечают за десятки миллисекунд. Брать тяжёлый SDK ради четырёх read-only операций - избыточно.

Спека MCP (ревизия 2025-03-26) прямо допускает простейший вариант Streamable HTTP: клиент отправляет JSON-RPC POST, сервер возвращает один JSON-документ. Без стриминга. Именно это и реализовали - один файл mcp.go примерно на 200 строк внутри уже работающего монолита.

  • Никаких новых зависимостей в проекте
  • Переиспользуется пул соединений к Postgres, авторизация токенов и таймауты из основного API
  • Stateless-архитектура: каждый запрос авторизуется Bearer-токеном заново, никакого состояния между вызовами
  • Тенант прошивается из токена в каждый SQL-запрос - инструмент физически не может заглянуть в чужую организацию

Что внутри и какие грабли нашли

Реализованы только методы, которые реально нужны: initialize, ping, tools/list и tools/call. Уведомления от клиента принимаются и молча возвращают 202. Ни resources, ни prompts, ни sampling - capabilities честно декларируют только tools.

Самое неочевидное место во всей спеке - обработка ошибок при вызове инструмента. Интуиция подсказывает вернуть JSON-RPC error. Спека говорит противоположное: ошибка инструмента должна приходить как успешный result с флагом isError. Потому что её адресат - языковая модель, а не транспортный слой. LLM прочитает текст ошибки и отреагирует осмысленно; JSON-RPC-ошибки клиентская обвязка до модели обычно не доносит вовсе.

Отдельное внимание - описаниям инструментов. Их читает не человек, а модель, и от формулировки зависит, догадается ли она позвать нужный инструмент на вопрос «как дела у сайтов за месяц». Авторы относятся к ним как к микро-документации: что вернётся и когда уместно вызывать.