← Создание агентов на Cloudflare / agents / model-context-protocol / guides
Мигрировать на MCP SDK v2
Это руководство охватывает MCP SDK v2 ↗ обновление в Agents SDK v0.20.0. Оно объясняет, как перенести серверы на @modelcontextprotocol/server, используйте временный устаревший канал только тогда, когда этого требуют функции с состоянием сессии, и обновляйте MCP-клиенты.
Выберите путь сервера
Используйте следующую таблицу, чтобы выбрать путь миграции:
| Текущий сервер | Путь миграции |
|---|---|
| Сервер SDK v1 без зависимостей от сессии | Перенесите определение сервера в фабрику SDK v2 и передайте фабрику в createMcpHandler. |
| Сервер SDK v1 с зависимостями от сессии | Добавьте SDK v2 route. Оставьте createLegacyMcpHandler только на временном устаревшем пути, пока эти зависимости заменяются. |
McpAgent без устаревших функций с сохранением состояния |
Мигрировать напрямую на фабрику SDK v2 и createMcpHandler. |
McpAgent который использует устаревшие функции с сохранением состояния |
Спроектируйте эквиваленты без сохранения состояния, обслуживайте путь без сохранения состояния и устаревший путь одновременно, а затем опустошите устаревший путь. |
Agents SDK v0.20.0 помечает следующие API как устаревшие:
- Передача сервера SDK v1 в
createMcpHandler. Перенесите сервер на фабрику SDK v2. ИспользуйтеcreateLegacyMcpHandlerтолько как временный мост для поведения с поддержкой сессий. Эта перегрузка будет удалена в следующей крупной версии. McpAgent. Он устарел и не получает новых функций. Перенесите код при первой возможности. Версия удаления не объявлена.MCPClientManager.callTool(params, resultSchema, options)иwithX402Client(...).callTool(confirm, params, resultSchema, options). ИспользуйтеcallTool(params, options)илиcallTool(confirm, params, options)вместо этого. Версия удаления не объявлена.
experimental_createMcpHandler уже был устаревшим и по-прежнему запланирован к удалению в следующей крупной версии. Перенесите его сервер SDK v1 на фабрику SDK v2. Используйте createLegacyMcpHandler только на временном пути с поддержкой сессий во время миграции.
Установка пакетов MCP
Устанавливайте только те поколения пакета MCP, которые импортирует ваше приложение. Версию v2 сохраняйте точно.
Для сервера без сохранения состояния:
npm i agents @modelcontextprotocol/[email protected] zodДля временного устаревшего пути:
npm i agents @modelcontextprotocol/[email protected] zodДля Agent, который подключается к серверам MCP:
npm i agents @modelcontextprotocol/[email protected]Следуйте указаниям вашего менеджера пакетов о peer-зависимостях. Обновляйте конкретные версии MCP вместе с релизом Agents, который их поддерживает.
Определите, нужен ли временный устаревший канал
Не оставляйте SDK v1 только потому, что сервер сейчас его импортирует. Переходите сразу на фабрику SDK v2, если конечная точка не зависит ни от одной из этих функций, зависящих от сессии:
- Протокольные сессии или предоставленный
WorkerTransport - Хранение транспорта или повтор событий
- Отдельные GET-потоки
- Отправленные запросы elicitation, sampling или roots
- Удаление Session с помощью HTTP
DELETE
Если эндпойнт использует одну из этих функций, разверните сначала маршрут без сохранения состояния. Оставляйте маршрут SDK v1 только до тех пор, пока не замените зависимость от сессий. Направляйте запросы с помощью isLegacyRequest() как показано в Совместный запуск каналов без сохранения состояния и устаревших каналов.
Для эндпойнта SDK v1, который не использует McpAgent, используйте createLegacyMcpHandler только на этой временной устаревшей ветке. Удалите её после того, как клиенты мигрируют, а существующие сессии завершатся.
Перенос сервера без сохранения состояния на SDK v2
Стейтлес createMcpHandler принимает фабрику. Фабрика возвращает McpServer или Server от @modelcontextprotocol/server.
-
Следуйте указаниям upstream Руководство по миграции TypeScript SDK v2 ↗ для изменений регистрации сервера.
-
Импортируйте сервер из
@modelcontextprotocol/server. -
Перенесите создание и регистрацию сервера в фабрику.
-
Сохраните экспорт объекта Worker по умолчанию. Внутри его
fetch()метод, передайте фабрику вcreateMcpHandlerи вызывайте возвращённый вызываемый объект как раньше. Используйтеfetch(request, options?)метод только для низкоуровневой интеграции запросов. -
Не экспортируйте по умолчанию вызываемый объект, возвращаемый обработчиком Agents. Wrangler интерпретирует экспорты функций по умолчанию как
WorkerEntrypointклассы. -
Удалите параметры транспорта и сессии SDK v1.
-
Проверьте эндпойнт с помощью stateless- и legacy-клиентов.
import { McpServer } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";
import { z } from "zod";
function createServer() {
const server = new McpServer({
name: "example-server",
version: "1.0.0",
});
server.registerTool(
"hello",
{
description: "Return a greeting",
inputSchema: { name: z.string().optional() },
},
async ({ name }) => ({
content: [{ type: "text", text: `Hello, ${name ?? "World"}!` }],
}),
);
return server;
}
export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer)(request, env, ctx);
},
};import { McpServer } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";
import { z } from "zod";
function createServer() {
const server = new McpServer({
name: "example-server",
version: "1.0.0",
});
server.registerTool(
"hello",
{
description: "Return a greeting",
inputSchema: { name: z.string().optional() },
},
async ({ name }) => ({
content: [{ type: "text", text: `Hello, ${name ?? "World"}!` }],
}),
);
return server;
}
export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer)(request, env, ctx);
},
} satisfies ExportedHandler;Точка входа Worker остаётся объектом. Меняется только вызов обработчика:
// SDK v1: pass a fresh constructed server.
return createMcpHandler(createServer())(request, env, ctx);
// SDK v2: pass the factory itself.
return createMcpHandler(createServer)(request, env, ctx);Не упрощайте это до export default createMcpHandler(createServer). Обработчик Agents можно вызывать для композиции внутри другого обработчика, но Wrangler рассматривает любой экспорт функции по умолчанию как WorkerEntrypoint в качестве класса.
Обработчик SDK v2 создаёт отдельный сервер для каждого запроса MCP. Параллельные запросы Worker никогда не используют общий экземпляр подключённого сервера.
Параметры обработчика для серверов без сохранения состояния
Обёртка Agents добавляет route, corsOptions, allowedHostnames, allowedOriginHostnames, а также authContext. Она также передаёт поддерживаемые параметры SDK v2 в upstream-обработчик.
К типичным параметрам относятся:
| Опция | Поведение |
|---|---|
route |
Задаёт точный путь запроса. Значение по умолчанию: /mcp. |
legacy |
По умолчанию используется устаревший режим совместимости. Задайте "reject" для эндпойнта, работающего только без сохранения состояния. |
responseMode |
Выбирает автоматическую, JSON или SSE обработку ответов. |
allowedHostnames |
Ограничивает заголовки Host конкретными именами хостов. |
allowedOriginHostnames |
Ограничивает браузерные Origins или принимает "*" когда доверенный middleware проверяет их. |
corsOptions |
Управляет заголовками ответа CORS. Установите false чтобы удалить их. |
onerror |
Сообщает об ошибках обработчика, не изменяя ответ. |
maxSubscriptions, keepAliveMs |
Настройте subscriptions/listen доставка. |
Стейтлес-обработчик отклоняет следующие опции SDK v1:
transportstoragesessionIdGeneratoronsessioninitializedиonsessionclosedenableJsonResponseeventStoreallowedHostsиallowedOriginsenableDnsRebindingProtectionretryInterval
Используйте responseMode: "json" вместо enableJsonResponse: true. Режим JSON отбрасывает уведомления, отправленные до финального результата.
Проверка Origin в Workers
Обёртка Workers проверяет каждое присутствующее значение Origin. Она отклоняет некорректные, непрозрачные и не HTTP значения Origin с 403.
Список разрешённых источников по умолчанию включает источники класса localhost и конечной точки workers.dev hostname. Конкретный corsOptions.origin также автоматически добавляет своё имя хоста. Обработчик применяет соответствующие проверки Host к localhost и workers.dev конечные точки.
Для пользовательского домена с wildcard-CORS явно настройте ограничения и Host, и Origin:
export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer, {
allowedHostnames: ["mcp.example.com"],
allowedOriginHostnames: ["app.example.com"],
corsOptions: { origin: "https://app.example.com" },
})(request, env, ctx);
},
};export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer, {
allowedHostnames: ["mcp.example.com"],
allowedOriginHostnames: ["app.example.com"],
corsOptions: { origin: "https://app.example.com" },
})(request, env, ctx);
},
} satisfies ExportedHandler;Задайте allowedOriginHostnames: "*" только если доверенный middleware проверяет Origin перед вызовом обработчика. Это значение отключает проверку Origin в обработчике. HTTP-серверы MCP обязаны проверять Origin браузера.
Заголовки CORS не аутентифицируют запрос. Защитите эндпойнт с помощью OAuth или другого уровня аутентификации.
Handler не выводит доверенный allowlist значений Host из request.url. Если ваше развёртывание принимает произвольные значения Host, проверяйте их перед вызовом обработчика. Для локальных серверов за пределами Cloudflare Workers следуйте рекомендациям upstream SDK по проверке Host и Origin.
Разберитесь с совместимостью с устаревшими клиентами
По умолчанию legacy: "stateless" параметр поддерживает обычные устаревшие инструменты, ресурсы и промпты. Этот вариант использует транспорт SDK v2 на основе веб-стандартов. Он не импортирует WorkerTransport и не является полноценным транспортом с поддержкой сессий.
Fallback имеет следующие ограничения:
- Каждый POST получает новый сервер и транспорт.
- HTTP GET и DELETE возвращают
405. - Идентификатор сессии MCP и состояние сессии протокола не сохраняются.
- Отправленные запросы sampling, elicitation и roots немедленно завершаются ошибкой.
- Автономные потоки, воспроизведение событий и удаление сессии недоступны.
- Опубликованные экспериментальные задачи не поддерживаются через этот fallback.
При миграции этих функций направляйте затронутых устаревших клиентов на временный createLegacyMcpHandler или McpAgent дорожка.
Мигрировать McpAgent сервер
Во время миграции, McpAgent остаётся сервером SDK v1. Не меняйте импорт сервера внутри устаревшего route на @modelcontextprotocol/server.
Мигрировать напрямую без устаревших функций с сохранением состояния
Если сервер не зависит от состояния сессии MCP, RPC, отправляемых от сервера к клиенту запросов, автономных потоков или воспроизведения событий, перенесите его инструменты в фабрику SDK v2 и обслуживайте его с помощью createMcpHandler.
Спланируйте эквиваленты без сохранения состояния для функций с сохранением состояния
Если сервер использует устаревшие функции с сохранением состояния, оставьте существующий McpAgent route, пока вы проектируете и развёртываете stateless-эквиваленты:
| Функция с сохранением состояния на устаревшем пути | Спроектируйте путь без сохранения состояния |
|---|---|
| Данные приложения с ключом по сессии MCP | Храните данные за явной границей приложения, например в Durable Object, D1, KV или R2. Обращайтесь к ним через аутентифицированный идентификатор, выданный сервером, а не через ID сессии MCP. |
| Состояние многошагового взаимодействия | Верните защищённые по целостности requestState с input_required. Привяжите его к аутентифицированному пользователю, исходному методу и параметрам, а также сроку действия. |
| Отправленные запросы elicitation, sampling или roots | Верните inputRequired(...). Клиент выполняет встроенные запросы и повторяет исходную операцию. |
| Отдельный поток изменений списка | Публикация изменений через subscriptions/listen. Клиенты заново открывают подписку, если её поток завершается. |
| Воспроизведение Session или восстановление транспорта | Делайте каждый запрос без сохранения состояния независимо восстанавливаемым. Сохраняйте бизнес-прогресс в хранилище приложения, а не в транспорте MCP. |
Agent-to-McpAgent RPC |
Замените зависимость от сессии протокола явной границей RPC или HTTP на уровне приложения, а затем предоставьте инструменты MCP без сохранения состояния отдельно. |
Не удаляйте устаревший route сразу после появления реализации без сохранения состояния. Обслуживайте оба пути, пока клиенты не перейдут, а существующие сессии не завершатся.
Совместный запуск каналов без сохранения состояния и устаревших каналов
Один URL может маршрутизировать запросы без сохранения состояния на SDK v2, а устаревшие запросы направлять на существующий сервер с поддержкой сессий.
import { isLegacyRequest } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";
const stateless = createMcpHandler(createStatelessServer, {
route: "/mcp",
legacy: "reject",
});
const legacy = MyMcpAgent.serve("/mcp");
export default {
async fetch(request, env, ctx) {
if (await isLegacyRequest(request)) {
return legacy.fetch(request, env, ctx);
}
return stateless(request, env, ctx);
},
};import { isLegacyRequest } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";
const stateless = createMcpHandler(createStatelessServer, {
route: "/mcp",
legacy: "reject",
});
const legacy = MyMcpAgent.serve("/mcp");
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
if (await isLegacyRequest(request)) {
return legacy.fetch(request, env, ctx);
}
return stateless(request, env, ctx);
},
} satisfies ExportedHandler<Env>;Оставьте legacy: "reject" для обработчика без сохранения состояния. Иначе его устаревший режим совместимости перехватывает запросы раньше, чем их получает маршрут с сохранением сессии.
Разверните оба маршрута, прежде чем переводить на них клиентов. Отслеживайте устаревший канал и дайте существующим сессиям завершиться естественным образом. Удаляйте устаревший маршрут и его привязку Durable Object, предназначенную только для протокола, только после того, как от них перестанут зависеть все клиенты. Настройку миграции Durable Object выполняйте отдельным этапом развёртывания.
Обновите клиенты MCP
Agents теперь использует @modelcontextprotocol/client внутренне. Существующие addMcpServer вызовы автоматически согласовывают поколение протокола.
Серверы на маршруте без сохранения состояния используют server/discover. Agents откатывается к initialize для устаревших серверов Streamable HTTP, SSE и RPC.
Клиентский API включает следующие изменения:
callTool(params, options)это предпочтительная сигнатура.callTool(params, resultSchema, options)остаётся доступным, но считается устаревшим.- Типы MCP-клиента теперь берутся из
@modelcontextprotocol/client. - Обязательные stateless HTTP-заголовки обрабатываются SDK.
- Изменения списков передаются через stateless-подписки или устаревшие уведомления, в зависимости от согласованного lane.
Настройка elicitation для запросов без сохранения состояния
Инструменты, промпты и ресурсы в пути без сохранения состояния могут возвращать input_required через запросы с несколькими раундами обмена (MRTR). SDK вызывает настроенный обработчик elicitation и повторяет исходную операцию. Ваш исходный callTool, getPrompt, или readResource promise остаётся в состоянии ожидания.
Каждая повторная попытка содержит ответы только на непосредственно предшествующий раунд ввода, а не на все более ранние ответы. Клиент также повторно отправляет последний непрозрачный requestState. Запечатывайте доверенные промежуточные значения, необходимые для последующих раундов, в защищённые от изменения requestState; не ожидайте inputResponses накапливаться между раундами.
См. пример elicitation без сохранения состояния ↗ для двухраундового потока вызова инструмента.
export class MyAgent extends Agent {
onStart() {
this.mcp.configureElicitationHandlers({
form: async (request, serverId, signal) => {
return collectInput(request, serverId, signal);
},
url: async (request, serverId, signal) => {
return openExternalFlow(request, serverId, signal);
},
});
}
}export class MyAgent extends Agent<Env> {
onStart() {
this.mcp.configureElicitationHandlers({
form: async (request, serverId, signal) => {
return collectInput(request, serverId, signal);
},
url: async (request, serverId, signal) => {
return openExternalFlow(request, serverId, signal);
},
});
}
}Обработчики и выполняющиеся вызовы остаются в памяти. Гибернация, перезапуск isolate, потеря транспорта или восстановление соединения приводят к отклонению активного интерактивного вызова. Повторите операцию после восстановления соединения.
Считайте обрабатываемые вручную requestState как недоверенные входные данные. Привяжите их к аутентифицированному пользователю и операции, защитите их целостность и задайте короткий срок действия.
Обновите собственных провайдеров OAuth
Пользовательский AgentMcpOAuthProvider должен реализовывать v2 OAuthClientProvider контракт:
- Импортируйте типы OAuth из
@modelcontextprotocol/client. - Сохраните
StoredOAuthClientInformationиStoredOAuthTokens. - Сохраняйте отметку издателя SDK на учётных данных.
- Сохраните
OAuthDiscoveryStateпри перенаправлениях браузера. - Принимайте
"discovery"вinvalidateCredentials. - Храните учётные данные раздельно, если издатели авторизации различаются.
SDK v2 по умолчанию проверяет издателей метаданных OAuth. Доверенный устаревший сервер с заведомо несовпадающими метаданными может использовать skipIssuerMetadataValidation: true. Это ослабляет защиту от OAuth mix-up и не должно использоваться как запасной вариант по умолчанию.
Обзор различий протоколов
Модель MCP без сохранения состояния меняет транспорт и жизненный цикл:
| Область | Предыдущее поведение | Новое поведение |
|---|---|---|
| Запуск | initialize handshake |
Без handshake. server/discover необязателен для клиентов |
| Метаданные запроса | Согласование в рамках подключения | Версия, возможности клиента и метаданные идентичности при каждом запросе |
| Сеансы | Необязательно Mcp-Session-Id |
Нет сессии протокола |
| Запросы сервера на ввод | Сервер отправляет запросы JSON-RPC | Сервер возвращает input_required. Клиент повторяет исходную операцию |
| Уведомления об изменениях | Отдельный GET-поток и уведомления об изменении списка | subscriptions/listen POST с ответом SSE |
| Восстановление потока | Last-Event-ID может возобновлять настроенные потоки |
Потоки прослушивания переоткрываются после сбоя. Здесь отсутствует Last-Event-ID воспроизведении. |
Пользовательские транспорты, прокси и шлюзы должны сохранять заголовки черновика запроса:
MCP-Protocol-VersionMcp-MethodMcp-Nameдля операций с инструментами, промптами и ресурсами- Объявлено
Mcp-Param-*заголовки инструмента
Точная версия SDK, используемая Agents, реализует редакцию MCP 2026-07-28. Она делает clientInfo необязательный и помещает идентификатор сервера в результат _meta. Используйте высокоуровневые API SDK и обновляйте пакеты MCP вместе с релизом Agents, поддерживающим соответствующую версию протокола. Необработанные результаты без сохранения состояния должны включать resultType.
Черновик спецификации помечает Roots, Sampling, Logging, старый транспорт HTTP+SSE и Dynamic Client Registration как устаревшие. На время переходного периода эти типы остаются доступны для обратной совместимости со старыми версиями. Опубликованные экспериментальные методы задач становятся io.modelcontextprotocol/tasks расширение. Agents SDK v0.20.0 не добавляет это расширение.
Совместимость интеграции
В этом релизе следующие интеграции сохраняют формат вывода сервера SDK v1:
- Текущий Code Mode
codeMcpServerиopenApiMcpServerвспомогательные функции - Серверная сторона
withX402вспомогательная функция - Существующие примеры OpenAI Apps, которые импортируют SDK v1
McpServer
Пока эти интеграции не начнут выдавать серверы SDK v2, изолируйте их вывод за временным createLegacyMcpHandler route. Коннектор Code Mode MCP и withX402Client принимают клиента любого поколения.
Спланируйте развёртывание
-
Классифицируйте каждый эндпойнт по его зависимостям от сессии.
-
Зафиксируйте версии MCP SDK, которые требует релиз Agents.
-
Перенесите каждое определение сервера, которое может быть без сохранения состояния, в фабрику SDK v2.
-
Добавьте обработчики без сохранения состояния рядом с конечными точками, которым по-прежнему нужен временный устаревший путь.
-
Маршрутизируйте запросы без сохранения состояния и устаревшие запросы с помощью
isLegacyRequest(). -
Тестируйте stateless- и legacy-клиентов по отдельности.
-
Проверьте обязательные HTTP-заголовки на каждом прокси и шлюзе.
-
Протестируйте OAuth после чистого входа и после гибернации Durable Object.
-
Протестируйте отмену, несколько раундов ввода и потерю транспорта.
-
Проверяйте допустимые Origins и отклоняйте недопустимые Origins с
403. -
Удаляйте устаревшие маршруты только после того, как завершатся существующие сессии.
Сохранённые ID HTTP-сессий из версий Agents до v0.20.0 не содержат согласованную версию протокола. Обновлённый клиент отбрасывает такие ID и переподключается заново, вместо того чтобы отправлять небезопасный запрос на возобновление. Незавершённая работа, привязанная к старой удалённой сессии, не возобновляется.
Подробности об API см. в createMcpHandler и McpClient.