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 依次处理:

  1. CORS 预检请求(OPTIONS):Cloudflare Workers 部署为公网服务后,浏览器侧的 AI 客户端会发送预检请求,此处统一放行。
  2. 方法校验:MCP 仅使用 POST,其他方法直接拒绝。
  3. 请求体解析: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 字符串,适用于绝大多数场景。

两个辅助函数 jsonrpcjsonrpcError 封装了 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_KEYenv.API_BASE 引用,无需区分来源。


客户端接入

部署完成后,在 Cursor 或其他支持 MCP 的客户端中添加如下配置即可接入:

{
  "mcpServers": {
    "your-server": {
      "url": "https://your-worker.workers.dev/mcp"
    }
  }
}

由于 Cloudflare Workers 本身提供全球边缘节点分发,无需额外配置 CDN 或负载均衡,客户端请求会自动路由至延迟最低的节点。

标签:无

你的评论