使用 Cloudflare Workers 将任意 API 封装为 MCP Server
Model Context Protocol(MCP)是 Anthropic 提出的一套开放协议,旨在标准化 AI 模型与外部工具、数据源之间的交互方式。其设计思路类似于 LSP(Language Server Protocol)对编辑器生态的统一——通过定义统一的通信契约,使任何符合规范的客户端(如 Claude、Cursor)都能无缝调用任何符合规范的服务端工具。
本文将介绍如何借助 Cloudflare Workers 的边缘计算能力,编写一个轻量、可复用的 MCP Server 框架模板,从而将任意第三方 REST API 快速包装为可供 AI 调用的工具服务。
MCP 协议概述
MCP 采用 JSON-RPC 2.0 作为底层传输格式。一次典型的工具调用会经历如下生命周期:
sequenceDiagram
participant Client as AI Client (e.g. Cursor)
participant Server as MCP Server (CF Worker)
participant API as Third-party API
Client->>Server: initialize
Server-->>Client: protocolVersion, capabilities, serverInfo
Client->>Server: tools/list
Server-->>Client: [{ name, description, inputSchema }, ...]
Client->>Server: tools/call { name, arguments }
Server->>API: HTTP Request
API-->>Server: Response
Server-->>Client: { content: [{ type: "text", text: "..." }] }
协议层面只有三个核心方法需要实现:
| 方法 | 用途 |
|---|---|
initialize |
握手,交换协议版本与能力声明 |
tools/list |
返回当前 Server 暴露的工具列表及其 Schema |
tools/call |
执行指定工具,传入参数,返回结果 |
这种极简的接口设计使得 MCP Server 本质上就是一个处理三种 POST 请求的 HTTP 服务,非常适合部署在 Cloudflare Workers 这类无状态边缘运行时上。
框架结构总览
整个模板分为三层,职责清晰分离:
- 业务层(需填写):TOOLS 定义 + callTool 实现
- 协议层(通常不需修改):handleMCP → JSON-RPC 路由
- 入口层:fetch handler → 路径分发
所以说,开发者只需关注业务层,协议层与入口层作为固定基础设施复用即可。
工具定义:TOOLS 数组
定义哪些工具可用
const TOOLS = [
{
name: "tool_name",
description: "What this tool does.",
inputSchema: {
type: "object",
properties: {
param1: {
type: "string",
description: "What param1 is.",
},
param2: {
type: "number",
description: "What param2 is.",
},
},
required: ["param1"],
},
},
];
TOOLS 是一个符合 JSON Schema(Draft 7)规范的对象数组,每个元素描述一个可供 AI 调用的工具能力。三个字段各有侧重:
name:工具的程序化标识符,建议使用snake_case,AI 将通过此名称发起调用。description:这是写给语言模型而非人类的说明,应当准确描述工具的用途、适用场景以及参数的语义含义。description 的质量直接影响模型选择工具的准确率。inputSchema:遵循 JSON Schema 格式,定义参数的类型与约束。required数组中列出的参数,模型在调用前必须提供。
工具执行:callTool 函数
具体工具执行实现逻辑
async function callTool(name, args, env) {
if (name === "tool_name") {
const { param1, param2 = 10 } = args;
if (!param1) throw new Error("param1 is required");
const res = await fetch(`${API_BASE}/some-endpoint?q=${param1}`, {
headers: {
Authorization: `Bearer ${env.API_KEY}`,
"Content-Type": "application/json",
},
});
if (!res.ok) throw new Error(`API error: ${res.status}`);
const data = await res.json();
return {
count: data.total,
results: data.items.slice(0, param2),
};
}
throw new Error(`Unknown tool: ${name}`);
}
callTool 是框架的核心扩展点,接收三个参数:
name:工具名,用于路由到对应的处理逻辑。args:由 AI 客户端传入的参数对象,结构与inputSchema对应。env:Cloudflare Workers 的环境绑定对象,用于安全访问 Secrets 与环境变量,避免硬编码敏感信息。
函数体内按 name 进行分支处理,完成参数解构、API 请求、响应解析,最终返回一个可序列化的对象。若工具名未匹配,则抛出异常,协议层会将其捕获并以 isError: true 的形式返回给客户端。
关于错误处理的设计选择:框架有意将工具级别的错误(callTool 内部抛出)与协议级别的错误(无法解析请求体、未知方法等)区分对待。前者返回 HTTP 200 并在响应体中标记 isError: true,后者才返回对应的 HTTP 错误状态码,这符合 MCP 规范的要求。
协议层:handleMCP 函数
MCP对外协议的处理
async function handleMCP(request, env) {
if (request.method === "OPTIONS") {
return new Response(null, {
status: 204,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
},
});
}
if (request.method !== "POST") {
return new Response("Method Not Allowed", { status: 405 });
}
let body;
try {
body = await request.json();
} catch {
return mcpResponse(jsonrpcError(null, -32700, "Parse error"), 400);
}
const { id, method, params } = body;
// ... 方法路由
}
handleMCP 依次处理:
- CORS 预检请求(OPTIONS):Cloudflare Workers 部署为公网服务后,浏览器侧的 AI 客户端会发送预检请求,此处统一放行。
- 方法校验:MCP 仅使用 POST,其他方法直接拒绝。
- 请求体解析:JSON 解析失败时返回 JSON-RPC 标准错误码
-32700(Parse error)。
方法路由段如下:
if (method === "initialize") {
return mcpResponse(
jsonrpc(id, {
protocolVersion: "2024-11-05",
capabilities: { tools: {} },
serverInfo: {
name: "my-mcp-server",
version: "1.0.0",
},
})
);
}
if (method === "tools/list") {
return mcpResponse(jsonrpc(id, { tools: TOOLS }));
}
if (method === "tools/call") {
const { name, arguments: args = {} } = params ?? {};
try {
const output = await callTool(name, args, env);
return mcpResponse(
jsonrpc(id, {
content: [{ type: "text", text: JSON.stringify(output, null, 2) }],
})
);
} catch (err) {
return mcpResponse(
jsonrpc(id, {
content: [{ type: "text", text: `Error: ${err.message}` }],
isError: true,
})
);
}
}
initialize阶段声明协议版本与服务器元信息,capabilities.tools: {}表明本服务器具备工具能力。tools/list直接返回TOOLS数组,无需额外处理。tools/call调用callTool并将结果序列化为content数组格式。MCP 规范允许content包含多个块(文本、图像等),当前实现统一以type: "text"返回 JSON 字符串,适用于绝大多数场景。
两个辅助函数 jsonrpc 与 jsonrpcError 封装了 JSON-RPC 2.0 的响应格式,确保每个响应都携带正确的 jsonrpc: "2.0" 版本标识:
function jsonrpc(id, result) {
return { jsonrpc: "2.0", id, result };
}
function jsonrpcError(id, code, message) {
return { jsonrpc: "2.0", id, error: { code, message } };
}
入口与路由
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname === "/mcp") {
return handleMCP(request, env);
}
return new Response("Not Found", { status: 404 });
},
};
Workers 的标准入口形式。所有 MCP 流量统一收敛至 /mcp 路径,其余路径预留给健康检查、原始 API 代理等附加功能。
环境变量与密钥管理
框架通过 env 对象访问所有运行时配置,绝不在代码中硬编码密钥。推荐的两种配置方式:
方式一:wrangler.toml 中的明文变量(适用于非敏感配置)
[vars]
API_BASE = "https://api.example.com"
方式二:Cloudflare Dashboard Secrets(适用于 API Key 等敏感信息)
npx wrangler secret put API_KEY
代码中统一通过 env.API_KEY、env.API_BASE 引用,无需区分来源。
客户端接入
部署完成后,在 Cursor 或其他支持 MCP 的客户端中添加如下配置即可接入:
{
"mcpServers": {
"your-server": {
"url": "https://your-worker.workers.dev/mcp"
}
}
}
由于 Cloudflare Workers 本身提供全球边缘节点分发,无需额外配置 CDN 或负载均衡,客户端请求会自动路由至延迟最低的节点。
- 本文标题:使用 Cloudflare Workers 将任意 API 封装为 MCP Server
- 本文作者:uygnil
- 本文链接:https://blog.zhoulingyu.net/index.php/archives/28/
- 版权声明:本文采用 CC BY 4.0 协议进行许可
标签:无