Главная / Статьи

Развертывание сервера MCP на EC2 после изменений в спецификации безсостоянийных сессий

Перенос сервера MCP с localhost на EC2: потоковый HTTP, nginx и аутентификация через токены, а также что означают безсостоянийные сессии и OAuth 2.1 для реальной развертки.

Издатель: REACTAPP.TOP11 мин чтения2446 слов

Источники: MCP Servers Explained: A Complete Guide to What I Learned Deploying One to AWS EC2

От localhost до настоящего сервера

Учебные материалы по MCP, как правило, остаются абстрактными. В них показан клиент рядом с сервером, протокол сравнивается с портом USB-C, или приводится пятистрочный пример, работающий только на localhost и не покидающий ноутбук разработчика. Настоящая работа начинается после этого: инструмент, написанный локально, должен работать на реальном сервере, за реальным обратным прокси, чтобы реальный клиент мог обращаться к нему через общественный Интернет. Это отдельная проблема, которой почти не уделяется внимания.

Описанный здесь процесс развертывания начинается с локального сервера MCP, затем он перемещается на инстанцию EC2 и обслуживается через протокол HTTP с возможностью потоковой передачи данных, причем nginx требует наличия токена-переносчика заранее. Всё работало нормально. Вскоре после этого протокол был перенесен под его управление. 28 июля 2026 года была выпущена крупнейшая на сегодняшний день версия спецификации MCP — она перешла из статуса кандидата на выпуск в статус окончательной, что сделало ядро протокола бессостоянийным. Команды часто отмечают «поддержку MCP» как единый пункт, но на самом деле это включает три аспекта: способ передачи данных, аутентификацию и, начиная с этого обновления, масштабируемость. Неправильный выбор в любом из этих аспектов определяет разницу между инструментом демонстрационного уровня и тем, который можно использовать в производственных условиях.

В статье рассматриваются несколько вопросов: какие аспекты проблемы определяются стандартом MCP, а какие остаются нерешенными, почему протокол streamable HTTP заменил транспорт на основе SSE, как nginx и токен-носитель позволяют обращаться к локальному серверу на EC2, какие изменения происходят при бессостоянийной переработке запросов, почему статический токен считается средством аутентификации, но не соответствует требованиям спецификации, и какие части процесса развертывания пришлось изменить, чтобы идти в ногу с развитием технологий.

Что стандартизирует, а что нет MCP

На бумаге протокол Model Context Protocol определяет лишь один аспект: способ, которым приложение ИИ находит и вызывает инструменты, а также читает ресурсы, предоставляемые отдельным серверным процессом, с помощью сообщений JSON-RPC, передаваемых по определённому каналу связи. Логика инструментов, проектирование агентов и их развертывание находятся вне его рамок. Это стандарт для подключения, а не фреймворк. Ранее каждому приложению ИИ, желающему получить доступ к внутреннему API, требовалась индивидуальная интеграция. При использовании MCP один сервер обслуживает всех соответствующих клиентов.

Если посмотреть на это с такой точки зрения, становится ясно, почему возникают трудности при развертывании. Протокол описывает структуру сообщений, но не упоминает, можно ли подключиться к серверу только с одного ноутбука или из любого места, защищён ли он, и справляется ли он с несколькими клиентами одновременно. Ответы на все эти вопросы зависят от оператора.

Почему публичное развертывание отличается

  • Локальные серверы почти ничего не открывают наружу, тогда как публичные — многое. При наличии публичного URL сервер превращается в обычный аутентифицированный API, поэтому обработка токенов и проверка входных данных имеют такое же большое значение.
  • Раньше правила работы сессий и масштабирования были неясными. Неправильные предположения приводили либо к тому, что сервер тихо выходил из строя под совместной нагрузкой, либо к тому, что он становился перегруженным ненужными «липкими» сессиями.
  • Спецификация постоянно развивается. Решения, созданные на основе предположений, устаревших на шесть месяцев, могут перестать соответствовать требованиям без единой ошибки, поскольку клиенты просто соглашаются на более старую версию протокола.

Архитектура выглядит следующим образом.

AI Client ── HTTPS POST ──▶ nginx (TLS termination, auth check, reverse proxy)
                                    │
                                    ▼
                          MCP Server Process
                          (Streamable HTTP transport)
                                    │
                       ┌────────────┴────────────┐
                    Tools                    Resources

Всё это регулируется одним принципом. Как только сервер MCP получает публичный URL, его следует обрабатывать как любой аутентифицированный API, предоставляемый через EC2, поскольку по структуре они идентичны. MCP представляет собой лишь формат сообщений, тогда как вопросы безопасности и масштабируемости остаются теми же, что и у любого бэкенда.

1. Транспорт Streamable HTTP

Streamable HTTP — это один HTTP-эндпоинт, принимающий запросы типа POST с сообщениями в формате JSON-RPC. Он заменил более ранний транспорт HTTP+SSE, который требовал постоянного потока серверных событий наряду с обычными HTTP-запросами.

Один POST-эндпоинт хорошо знаком любому обратному прокси, балансировщику нагрузки или шлюзу API, поэтому нет проблем с поддержанием долгоживущего потока через nginx или ALB. Трафик выглядит как обычный HTTP-API, и блоки настройки в nginx остаются краткими.

location /mcp {
    proxy_pass http://127.0.0.1:8000;
    proxy_set_header Host $host;
    proxy_set_header Authorization $http_authorization;
    proxy_http_version 1.1;
    proxy_read_timeout 300s;
}

Совет для производственной среды: даже при транспортировке через один конечный пункт обеспечьте достаточно большой временной интервал ожидания чтения у прокси. Отдельные вызовы инструментов могут заканчиваться дольше, чем типичный запрос API, и слишком строгий таймаут приведет к прерыванию как действительно зациклившихся запросов, так и законных длительных операций.

2. Аутентификация с использованием токена Bearer

В этом схеме фиксированный токен находится в заголовке Authorization и проверяется еще до того, как запрос дойдет до процесса сервера MCP, будь то в nginx или в промежуточном слое приложения. Для любого контента, доступного по публичному URL, это наименее безопасный вариант, но при этом разумный первый шаг. Однако токен никогда не истекает, не связан ни с одним конкретным сервером и не обеспечивает защиты, если попадает в логи. Он лишь указывает на наличие у запроса учетных данных.

Пример промежуточного слоя FastAPI начинается с импортов.

from fastapi import Request, HTTPException

Затем следует сама проверка.

VALID_TOKEN = "your-rotated-secret-token"async def verify_bearer(request: Request):
    auth = request.headers.get("authorization", "")
    if auth != f"Bearer {VALID_TOKEN}":
        raise HTTPException(status_code=401, detail="Unauthorized")

Ещё один совет: не включайте необработанный заголовок Authorization в журналы доступа. Стандартные форматы журналов nginx и приложений затрудняют его обнаружение, и как только он попадает туда, файл журнала превращается в источник утечки учетных данных.

3. Безсостоянийность — основа переписывания в июле 2026 года

Согласно спецификации от 2026-07-28 сессии на уровне протокола исчезают. Заголовок Mcp-Session-Id больше не существует, а транспортный слой также отказывается от долговечных потоков GET, которые ранние версии использовали для синхронизации клиента и сервера в ходе общения. Каждый запрос содержит всё необходимое.

Ключевой момент — масштабируемость. Старая модель позволяла серверу запоминать информацию о клиенте между запросами, и когда за балансиром нагрузки оказывалось несколько инстансов, для хранения этой информации требовались «липкие сессии». Без состояния на уровне протокола любая инстанс может обрабатывать любой запрос, что обеспечивает настоящее горизонтальное масштабирование и освобождает клиентов от привязки к одной конкретной машине.

На практике сервер, сохраняющий в памяти информацию о клиенте между запросами, перестанет работать согласно новым требованиям. Вся важная информация должна переноситься в тело запроса или во внешнее хранилище, такое как Redis, к которому могут обращаться все инстансы.

4. Многократные запросы с обратными поездками

Даже протокол без состояния требует способа, позволяющего серверу задать вопрос клиенту в процессе выполнения запроса, например, запросить подтверждение или уточнить отсутствующий параметр. Новое описание решает эту проблему с помощью многократных запросов с обратным ходом. Вместо того чтобы поддерживать открытый поток, сервер отвечает с помощью объекта InputRequiredResult, в котором перечисляются его вопросы вместе с нечитаемым значением requestState. Клиент собирает ответы, снова отправляет исходный запрос, добавляет эти ответы и возвращает состояние без изменений.

Именно это делает истинное отсутствие состояния работоспособным. Поскольку всё, что необходимо серверу для возобновления работы, находится в данных, которые клиент возвращает, любой экземпляр, не обязательно тот, что начал запрос, может перепробовать его выполнение и завершить его.

Клиентам следует не вмешиваться в значение requestState: ни проверять его, ни изменять. Необходимо сохранять его в том виде, в котором он был получен, и возвращать без изменений, иначе процессы, зависящие от его целостности, могут сорваться.

5. Усиление механизмов авторизации

Изменённые спецификации направляют удалённые серверы MCP к протоколу OAuth 2.1 с поддержкой PKCE и требуют наличия индикаторов ресурсов (RFC 8707), которые связывают выданный токен с конкретным сервером, для которого он предназначен.

Основной проблемой является возможность повторного использования токенов. Если утечёт статический токен-носитель, любой сервер, принимающий его, может стать мишенью. Токен, привязанный к конкретному ресурсу, закрывает эту уязвимость, поэтому токен, выданный для одного сервера MCP, не будет работать на другом, даже если оба сервера используют одного и того же поставщика идентификации.

Режим работы с токенами-носителями, с которого начинают многие, соответствует требованию «для доступа к этому конечному пункту необходима аутентификация». Однако он не обеспечивает уровня взаимодействия и защиты от повторной обработки данных, которые предусмотрены новыми спецификациями для совместимого удаленного сервера; этот разрыв необходимо устранить до того, как URL станет доступен кому-либо вне основной команды.

6. Политика устаревания и расширения

Функции, описанные в спецификациях, теперь проходят формальный жизненный цикл: «Активные», «Устаревшие» и «Удаленные», причем между стадиями устаревания и удаления предусмотрено не менее двенадцати месяцев. Новые функции, такие как интерфейс, генерируемый сервером, или задачи с длительным временем выполнения, сначала появляются в виде факультативных расширений, а не сразу входят в основную часть системы. Некоторые более старые функции, включая методы roots, sampling и логирование в их первоначальной форме, находятся на пути к устареванию в пользу более современных заменителей.

Для операторов это означает, что рабочая интеграция не будет нарушена внезапной будущей версией обновления, а новые функции можно внедрять осознанно, без необходимости спешки, чтобы соответствовать всем добавлениям в спецификацию.

Пошаговое руководство

Путь от локального прототипа до развертывания на EC2 в соответствии с текущей спецификацией выглядит следующим образом:

  1. Локальные тесты. Сервер работает через стандартный ввод-вывод с локальным клиентом без использования сети и аутентификации, что позволяет быстро выполнять итерации.
  2. Переход на потоковый HTTP. Сервер перенастраивается для использования потокового протокола HTTP и развертывается на инстансе EC2.
  3. nginx в качестве прокси. nginx обрабатывает шифрование TLS, проверяет токен-переносчик перед тем, как запрос попадёт в процесс MCP, а затем перенаправляет его дальше.
  • Простой вызов инструмента. Один запрос типа POST передаёт запрос JSON-RPC, а результат возвращается в том же запросе и ответе.
  • Согласование версии. После окончательного утверждения спецификации 2026-07-28 клиент и сервер договариваются о версии протокола. Клиент, который не обновился, автоматически переходит на версию 2025-11-25 и не выходит из строя.
  • Требуется дополнительный ввод. Вместо того чтобы оставлять соединение открытым, сервер отвечает с кодом InputRequiredResult, указывающим, что ему ещё нужно получить.
  • Возобновление. Клиент повторяет вызов, прикрепляя ответы и возвращая значение requestState. Повторная попытка не зависит от конкретной инстанции, поэтому её может выполнить любая машина, работающая за nginx.
  • Сбои аутентификации. Запросы без токена или с некорректным токеном отклоняются на уровне nginx. Код приложения никогда с ними не сталкивается.
  • Особые случаи

    Медленные операции. Задачи, ранее требовавшие открытого потока на протяжении всего времени выполнения, следует перевести на использование расширения Tasks. Попытка создать постоянное соединение в транспортном слое, не предусматривающем его, — неверный подход.

    Инструменты, которые никогда не будут работать удаленно. Для сервера, который всегда запускается локально рядом с клиентом, наилучшим решением является использование стандартного ввода-вывода, и здесь практически не применимы вопросы развертывания.

    Клиенты с разными версиями. Поскольку старые клиенты автоматически переходят на версию 2025-11-25, одно развертывание может разумно обслуживать обе версии протокола в течение некоторого времени, поэтому не все клиенты обязаны обновляться одновременно с сервером.

    Проблемы масштабирования и работы в производстве

    Множественные экземпляры. В рамках модели сессий для поддержания связи клиента с конкретным экземпляром использовались «липкие» сессии или общий хранилище сессий. Эта необходимость исчезла, и для тех, кто управляет более чем одним сервером, это является основным преимуществом переписывания кода.

    TLS в расширяющейся сети серверов. Управление сертификатом на каждом экземпляре EC2 быстро становится неэффективным. Использование управляемого балансировщика нагрузки с сертификатом ACM перед сетью серверов требует гораздо меньше усилий, чем настройка TLS в nginx на каждом отдельном сервере.

    Выдача и обновление токенов. Статические токены имеют ограничения с точки зрения безопасности, к тому же их использование создаёт операционные сложности при большем количестве клиентов, поскольку каждое обновление требует ручной координации. Механизм выдачи токенов на основе OAuth 2.1 одновременно устраняет проблемы с безопасностью и упрощает процесс обновления токенов.

    Отслеживание действий в ходе нескольких вызовов без сессий на стороне сервера. Поскольку на сервере отсутствуют сессии, связывающие последовательность вызовов, идентификаторы корреляции, передаваемые в теле запроса, становятся единственным надежным способом восстановления действий, совершенных в ходе одного взаимодействия агента в рамках нескольких вызовов.

    Обработка возобновления работы на стороне клиента

    Конфигурация nginx и промежуточный модуль bearer-check обеспечивают транспортировку данных и базовую аутентификацию. Ниже приведен минимальный пример реализации для стороны клиента в рамках запроса с несколькими раунд-трипами.

    async def call_tool_with_resume(client, tool_name, params):
        result = await client.call_tool(tool_name, params)
        if result.get("type") == "InputRequiredResult":
            answers = collect_answers(result["questions"])
            return await client.call_tool(
                tool_name,
                {**params, "answers": answers, "requestState": result["requestState"]},
            )
        return result
    

    Важна последняя строка, в которой значение requestState возвращается точно таким, каким его передал сервер.

    Распространённые ошибки

    • Считать, что приложение «развернуто» — значит оно готово к использованию в производстве». nginx вместе с токеном-носителем снимает только самые простые требования, но не все. Сохраняйте стандарты MCP-эндпоинта на уровне любого публичного API: используйте надлежащую аутентификацию, тщательную логгирование и ограничение частоты запросов перед тем, как URL будет широко распространяться.
    • Использование серверной памяти. В некоторых ранних версиях приложений тихо предполагалось, что сервер запомнит клиента из предыдущего запроса. Учитывайте, что каждый запрос может попадать на другой экземпляр сервера, поскольку текущие спецификации именно это позволяют.
    • Фиксация одной версии протокола. Клиент, привязанный к определённой ревизии, перестаёт работать при обновлении сервера. Необходимо внедрить механизм переговоров с разумным резервным вариантом, чтобы обновление одной стороны не приводило к сбою у другой.
    • Отказ от аутентификации для внутреннего инструмента. Инструмент, сейчас используемый внутри организации, в будущем может быть передан партнёрской команде, и тогда статический токен окажется недостаточным. Если сервер может находиться вне ноутбука или VPC, с самого начала следует использовать OAuth 2.1 и индикаторы ресурсов.

    Практики, эффективные в производственных условиях

    • Избегайте ситуаций, когда ваша инфраструктура не может масштабироваться. Всё, что должно сохраняться между вызовами, должно храниться в теле запроса или во внешнем хранилище.
    • Связывайте каждый токен с конкретным ресурсом, поскольку токен, принимаемый всеми доверенными серверами, рано или поздно может быть использован там, где это недопустимо.
    • Договаривайтесь о версиях протокола и не предполагайте использование одной конкретной версии. Клиенты и серверы редко обновляются в один и тот же день, поэтому необходимо учитывать эту разницу.
    • Проверяйте процесс аутентификации на уровне края сети. Когда nginx отклоняет некорректный запрос, процесс MCP остается проще и выдает меньше информации.
    • Не трогайте непрозрачные поля. Поля вроде requestState существуют для того, чтобы сервер мог полагаться на возвращаемые данные, поэтому клиенты не должны их читать или изменять.

    Как это влияет на процесс развертывания

    В теории MCP кажется простым. Решения, имеющие значение для развертывания, были изменены в обновлении спецификации от 28 июля 2026 года. Streamable HTTP легче запускать на обычной инфраструктуре, отсутствие состояния делает добавление инстанса EC2 реалистичной альтернативой вместо проекта по управлению сессиями, а модель авторизации теперь подходит для серверов, обращенных к публике. Все это становится понятным после первого рассмотрения, но теоретические описания обычно это игнорируют.

    Связанные статьи

  • Пересчёт налога на токены MCP: рост обусловлен описаниями двух инструментов — Повторная работа девяти серверов MCP в течение 13 дней показала, что количество токенов в определениях инструментов выросло с 36 320 до 38 738, причём почти весь прирост произошёл из-за того, что один из серверов переписал уже существовавшие у него описания.