AmigaОбучение ИИ
Модуль 4 · Итоги · урок 13 из 13

Итоги

5 мин чтения▶ есть видеоверсия

Курс начинался с вопроса «что происходит под декоратором @mcp.tool()». Теперь вы знаете ответ на трёх уровнях: что сервер может попросить у клиента, как сообщения устроены и доставляются, и какое состояние сервер вправе держать. Соберём это в одну картину.

Обратные возможности

Сервер не только отвечает. Он может попросить модель хоста сгенерировать текст (sampling), сообщить о ходе долгой работы (прогресс), прислать логи и узнать рабочие папки клиента (roots). Всё это в SDK v2 выражается двумя механизмами: ctx.report_progress() для прогресса и резолверы с маркерами Sample() и ListRoots() через Annotated[..., Resolve(...)] для всего, что требует ответа клиента.

Три из четырёх возможностей — sampling, протокольное логирование и roots — устарели с ревизии 2026-07-28. Они работают, SDK их поддерживает, но новый код стоит писать иначе: прямой вызов API модели вместо sampling, logging в stderr вместо ctx.info(), папки из аргументов или конфигурации вместо roots. Прогресс остаётся и остаётся главным способом не выглядеть зависшим.

Общее, что стоит вынести: сервер обязан проверять возможности клиента до того, как что-то у него просить, и должен быть готов, что клиент откажет.

Провод

Всё — JSON-RPC 2.0: запрос, результат, ошибка, уведомление. До 2025-11-25 соединение начиналось с рукопожатия initialize, с 2026-07-28 версия и возможности клиента лежат в _meta каждого запроса, а сервер больше не отправляет клиенту запросов: sampling и roots вкладываются в результат input_required, и клиент повторяет вызов с ответами.

Два транспорта переносят одни и те же сообщения. STDIO — дочерний процесс, строка JSON на сообщение, stdout только для протокола, секреты из окружения, отмена уведомлением. Streamable HTTP — один endpoint, каждый запрос отдельным POST, ответ JSON или SSE-поток с уведомлениями, заголовки-зеркала, отмена закрытием потока, проверка Origin и аутентификация. Предыдущее поколение транспорта с сессиями Mcp-Session-Id, GET-потоком и Last-Event-ID вы теперь узнаете в логах и знаете, почему его упростили.

Состояние

Протокол без состояния не означает сервер без памяти. Он означает, что память лежит в правильных местах: процессные ресурсы — в lifespan, контекст между раундами — в защищённом requestState, долгие задачи — во внешнем хранилище по явному идентификатору, подписки — на общей шине. Экземпляры сервера делят ключ RequestStateSecurity и имя, старые клиенты получают либо липкую маршрутизацию, либо stateless_http. Личность пользователя приходит из проверенного OAuth-токена по HTTP или из окружения по stdio.

Что дальше

Три направления, в которых стоит копать после курса.

Элиситация — способ задать пользователю вопрос из инструмента через форму или ссылку. Она построена на том же MRTR, что sampling и roots, но не устарела и в SDK выражается маркером Elicit(...). Если вам нужно подтверждение опасной операции, это её инструмент.

Расширения — Tasks для долгих операций с долговечными ссылками, MCP Apps для интерактивных элементов в чате. Они необязательные, договариваются через capabilities и описаны на сайте спецификации.

Наблюдаемость — OpenTelemetry-контекст, который ходит в _meta (traceparent), и раздел OpenTelemetry в документации SDK. Когда сервер работает в трёх экземплярах за прокси, трассировка становится единственным способом понять, где потерялся запрос.

И, как всегда, спецификация: modelcontextprotocol.io/specification/latest. Она меняется, и следующая ревизия наверняка что-то ещё уберёт или добавит. Теперь вы умеете это читать.

Попробуйте сами

10–15 мин на рабочем месте
  1. Возьмите сервер, который вы написали до курса, и прогоните его по чек-листу из урока о состоянии. Запишите, что нужно изменить, чтобы запустить его в трёх экземплярах за балансировщиком.
  2. Добавьте в него прогресс в самый долгий инструмент и замените print/ctx.info на logging. Это два изменения, которые окупаются в любом сервере.

Коротко

  • Обратные возможности в SDK: report_progress() для прогресса, резолверы с Sample()/ListRoots() для запросов к клиенту.
  • Sampling, протокольные логи и roots устарели с 2026-07-28; прогресс — нет.
  • JSON-RPC 2.0, _meta с версией и возможностями в каждом запросе, запросы сервера — через input_required.
  • STDIO для локальных серверов, Streamable HTTP для удалённых; оба переносят одни сообщения.
  • Состояние — в lifespan, requestState, внешнем хранилище и общей шине; личность — из токена или окружения.
  • Дальше: элиситация, расширения Tasks и Apps, OpenTelemetry.

Видеоверсия

Сценарий озвучки · 322 слова, ≈ 2 мин

Курс начинался с вопроса: что происходит под декоратором, который превращает функцию в инструмент. Теперь вы знаете ответ на трёх уровнях. Соберём их вместе.

Первый уровень — что сервер может попросить у клиента. Сгенерировать текст моделью хоста, это sampling. Сообщить о ходе долгой работы, это прогресс. Прислать логи. Узнать рабочие папки, это roots. В SDK всё это два механизма: метод report_progress для прогресса и резолверы с маркерами для всего, что требует ответа клиента. Три из четырёх возможностей устарели с последней ревизии: sampling, логи через протокол и roots. Они работают, но новый код стоит писать иначе — прямой вызов API вместо sampling, обычный логгер вместо протокольных логов, папки из конфигурации вместо roots. Прогресс остаётся.

Второй уровень — провод. Всё это JSON-RPC: запрос, результат, ошибка, уведомление. В новой ревизии рукопожатия нет, версия и возможности клиента приходят в каждом запросе, а сервер больше не задаёт клиенту вопросов напрямую — он возвращает результат «нужен ввод», и клиент повторяет вызов с ответами. Два транспорта переносят одни и те же сообщения. Стандартный ввод-вывод — для локальных серверов: дочерний процесс, строка джейсона на сообщение, вывод только для протокола. Streamable HTTP — для удалённых: один адрес, каждый запрос отдельным пост-запросом, ответ джейсоном или потоком событий. И вы теперь узнаете в логах предыдущее поколение транспорта с сессиями и понимаете, почему его упростили.

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

Куда дальше. Элиситация — способ задать пользователю вопрос из инструмента; она построена на том же механизме, что sampling, но не устарела. Расширения — задачи для долгих операций и интерактивные элементы в чате. И наблюдаемость: трассировка через OpenTelemetry, без которой сервер в трёх экземплярах за прокси не отладить.

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

Отметка хранится только в вашем браузере