mcpField
C
cloudflare-mcp-server

cloudflare-mcp-server

github.com/ovachiever云与 DevOps5650 次安装48 周前更新
代码仓库

关于 cloudflare-mcp-server

cloudflare-mcp-server 是面向开发者的技能,帮助在 Cloudflare Workers 上构建 TypeScript MCP 服务。它提供传输方式、身份验证、状态管理和 Cloudflare 服务集成的实现模式与部署指南。

主要功能

  1. 01TypeScript MCP 服务实现模式
  2. 02SSE 与 Streamable HTTP 指南
  3. 03OAuth 和 bearer token 身份验证
  4. 04Durable Objects 会话状态
  5. 05Cloudflare 服务集成示例
  6. 06部署与故障排查指南

适用场景

  1. 01在 Workers 上启动远程 MCP 服务
  2. 02添加 OAuth 或 bearer token 身份验证
  3. 03构建带会话状态的服务
  4. 04排查传输路径与部署错误

MCP 相关

该技能讲解如何在 Cloudflare Workers 上构建和部署远程 MCP 服务,涵盖工具、HTTP 传输、身份验证,以及将 MCP 客户端连接到已部署服务。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ovachiever/droid-tings --skill cloudflare-mcp-server

安装后在 Claude Code 中输入/cloudflare-mcp-server确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
.claude-plugin/
plugin.json
references/
authentication.md
common-issues.md
debugging-guide.md
http-transport-fundamentals.md
oauth-providers.md
official-examples.md
transport-comparison.md
transport.md
templates/
basic-mcp-server.ts
claude_desktop_config.json
mcp-bearer-auth.ts
mcp-http-fundamentals.ts
mcp-oauth-proxy.ts
mcp-stateful-do.ts
mcp-with-d1.ts
mcp-with-workers-ai.ts
package.json
wrangler-basic.jsonc
wrangler-oauth.jsonc

详细介绍

Cloudflare MCP 服务技能

使用 TypeScript 在 Cloudflare Workers 上构建和部署 Model Context Protocol(MCP)服务。


这是什么技能?

此技能将教你如何在 Cloudflare 上构建 远程 MCP 服务——截至 2025 年,Cloudflare 是唯一官方支持远程 MCP 的平台。

在以下情况下使用此技能:

  • 使用 TypeScript(@modelcontextprotocol/sdk)构建 MCP 服务
  • 将远程 MCP 服务部署到 Cloudflare Workers
  • 实现 OAuth 身份验证(GitHub、Google、Azure、自定义)
  • 使用 Durable Objects 创建有状态的 MCP 服务
  • 通过 WebSocket 休眠优化成本
  • 同时支持 SSE 和 Streamable HTTP 传输
  • 避免 22 个以上常见的 MCP + Cloudflare 错误(尤其是 URL 路径不匹配!)

你将学到:

  1. HTTP 传输基础知识(URL 路径配置、路由)
  2. 传输方式选择(SSE 与 Streamable HTTP)
  3. McpAgent 类模式和工具定义
  4. OAuth 集成(全部 5 种身份验证模式)
  5. Cloudflare 服务集成(Workers AI、D1、Vectorize 等)
  6. 用于管理每个会话状态的 Durable Objects
  7. WebSocket 休眠 API
  8. 完整的部署工作流

🚀 Cloudflare 官方模板(从这里开始!)

使用此技能的模板之前,请先了解 Cloudflare 通过 npm create 提供了官方入门模板。

推荐的起点

对于大多数项目,建议从 Cloudflare 官方的无身份验证模板开始:

npm create cloudflare@latest -- my-mcp-server \
  --template=cloudflare/ai/demos/remote-mcp-authless

cd my-mcp-server
npm install
npm run dev

你将获得:

  • ✅ 可运行的最简 MCP 服务(约 50 行)
  • ✅ 支持双传输方式(SSE + Streamable HTTP)
  • ✅ 预配置的 wrangler.jsonc
  • ✅ 可立即部署

然后使用此技能中的模式进行自定义,以避免 22 个以上常见错误!


所有可用的 Cloudflare 模板

Cloudflare 维护着 14 个以上的官方 MCP 模板。可将它们作为起点:

基础模板
模板命令用途适用场景
--template=cloudflare/ai/demos/remote-mcp-authless黄金标准入门模板——无需身份验证,提供简单工具新项目、学习、公共 API
--template=cloudflare/ai/demos/remote-mcp-github-oauthGitHub OAuth + Workers AI开发者工具、GitHub 集成
--template=cloudflare/ai/demos/remote-mcp-google-oauthGoogle OAuthGoogle Workspace 集成
高级身份验证模板
模板命令身份验证方式使用场景
--template=cloudflare/ai/demos/remote-mcp-auth0Auth0企业级 SSO
--template=cloudflare/ai/demos/remote-mcp-authkitWorkOS AuthKitB2B SaaS 应用
--template=cloudflare/ai/demos/remote-mcp-logtoLogto开源身份验证
--template=cloudflare/ai/demos/remote-mcp-cf-accessCloudflare Access公司内部工具
--template=cloudflare/ai/demos/mcp-server-bearer-authBearer 令牌自定义身份验证系统
集成示例
模板命令展示内容Cloudflare 服务
--template=cloudflare/ai/demos/remote-mcp-server-autoragRAG(检索增强生成)Workers AI + Vectorize
--template=cloudflare/ai/demos/python-workers-mcpPython MCP 服务Python Workers

何时使用此技能的模板

在以下情况下使用此技能的模板:

  • 学习 URL 路径的工作原理(使用 mcp-http-fundamentals.ts)
  • 需要全面预防错误(所有模板都包含警告)
  • 希望通过详细注释了解每项决策的原因
  • 构建复杂集成(Workers AI、D1、Bearer 身份验证)

相比 Cloudflare 的模板,此技能的模板更有助于学习(注释更多、防御性模式更完善、错误处理更全面)。

Cloudflare 的模板启动速度更快(精简、可用于生产环境)。

最佳做法:从 Cloudflare 的模板开始,然后参考此技能以避免错误!


生产级 MCP 服务(请参考!)

Cloudflare 维护着 15 个生产级 MCP 服务,展示了真实场景中的集成模式:

值得参考的服务:

  • workers-bindings - D1、KV、R2、AI、Durable Objects 的用法
  • browser-rendering - 网页抓取和截图工具
  • autorag - Vectorize RAG 模式
  • ai-gateway - Workers AI Gateway 分析
  • docs - Cloudflare 文档搜索

代码仓库:https://github.com/cloudflare/mcp-server-cloudflare

为什么要参考这些服务? 它们展示了生产级模式,包括:

  • 错误处理
  • 速率限制
  • 缓存策略
  • 真实 API 集成
  • 安全最佳实践

🎯 快速入门工作流(分步指南)

按照此工作流构建下一个 MCP 服务,避免错误并快速交付。


步骤 1:选择起始模板

决策树:

What are you building?

├─ 🆓 Public/dev server (no auth needed)
│  └─> Use: remote-mcp-authless ⭐ RECOMMENDED FOR MOST PROJECTS
│
├─ 🔐 GitHub integration
│  └─> Use: remote-mcp-github-oauth (includes Workers AI example)
│
├─ 🔐 Google Workspace integration
│  └─> Use: remote-mcp-google-oauth
│
├─ 🏢 Enterprise SSO (Auth0, Okta, etc.)
│  └─> Use: remote-mcp-auth0 or remote-mcp-authkit
│
├─ 🔑 Custom auth system / API keys
│  └─> Start with authless, then add bearer auth (see Step 3)
│
└─ 🏠 Internal company tool
   └─> Use: remote-mcp-cf-access (Cloudflare Zero Trust)

不确定? 从 remote-mcp-authless 开始——之后可以再添加身份验证!


步骤 2:基于模板创建
# Replace [TEMPLATE] with your choice from Step 1
npm create cloudflare@latest -- my-mcp-server \
  --template=cloudflare/ai/demos/[TEMPLATE]

# Example: authless template (most common)
npm create cloudflare@latest -- my-mcp-server \
  --template=cloudflare/ai/demos/remote-mcp-authless

# Navigate and install
cd my-mcp-server
npm install

# Start dev server
npm run dev

你的 MCP 服务现已运行于:http://localhost:8788/sse


步骤 3:应用此技能中的模式进行自定义

现在,通过复制此技能中的模式来添加功能:

需要 Workers AI(图像/文本生成)?
# Copy our Workers AI template
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-with-workers-ai.ts src/my-ai-tools.ts

# Add AI binding to wrangler.jsonc:
# { "ai": { "binding": "AI" } }

你将获得的工具:generate_image、generate_text、list_ai_models


需要数据库(D1)?
# Copy our D1 template
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-with-d1.ts src/my-db-tools.ts

# Create D1 database:
npx wrangler d1 create my-database

# Add binding to wrangler.jsonc

你将获得的工具:create_user、get_user、list_users、update_user、delete_user、search_users


需要 Bearer 令牌身份验证?
# Copy our bearer auth template
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-bearer-auth.ts src/index.ts

# Add token validation (KV, external API, or static)

你将获得:Authorization 请求头中间件、令牌验证、经过身份验证的工具


步骤 4:部署到 Cloudflare
# Login (first time only)
npx wrangler login

# Deploy to production
npx wrangler deploy

输出会显示你的部署 URL:

✨ Deployment complete!
https://my-mcp-server.YOUR_ACCOUNT.workers.dev

⚠️ 重要:记下此 URL——步骤 5 中会用到!


步骤 5:测试并配置客户端
A. 使用 curl 测试(可避免 80% 的错误!)
# Test the exact URL you'll use in client config
curl https://my-mcp-server.YOUR_ACCOUNT.workers.dev/sse

预期响应:

{
  "name": "My MCP Server",
  "version": "1.0.0",
  "transports": ["/sse", "/mcp"]
}

遇到 404? → 客户端 URL 会出错!请参阅下方的“HTTP 传输基础知识”。


B. 更新 Claude Desktop 配置

Linux/Mac:~/.config/claude/claude_desktop_config.json Windows:%APPDATA%/Claude/claude_desktop_config.json

对于无需身份验证的服务:

{
  "mcpServers": {
    "my-mcp": {
      "url": "https://my-mcp-server.YOUR_ACCOUNT.workers.dev/sse"
    }
  }
}

⚠️ 重要:URL 必须与步骤 5A 中测试成功的 curl 命令中的 URL 一致!

使用 OAuth 时:

{
  "mcpServers": {
    "my-mcp": {
      "url": "https://my-mcp-server.YOUR_ACCOUNT.workers.dev/sse",
      "auth": {
        "type": "oauth",
        "authorizationUrl": "https://my-mcp-server.YOUR_ACCOUNT.workers.dev/authorize",
        "tokenUrl": "https://my-mcp-server.YOUR_ACCOUNT.workers.dev/token"
      }
    }
  }
}

三个 URL 必须使用同一个域名!


C. 重启 Claude Desktop

配置仅在启动时加载:

  1. 完全退出 Claude Desktop
  2. 重新打开
  3. 在工具列表中查找你的 MCP 服务

步骤 6:验证是否正常运行

测试工具调用:

  1. 打开 Claude Desktop
  2. 输入:“列出可用的 MCP 工具”
  3. 你的服务工具应该会显示
  4. 尝试调用一个工具:“使用 add 工具计算 5 + 3”

如果工具没有显示 → 请参阅 references/ 中的“调试指南”


部署后检查清单

宣布成功之前,请确认:

  • curl https://worker.dev/sse 返回服务信息(而非 404)
  • 客户端配置中的 URL 与 curl URL 完全一致
  • 更新配置后已重启 Claude Desktop
  • Claude Desktop 中可见工具
  • 工具调用测试成功
  • (仅 OAuth)三个 URL 使用同一个域名
  • npx wrangler tail 日志中没有错误

全部确认? 🎉 你的 MCP 服务已上线!


后续常见步骤

想要添加更多功能?

  1. 更多工具 - 添加到 MCP Agent 类的 init() 方法中
  2. Workers AI - 复制 mcp-with-workers-ai.ts 中的模式
  3. 数据库 - 复制 mcp-with-d1.ts 中的模式
  4. 身份验证 - 复制 mcp-bearer-auth.ts 或 mcp-oauth-proxy.ts 中的模式
  5. Durable Objects 状态 - 复制 mcp-stateful-do.ts 中的模式

想要避免错误?

  • 阅读下方的“HTTP 传输基础知识”部分(避免 URL 路径错误)
  • 阅读“22 个已知错误”部分(避免所有常见错误)
  • 遇到问题时查看 references/debugging-guide.md

TL;DR——5 分钟工作流
# 1. Create from template (30 seconds)
npm create cloudflare@latest -- my-mcp \
  --template=cloudflare/ai/demos/remote-mcp-authless
cd my-mcp && npm install

# 2. Customize (optional, 2 minutes)
# Copy patterns from this skill if needed

# 3. Deploy (30 seconds)
npx wrangler deploy

# 4. Test (30 seconds)
curl https://YOUR-WORKER.workers.dev/sse

# 5. Configure client (1 minute)
# Update claude_desktop_config.json with URL from step 4
# Restart Claude Desktop

# 6. Verify (30 seconds)
# Test a tool call in Claude Desktop

总耗时:从零开始,到 MCP 服务正常运行,只需约 5 分钟!🚀


⚠️ 重要:HTTP 传输基础知识

MCP 服务无法连接的首要原因是 URL 路径配置错误。

URL 路径配置详解

在特定路径上提供 MCP 服务时,客户端 URL 必须完全匹配。

示例 1:在 /sse 上提供服务

// src/index.ts
export default {
  fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const { pathname } = new URL(request.url);

    if (pathname.startsWith("/sse")) {
      return MyMCP.serveSSE("/sse").fetch(request, env, ctx);  // ← Base path is "/sse"
    }

    return new Response("Not Found", { status: 404 });
  }
};

客户端配置必须包含 /sse:

{
  "mcpServers": {
    "my-mcp": {
      "url": "https://my-mcp.workers.dev/sse"  // ✅ Correct
    }
  }
}

❌ 错误的客户端配置:

"url": "https://my-mcp.workers.dev"      // Missing /sse → 404
"url": "https://my-mcp.workers.dev/"     // Missing /sse → 404
"url": "http://localhost:8788"           // Wrong after deploy

示例 2:在 /(根路径)上提供服务

export default {
  fetch(request: Request, env: Env, ctx: ExecutionContext) {
    return MyMCP.serveSSE("/").fetch(request, env, ctx);  // ← Base path is "/"
  }
};

客户端配置:

{
  "mcpServers": {
    "my-mcp": {
      "url": "https://my-mcp.workers.dev"  // ✅ Correct (no /sse)
    }
  }
}

基础路径如何影响工具 URL

调用 serveSSE("/sse") 时,MCP 工具的服务地址为:

https://my-mcp.workers.dev/sse/tools/list
https://my-mcp.workers.dev/sse/tools/call
https://my-mcp.workers.dev/sse/resources/list

调用 serveSSE("/") 时,MCP 工具的服务地址为:

https://my-mcp.workers.dev/tools/list
https://my-mcp.workers.dev/tools/call
https://my-mcp.workers.dev/resources/list

基础路径会自动添加到所有 MCP 端点之前。


请求/响应生命周期
1. Client connects to: https://my-mcp.workers.dev/sse
                                ↓
2. Worker receives request: { url: "https://my-mcp.workers.dev/sse", ... }
                                ↓
3. Your fetch handler: const { pathname } = new URL(request.url)
                                ↓
4. pathname === "/sse" → Check passes
                                ↓
5. MyMCP.serveSSE("/sse").fetch() → MCP server handles request
                                ↓
6. Tool calls routed to: /sse/tools/call

如果客户端连接到 https://my-mcp.workers.dev(缺少 /sse):

pathname === "/" → Check fails → 404 Not Found

测试 URL 配置

步骤 1:部署 MCP 服务

npx wrangler deploy
# Output: Deployed to https://my-mcp.YOUR_ACCOUNT.workers.dev

步骤 2:使用 curl 测试基础路径

# If serving at /sse, test this URL:
curl https://my-mcp.YOUR_ACCOUNT.workers.dev/sse

# Should return MCP server info (not 404)

步骤 3:使用你测试过的准确 URL 更新客户端配置

{
  "mcpServers": {
    "my-mcp": {
      "url": "https://my-mcp.YOUR_ACCOUNT.workers.dev/sse"  // Match curl URL
    }
  }
}

步骤 4:重启 Claude Desktop


部署后检查清单

部署后,请确认:

  • curl https://worker.dev/sse 返回 MCP 服务信息(而不是 404)
  • 客户端配置中的 URL 与部署的 URL 完全一致
  • URL 中没有拼写错误(常见错误:将 workers.dev 写成 workes.dev)
  • 部署的 Workers 使用 https://(而不是 http://)
  • 如果使用 OAuth,重定向 URI 也已更新

传输方式选择指南

MCP 支持两种传输方式:SSE(旧版)和 Streamable HTTP(2025 年标准)。

SSE(服务器发送事件)

适用场景:兼容广泛的客户端(2024 年客户端)、旧版支持

提供服务:

MyMCP.serveSSE("/sse").fetch(request, env, ctx)

客户端配置:

{
  "url": "https://my-mcp.workers.dev/sse"
}

优点:

  • ✅ 所有 MCP 客户端(2024 年及以后)均支持
  • ✅ 易于调试(纯 HTTP)
  • ✅ 可与 MCP Inspector 配合使用

缺点:

  • ❌ 效率低于 HTTP 流式传输
  • ❌ 将于 2025 年弃用

Streamable HTTP

适用场景:现代客户端(2025 年及以后)、性能更佳

提供服务:

MyMCP.serve("/mcp").fetch(request, env, ctx)

客户端配置:

{
  "url": "https://my-mcp.workers.dev/mcp"
}

优点:

  • ✅ 效率高于 SSE
  • ✅ 2025 年标准
  • ✅ 流式传输支持更佳

缺点:

  • ❌ 仅适用于较新的客户端
  • ❌ 工具链成熟度较低

同时支持两种方式(推荐)

同时提供两种传输方式,以实现最大兼容性:

export default {
  fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const { pathname } = new URL(request.url);

    // SSE transport (legacy)
    if (pathname.startsWith("/sse")) {
      return MyMCP.serveSSE("/sse").fetch(request, env, ctx);
    }

    // HTTP transport (2025 standard)
    if (pathname.startsWith("/mcp")) {
      return MyMCP.serve("/mcp").fetch(request, env, ctx);
    }

    // Health check endpoint (optional but recommended)
    if (pathname === "/" || pathname === "/health") {
      return new Response(
        JSON.stringify({
          name: "My MCP Server",
          version: "1.0.0",
          transports: {
            sse: "/sse",
            http: "/mcp"
          },
          status: "ok",
          timestamp: new Date().toISOString()
        }),
        {
          headers: { "Content-Type": "application/json" },
          status: 200
        }
      );
    }

    return new Response("Not Found", { status: 404 });
  }
};

这样做的原因:

  • SSE 客户端连接到 /sse
  • HTTP 客户端连接到 /mcp
  • 可通过 / 或 /health 进行健康检查
  • 不会发生传输冲突

重要:使用 pathname.startsWith() 正确匹配路径!


快速入门(5 分钟)

了解 URL 配置后,现在来构建你的第一个 MCP 服务。

选项 1:复制最简模板

使用 mcp-http-fundamentals.ts 模板,这是最简单的可运行示例。

# Copy minimal template
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-http-fundamentals.ts src/index.ts

# Install dependencies
npm install

# Start dev server
npm run dev

# Test connection
curl http://localhost:8788/sse
# Should return: {"name":"My MCP Server","version":"1.0.0",...}
选项 2:从 Cloudflare 模板部署
# Create new MCP server from official template
npm create cloudflare@latest -- my-mcp-server \
  --template=cloudflare/ai/demos/remote-mcp-authless

cd my-mcp-server
npm install
npm run dev

现在,你的 MCP 服务已在 http://localhost:8788/sse 上运行。

使用 MCP Inspector 测试
# In a new terminal
npx @modelcontextprotocol/inspector@latest

# Open http://localhost:5173
# Enter: http://localhost:8788/sse
# Click "Connect" and test tools
部署到 Cloudflare
# Deploy
npx wrangler deploy

# Output shows your URL:
# https://my-mcp-server.YOUR_ACCOUNT.workers.dev

# ⚠️ REMEMBER: Update client config with this URL + /sse!

核心概念

1. McpAgent 类

来自 Cloudflare Agents SDK 的 McpAgent 基类提供:

  • 自动集成 Durable Objects
  • 基于 SQL 数据库的内置状态管理
  • 工具、资源和提示词注册
  • 传输处理(SSE + HTTP)

基本模式:

import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

export class MyMCP extends McpAgent<Env> {
  server = new McpServer({
    name: "My MCP Server",
    version: "1.0.0"
  });

  async init() {
    // Register tools here
    this.server.tool(
      "tool_name",
      "Tool description",
      { param: z.string() },
      async ({ param }) => ({
        content: [{ type: "text", text: "Result" }]
      })
    );
  }
}
2. 工具定义

工具是 MCP 客户端可以调用的函数。使用 Zod 验证参数。

模式:

this.server.tool(
  "tool_name",           // Tool identifier
  "Tool description",    // What it does (for LLM)
  {                      // Parameters (Zod schema)
    param1: z.string().describe("Parameter description"),
    param2: z.number().optional()
  },
  async ({ param1, param2 }) => {  // Handler
    // Your logic here
    return {
      content: [{ type: "text", text: "Result" }]
    };
  }
);

最佳实践:

  • 详细描述:帮助大模型理解工具的用途
  • 参数描述:说明预期值和约束条件
  • 错误处理:发生错误时返回 { isError: true }
  • 工具数量精简且目标明确:优于数量繁多且过于细分的工具

身份验证模式

Cloudflare MCP 服务支持4 种身份验证模式:

模式 1:无身份验证

适用场景:内部工具、开发、公共 API

模板:templates/mcp-http-fundamentals.ts

设置:无需设置

安全性:⚠️ 任何人都可以访问你的 MCP 服务


模式 2:令牌验证(JWTVerifier)

适用场景:预先完成身份验证的客户端、自定义身份验证系统

工作原理:客户端发送 Bearer 令牌,服务端进行验证

模板:创建自定义 JWTVerifier 中间件

设置:

import { JWTVerifier } from "agents/mcp";

const verifier = new JWTVerifier({
  secret: env.JWT_SECRET,
  issuer: "your-auth-server"
});

// Validate token before serving MCP requests

安全性:✅ 令牌管理得当时安全


模式 3:OAuth 代理(workers-oauth-provider)

适用场景:集成 GitHub、Google、Azure OAuth

工作原理:Cloudflare Worker 将 OAuth 请求代理到第三方提供商

模板:templates/mcp-oauth-proxy.ts

设置:

import { OAuthProvider, GitHubHandler } from "@cloudflare/workers-oauth-provider";

export default new OAuthProvider({
  authorizeEndpoint: "/authorize",
  tokenEndpoint: "/token",
  clientRegistrationEndpoint: "/register",

  defaultHandler: new GitHubHandler({
    clientId: (env) => env.GITHUB_CLIENT_ID,
    clientSecret: (env) => env.GITHUB_CLIENT_SECRET,
    scopes: ["repo", "user:email"],

    context: async (accessToken) => {
      // Fetch user info from GitHub
      const octokit = new Octokit({ auth: accessToken });
      const { data: user } = await octokit.rest.users.getAuthenticated();

      return {
        login: user.login,
        email: user.email,
        accessToken
      };
    }
  }),

  kv: (env) => env.OAUTH_KV,
  apiHandlers: {
    "/sse": MyMCP.serveSSE("/sse"),
    "/mcp": MyMCP.serve("/mcp")
  },

  allowConsentScreen: true,
  allowDynamicClientRegistration: true
});

必需绑定:

{
  "kv_namespaces": [
    { "binding": "OAUTH_KV", "id": "YOUR_KV_ID" }
  ]
}

⚠️ OAuth URL 配置至关重要:使用 OAuth 时,你的重定向 URI 必须匹配:

{
  "mcpServers": {
    "my-mcp": {
      "url": "https://my-mcp.YOUR_ACCOUNT.workers.dev/sse",
      "auth": {
        "type": "oauth",
        "authorizationUrl": "https://my-mcp.YOUR_ACCOUNT.workers.dev/authorize",
        "tokenUrl": "https://my-mcp.YOUR_ACCOUNT.workers.dev/token"
      }
    }
  }
}

所有 URL 必须使用相同的域名和协议(https://)。

安全性:✅✅ 安全,适用于生产环境


模式 4:使用 DCR 的远程 OAuth

适用场景:完整的 OAuth 提供商、自定义授权页面

工作原理:你的 Worker 就是 OAuth 提供商

模板:参阅 Cloudflare 的 remote-mcp-authkit 演示

设置:较复杂,需要完整实现 OAuth 2.1

安全性:✅✅✅ 安全性最高,完全可控


使用 Durable Objects 的有状态 MCP 服务

当 MCP 服务需要以下功能时,请使用 Durable Objects:

  • 每个会话的持久状态
  • 对话历史记录
  • 游戏状态(国际象棋、井字棋)
  • 缓存的 API 响应
  • 用户偏好设置
存储 API 模式

模板:templates/mcp-stateful-do.ts

存储值:

await this.state.storage.put("key", "value");
await this.state.storage.put("user_prefs", { theme: "dark" });

获取值:

const value = await this.state.storage.get<string>("key");
const prefs = await this.state.storage.get<object>("user_prefs");

列出键:

const allKeys = await this.state.storage.list();

删除键:

await this.state.storage.delete("key");
配置

wrangler.jsonc:

{
  "durable_objects": {
    "bindings": [
      {
        "name": "MY_MCP",
        "class_name": "MyMCP",
        "script_name": "my-mcp-server"
      }
    ]
  },

  "migrations": [
    { "tag": "v1", "new_classes": ["MyMCP"] }
  ]
}

重要:首次部署时必须执行迁移!


通过 WebSocket 休眠优化成本

问题:长时间运行的 WebSocket 连接会消耗 CPU 时间

解决方案:WebSocket 休眠 API 会在连接空闲时将其挂起

模式

序列化元数据(在休眠期间保留数据):

webSocket.serializeAttachment({
  userId: "123",
  sessionId: "abc",
  connectedAt: Date.now()
});

唤醒时获取:

const metadata = webSocket.deserializeAttachment();
console.log(metadata.userId); // "123"

用于持久状态的存储:

// ❌ DON'T: In-memory state lost on hibernation
this.userId = "123";

// ✅ DO: Use storage API
await this.state.storage.put("userId", "123");
节省成本

不使用休眠时:

  • 1000 个并发 WebSocket × 10ms CPU/秒 = 10 CPU-秒/秒
  • 成本:约 $0.50/天

使用休眠时:

  • 仅在收到消息时使用 CPU(99% 的空闲时间处于挂起状态)
  • 成本:约 $0.01/天(减少 50 倍!)

常见模式

API 代理 MCP 服务

适用场景:用 MCP 工具封装外部 API

模式:

this.server.tool(
  "search_wikipedia",
  "Search Wikipedia for a topic",
  { query: z.string() },
  async ({ query }) => {
    const response = await fetch(
      `https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(query)}`
    );
    const data = await response.json();

    return {
      content: [{
        type: "text",
        text: data.extract
      }]
    };
  }
);
数据库支持的工具

适用场景:查询 D1、KV 或外部数据库

模式:

this.server.tool(
  "get_user",
  "Get user details from database",
  { userId: z.string() },
  async ({ userId }) => {
    // Query Durable Objects storage
    const user = await this.state.storage.get<User>(`user:${userId}`);

    // Or query D1 database
    const result = await env.DB.prepare(
      "SELECT * FROM users WHERE id = ?"
    ).bind(userId).first();

    return {
      content: [{
        type: "text",
        text: JSON.stringify(user || result, null, 2)
      }]
    };
  }
);
多工具协同

适用场景:调用其他工具的工具

模式:

// Store result from first tool
await this.state.storage.put("last_search", result);

// Second tool reads it
const lastSearch = await this.state.storage.get("last_search");
缓存策略

适用场景:缓存开销较大的 API 调用

模式:

this.server.tool(
  "get_weather",
  "Get weather (cached 5 minutes)",
  { city: z.string() },
  async ({ city }) => {
    const cacheKey = `weather:${city}`;
    const cached = await this.state.storage.get<CachedWeather>(cacheKey);

    // Check cache freshness
    if (cached && Date.now() - cached.timestamp < 5 * 60 * 1000) {
      return {
        content: [{ type: "text", text: cached.data }]
      };
    }

    // Fetch fresh data
    const weather = await fetchWeatherAPI(city);

    // Cache it
    await this.state.storage.put(cacheKey, {
      data: weather,
      timestamp: Date.now()
    });

    return {
      content: [{ type: "text", text: weather }]
    };
  }
);
使用 Durable Objects 进行速率限制

适用场景:防止滥用、遵守上游速率限制

模式:

async rateLimit(key: string, maxRequests: number, windowMs: number): Promise<boolean> {
  const now = Date.now();
  const requests = await this.state.storage.get<number[]>(`ratelimit:${key}`) || [];

  // Remove old requests outside window
  const recentRequests = requests.filter(ts => now - ts < windowMs);

  if (recentRequests.length >= maxRequests) {
    return false; // Rate limited
  }

  // Add this request
  recentRequests.push(now);
  await this.state.storage.put(`ratelimit:${key}`, recentRequests);

  return true; // Allowed
}

// Use in tool
if (!await this.rateLimit(userId, 10, 60 * 1000)) {
  return {
    content: [{ type: "text", text: "Rate limit exceeded (10 requests/minute)" }],
    isError: true
  };
}

22 个已知错误(及解决方案)

1. 未导出 McpAgent 类

错误:TypeError: Cannot read properties of undefined (reading 'serve')

原因:忘记导出 McpAgent 类

解决方案:

export class MyMCP extends McpAgent { ... }  // ✅ Must export
export default { fetch() { ... } }

2. 基础路径配置不匹配(最常见!)

错误:404 Not Found 或 Connection failed

原因:使用了 serveSSE("/sse"),但客户端配置为 https://worker.dev(缺少 /sse)

解决方案:确保基础路径完全匹配

// Server serves at /sse
MyMCP.serveSSE("/sse").fetch(...)

// Client MUST include /sse
{ "url": "https://worker.dev/sse" }  // ✅ Correct
{ "url": "https://worker.dev" }      // ❌ Wrong - 404

调试步骤:

  1. 检查服务端使用的路径:serveSSE("/sse") 还是 serveSSE("/")
  2. 使用 curl 测试:curl https://worker.dev/sse
  3. 更新客户端配置,使其与 curl URL 匹配

3. 传输类型混淆

错误:Connection failed: Unexpected response format

原因:客户端期望 SSE,却连接到 HTTP 端点(或反之)

解决方案:确保传输类型匹配

// SSE transport
MyMCP.serveSSE("/sse")  // Client URL: https://worker.dev/sse

// HTTP transport
MyMCP.serve("/mcp")     // Client URL: https://worker.dev/mcp

最佳实践:同时支持两种传输方式(参见《传输方式选择指南》)


4. pathname.startsWith() 逻辑错误

错误:/sse 和 /mcp 路由均无法使用或发生冲突

原因:路径匹配逻辑不正确

解决方案:正确使用 startsWith()

// ✅ CORRECT
if (pathname.startsWith("/sse")) {
  return MyMCP.serveSSE("/sse").fetch(...);
}
if (pathname.startsWith("/mcp")) {
  return MyMCP.serve("/mcp").fetch(...);
}

// ❌ WRONG: Exact match breaks sub-paths
if (pathname === "/sse") {  // Breaks /sse/tools/list
  return MyMCP.serveSSE("/sse").fetch(...);
}

5. 本地与部署 URL 不匹配

错误:开发环境中正常运行,部署后失败

原因:客户端仍配置为 localhost URL

解决方案:部署后更新客户端配置

// Development
{ "url": "http://localhost:8788/sse" }

// ⚠️ MUST UPDATE after npx wrangler deploy
{ "url": "https://my-mcp.YOUR_ACCOUNT.workers.dev/sse" }

部署后检查清单:

  • 运行 npx wrangler deploy 并记下输出的 URL
  • 使用部署后的 URL 更新客户端配置
  • 使用 curl 测试
  • 重启 Claude Desktop

6. OAuth 重定向 URI 不匹配

错误:OAuth error: redirect_uri does not match

原因:OAuth 重定向 URI 与部署后的 URL 不匹配

解决方案:部署后更新所有 OAuth URL

{
  "url": "https://my-mcp.YOUR_ACCOUNT.workers.dev/sse",
  "auth": {
    "type": "oauth",
    "authorizationUrl": "https://my-mcp.YOUR_ACCOUNT.workers.dev/authorize",  // Must match deployed domain
    "tokenUrl": "https://my-mcp.YOUR_ACCOUNT.workers.dev/token"
  }
}

重要:所有 URL 必须使用相同的协议和域名!


7. 缺少 OPTIONS 处理程序(CORS 预检)

错误:Access to fetch at '...' blocked by CORS policy 或 Method Not Allowed

原因:浏览器客户端会为 CORS 预检发送 OPTIONS 请求,但服务端未处理这些请求

解决方案:添加 OPTIONS 处理程序

export default {
  fetch(request: Request, env: Env, ctx: ExecutionContext) {
    // Handle CORS preflight
    if (request.method === "OPTIONS") {
      return new Response(null, {
        status: 204,
        headers: {
          "Access-Control-Allow-Origin": "*",
          "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
          "Access-Control-Allow-Headers": "Content-Type, Authorization",
          "Access-Control-Max-Age": "86400"
        }
      });
    }

    // ... rest of your fetch handler
  }
};

适用情形:基于浏览器的 MCP 客户端(例如浏览器中的 MCP Inspector)


8. 缺少请求正文验证

错误:JSON 解析时出现 TypeError: Cannot read properties of undefined 或 Unexpected token

原因:客户端发送了格式错误的 JSON,服务端在解析前未进行验证

解决方案:使用 try/catch 包装请求处理

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    try {
      // Your MCP server logic
      return await MyMCP.serveSSE("/sse").fetch(request, env, ctx);
    } catch (error) {
      console.error("Request handling error:", error);
      return new Response(
        JSON.stringify({
          error: "Invalid request",
          details: error.message
        }),
        {
          status: 400,
          headers: { "Content-Type": "application/json" }
        }
      );
    }
  }
};

9. 缺少环境变量验证

错误:出现 TypeError: env.API_KEY is undefined 或静默失败(工具返回空数据)

原因:未配置必需的环境变量,或运行时缺少这些变量

解决方案:添加启动时验证

export class MyMCP extends McpAgent<Env> {
  async init() {
    // Validate required environment variables
    if (!this.env.API_KEY) {
      throw new Error("API_KEY environment variable not configured");
    }
    if (!this.env.DATABASE_URL) {
      throw new Error("DATABASE_URL environment variable not configured");
    }

    // Continue with tool registration
    this.server.tool(...);
  }
}

配置检查清单:

  • 开发环境:添加到 .dev.vars(仅限本地,并已加入 gitignore)
  • 生产环境:添加到 wrangler.jsonc 的 vars(公开变量),或使用 wrangler secret(敏感变量)

最佳实践:

# .dev.vars (local development, gitignored)
API_KEY=dev-key-123
DATABASE_URL=http://localhost:3000

# wrangler.jsonc (public config)
{
  "vars": {
    "ENVIRONMENT": "production",
    "LOG_LEVEL": "info"
  }
}

# wrangler secret (production secrets)
npx wrangler secret put API_KEY
npx wrangler secret put DATABASE_URL

10. McpAgent 与 McpServer 混淆

错误:出现 TypeError: server.registerTool is not a function 或 this.server is undefined

原因:尝试将独立 SDK 的用法用于 McpAgent 类

解决方案:使用 McpAgent 的 this.server.tool() 模式

// ❌ WRONG: Mixing standalone SDK with McpAgent
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

const server = new McpServer({ name: "My Server" });
server.registerTool(...);  // Not compatible with McpAgent!

export class MyMCP extends McpAgent { /* no server property */ }

// ✅ CORRECT: McpAgent pattern
export class MyMCP extends McpAgent<Env> {
  server = new McpServer({
    name: "My MCP Server",
    version: "1.0.0"
  });

  async init() {
    this.server.tool("tool_name", ...);  // Use this.server
  }
}

主要区别:McpAgent 提供 this.server 属性,独立 SDK 则不提供。


11. WebSocket 休眠导致状态丢失

错误:重新连接后,工具调用因“state not found”而失败

原因:休眠时内存中的状态被清除

解决方案:使用 this.state.storage,而不是实例属性

// ❌ DON'T: Lost on hibernation
this.userId = "123";

// ✅ DO: Persists through hibernation
await this.state.storage.put("userId", "123");

12. 缺少 Durable Objects 绑定

错误:TypeError: Cannot read properties of undefined (reading 'idFromName')

原因:忘记在 wrangler.jsonc 中配置 DO 绑定

解决方案:添加绑定(参见 Stateful MCP Servers 部分)

{
  "durable_objects": {
    "bindings": [
      {
        "name": "MY_MCP",
        "class_name": "MyMCP",
        "script_name": "my-mcp-server"
      }
    ]
  }
}

13. 未定义迁移

错误:Error: Durable Object class MyMCP has no migration defined

原因:首次部署 DO 需要迁移

解决方案:

{
  "migrations": [
    { "tag": "v1", "new_classes": ["MyMCP"] }
  ]
}

14. 未使用 serializeAttachment()

错误:休眠唤醒后 WebSocket 元数据丢失

原因:未使用 serializeAttachment() 保留连接元数据

解决方案:参见 WebSocket Hibernation 部分


15. OAuth 同意屏幕已禁用

安全风险:用户看不到自己授予的权限

原因:生产环境中设置了 allowConsentScreen: false

解决方案:始终在生产环境中启用

export default new OAuthProvider({
  allowConsentScreen: true,  // ✅ Always true in production
  // ...
});

16. 缺少 JWT 签名密钥

错误:Error: JWT_SIGNING_KEY environment variable not set

原因:OAuth Provider 需要签名密钥来签发令牌

解决方案:

# Generate secure key
openssl rand -base64 32

# Add to wrangler secret
npx wrangler secret put JWT_SIGNING_KEY

17. 工具架构验证错误

错误:ZodError: Invalid input type

原因:客户端发送字符串,但架构要求数字(或反之)

解决方案:使用 Zod 转换

// Accept string, convert to number
param: z.string().transform(val => parseInt(val, 10))

// Or: Accept both types
param: z.union([z.string(), z.number()]).transform(val =>
  typeof val === "string" ? parseInt(val, 10) : val
)

18. 多个传输端点冲突

错误:添加 /mcp 后,/sse 返回 404

原因:路径匹配不正确(缺少 startsWith())

解决方案:正确使用 startsWith() 或精确匹配(参见错误 #4)


19. 使用 Miniflare 进行本地测试的限制

错误:本地开发时 OAuth 流程失败,或 Durable Objects 的行为有所不同

原因:Miniflare 不支持所有 DO 功能

解决方案:使用 npx wrangler dev --remote 以获得完整的 DO 支持

# Local simulation (faster but limited)
npm run dev

# Remote DOs (slower but accurate)
npx wrangler dev --remote

20. 客户端配置格式错误

错误:Claude Desktop 无法识别服务

原因:claude_desktop_config.json 中的 JSON 格式错误

解决方案:查看“连接 Claude Desktop”部分,了解正确格式

常见错误:

// ❌ WRONG: Missing "mcpServers" wrapper
{
  "my-mcp": {
    "url": "https://worker.dev/sse"
  }
}

// ❌ WRONG: Trailing comma
{
  "mcpServers": {
    "my-mcp": {
      "url": "https://worker.dev/sse",  // ← Remove comma
    }
  }
}

// ✅ CORRECT
{
  "mcpServers": {
    "my-mcp": {
      "url": "https://worker.dev/sse"
    }
  }
}

21. 缺少健康检查端点

问题:无法判断 Worker 是否正在运行,或 URL 是否正确

影响:排查连接问题需要更长时间

解决方案:添加健康检查端点(参见传输方式选择指南)

测试:

curl https://my-mcp.workers.dev/health
# Should return: {"status":"ok","transports":{...}}

22. 缺少 CORS 标头

错误:Access to fetch at '...' blocked by CORS policy

原因:MCP 服务未为跨源请求返回 CORS 标头

解决方案:为所有响应添加 CORS 标头

// Manual CORS (if not using OAuthProvider)
const corsHeaders = {
  "Access-Control-Allow-Origin": "*",  // Or specific origin
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Authorization"
};

// Add to responses
return new Response(body, {
  headers: {
    ...corsHeaders,
    "Content-Type": "application/json"
  }
});

注意:OAuthProvider 会自动处理 CORS!


部署与测试

本地开发
# Start dev server (uses Miniflare for local DOs)
npm run dev

# Start dev server with remote Durable Objects (more accurate)
npx wrangler dev --remote

访问地址:http://localhost:8788/sse

使用 MCP Inspector 测试
npx @modelcontextprotocol/inspector@latest
  1. 打开 http://localhost:5173
  2. 输入 MCP 服务 URL
  3. 点击“连接”
  4. 使用“列出工具”查看可用工具
  5. 使用参数测试工具调用
部署到 Cloudflare
# First time: Login
npx wrangler login

# Deploy
npx wrangler deploy

# Output shows your deployed URL:
# https://my-mcp-server.YOUR_ACCOUNT.workers.dev

# ⚠️ CRITICAL: Update client config with this URL!

# Check deployment logs
npx wrangler tail
连接 Claude Desktop

~/.config/claude/claude_desktop_config.json(Linux/Mac):

{
  "mcpServers": {
    "my-mcp": {
      "url": "https://my-mcp-server.YOUR_ACCOUNT.workers.dev/sse"
    }
  }
}

%APPDATA%/Claude/claude_desktop_config.json(Windows)

使用 OAuth:

{
  "mcpServers": {
    "my-mcp": {
      "url": "https://my-mcp-oauth.YOUR_ACCOUNT.workers.dev/sse",
      "auth": {
        "type": "oauth",
        "authorizationUrl": "https://my-mcp-oauth.YOUR_ACCOUNT.workers.dev/authorize",
        "tokenUrl": "https://my-mcp-oauth.YOUR_ACCOUNT.workers.dev/token"
      }
    }
  }
}

⚠️ 请记住:更改配置后,重启 Claude Desktop!


配置参考

完整的 wrangler.jsonc(所有功能)
{
  "name": "my-mcp-server",
  "main": "src/index.ts",
  "compatibility_date": "2025-01-01",
  "compatibility_flags": ["nodejs_compat"],
  "account_id": "YOUR_ACCOUNT_ID",

  "vars": {
    "ENVIRONMENT": "production",
    "GITHUB_CLIENT_ID": "optional-pre-configured-id"
  },

  "kv_namespaces": [
    {
      "binding": "OAUTH_KV",
      "id": "YOUR_KV_ID",
      "preview_id": "YOUR_PREVIEW_KV_ID"
    }
  ],

  "durable_objects": {
    "bindings": [
      {
        "name": "MY_MCP",
        "class_name": "MyMCP",
        "script_name": "my-mcp-server"
      }
    ]
  },

  "migrations": [
    { "tag": "v1", "new_classes": ["MyMCP"] }
  ],

  "node_compat": true
}
完整的 package.json

参见 templates/package.json

完整的 claude_desktop_config.json

参见 templates/claude_desktop_config.json


Worker 与 Durable Objects 基础知识

可独立使用的自包含章节

Worker 导出模式

Workers 必须导出一个 fetch 处理程序:

export default {
  fetch(request: Request, env: Env, ctx: ExecutionContext): Response | Promise<Response> {
    // Handle request
    return new Response("Hello");
  }
};
Durable Objects 类结构

DO 继承 McpAgent(用于 MCP 服务):

export class MyMCP extends McpAgent<Env> {
  constructor(state: DurableObjectState, env: Env) {
    super(state, env);
  }

  // Your methods here
}
绑定配置

环境绑定使 Workers 能够访问资源:

{
  "kv_namespaces": [{ "binding": "MY_KV", "id": "..." }],
  "durable_objects": {
    "bindings": [{ "name": "MY_DO", "class_name": "MyDO" }]
  },
  "r2_buckets": [{ "binding": "MY_BUCKET", "bucket_name": "..." }]
}

在代码中访问:

env.MY_KV.get("key");
env.MY_DO.idFromName("session-123").getStub(env);
env.MY_BUCKET.get("file.txt");

其他资源

官方文档
官方示例
工具
此技能的资源
  • references/http-transport-fundamentals.md - 深入了解 URL 路径与路由
  • references/transport-comparison.md - SSE 与 HTTP 的技术细节
  • references/debugging-guide.md - 常见连接问题及解决方法
  • references/authentication.md - 身份验证模式比较
  • references/oauth-providers.md - GitHub、Google、Azure 配置
  • references/common-issues.md - 错误排查详解
  • references/official-examples.md - 精选的 Cloudflare 示例链接

何时不应使用此技能

以下情况不要使用此技能:

  • 构建 Python MCP 服务(请改用 fastmcp 技能)
  • 构建仅限本地的 MCP 服务(请改用 typescript-mcp 技能)
  • 需要使用非 Cloudflare 托管服务(如 AWS Lambda、GCP 等)
  • 使用 Claude.ai 网页界面技能(与 MCP 不同)

此技能专用于:TypeScript + Cloudflare Workers + 远程 MCP


版本信息

  • @modelcontextprotocol/sdk:1.21.0
  • @cloudflare/workers-oauth-provider:0.0.13
  • agents(Cloudflare Agents SDK):0.2.20
  • 上次验证时间:2025-11-08

已通过生产环境测试:基于 Cloudflare 官方 MCP 服务(mcp-server-cloudflare、workers-mcp)


Token 效率

不使用此技能时:

  • 查阅分散的文档:约 10k tokens
  • 调试 URL 路径问题:约 15k tokens
  • 调试其他 21 个错误:约 30k tokens
  • 合计:约 55k tokens

使用此技能时:

  • 阅读技能基础内容:约 4k tokens
  • 复制模板:约 1k tokens
  • 快速参考:约 1k tokens
  • 合计:约 6k tokens

节省:约 88%(55k → 6k tokens)

可预防的错误:22 个(预防率 100%)

评论

支持 Markdown