Разделите MCP Host, Client и Server
Сторона MCP держится на трёх ролях, и путаница между ними - самая частая причина небезопасного дизайна. Host - это само AI-приложение: chat, IDE, агент или backend. Он контролирует permissions, UX и модель, выбирает, к каким серверам подключаться, показывает подтверждения, хранит идентичность пользователя и решает, что вообще попадёт модели. Client - это одна протокольная сессия: внутри host на каждое соединение с сервером создаётся отдельный client, который делает discovery, отправляет вызовы и проверяет capabilities. Server - это провайдер возможностей: он оборачивает БД, API или локальные данные в tools, resources и prompts, валидирует вход и применяет authorization. Один host, много клиентов, много серверов - и каждый server видит только своё.
На схеме это выглядит как host с двумя независимыми соединениями.
Release Review Host
├─ MCP Client A ── stdio ── Runbook Server
└─ MCP Client B ── HTTP ── CI Evidence Server
Model loop видит разрешенное объединение capabilities.
Server A не получает внутреннее состояние Server B.Ключевое здесь - что model loop видит разрешённое объединение возможностей, но server A не получает внутреннее состояние server B. Границы доверия проходят между серверами, а не размазаны по одному большому процессу.
Наивный дизайн ставит один монолитный сервер, который получает пользовательский transcript, секреты всех систем и право на любую операцию. В демо это удобно, но так разрушается least privilege, а аудит становится невозможным: непонятно, кто и на каком основании что вызвал.
Профессиональный дизайн делит серверы по владельцу данных и уровню риска. Host фильтрует список возможностей по пользователю и окружению, а server сам повторно проверяет authorization и никогда не полагается на то, что модель "правильно поняла" права. Разделение стоит нескольких лишних объектов, но именно оно делает систему проверяемой.
Кому принадлежит orchestration. MCP-server отвечает на протокольные запросы. Решение "какой tool вызвать следующим" обычно живёт в host. Если server сам ведёт долгую агентную работу - это уже отдельный runtime и, возможно, граница A2A, а не MCP.
Роли разведены - можно брать конкретный SDK. И здесь важно не потянуть за собой привычки из старых туториалов.
Кто в MCP обычно решает, какой tool вызвать следующим?