跳转到内容
搜索文档

传输

最后更新 查看 MarkdownAgent 设置

Model Context Protocol (MCP) 规范定义了客户端与服务器之间通信的两种标准传输机制

  1. stdio — 通过标准输入和标准输出通信,适用于本地 MCP 连接。
  2. Streamable HTTP — 远程 MCP 连接的标准传输方式,于 2025 年 3 月引入。它使用单个 HTTP 端点进行双向消息传递。

使用 Agents SDK 构建的 MCP 服务器通过 createMcpHandler 处理 Streamable HTTP 传输。

实现远程 MCP 传输

使用 createMcpHandler 创建处理 Streamable HTTP 传输的 MCP 服务器。这是新 MCP 服务器的推荐方式。

快速入门

你可以使用「部署到 Cloudflare」按钮创建远程 MCP 服务器。

部署到 Workers

远程 MCP 服务器(无身份验证)

使用 createMcpHandler 创建 MCP 服务器。在 GitHub 上查看完整示例

import { createMcpHandler } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
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) => {
		// Create a new server instance per request
		const server = createServer();
		return createMcpHandler(server)(request, env, ctx);
	},
};
import { createMcpHandler } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
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: Request, env: Env, ctx: ExecutionContext) => {
		// Create a new server instance per request
		const server = createServer();
		return createMcpHandler(server)(request, env, ctx);
	},
} satisfies ExportedHandler<Env>;

带身份验证的 MCP 服务器

如果你的 MCP 服务器使用 Workers OAuth Provider 库实现身份验证与授权,请使用带有 apiRouteapiHandler 属性的 createMcpHandler。在 GitHub 上查看完整示例

export default new OAuthProvider({
	apiRoute: "/mcp",
	apiHandler: {
		fetch: (request, env, ctx) => {
			// Create a new server instance per request
			const server = createServer();
			return createMcpHandler(server)(request, env, ctx);
		},
	},
	// ... other OAuth configuration
});
export default new OAuthProvider({
	apiRoute: "/mcp",
	apiHandler: {
		fetch: (request: Request, env: Env, ctx: ExecutionContext) => {
			// Create a new server instance per request
			const server = createServer();
			return createMcpHandler(server)(request, env, ctx);
		},
	},
	// ... other OAuth configuration
});

有状态 MCP 服务器

如果你的 MCP 服务器需要在请求之间保持状态,请在 Agent 类中使用带有 WorkerTransportcreateMcpHandler。这样可以在 Durable Object 存储中持久化会话状态,并使用 elicitationsampling 等高级 MCP 功能。

实现细节请参阅有状态 MCP 服务器

Streamable HTTP 流可恢复:配置 EventStore,使客户端可以使用 Last-Event-ID 标头重新连接并重放遗漏的事件,在边缘空闲流 watchdog 下保持进行中的工具调用存活。DurableObjectEventStoreagents/mcp 导出,供有状态 WorkerTransport 调用方使用。请参阅 McpAgent:流可恢复性

RPC 传输

RPC 传输适用于 MCP 服务器与 agent 均运行在 Cloudflare 上的内部应用——它们甚至可以运行在同一 Worker 中。它通过 Cloudflare 的 RPC 绑定直接发送 JSON-RPC 消息,无需经过公网。

  • 更快 — 无网络开销,Durable Objects 之间直接函数调用
  • 更简单 — 无 HTTP 端点,无连接管理
  • 仅限内部 — 适合同一 Worker 内 agent 调用 MCP 服务器

RPC 传输不支持身份验证。需要 OAuth 的外部连接请使用 Streamable HTTP。

通过 RPC 将 Agent 连接到 McpAgent

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 服务器

AgentonStart() 中调用 addMcpServer() 并传入 Durable Object 绑定:

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 匹配(详情请参阅 MCP Client API)。因此在 onStart() 中调用是安全的。

3. 配置 Durable Object 绑定

wrangler.jsonc 中为两个 Durable Object 定义绑定:

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

4. 设置 Worker fetch 处理程序

将请求路由到你的 Chat agent:

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>;

向 MCP 服务器传递 props

由于 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 从你的 McpAgent 泛型提取 Props 类型)、持久性(存储在 Durable Object 存储中),并在任何工具调用之前立即可用。

配置 RPC 传输服务器超时

RPC 传输具有可配置的工具响应等待超时。默认情况下,服务器等待工具处理程序响应 60 秒。你可以通过在 McpAgent 中覆盖 getRpcTransportOptions() 来自定义:

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 上的内部 agent 最快、设置最简单 无身份验证,仅 Durable Object 绑定
SSE 旧版兼容 向后兼容 已弃用,请使用 Streamable HTTP

从 McpAgent 迁移

如果你已有使用 McpAgent 类的 MCP 服务器:

  • 不使用状态?McpAgent 类替换为 @modelcontextprotocol/sdkMcpServer,并在 Worker fetch 处理程序中使用 createMcpHandler(server)
  • 使用状态?Agent 类中使用带有 WorkerTransportcreateMcpHandler。详情请参阅有状态 MCP 服务器
  • 需要 SSE 支持? 继续使用 McpAgentserveSSE() 以兼容旧版客户端。请参阅 McpAgent API 参考

使用 MCP 客户端测试

你可以使用支持远程连接的 MCP 客户端测试 MCP 服务器,或使用 mcp-remote——一个适配器,使仅支持本地连接的 MCP 客户端也能与远程 MCP 服务器配合使用。

按照本指南将远程 MCP 服务器连接到 Claude Desktop、Cursor、Windsurf 及其他 MCP 客户端。

这篇文档对您有帮助吗?