Восемь MCP-серверов у одного Claude-агента: тихие коллизии имён tools

Инженер kenimo49 подключил к одному агенту Claude восемь MCP-серверов — от веб-поиска до Postgres и Slack. Старт прошёл без ошибок и предупреждений, но три пары серверов зарегистрировали tools с одинаковыми именами; на каждую сессию клиент выбирал одну из реализаций случайно. Для vibe-coding со стеком MCP это не абстрактный баг конфига: вызов search или create_issue может уйти не в тот backend и подтянуть чужой контекст.
Почему UI молчит, а агент ведёт себя нестабильно
Model Context Protocol отдаёт агенту единый плоский реестр инструментов: имена tools — строки без пространства имён и без привязки к server_id в ответе tools/list. Если два MCP-сервера экспортируют, например, search, клиент не обязан предупредить о коллизии — срабатывает правило «последний записанный побеждает», без collision detection.
В конфигурации Claude Desktop / Claude Code (claude_desktop_config.json) поднялись все восемь процессов, в system prompt попали описания 87 tools (около 4 400 токенов только на схемы — отдельная нагрузка, которую автор выносит за рамки этой истории). Снаружи стек выглядел здоровым; внутри маршрутизация tool-calling уже была неоднозначной.
Восемь серверов в одном агенте
По материалу на Dev.to (27 мая 2026) в одном агенте соседствуют:
| Сервер в конфиге | Роль |
|---|---|
brave-search |
веб-поиск для фактчекинга |
filesystem |
чтение и запись vault Obsidian |
github |
issues и PR в своих репозиториях |
linear |
issues и проекты в клиентском репо |
s3 |
read-only к приватному bucket логов |
freee |
налоги и расходы (японский учётный сервис) |
slack |
read-only по двум каналам для саммари |
postgres |
read-only к личной analytics DB |
Типичный сценарий «навесил MCP под задачу» — и как раз тот случай, когда generic-имена (search, list, get, create, delete) при числе серверов больше двух почти неизбежно пересекаются. В посте ссылаются на ревизию спеки MCP 2026-03-26: коллизия трактуется как проблема конфигурации, а не протокола; namespace-префиксы обсуждаются в proposal #287, но в клиентах на момент материала ещё не в проде.
Три пары одинаковых имён и три разных сбоя
| Имя tool | Кто столкнулся | Что пошло не так |
|---|---|---|
search |
brave-search и filesystem |
Порядок загрузки из конфига (алфавит) оставил filesystem; запрос про «Anthropic safety paper» ушёл в regex по Obsidian — пустой результат. |
create_issue |
github и linear |
Сработал «второй» сервер (Linear); issue с упоминанием приватной Postgres-схемы попала в клиентский проект — тикет закрыли вручную. |
list_files |
filesystem и s3 |
Фраза «list files in inbox» вызвала S3-версию: в контекст улетело порядка 31 000 токенов метаданных (~40 000 объектов в prefix против 12 локальных файлов) — сессия стала непригодной. |
Аудит начался на шестой день эксплуатации, когда заметили, что search то находит веб, то «ничего не находит», а create_issue ведёт себя непредсказуемо. До явного разбора имён это выглядело как каприз модели, а не как конфликт MCP.
«What leaked» без CVE: подмена сервера и контекста
В заголовке и анонсе поста слово «leaked» — не про утечку CVE и не supply-chain инцидент. Речь о тихой подмене сервера при вызове tool и о перетекании данных между интеграциями: issue с приватными деталями в чужом Linear, листинг S3 вместо локальной папки «inbox». Именно это в материале называют «протеканием» между MCP-серверами при внешне чистом логе старта.
Один и тот же промпт в разных сессиях может бить в разные backends, если имена tools совпадают — без единого warning в UI.
Для агентных сценариев вывод жёсткий: стабильность tool-calling нельзя проверять только по экрану «всё подключилось».
Фикс: tool_prefix в mcpServers
Решение — не смена модели, а конфиг агента. В каждой записи mcpServers добавлено поле tool_prefix; клиент переписывает имена в {prefix}{tool_name} до регистрации. Пример префиксов из поста:
{
"mcpServers": {
"brave-search": { "tool_prefix": "brave_" },
"filesystem": { "tool_prefix": "fs_" },
"github": { "tool_prefix": "gh_" },
"linear": { "tool_prefix": "linear_" },
"s3": { "tool_prefix": "s3_" },
"freee": { "tool_prefix": "freee_" },
"slack": { "tool_prefix": "slack_" },
"postgres": { "tool_prefix": "pg_" }
}
}
После префиксов — 87 уникальных имён (brave_search / fs_search, gh_create_issue / linear_create_issue и т.д.). Поле tool_prefix — client-side в Claude Code, в релизе 2026-04 (стоит сверить версию сборки). Если клиент не умеет префикс, тот же эффект можно получить на стороне сервера — форк MCP с переименованием tools в источнике.
Дополнительно kenimo49 описывает два boot check у себя в репозитории:
- Collision scan после регистрации всех серверов — assert на отсутствие дубликатов, иначе не поднимать агент.
- Tool-call attribution log —
{server_name, tool_name, args_summary}в~/.claude/agent-tool-calls.jsonl; до префиксов в логе оказалось 22% вызовов на «не тот» сервер (цифра только из его замеров).
Политика после инцидента: не держать серверы с generic-именами без префикса даже в одиночку и не ждать предупреждений от клиента — проверять коллизии assert'ом у себя.
Что перенести в свой MCP-стек
- После подключения N≥3 серверов пройтись по
tools/listи выписать пересечения имён — UI может не подсказать. - Для production-агента предпочитать префиксы (
brave_,gh_, …) или серверные форки, пока namespace в спеке не закреплён в клиентах. - Логировать фактический
{server, tool}на каждый вызов — иначе «плавающее» поведение легко списать на модель. - Осторожно с tools вроде
list_filesна удалённых хранилищах: один неверный маршрут может сжечь контекст тысячами токенов метаданных.
В конце исходного поста — отсылка к книге Practical MCP Security (глава 6, аудит auth и регистрации tools); на разбор коллизий выше это не влияет, но полезно как следующий шаг после переименования.
Источники
- Kenimo49 — «I Wired 8 MCP Servers Into One Claude Agent. 3 Pairs Quietly Fought Over the Same Tool Name.» Dev.to, 27 мая 2026: Dev.to (дата доступа: 2026-05-27 UTC).