Сэмплирование и корневые каталоги
Машинный перевод
Эта страница переведена с английской документации автоматически, и основной версией остаётся английская страница. Если что-то читается неправильно, на странице Переводы объясняется, как об этом сообщить.
Обработчик может попросить у подключённого клиента ещё две вещи: завершение (completion) от собственной модели клиента — это сэмплирование (sampling), и рабочие папки клиента — это корневые каталоги (roots).
И то и другое по-прежнему работает, на каждой версии протокола, которую поддерживает SDK. Но прежде чем строить на них архитектуру, прочтите предупреждение:
Объявлено устаревшим в спецификации 2026-07-28
Сэмплирование и корневые каталоги объявлены устаревшими начиная с 2026-07-28 (SEP-2577). Они остаются полностью работоспособными и сохраняются в спецификации как минимум двенадцать месяцев, прежде чем их можно будет удалить, но новые реализации не должны на них опираться. Предлагаемые пути миграции: вместо сэмплирования интегрируйтесь напрямую с API вашего поставщика LLM, а вместо корневых каталогов передавайте каталоги через параметры инструментов, URI ресурсов или конфигурацию сервера. Общий для SDK список — на странице Устаревшие возможности.
Сэмплирование: одолжить модель клиента
Резолвер возвращает Sample(...), и инструмент получает завершение — через тот же механизм зависимостей, который выполняет Elicit на странице Зависимости:
from typing import Annotated
from mcp.server import MCPServer
from mcp.server.mcpserver import Resolve, Sample
from mcp.types import CreateMessageResult, SamplingMessage, TextContent
mcp = MCPServer("Bookshop")
def draft_blurb(title: str) -> Sample:
prompt = f"Write a one-sentence blurb for the book {title!r}."
return Sample(
[SamplingMessage(role="user", content=TextContent(type="text", text=prompt))],
max_tokens=60,
)
@mcp.tool()
async def blurb(title: str, draft: Annotated[CreateMessageResult, Resolve(draft_blurb)]) -> str:
"""Draft a blurb for a book."""
return draft.content.text if draft.content.type == "text" else "No blurb."
Sample(messages, max_tokens=...)повторяет параметрыsampling/createMessage. Внедряемое значение —CreateMessageResultклиента; передайтеtoolsилиtool_choice, и вместо него придётCreateMessageResultWithTools.- Клиент должен был объявить возможность
sampling(sampling.tools, если передаётеtoolsилиtool_choice). Если он этого не сделал, вызов завершается ошибкой протокола-32021, а не отправкой запроса, который клиент не сможет обработать. Сессия до 2026 года без обратного канала (back-channel) завершается своей обычной ошибкой об отсутствии обратного канала, поскольку отправлять запрос попросту некуда. - На
2026-07-28запрос доставляется внутри многораундового потока (Многораундовые запросы); на2025-11-25это самостоятельный запрос к клиенту. Код в обоих случаях один и тот же, но помните о правиле многораундовых запросов: запрос должен выглядеть одинаково во всех раундах повтора, поэтому стройте его только из аргументов инструмента и других стабильных данных. - Не трогайте
include_context: значения, отличные от"none", сами объявлены устаревшими (SEP-2596) и требуют возможности, которую почти ни один клиент не объявляет.
Корневые каталоги: куда это положить?
Корневые каталоги — это папки, с которыми, по словам клиента, серверу разрешено работать. Это справочная подсказка, а не механизм контроля доступа. Резолвер возвращает ListRoots():
from typing import Annotated
from mcp.server import MCPServer
from mcp.server.mcpserver import ListRoots, Resolve
from mcp.types import ListRootsResult
mcp = MCPServer("Bookshop")
def workspace_roots() -> ListRoots:
return ListRoots()
@mcp.tool()
async def catalog_folder(roots: Annotated[ListRootsResult, Resolve(workspace_roots)]) -> str:
"""Pick the folder the catalog export should go to."""
if not roots.roots:
return "No workspace folders shared."
return str(roots.roots[0].uri)
- Внедряемый
ListRootsResultсодержит список объектовRoot: URI видаfile://и необязательное отображаемое имя. - Проверка та же, что и для сэмплирования: без объявленной возможности
rootsвызов завершается ошибкой-32021, а не отправкой запроса.
На другой стороне соединения клиент отвечает на оба запроса уже имеющимися у него колбэками: sampling_callback и list_roots_callback, описанными на странице Колбэки клиента.
На подключениях поколения 2025
ctx.session.create_message(...) и ctx.session.list_roots() по-прежнему существуют для кода, который управляет сессией напрямую. Они работают только там, где есть обратный канал (подключения поколения 2025, не stateless), а их вызов выдаёт предупреждение об устаревании. Маркеры резолверов, показанные выше, — поддерживаемая форма: они выбирают способ доставки по согласованной версии и не выдают предупреждений.
Итоги
- Возвращайте
Sample(...)илиListRoots()из резолвера; инструмент получаетCreateMessageResultилиListRootsResultкак любую другую зависимость. - Клиент должен объявить соответствующую возможность, иначе вызов завершится ошибкой
-32021вместо отправки запроса. - Обе возможности объявлены устаревшими в
2026-07-28: пока полностью работоспособны, но для новых проектов не годятся. Предпочитайте API поставщика сэмплированию, а явные параметры — корневым каталогам.
Как сообщать, насколько продвинулся медленный инструмент: Ход выполнения.