createMcpHandler 函数创建 fetch 处理程序来提供你的 MCP 服务器。当你需要运行在普通 Worker(无 Durable Object)中的无状态 MCP 服务器时使用。对于跨请求持久化状态的有状态 MCP 服务器,请改用 McpAgent 类。
它使用 MCP Transport 接口的实现 WorkerTransport,基于 Web 标准构建,符合 streamable-http ↗ 传输规范。
import { createMcpHandler, type CreateMcpHandlerOptions } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
function createMcpHandler(
server: McpServer,
options?: CreateMcpHandlerOptions,
): (request: Request, env: Env, ctx: ExecutionContext) => Promise<Response>;- server — 来自
@modelcontextprotocol/sdk包的McpServer↗ 实例 - options — 可选配置对象(见
CreateMcpHandlerOptions)
签名 (request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response> 的 Worker fetch 处理函数。
创建 MCP 处理程序的配置选项。
interface CreateMcpHandlerOptions extends WorkerTransportOptions {
/**
* The route path that this MCP handler should respond to.
* If specified, the handler will only process requests that match this route.
* @default "/mcp"
*/
route?: string;
/**
* An optional auth context to use for handling MCP requests.
* If not provided, the handler will look for props in the execution context.
*/
authContext?: McpAuthContext;
/**
* An optional transport to use for handling MCP requests.
* If not provided, a WorkerTransport will be created with the provided WorkerTransportOptions.
*/
transport?: WorkerTransport;
// Inherited from WorkerTransportOptions:
sessionIdGenerator?: () => string;
enableJsonResponse?: boolean;
onsessioninitialized?: (sessionId: string) => void;
corsOptions?: CORSOptions;
storage?: MCPStorageApi;
}MCP 处理程序响应的 URL 路径。对其他路径的请求返回 404 响应。
默认值: "/mcp"
const handler = createMcpHandler(server, {
route: "/api/mcp", // Only respond to requests at /api/mcp
});const handler = createMcpHandler(server, {
route: "/api/mcp", // Only respond to requests at /api/mcp
});身份验证上下文对象,通过 getMcpAuthContext() 对 MCP 工具可用。
使用 @cloudflare/workers-oauth-provider 的 OAuthProvider 时,身份验证上下文会自动填充 OAuth 流程中的信息。通常无需手动设置。
自定义 WorkerTransport 实例。未提供时,每个请求都会创建新 transport。
import { createMcpHandler, WorkerTransport } from "agents/mcp";
const transport = new WorkerTransport({
sessionIdGenerator: () => `session-${crypto.randomUUID()}`,
storage: {
get: () => myStorage.get("transport-state"),
set: (state) => myStorage.put("transport-state", state),
},
});
const handler = createMcpHandler(server, { transport });import { createMcpHandler, WorkerTransport } from "agents/mcp";
const transport = new WorkerTransport({
sessionIdGenerator: () => `session-${crypto.randomUUID()}`,
storage: {
get: () => myStorage.get("transport-state"),
set: (state) => myStorage.put("transport-state", state),
},
});
const handler = createMcpHandler(server, { transport });许多 MCP 服务器是无状态的,意味着请求之间不维护任何会话状态。createMcpHandler 是 McpAgent 类的轻量替代,可直接从 Worker 提供 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: "Hello MCP Server",
version: "1.0.0",
});
server.tool(
"hello",
"Returns a greeting message",
{ name: z.string().optional() },
async ({ name }) => {
return {
content: [
{
text: `Hello, ${name ?? "World"}!`,
type: "text",
},
],
};
},
);
return server;
}
export default {
fetch: async (request, env, ctx) => {
// Create 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: "Hello MCP Server",
version: "1.0.0",
});
server.tool(
"hello",
"Returns a greeting message",
{ name: z.string().optional() },
async ({ name }) => {
return {
content: [
{
text: `Hello, ${name ?? "World"}!`,
type: "text",
},
],
};
},
);
return server;
}
export default {
fetch: async (request: Request, env: Env, ctx: ExecutionContext) => {
// Create new server instance per request
const server = createServer();
return createMcpHandler(server)(request, env, ctx);
},
} satisfies ExportedHandler<Env>;对此 MCP 服务器的每个请求都会创建新会话和服务器实例。服务器不在请求之间维护状态。这是实现 MCP 服务器的最简单方式。
对于需要在多个请求之间维护会话状态的有状态 MCP 服务器,你可以在 Agent 中直接使用带有 WorkerTransport 实例的 createMcpHandler 函数。如果你希望使用 elicitation 和 sampling 等高级客户端功能,这很有用。
提供带有持久存储的自定义 WorkerTransport。在 GitHub 上查看完整示例 ↗。
import { Agent } from "agents";
import { createMcpHandler, WorkerTransport } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const STATE_KEY = "mcp-transport-state";
export class MyStatefulMcpAgent extends Agent {
server = new McpServer({
name: "Stateful MCP Server",
version: "1.0.0",
});
transport = new WorkerTransport({
sessionIdGenerator: () => this.name,
storage: {
get: () => {
return this.ctx.storage.get(STATE_KEY);
},
set: (state) => {
this.ctx.storage.put(STATE_KEY, state);
},
},
});
async onRequest(request) {
return createMcpHandler(this.server, {
transport: this.transport,
})(request, this.env, this.ctx);
}
}import { Agent } from "agents";
import {
createMcpHandler,
WorkerTransport,
type TransportState,
} from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const STATE_KEY = "mcp-transport-state";
type State = { counter: number };
export class MyStatefulMcpAgent extends Agent<Env, State> {
server = new McpServer({
name: "Stateful MCP Server",
version: "1.0.0",
});
transport = new WorkerTransport({
sessionIdGenerator: () => this.name,
storage: {
get: () => {
return this.ctx.storage.get<TransportState>(STATE_KEY);
},
set: (state: TransportState) => {
this.ctx.storage.put(STATE_KEY, state);
},
},
});
async onRequest(request: Request) {
return createMcpHandler(this.server, {
transport: this.transport,
})(request, this.env, this.ctx as unknown as ExecutionContext);
}
}此例将 sessionIdGenerator 定义为返回 Agent 名称作为 session ID。要在 Worker 处理程序中路由到正确 Agent,可使用 getAgentByName:
import { getAgentByName } from "agents";
export default {
async fetch(request, env, ctx) {
// 从 header 提取 session ID 或生成新 ID
const sessionId =
request.headers.get("mcp-session-id") ?? crypto.randomUUID();
// 按名称/session ID 获取 Agent 实例
const agent = await getAgentByName(env.MyStatefulMcpAgent, sessionId);
// 将 MCP 请求路由到 agent
return await agent.onRequest(request);
},
};import { getAgentByName } from "agents";
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
// 从 header 提取 session ID 或生成新 ID
const sessionId =
request.headers.get("mcp-session-id") ?? crypto.randomUUID();
// 按名称/session ID 获取 Agent 实例
const agent = await getAgentByName(env.MyStatefulMcpAgent, sessionId);
// 将 MCP 请求路由到 agent
return await agent.onRequest(request);
},
} satisfies ExportedHandler<Env>;持久化 storage 下,transport 保留:
- 重连时的 Session ID
- 协议版本协商 state
- 初始化状态
这使 MCP 客户端可在连接丢失后重连并恢复会话。
MCP SDK 1.26.0 为无状态 MCP server 引入破坏性变更,修复使用共享 server 或 transport 实例时,一个客户端的响应可能泄漏给另一客户端的关键安全漏洞。
| Server 类型 | 受影响? | 所需操作 |
|---|---|---|
使用 Agent/Durable Object 的有状态 server |
否 | 无需更改 |
使用 createMcpHandler 的无状态 server |
是 | 每个请求创建新 McpServer |
| 使用原始 SDK transport 的无状态 server | 是 | 每个请求创建新 McpServer 与 transport |
在全局作用域声明 McpServer 实例的旧模式允许一个客户端的响应泄漏给另一个客户端。这是安全漏洞。新版 SDK 在尝试连接已连接的 server 时会抛出错误,从而防止此问题。
import { createMcpHandler } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
// INCORRECT: Global server instance
const server = new McpServer({
name: "Hello MCP Server",
version: "1.0.0",
});
server.tool("hello", "Returns a greeting", {}, async () => {
return {
content: [{ text: "Hello, World!", type: "text" }],
};
});
export default {
fetch: async (request, env, ctx) => {
// This will fail on second request with MCP SDK 1.26.0+
return createMcpHandler(server)(request, env, ctx);
},
};import { createMcpHandler } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
// INCORRECT: Global server instance
const server = new McpServer({
name: "Hello MCP Server",
version: "1.0.0",
});
server.tool("hello", "Returns a greeting", {}, async () => {
return {
content: [{ text: "Hello, World!", type: "text" }],
};
});
export default {
fetch: async (request: Request, env: Env, ctx: ExecutionContext) => {
// This will fail on second request with MCP SDK 1.26.0+
return createMcpHandler(server)(request, env, ctx);
},
} satisfies ExportedHandler<Env>;import { createMcpHandler } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
// CORRECT: Factory function to create server instance
function createServer() {
const server = new McpServer({
name: "Hello MCP Server",
version: "1.0.0",
});
server.tool("hello", "Returns a greeting", {}, async () => {
return {
content: [{ text: "Hello, World!", type: "text" }],
};
});
return server;
}
export default {
fetch: async (request, env, ctx) => {
// Create 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";
// CORRECT: Factory function to create server instance
function createServer() {
const server = new McpServer({
name: "Hello MCP Server",
version: "1.0.0",
});
server.tool("hello", "Returns a greeting", {}, async () => {
return {
content: [{ text: "Hello, World!", type: "text" }],
};
});
return server;
}
export default {
fetch: async (request: Request, env: Env, ctx: ExecutionContext) => {
// Create new server instance per request
const server = createServer();
return createMcpHandler(server)(request, env, ctx);
},
} satisfies ExportedHandler<Env>;若直接使用原始 SDK transport(非通过 createMcpHandler),每个请求也必须创建新 transport 实例:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
function createServer() {
const server = new McpServer({
name: "Hello MCP Server",
version: "1.0.0",
});
// Register tools...
return server;
}
export default {
async fetch(request) {
// 创建新 transport 与 server
const transport = new WebStandardStreamableHTTPServerTransport();
const server = createServer();
server.connect(transport);
return transport.handleRequest(request);
},
};import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
function createServer() {
const server = new McpServer({
name: "Hello MCP Server",
version: "1.0.0",
});
// Register tools...
return server;
}
export default {
async fetch(request: Request) {
// 创建新 transport 与 server
const transport = new WebStandardStreamableHTTPServerTransport();
const server = createServer();
server.connect(transport);
return transport.handleRequest(request);
},
} satisfies ExportedHandler<Env>;WorkerTransport 类实现 MCP Transport 接口,处理 HTTP 请求/响应周期、Server-Sent Events (SSE) 流式传输、会话管理与 CORS。
class WorkerTransport implements Transport {
sessionId?: string;
started: boolean;
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage, extra?: MessageExtraInfo) => void;
constructor(options?: WorkerTransportOptions);
async handleRequest(
request: Request,
parsedBody?: unknown,
): Promise<Response>;
async send(
message: JSONRPCMessage,
options?: TransportSendOptions,
): Promise<void>;
async start(): Promise<void>;
async close(): Promise<void>;
}interface WorkerTransportOptions {
/**
* Function that generates a unique session ID.
* Called when a new session is initialized.
*/
sessionIdGenerator?: () => string;
/**
* Enable traditional Request/Response mode, disabling streaming.
* When true, responses are returned as JSON instead of SSE streams.
* @default false
*/
enableJsonResponse?: boolean;
/**
* Callback invoked when a session is initialized.
* Receives the generated or restored session ID.
*/
onsessioninitialized?: (sessionId: string) => void;
/**
* CORS configuration for cross-origin requests.
* Configures Access-Control-* headers.
*/
corsOptions?: CORSOptions;
/**
* Optional storage API for persisting transport state.
* Use this to store session state in Durable Object/Agent storage
* so it survives hibernation/restart.
*/
storage?: MCPStorageApi;
}提供自定义 session 标识符。该标识符用于在 MCP Client 中识别会话。
const transport = new WorkerTransport({
sessionIdGenerator: () => `user-${Date.now()}-${Math.random()}`,
});const transport = new WorkerTransport({
sessionIdGenerator: () => `user-${Date.now()}-${Math.random()}`,
});禁用 SSE 流式传输,以标准 JSON 返回响应。
const transport = new WorkerTransport({
enableJsonResponse: true, // 禁用流式传输,返回 JSON 响应
});const transport = new WorkerTransport({
enableJsonResponse: true, // 禁用流式传输,返回 JSON 响应
});会话初始化时触发的回调——无论是创建新会话还是从 storage 恢复。
const transport = new WorkerTransport({
onsessioninitialized: (sessionId) => {
console.log(`MCP session initialized: ${sessionId}`);
},
});const transport = new WorkerTransport({
onsessioninitialized: (sessionId) => {
console.log(`MCP session initialized: ${sessionId}`);
},
});配置跨域请求的 CORS 头。
interface CORSOptions {
origin?: string;
methods?: string;
headers?: string;
maxAge?: number;
exposeHeaders?: string;
}const transport = new WorkerTransport({
corsOptions: {
origin: "https://example.com",
methods: "GET, POST, OPTIONS",
headers: "Content-Type, Authorization",
maxAge: 86400,
},
});const transport = new WorkerTransport({
corsOptions: {
origin: "https://example.com",
methods: "GET, POST, OPTIONS",
headers: "Content-Type, Authorization",
maxAge: 86400,
},
});持久化传输状态,以度过 Durable Object 休眠或重启。
interface MCPStorageApi {
get(): Promise<TransportState | undefined> | TransportState | undefined;
set(state: TransportState): Promise<void> | void;
}
interface TransportState {
sessionId?: string;
initialized: boolean;
protocolVersion?: ProtocolVersion;
}// 在 Agent 或 Durable Object 类方法内:
const transport = new WorkerTransport({
storage: {
get: async () => {
return await this.ctx.storage.get("mcp-state");
},
set: async (state) => {
await this.ctx.storage.put("mcp-state", state);
},
},
});// 在 Agent 或 Durable Object 类方法内:
const transport = new WorkerTransport({
storage: {
get: async () => {
return await this.ctx.storage.get<TransportState>("mcp-state");
},
set: async (state) => {
await this.ctx.storage.put("mcp-state", state);
},
},
});将 createMcpHandler 与 OAuth 身份验证 配合使用时,用户信息通过 getMcpAuthContext() 对 MCP tool 可用。底层使用 AsyncLocalStorage 将请求传递给 tool 处理程序,保持身份验证上下文可用。
interface McpAuthContext {
props: Record<string, unknown>;
}在 MCP tool 处理程序内获取当前身份验证上下文。返回 OAuth 提供商填充的用户信息。若使用 McpAgent,此信息可直接从 this.props 访问。
import { getMcpAuthContext } from "agents/mcp";
function getMcpAuthContext(): McpAuthContext | undefined;import { getMcpAuthContext } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
function createServer() {
const server = new McpServer({ name: "Auth Server", version: "1.0.0" });
server.tool("getProfile", "Get the current user's profile", {}, async () => {
const auth = getMcpAuthContext();
const username = auth?.props?.username;
const email = auth?.props?.email;
return {
content: [
{
type: "text",
text: `User: ${username ?? "anonymous"}, Email: ${email ?? "none"}`,
},
],
};
});
return server;
}import { getMcpAuthContext } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
function createServer() {
const server = new McpServer({ name: "Auth Server", version: "1.0.0" });
server.tool("getProfile", "Get the current user's profile", {}, async () => {
const auth = getMcpAuthContext();
const username = auth?.props?.username as string | undefined;
const email = auth?.props?.email as string | undefined;
return {
content: [
{
type: "text",
text: `User: ${username ?? "anonymous"}, Email: ${email ?? "none"}`,
},
],
};
});
return server;
}createMcpHandler 自动捕获错误并返回代码 -32603(Internal error)的 JSON-RPC 错误响应。
server.tool("riskyOperation", "An operation that might fail", {}, async () => {
if (Math.random() > 0.5) {
throw new Error("Random failure occurred");
}
return {
content: [{ type: "text", text: "Success!" }],
};
});
// 错误自动捕获并返回为:
// {
// "jsonrpc": "2.0",
// "error": {
// "code": -32603,
// "message": "Random failure occurred"
// },
// "id": <request_id>
// }server.tool("riskyOperation", "An operation that might fail", {}, async () => {
if (Math.random() > 0.5) {
throw new Error("Random failure occurred");
}
return {
content: [{ type: "text", text: "Success!" }],
};
});
// 错误自动捕获并返回为:
// {
// "jsonrpc": "2.0",
// "error": {
// "code": -32603,
// "message": "Random failure occurred"
// },
// "id": <request_id>
// }