Глава 5 — Транспортные протоколы и обнаружение
Пятый пост поглавного разбора LLM Primer IV: Designing AI Cognition with MCP. Каждое сообщение из глав 3 и 4 парило в воздухе между хостом и сервером — но сообщения не парят, они едут на транспорте, и транспорт тихо решает почти всё операционное в интеграции.
Почему существует эта глава
MCP определяет формат сообщений — JSON-RPC 2.0 поверх дуплексного канала — а затем определяет три транспорта, которые реализуют этот канал. Транспорты не взаимозаменяемы. Каждый подходит своему паттерну развёртывания, несёт разный операционный багаж и открывает разные поверхности безопасности. Второй вопрос висит над той же территорией: как хост вообще находит сервер? Пока хост не знает, что сервер существует и где он живёт, самая красиво специфицированная спецификация не порождает разговоров.
Эта глава проходит оба. Транспорты решают, локализован ли сервер вместе с хостом или удалён, есть ли у вас аутентификация или изоляция процессов и как сервер масштабируется. Слой обнаружения решает, ваш сервер — то, чем пользуется один инженер, или то, что может принять команда.
.well-known/mcp.json плюс Server Cards — то, что превращает проблему конфигурации в проблему поиска.
5.1 stdio, SSE и Streamable HTTP
stdio — это хост, запускающий сервер как дочерний процесс. Хост пишет JSON-RPC в stdin ребёнка и читает ответы из stdout; stderr несёт логи. Ни порта, ни сокета, ни сети. Аутентификация обеспечивается границей запуска процесса в ОС. Claude Desktop, Cursor и официальный инспектор MCP — все используют stdio для локальных серверов. Модель честна относительно того, чем она является: инструмент на вашей собственной машине, co-located, в том же домене доверия, что и хост. Его нельзя разделять между хостами, нельзя запустить на другой машине, и единственная доступная множественность — один на хост: пять клиентов, желающих один сервер, жгут пять процессов.
HTTP+SSE был первым ответом MCP на сетевой случай. Двунаправленный, но дуплекс, склеенный из двух однонаправленных кусков. Устарел. Всё ещё встречается в дикой природе. SSE-серверы вы будете встречать ещё какое-то время.
Streamable HTTP — предпочтительный сетевой транспорт. Единственная конечная точка — обычно /mcp — принимает JSON-RPC-запросы и отвечает либо одним ответом (для синхронных вызовов), либо потоком Server-Sent Events, когда сообщений несколько, включая инициированные сервером уведомления. Сессии идентифицируются заголовком Mcp-Session-Id, выставленным при инициализации и продёрнутым через каждый последующий запрос. Сессия — единица состояния, освобождаемая через DELETE или собираемая по таймауту. Транспорт чисто компонуется с балансировщиками, обратными прокси, edge-кэшами и TLS. Горизонтальное масштабирование — sticky-session по идентификатору сессии. Ничто из этого не является новой HTTP-инженерией; смысл в том, что MCP помещается внутри неё без изобретения нового слоя.
Выбор — решение безопасности в той же мере, что и развёртывания. stdio-серверы склонны к избыточным привилегиям — они наследуют права пользователя на файловую систему и сеть без аутентификации, потому что нет удалённого вызывающего. Сетевые серверы смотрят в открытый интернет и обязаны аутентифицировать каждый запрос, причём OAuth 2.1 сейчас сходящийся стандарт. Выбор не того транспорта под вашу позицию безопасности заставляет прикручивать то, что должно было быть встроено.
5.2 Обнаружение серверов: .well-known/mcp.json и Server Cards
Протокол, требующий ручной конфигурации каждого хоста с адресом каждого сервера, не превращается в экосистему. Он превращается в кошмар конфигурации. Слой обнаружения MCP заимствует паттерн well-known URI из RFC 8615 — тот же механизм, что и у robots.txt и .well-known/openid-configuration. Сервер публикует .well-known/mcp.json по своему базовому URL. Хост его выбирает, разбирает и узнаёт, что сервер заявляет о себе: MCP-конечную точку, версию протокола, схему аутентификации, метаданные идентичности и указатель на Server Card.
Server Card — это openapi.json для MCP: самоописывающий артефакт, потребляемый и машинами, и людьми. Хост может показать карту пользователю при flow подключения — «этот сервер говорит, что может работать с вашим Linear-воркспейсом, читать тикеты, но не удалять, запускается самим Linear, использует OAuth» — и пользователь может решить, приемлемо ли заявление. Карты в неподписанной форме — это заявления, а не доказательства. Смягчение — подписанная аттестация со схемой подписи, сошедшейся на sigstore-стиле OIDC: карта, подписанная через OIDC-интеграцию GitHub под github.com/some-org/mcp-server, может быть проверена любым хостом, доверяющим заявлениям идентичности GitHub. Хосты могут наслаивать политику сверху — доверять только подписанным картам, только подписанным картам от конкретного провайдера, только не из списка отозванных.
Flow выглядит как добавление Wi-Fi-сети. Один раз. Хост запоминает конфигурацию; последующие сессии пропускают обнаружение. То, что значит «что-то изменилось» на практике — бамп версии, расширение скоупов, сдвиг возможностей, — должно вызывать повторное согласие, как это делает смена TLS-сертификата. Хосты, пропускающие этот шаг, позволяют серверам тихо расширять свой охват во времени, что и есть медленный ползучий рост возможностей, подрывающий доверие к любой долгоживущей интеграции.
5.3 Скучные части, решающие, выпустите ли вы продукт
Три операционные заботы заслуживают собственного рассмотрения, потому что каждая — место, где небрежная реализация даёт либо сломанные интеграции, либо дыры в безопасности.
CORS важен для любого MCP-сервера, достижимого из браузерного хоста. Соблазн — выставить Access-Control-Allow-Origin: * и двинуться дальше. Это неправильно. В сочетании с cookie-аутентификацией это CSRF-катастрофа; в сочетании с bearer-токенами в localStorage — риск утечки токенов. Используйте allowlist по origin-у и предпочитайте заголовки Authorization cookie, чтобы same-origin не был единственной линией обороны.
Валидация origin — это CORS, применяемый на стороне сервера, потому что не-браузерные клиенты ничего не обеспечивают. Классический отказ: разработчик запускает MCP-сервер на localhost:8000, посещает веб-страницу, знающую соглашение, страница стреляет запросом, и сервер — без проверки origin — делает всё, что страница попросила. Валидируйте Origin на каждом Streamable HTTP-сервере.
Заголовки кэширования — третье. Статическая документация может кэшироваться агрессивно; строка БД — только пока подписки подключены; документ, который активно редактируется, — никак. Возвращайте правильные Cache-Control и ETag на ресурс. Взаимодействие кэширования и подписок — место, где инженеров кусает: посредник, отдающий устаревшую копию, означает, что уведомление resources/updated хоста никогда не сработает, потому что механизм подписки не дотягивается до живого сервера.
DNS rebinding замыкает соседство и непропорционально затрагивает локальные серверы. Привязывайтесь к 127.0.0.1, а не к 0.0.0.0, валидируйте заголовок Host против allowlist, требуйте auth-токен даже для localhost. Локальный MCP-сервер без всего этого — одно демо от того, чтобы стать security advisory.
Что подготавливает глава 5
Это закрывает часть II книги. Протокол в руках: серверные примитивы в главе 3, клиентские в главе 4, провод и слой обнаружения здесь. Мы знаем, какие сообщения путешествуют, в каком направлении, по какому транспорту, между какими доменами доверия, после какого рукопожатия. Часть III поворачивает от примитивов к паттернам. Единственный сервер, подключённый к единственному хосту, полезен; архитектурная отдача от MCP — это композиция: несколько серверов, несколько агентов, несколько моделей, сотрудничающих ради больших целей.
Дальше — Глава 6: Фундаментальные стратегии оркестрации. Когда один хорошо оснащённый агент бьёт мультиагентный дизайн, и две базовые формы — последовательные пайплайны и параллельность scatter-gather, — на которые опирается большинство продакшен-развёртываний.