MCP-зоопарк уже ломает команды: как выбрать один runtime для агентов вместо 10 несовместимых тулов
Я Denis Shokhirev, Agentic AI Systems Architect из Freiburg im Breisgau, Germany, и в DennisCraft AI Studio я собираю production-grade агентные системы на Claude, Supabase, n8n, Doppler и self-hosted Postgres. Последние месяцы я вижу один и тот же сбойный паттерн: команда уже подключила MCP-серверы, локальные tools, workflow-автоматизацию и кастомные wrappers, а потом выясняется, что агент проходит demo, но ломается на правах доступа, таймаутах и несовместимых схемах вызова в реальной среде. Пр
Я Denis Shokhirev, Agentic AI Systems Architect из Freiburg im Breisgau, Germany, и в DennisCraft AI Studio я собираю production-grade агентные системы на Claude, Supabase, n8n, Doppler и self-hosted Postgres. Последние месяцы я вижу один и тот же сбойный паттерн: команда уже подключила MCP-серверы, локальные tools, workflow-автоматизацию и кастомные wrappers, а потом выясняется, что агент проходит demo, но ломается на правах доступа, таймаутах и несовместимых схемах вызова в реальной среде.
Проблема не в том, что MCP плох сам по себе. Проблема в том, что команды превращают runtime в зоопарк: один инструмент для orchestration, другой для tool calling, третий для secrets, четвертый для observability, пятый для human review, и все это живет без единого контракта выполнения. В regulated среде это особенно быстро всплывает: кто имеет доступ к данным, где логируется вызов, как ограничивается действие агента, и кто вообще отвечает за отказоустойчивость.
Почему MCP-sprawl ломает команды раньше, чем модель начинает ошибаться
Когда у вас 10 несовместимых тулов, вы платите не только временем на интеграцию. Вы создаете 10 разных моделей отказа. Один сервер возвращает JSON-схему, другой — свободный текст, третий требует отдельной аутентификации, четвертый не умеет идемпотентность. В итоге вы дебажите не поведение агента, а поведение glue-code между тулзами.
Anthropic в документации по tool use и Model Context Protocol прямо показывает, что ценность появляется там, где есть стандартный интерфейс вызова инструмента и предсказуемый обмен контекстом, а не просто длинный список подключений. Источник: Anthropic Docs, 2025, https://docs.anthropic.com/. Я с этим согласен по практическим причинам: на 3 недавних внедрениях самые дорогие инциденты были не в модели, а в слое исполнения между моделью и инфраструктурой.
Типичные симптомы tool sprawl
| Симптом | Как выглядит | Что ломается |
|---|---|---|
| Дублирование tool registry | Одни и те же функции описаны в Claude Code, n8n и локальном сервисе | Разъезжаются схемы и права |
| Разные контракты ошибок | Где-то 500, где-то text error, где-то timeout без тела | Агент не умеет восстанавливаться |
| Секреты разбросаны | Doppler, env, ручные токены в n8n | Аудит и ротация становятся ручными |
| Нет единого state layer | Часть состояния в памяти агента, часть в Supabase, часть в workflow | Нельзя воспроизвести решение |
Что считать runtime для агентов на практике
Я называю runtime не библиотеку и не protocol-spec. Runtime — это слой, который принимает решение о вызове tools, исполняет их по единому контракту, логирует действия, контролирует state, retries, timeouts и доступ к данным. Если этого слоя нет, у вас не runtime, а набор интеграций.
В моем стеке чаще всего работает такой принцип: Claude или Anthropic SDK принимает решение, Postgres или Supabase хранит state и audit trail, n8n исполняет внешние бизнес-процессы там, где важна интеграционная наглядность, а секреты живут в Doppler. Ключевой момент: для агента все это должно выглядеть как один исполнимый слой, а не как 5 независимых миров.
Минимальный контракт tool execution
from anthropic import Anthropic
import os, json
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
tools = [{
"name": "create_invoice",
"description": "Create invoice in ERP",
"input_schema": {
"type": "object",
"properties": {
"customer_id": {"type": "string"},
"amount": {"type": "number"}
},
"required": ["customer_id", "amount"]
}
}]
msg = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=800,
tools=tools,
messages=[{"role": "user", "content": "Create invoice for C-102 with 1200 EUR"}]
)
print(json.dumps(msg.model_dump(), indent=2, ensure_ascii=False))Этот код не решает orchestration целиком, но показывает главное: инструмент описан схемой, вызов модели предсказуем, а не завязан на случайные парсеры текста. Дальше вы уже оборачиваете исполнение в retries, policy checks и persistent state.
Как выбрать один runtime вместо 10 тулов
Я смотрю не на количество интеграций в каталоге, а на 5 жестких критериев.
1. Единый контракт вызова tools
Если tools в одной системе описаны JSON schema, а в другой — prompt-конвенцией, команда быстро теряет контроль. Нужен один формат определения входов, выходов и ошибок.
2. Наблюдаемость на уровне действия
Мне нужен не просто application log, а запись: какой агент, с каким prompt/context, какой tool вызвал, с каким аргументом, к какому результату это привело, и можно ли это воспроизвести. Без этого root cause analysis превращается в догадки.
3. Состояние вне модели
Если критическое состояние живет только в контекстном окне, вы потеряете повторяемость. State должен быть в Postgres или Supabase, с версионированием и понятной моделью блокировок.
4. Policy enforcement до вызова side effects
Агент не должен сам решать, можно ли отправлять письмо, менять лимит или трогать PII. Эти проверки должны жить вне модели.
type ToolCall = { name: string; input: Record<string, unknown> };
export function allowTool(call: ToolCall, role: string): boolean {
const restricted = ["send_email", "update_payout", "delete_record"];
if (restricted.includes(call.name) && role !== "approved_operator") {
return false;
}
if (call.name === "update_payout" && typeof call.input["amount"] === "number") {
return Number(call.input["amount"]) <= 1000;
}
return true;
}5. Сканирование кода и workflow до релиза
Если вы генерируете код, SQL или automation, проверяйте это до выхода в prod. OWASP публикует LLM Top 10 как список типовых рисков для приложений с LLM, включая excessive agency и insecure output handling. Источник: OWASP GenAI Security Project, 2025, https://genai.owasp.org/. Для Python и инфраструктуры я обычно ставлю semgrep, bandit и gitleaks в CI.
semgrep --config=p/owasp-top-ten .
bandit -r app/ -f json -o bandit-report.json
gitleaks detect --source . --report-format json --report-path gitleaks.jsonКогда n8n, Supabase и Postgres помогают, а когда мешают
n8n полезен там, где у вас много внешних систем и нужно быстро, прозрачно собирать бизнес-процессы. Но n8n не должен становиться hidden runtime, в котором живет половина агентной логики без версионирования и тестов. Supabase удобен как managed слой для state, auth и быстрых внутренних интерфейсов, но для чувствительных сценариев я часто оставляю self-hosted Postgres как source of truth.
Хороший признак архитектуры: если завтра вы меняете модель или добавляете еще один tool provider, state model, policy layer и audit trail не меняются радикально. Плохой признак: смена одного инструмента тянет переписывание всех workflow.
Практическая схема для regulated рынка
Если вы работаете с B2B-клиентами в Европе, мой базовый шаблон простой. Модель принимает решение, но не исполняет side effects напрямую. Все tool calls проходят через policy layer. Все состояния и решения пишутся в Postgres. Секреты управляются централизованно. Внешние процессы, которым нужна визуальная orchestration, уходят в n8n. Все generated artifacts проходят статический анализ и ручной review там, где есть риск денег, персональных данных или внешних сообщений.
Такой подход не делает систему идеальной. Но он убирает главный источник хаоса: когда команда думает, что строит агентов, а по факту строит набор несовместимых переходников.
FAQ
MCP достаточно, чтобы стандартизировать весь стек?
Нет. MCP помогает стандартизировать способ описания и вызова инструментов, но не заменяет policy layer, state management, audit trail и контроль side effects.
Стоит ли держать orchestration внутри n8n?
Только для части процессов. Если основная логика принятия решений и recovery живет в n8n без тестируемого кода и явного state layer, поддержка быстро становится дорогой.
Можно ли выбрать runtime без self-hosted Postgres?
Да, если managed среда закрывает ваши требования к журналированию, резервированию и доступу. Но source of truth должен быть один, а не размазан по памяти агента и workflow-нодам.
Что важнее: выбор модели или выбор runtime?
Для production почти всегда важнее runtime. Модель можно заменить за неделю, а плохой execution layer ломает доступы, наблюдаемость и воспроизводимость месяцами.
С чего начать аудит tool sprawl?
С карты всех tool calls, секретов, state stores и точек side effects. Если вы не можете за 30 минут объяснить, где агент принимает решение и где оно исполняется, sprawl уже начался.
Где у вас сегодня больше всего отказов в агентной системе: в model reasoning, в policy checks, в tool execution или в state recovery после ошибки? Мне правда интересно сравнить это с тем, что я вижу в проде у B2B-команд в Европе.
I run a free 30-min stack audit for DACH founders building AI in regulated markets. DM me on LinkedIn or write to @ger_dennis_ai.
Превратить процесс в систему, которая работает
Продакшн-качество, а не демо.