building-mcp-server-on-cloudflare

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Building MCP Servers on Cloudflare

在Cloudflare上构建MCP服务器

Creates production-ready Model Context Protocol servers on Cloudflare Workers with tools, authentication, and deployment.
在Cloudflare Workers上创建可用于生产环境的Model Context Protocol(MCP)服务器,包含工具、认证和部署功能。

When to Use

适用场景

  • User wants to build a remote MCP server
  • User needs to expose tools via MCP
  • User asks about MCP authentication or OAuth
  • User wants to deploy MCP to Cloudflare Workers
  • 用户想要构建远程MCP服务器
  • 用户需要通过MCP暴露工具
  • 用户询问MCP认证或OAuth相关问题
  • 用户想要将MCP部署至Cloudflare Workers

Prerequisites

前置条件

  • Cloudflare account with Workers enabled
  • Node.js 18+ and npm/pnpm/yarn
  • Wrangler CLI (
    npm install -g wrangler
    )
  • 已启用Workers的Cloudflare账户
  • Node.js 18+ 及 npm/pnpm/yarn
  • Wrangler CLI(
    npm install -g wrangler

Quick Start

快速开始

Option 1: Public Server (No Auth)

选项1:公开服务器(无认证)

bash
npm create cloudflare@latest -- my-mcp-server \
  --template=cloudflare/ai/demos/remote-mcp-authless
cd my-mcp-server
npm start
Server runs at
http://localhost:8788/mcp
bash
npm create cloudflare@latest -- my-mcp-server \
  --template=cloudflare/ai/demos/remote-mcp-authless
cd my-mcp-server
npm start
服务器运行在
http://localhost:8788/mcp

Option 2: Authenticated Server (OAuth)

选项2:认证服务器(OAuth)

bash
npm create cloudflare@latest -- my-mcp-server \
  --template=cloudflare/ai/demos/remote-mcp-github-oauth
cd my-mcp-server
Requires OAuth app setup. See references/oauth-setup.md.
bash
npm create cloudflare@latest -- my-mcp-server \
  --template=cloudflare/ai/demos/remote-mcp-github-oauth
cd my-mcp-server
需要设置OAuth应用。请查看 references/oauth-setup.md

Core Workflow

核心工作流

Step 1: Define Tools

步骤1:定义工具

Tools are functions MCP clients can call. Define them using
server.tool()
:
typescript
import { McpAgent } from "agents/mcp";
import { z } from "zod";

export class MyMCP extends McpAgent {
  server = new Server({ name: "my-mcp", version: "1.0.0" });

  async init() {
    // Simple tool with parameters
    this.server.tool(
      "add",
      { a: z.number(), b: z.number() },
      async ({ a, b }) => ({
        content: [{ type: "text", text: String(a + b) }],
      })
    );

    // Tool that calls external API
    this.server.tool(
      "get_weather",
      { city: z.string() },
      async ({ city }) => {
        const response = await fetch(`https://api.weather.com/${city}`);
        const data = await response.json();
        return {
          content: [{ type: "text", text: JSON.stringify(data) }],
        };
      }
    );
  }
}
工具是MCP客户端可以调用的函数。使用
server.tool()
定义工具:
typescript
import { McpAgent } from "agents/mcp";
import { z } from "zod";

export class MyMCP extends McpAgent {
  server = new Server({ name: "my-mcp", version: "1.0.0" });

  async init() {
    // 带参数的简单工具
    this.server.tool(
      "add",
      { a: z.number(), b: z.number() },
      async ({ a, b }) => ({
        content: [{ type: "text", text: String(a + b) }],
      })
    );

    // 调用外部API的工具
    this.server.tool(
      "get_weather",
      { city: z.string() },
      async ({ city }) => {
        const response = await fetch(`https://api.weather.com/${city}`);
        const data = await response.json();
        return {
          content: [{ type: "text", text: JSON.stringify(data) }],
        };
      }
    );
  }
}

Step 2: Configure Entry Point

步骤2:配置入口点

Public server (
src/index.ts
):
typescript
import { MyMCP } from "./mcp";

export default {
  fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const url = new URL(request.url);
    if (url.pathname === "/mcp") {
      return MyMCP.serveSSE("/mcp").fetch(request, env, ctx);
    }
    return new Response("MCP Server", { status: 200 });
  },
};

export { MyMCP };
Authenticated server — See references/oauth-setup.md.
公开服务器
src/index.ts
):
typescript
import { MyMCP } from "./mcp";

export default {
  fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const url = new URL(request.url);
    if (url.pathname === "/mcp") {
      return MyMCP.serveSSE("/mcp").fetch(request, env, ctx);
    }
    return new Response("MCP Server", { status: 200 });
  },
};

export { MyMCP };
认证服务器 — 请查看 references/oauth-setup.md

Step 3: Test Locally

步骤3:本地测试

bash
undefined
bash
undefined

Start server

启动服务器

npm start
npm start

In another terminal, test with MCP Inspector

在另一个终端中,使用MCP Inspector进行测试

npx @modelcontextprotocol/inspector@latest
npx @modelcontextprotocol/inspector@latest
undefined
undefined

Step 4: Deploy

步骤4:部署

bash
npx wrangler deploy
Server accessible at
https://[worker-name].[account].workers.dev/mcp
bash
npx wrangler deploy
服务器可通过
https://[worker-name].[account].workers.dev/mcp
访问

Step 5: Connect Clients

步骤5:连接客户端

Claude Desktop (
claude_desktop_config.json
):
json
{
  "mcpServers": {
    "my-server": {
      "command": "npx",
      "args": ["mcp-remote", "https://my-mcp.workers.dev/mcp"]
    }
  }
}
Restart Claude Desktop after updating config.
Claude桌面端
claude_desktop_config.json
):
json
{
  "mcpServers": {
    "my-server": {
      "command": "npx",
      "args": ["mcp-remote", "https://my-mcp.workers.dev/mcp"]
    }
  }
}
更新配置后重启Claude桌面端。

Tool Patterns

工具模式

Return Types

返回类型

typescript
// Text response
return { content: [{ type: "text", text: "result" }] };

// Multiple content items
return {
  content: [
    { type: "text", text: "Here's the data:" },
    { type: "text", text: JSON.stringify(data, null, 2) },
  ],
};
typescript
// 文本响应
return { content: [{ type: "text", text: "result" }] };

// 多个内容项
return {
  content: [
    { type: "text", text: "以下是数据:" },
    { type: "text", text: JSON.stringify(data, null, 2) },
  ],
};

Input Validation with Zod

使用Zod进行输入验证

typescript
this.server.tool(
  "create_user",
  {
    email: z.string().email(),
    name: z.string().min(1).max(100),
    role: z.enum(["admin", "user", "guest"]),
    age: z.number().int().min(0).optional(),
  },
  async (params) => {
    // params are fully typed and validated
  }
);
typescript
this.server.tool(
  "create_user",
  {
    email: z.string().email(),
    name: z.string().min(1).max(100),
    role: z.enum(["admin", "user", "guest"]),
    age: z.number().int().min(0).optional(),
  },
  async (params) => {
    // 参数已完全类型化并验证
  }
);

Accessing Environment/Bindings

访问环境/绑定资源

typescript
export class MyMCP extends McpAgent<Env> {
  async init() {
    this.server.tool("query_db", { sql: z.string() }, async ({ sql }) => {
      // Access D1 binding
      const result = await this.env.DB.prepare(sql).all();
      return { content: [{ type: "text", text: JSON.stringify(result) }] };
    });
  }
}
typescript
export class MyMCP extends McpAgent<Env> {
  async init() {
    this.server.tool("query_db", { sql: z.string() }, async ({ sql }) => {
      // 访问D1绑定资源
      const result = await this.env.DB.prepare(sql).all();
      return { content: [{ type: "text", text: JSON.stringify(result) }] };
    });
  }
}

Authentication

认证

For OAuth-protected servers, see references/oauth-setup.md.
Supported providers:
  • GitHub
  • Google
  • Auth0
  • Stytch
  • WorkOS
  • Any OAuth 2.0 compliant provider
如需搭建受OAuth保护的服务器,请查看 references/oauth-setup.md
支持的提供商:
  • GitHub
  • Google
  • Auth0
  • Stytch
  • WorkOS
  • 任何兼容OAuth 2.0的提供商

Wrangler Configuration

Wrangler配置

Minimal
wrangler.toml
:
toml
name = "my-mcp-server"
main = "src/index.ts"
compatibility_date = "2024-12-01"

[durable_objects]
bindings = [{ name = "MCP", class_name = "MyMCP" }]

[[migrations]]
tag = "v1"
new_classes = ["MyMCP"]
With bindings (D1, KV, etc.):
toml
[[d1_databases]]
binding = "DB"
database_name = "my-db"
database_id = "xxx"

[[kv_namespaces]]
binding = "KV"
id = "xxx"
最小化
wrangler.toml
toml
name = "my-mcp-server"
main = "src/index.ts"
compatibility_date = "2024-12-01"

[durable_objects]
bindings = [{ name = "MCP", class_name = "MyMCP" }]

[[migrations]]
tag = "v1"
new_classes = ["MyMCP"]
带绑定资源(D1、KV等)的配置:
toml
[[d1_databases]]
binding = "DB"
database_name = "my-db"
database_id = "xxx"

[[kv_namespaces]]
binding = "KV"
id = "xxx"

Common Issues

常见问题

"Tool not found" in Client

客户端中出现「工具未找到」

  1. Verify tool name matches exactly (case-sensitive)
  2. Ensure
    init()
    registers tools before connections
  3. Check server logs:
    wrangler tail
  1. 确认工具名称完全匹配(区分大小写)
  2. 确保
    init()
    在建立连接前已注册工具
  3. 查看服务器日志:
    wrangler tail

Connection Fails

连接失败

  1. Confirm endpoint path is
    /mcp
  2. Check CORS if browser-based client
  3. Verify Worker is deployed:
    wrangler deployments list
  1. 确认端点路径为
    /mcp
  2. 若为基于浏览器的客户端,请检查CORS设置
  3. 验证Worker已部署:
    wrangler deployments list

OAuth Redirect Errors

OAuth重定向错误

  1. Callback URL must match OAuth app config exactly
  2. Check
    GITHUB_CLIENT_ID
    and
    GITHUB_CLIENT_SECRET
    are set
  3. For local dev, use
    http://localhost:8788/callback
  1. 回调URL必须与OAuth应用配置完全匹配
  2. 检查
    GITHUB_CLIENT_ID
    GITHUB_CLIENT_SECRET
    是否已设置
  3. 本地开发时,请使用
    http://localhost:8788/callback

References

参考资料

  • references/examples.md — Official templates and production examples
  • references/oauth-setup.md — OAuth provider configuration
  • references/tool-patterns.md — Advanced tool examples
  • references/troubleshooting.md — Error codes and fixes
  • references/examples.md — 官方模板和生产环境示例
  • references/oauth-setup.md — OAuth提供商配置
  • references/tool-patterns.md — 高级工具示例
  • references/troubleshooting.md — 错误代码及修复方案