INTEGRITY Документация

Транспорт

Спецификация Model Context Protocol (MCP) определяет два стандартных транспортные механизмы ↗ для взаимодействия между клиентами и серверами:

  1. stdio : Обмен данными через стандартный ввод и стандартный вывод, предназначенный для локальных подключений MCP.
  2. Streamable HTTP : стандартный способ транспорта для удалённых подключений MCP, введено ↗ в марте 2025 года. Он использует единую HTTP конечную точку для двусторонней передачи сообщений.

MCP-серверы, созданные с помощью Agents SDK используйте createMcpHandler чтобы обрабатывать транспорт Streamable HTTP.

Реализация удалённого транспорта MCP

Используйте createMcpHandler чтобы создать MCP-сервер, который обрабатывает транспорт Streamable HTTP. Это рекомендуемый подход для новых MCP-серверов.

Быстрое начало работы

Вы можете создать удалённый MCP-сервер с помощью кнопки «Deploy to Cloudflare».

Развертывание в Workers

Удалённый MCP-сервер (без аутентификации)

Создайте MCP-сервер с помощью createMcpHandler. Посмотрите полный пример на GitHub ↗.

import { createMcpHandler } from "agents/mcp/server";
import { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";

function createServer() {
	const server = new McpServer({
		name: "My MCP Server",
		version: "1.0.0",
	});

	server.registerTool(
		"hello",
		{
			description: "Returns a greeting message",
			inputSchema: { name: z.string().optional() },
		},
		async ({ name }) => {
			return {
				content: [{ text: `Hello, ${name ?? "World"}!`, type: "text" }],
			};
		},
	);

	return server;
}

export default {
	fetch(request, env, ctx) {
		return createMcpHandler(createServer)(request, env, ctx);
	},
};
import { createMcpHandler } from "agents/mcp/server";
import { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";

function createServer() {
	const server = new McpServer({
		name: "My MCP Server",
		version: "1.0.0",
	});

	server.registerTool(
		"hello",
		{
			description: "Returns a greeting message",
			inputSchema: { name: z.string().optional() },
		},
		async ({ name }) => {
			return {
				content: [{ text: `Hello, ${name ?? "World"}!`, type: "text" }],
			};
		},
	);

	return server;
}

export default {
	fetch(request, env, ctx) {
		return createMcpHandler(createServer)(request, env, ctx);
	},
} satisfies ExportedHandler;

MCP-сервер с аутентификацией

Если ваш сервер MCP реализует аутентификацию и авторизацию с помощью Workers OAuth Provider ↗ библиотеку, используйте createMcpHandler на apiRoute и apiHandler свойства. Просмотрите полный пример на GitHub ↗.

export default new OAuthProvider({
	apiRoute: "/mcp",
	apiHandler: createMcpHandler(createServer),
	// ... other OAuth configuration
});
export default new OAuthProvider({
	apiRoute: "/mcp",
	apiHandler: createMcpHandler(createServer),
	// ... other OAuth configuration
});

Серверы, которым нужны сессии протокола

У MCP нет сессии на уровне протокола на пути без сохранения состояния. Приложения могут хранить устойчивые бизнес-данные за отдельной границей хранилища.

При миграции устаревших сессий существующие серверы могут временно сохранять createLegacyMcpHandler с WorkerTransport или McpAgent route рядом с новым stateless route. Эти API поддерживают transport state, event replay, pushed elicitation, sampling и запросы roots. McpAgent устарел и не получает новых функций.

Добавьте маршрут без сохранения состояния перед переносом клиентов и сохраняйте обе линии, пока не завершатся существующие сессии. См. Мигрировать на MCP SDK v2 для поэтапной миграции. См. McpAgent: Возобновляемость потока для существующего поведения потока.

RPC-транспорт

RPC-транспорт предназначен для внутренних приложений, где ваш MCP-сервер и агент работают на Cloudflare: они могут даже работать в одном Worker. Он отправляет сообщения JSON-RPC напрямую через RPC-привязки не выходя в публичный интернет.

RPC-транспорт не поддерживает аутентификацию. Для внешних подключений, требующих OAuth, используйте Streamable HTTP.

Подключите Agent к существующему McpAgent через RPC

1. Определите свой MCP-сервер

Создайте свой McpAgent с инструментами, которые вы хотите предоставить:

import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

export class MyMCP extends McpAgent {
	server = new McpServer({ name: "MyMCP", version: "1.0.0" });
	initialState = { counter: 0 };

	async init() {
		this.server.tool(
			"add",
			"Add to the counter",
			{ amount: z.number() },
			async ({ amount }) => {
				this.setState({ counter: this.state.counter + amount });
				return {
					content: [
						{
							type: "text",
							text: `Added ${amount}, total is now ${this.state.counter}`,
						},
					],
				};
			},
		);
	}
}
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

type State = { counter: number };

export class MyMCP extends McpAgent<Env, State> {
	server = new McpServer({ name: "MyMCP", version: "1.0.0" });
	initialState: State = { counter: 0 };

	async init() {
		this.server.tool(
			"add",
			"Add to the counter",
			{ amount: z.number() },
			async ({ amount }) => {
				this.setState({ counter: this.state.counter + amount });
				return {
					content: [
						{
							type: "text",
							text: `Added ${amount}, total is now ${this.state.counter}`,
						},
					],
				};
			},
		);
	}
}

2. Подключите свой Agent к MCP-серверу

В вашем Agent, вызовите addMcpServer() с привязкой Durable Object в onStart():

import { AIChatAgent } from "@cloudflare/ai-chat";

export class Chat extends AIChatAgent {
	async onStart() {
		// Pass the DO namespace binding directly
		await this.addMcpServer("my-mcp", this.env.MyMCP);
	}

	async onChatMessage(onFinish) {
		const allTools = this.mcp.getAITools();

		const result = streamText({
			model,
			tools: allTools,
			// ...
		});

		return createUIMessageStreamResponse({ stream: result });
	}
}
import { AIChatAgent } from "@cloudflare/ai-chat";

export class Chat extends AIChatAgent<Env> {
	async onStart(): Promise<void> {
		// Pass the DO namespace binding directly
		await this.addMcpServer("my-mcp", this.env.MyMCP);
	}

	async onChatMessage(onFinish) {
		const allTools = this.mcp.getAITools();

		const result = streamText({
			model,
			tools: allTools,
			// ...
		});

		return createUIMessageStreamResponse({ stream: result });
	}
}

RPC-соединения автоматически восстанавливаются после гибернации Durable Object, как и HTTP-соединения. Имя привязки и props сохраняются в хранилище, поэтому соединение можно восстановить без дополнительного кода.

Для транспорта RPC, если addMcpServer вызывается с именем, для которого уже есть активное соединение, возвращается существующее соединение вместо создания дубликата. Для транспорта HTTP дедупликация выполняется как по имени сервера, так и по URL (см. API MCP-клиента для подробностей). Это делает безопасным вызов в onStart().

3. Настройте привязки Durable Object

В вашем wrangler.jsonc, определите привязки для обоих Durable Objects:

{
	"durable_objects": {
		"bindings": [
			{ "name": "Chat", "class_name": "Chat" },
			{ "name": "MyMCP", "class_name": "MyMCP" },
		],
	},
	"migrations": [
		{
			"new_sqlite_classes": ["MyMCP", "Chat"],
			"tag": "v1",
		},
	],
}

4. Настройте обработчик fetch для Worker

Маршрутизируйте запросы к своему Чат-агенту:

import { routeAgentRequest } from "agents";

export default {
	async fetch(request, env, ctx) {
		const url = new URL(request.url);

		// Optionally expose the MCP server via HTTP as well
		if (url.pathname.startsWith("/mcp")) {
			return MyMCP.serve("/mcp").fetch(request, env, ctx);
		}

		const response = await routeAgentRequest(request, env);
		if (response) return response;

		return new Response("Not found", { status: 404 });
	},
};
import { routeAgentRequest } from "agents";

export default {
	async fetch(request: Request, env: Env, ctx: ExecutionContext) {
		const url = new URL(request.url);

		// Optionally expose the MCP server via HTTP as well
		if (url.pathname.startsWith("/mcp")) {
			return MyMCP.serve("/mcp").fetch(request, env, ctx);
		}

		const response = await routeAgentRequest(request, env);
		if (response) return response;

		return new Response("Not found", { status: 404 });
	},
} satisfies ExportedHandler<Env>;

Передача props MCP-серверу

Поскольку у RPC-транспорта нет потока OAuth, вы можете передавать контекст пользователя напрямую через props:

await this.addMcpServer("my-mcp", this.env.MyMCP, {
	props: { userId: "user-123", role: "admin" },
});
await this.addMcpServer("my-mcp", this.env.MyMCP, {
	props: { userId: "user-123", role: "admin" },
});

Ваш McpAgent затем могут обращаться к этим props:

export class MyMCP extends McpAgent {
	async init() {
		this.server.tool("whoami", "Get current user info", {}, async () => {
			const userId = this.props?.userId || "anonymous";
			const role = this.props?.role || "guest";

			return {
				content: [{ type: "text", text: `User ID: ${userId}, Role: ${role}` }],
			};
		});
	}
}
export class MyMCP extends McpAgent<
	Env,
	State,
	{ userId?: string; role?: string }
> {
	async init() {
		this.server.tool("whoami", "Get current user info", {}, async () => {
			const userId = this.props?.userId || "anonymous";
			const role = this.props?.role || "guest";

			return {
				content: [{ type: "text", text: `User ID: ${userId}, Role: ${role}` }],
			};
		});
	}
}

Props типобезопасны (TypeScript извлекает тип Props из вашего McpAgent обобщённый тип), постоянные (хранятся в хранилище Durable Object) и доступны сразу же, ещё до каких-либо вызовов инструментов.

Настройка тайм-аута транспортного сервера RPC

Транспорт RPC имеет настраиваемый тайм-аут ожидания ответов инструментов. По умолчанию сервер ждёт 60 секунд для ответа обработчика инструмента. Это можно настроить, переопределив getRpcTransportOptions() в вашем McpAgent:

export class MyMCP extends McpAgent {
	server = new McpServer({ name: "MyMCP", version: "1.0.0" });

	getRpcTransportOptions() {
		return { timeout: 120000 }; // 2 minutes
	}

	async init() {
		this.server.tool(
			"long-running-task",
			"A tool that takes a while",
			{ input: z.string() },
			async ({ input }) => {
				await longRunningOperation(input);
				return {
					content: [{ type: "text", text: "Task completed" }],
				};
			},
		);
	}
}
export class MyMCP extends McpAgent<Env, State> {
	server = new McpServer({ name: "MyMCP", version: "1.0.0" });

	protected getRpcTransportOptions() {
		return { timeout: 120000 }; // 2 minutes
	}

	async init() {
		this.server.tool(
			"long-running-task",
			"A tool that takes a while",
			{ input: z.string() },
			async ({ input }) => {
				await longRunningOperation(input);
				return {
					content: [{ type: "text", text: "Task completed" }],
				};
			},
		);
	}
}

Выбор транспорта

Транспорт Когда использовать Плюсы Недостатки
Streamable HTTP Внешние серверы MCP, продакшен-приложения Стандартный протокол, безопасный, поддерживает аутентификацию Небольшие накладные расходы на сеть
RPC Внутренние агенты на Cloudflare Самая быстрая и простая настройка Без аутентификации, только привязки Durable Object
SSE Совместимость с более старыми клиентами Обратно совместимый Устарело, используйте Streamable HTTP

Мигрировать с McpAgent

Если эндпойнт не использует устаревшие функции с сохранением состояния, переходите сразу на фабрику сервера без сохранения состояния из @modelcontextprotocol/server и передайте его в createMcpHandler.

Если это зависит от состояния сессии MCP, RPC, отправляемых от сервера к клиенту запросов, автономных потоков или replay, сначала спроектируйте эквиваленты без сохранения состояния. Например, перенесите бизнес-состояние в явное хранилище приложения и замените отправляемые запросы на ввод elicitation без сохранения состояния. Обслуживайте путь без сохранения состояния и устаревший путь одновременно, пока клиенты не перейдут, а существующие сессии не завершатся.

См. Мигрировать на MCP SDK v2 для сопоставления функций, маршрутизации между двумя поколениями и шагов развёртывания.

Тестирование с MCP-клиентами

Вы можете протестировать свой MCP-сервер с помощью MCP-клиента, поддерживающего удалённые подключения, либо использовать mcp-remote ↗, адаптер, который позволяет MCP клиентам, поддерживающим только локальные подключения, работать с удалёнными MCP серверами.

Следуйте это руководство для инструкций о том, как подключить ваш удалённый MCP-сервер к Claude Desktop, Cursor, Windsurf и другим MCP-клиентам.