cloudflare-mcp-server
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCloudflare MCP Server Skill
Cloudflare MCP Server 技能
Build and deploy Model Context Protocol (MCP) servers on Cloudflare Workers with TypeScript.
使用TypeScript在Cloudflare Workers上构建并部署Model Context Protocol (MCP)服务器。
What is This Skill?
什么是该技能?
This skill teaches you to build remote MCP servers on Cloudflare - the ONLY platform with official remote MCP support as of 2025.
Use this skill when:
- Building MCP servers with TypeScript (@modelcontextprotocol/sdk)
- Deploying remote MCP servers to Cloudflare Workers
- Implementing OAuth authentication (GitHub, Google, Azure, custom)
- Creating stateful MCP servers with Durable Objects
- Optimizing costs with WebSocket hibernation
- Supporting both SSE and Streamable HTTP transports
- Avoiding 22+ common MCP + Cloudflare errors (especially URL path mismatches!)
You'll learn:
- HTTP transport fundamentals (URL path configuration, routing)
- Transport selection (SSE vs Streamable HTTP)
- McpAgent class patterns and tool definitions
- OAuth integration (all 5 auth patterns)
- Cloudflare service integrations (Workers AI, D1, Vectorize, etc.)
- Durable Objects for per-session state
- WebSocket hibernation API
- Complete deployment workflow
本技能将教你在Cloudflare上构建远程MCP服务器——截至2025年,这是唯一官方支持远程MCP的平台。
在以下场景使用本技能:
- 使用TypeScript (@modelcontextprotocol/sdk)构建MCP服务器
- 将远程MCP服务器部署到Cloudflare Workers
- 实现OAuth身份验证(GitHub、Google、Azure、自定义)
- 使用Durable Objects创建有状态的MCP服务器
- 通过WebSocket休眠优化成本
- 同时支持SSE和Streamable HTTP传输协议
- 避免22+种常见的MCP + Cloudflare错误(尤其是URL路径不匹配问题!)
你将学到:
- HTTP传输基础(URL路径配置、路由)
- 传输协议选择(SSE vs Streamable HTTP)
- McpAgent类模式与工具定义
- OAuth集成(全部5种认证模式)
- Cloudflare服务集成(Workers AI、D1、Vectorize等)
- 用于会话级状态管理的Durable Objects
- WebSocket休眠API
- 完整的部署流程
🚀 Official Cloudflare Templates (Start Here!)
🚀 官方Cloudflare模板(从这里开始!)
Before using this skill's templates, know that Cloudflare provides official starter templates via .
npm create在使用本技能的模板之前,请了解Cloudflare通过提供官方启动模板。
npm createRecommended Starting Point
推荐起始点
For most projects, start with Cloudflare's official authless template:
bash
npm create cloudflare@latest -- my-mcp-server \
--template=cloudflare/ai/demos/remote-mcp-authless
cd my-mcp-server
npm install
npm run devWhat you get:
- ✅ Minimal working MCP server (~50 lines)
- ✅ Dual transport support (SSE + Streamable HTTP)
- ✅ Pre-configured wrangler.jsonc
- ✅ Ready to deploy immediately
Then customize with patterns from this skill to avoid the 22+ common errors!
对于大多数项目,从Cloudflare的官方无认证模板开始:
bash
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+种常见错误!
All Available Cloudflare Templates
所有可用的Cloudflare模板
Cloudflare maintains 14+ official MCP templates. Use these as starting points:
Cloudflare维护着14+个官方MCP模板。将这些作为起始点:
Basic Templates
基础模板
| Template Command | Purpose | When to Use |
|---|---|---|
| Gold standard starter - No auth, simple tools | New projects, learning, public APIs |
| GitHub OAuth + Workers AI | Developer tools, GitHub integrations |
| Google OAuth | Google Workspace integration |
| 模板命令 | 用途 | 使用场景 |
|---|---|---|
| 黄金标准启动模板 - 无认证,工具简单 | 新项目、学习、公开API |
| GitHub OAuth + Workers AI | 开发者工具、GitHub集成 |
| Google OAuth | Google Workspace集成 |
Advanced Authentication Templates
高级认证模板
| Template Command | Auth Method | Use Case |
|---|---|---|
| Auth0 | Enterprise SSO |
| WorkOS AuthKit | B2B SaaS applications |
| Logto | Open-source auth |
| Cloudflare Access | Internal company tools |
| Bearer tokens | Custom auth systems |
| 模板命令 | 认证方式 | 使用场景 |
|---|---|---|
| Auth0 | 企业SSO |
| WorkOS AuthKit | B2B SaaS应用 |
| Logto | 开源认证 |
| Cloudflare Access | 内部公司工具 |
| Bearer令牌 | 自定义认证系统 |
Integration Examples
集成示例
| Template Command | Demonstrates | Cloudflare Services |
|---|---|---|
| RAG (Retrieval-Augmented Generation) | Workers AI + Vectorize |
| Python MCP servers | Python Workers |
| 模板命令 | 演示内容 | Cloudflare服务 |
|---|---|---|
| RAG(检索增强生成) | Workers AI + Vectorize |
| Python MCP服务器 | Python Workers |
When to Use This Skill's Templates
何时使用本技能的模板
Use this skill's templates when:
- Learning how URL paths work (use )
mcp-http-fundamentals.ts - Need comprehensive error prevention (all templates include warnings)
- Want detailed comments explaining every decision
- Building complex integrations (Workers AI, D1, Bearer auth)
This skill's templates are MORE educational than Cloudflare's (more comments, defensive patterns, error handling).
Cloudflare's templates are FASTER to start with (minimal, production-ready).
Best approach: Start with Cloudflare's template, then reference this skill to avoid errors!
在以下场景使用本技能的模板:
- 学习URL路径的工作原理(使用)
mcp-http-fundamentals.ts - 需要全面的错误预防(所有模板均包含警告)
- 需要详细注释解释每个决策
- 构建复杂集成(Workers AI、D1、Bearer认证)
本技能的模板比Cloudflare的模板更具教育意义(包含更多注释、防御性模式、错误处理)。
Cloudflare的模板启动速度更快(极简、生产就绪)。
最佳实践:从Cloudflare的模板开始,然后参考本技能避免错误!
Production MCP Servers (Study These!)
生产级MCP服务器(务必学习!)
Cloudflare maintains 15 production MCP servers showing real-world integration patterns:
Key servers to study:
- - D1, KV, R2, AI, Durable Objects usage
workers-bindings - - Web scraping + screenshot tools
browser-rendering - - Vectorize RAG pattern
autorag - - Workers AI Gateway analytics
ai-gateway - - Cloudflare documentation search
docs
Why study these? They show production-grade patterns for:
- Error handling
- Rate limiting
- Caching strategies
- Real API integrations
- Security best practices
Cloudflare维护着15个生产级MCP服务器,展示了真实世界的集成模式:
重点学习的服务器:
- - D1、KV、R2、AI、Durable Objects的使用
workers-bindings - - 网页抓取+截图工具
browser-rendering - - Vectorize RAG模式
autorag - - Workers AI网关分析
ai-gateway - - Cloudflare文档搜索
docs
为什么要学习这些? 它们展示了生产级别的模式:
- 错误处理
- 速率限制
- 缓存策略
- 真实API集成
- 安全最佳实践
🎯 Quick Start Workflow (Your Step-by-Step Guide)
🎯 快速启动流程(分步指南)
Follow this workflow for your next MCP server to avoid errors and ship fast.
遵循此流程构建你的下一个MCP服务器,以避免错误并快速交付。
Step 1: Choose Your Starting Template
步骤1:选择起始模板
Decision tree:
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)Not sure? Start with - you can add auth later!
remote-mcp-authless决策树:
你要构建什么?
├─ 🆓 公开/开发服务器(无需认证)
│ └─> 使用:remote-mcp-authless ⭐ 推荐用于大多数项目
│
├─ 🔐 GitHub集成
│ └─> 使用:remote-mcp-github-oauth(包含Workers AI示例)
│
├─ 🔐 Google Workspace集成
│ └─> 使用:remote-mcp-google-oauth
│
├─ 🏢 企业SSO(Auth0、Okta等)
│ └─> 使用:remote-mcp-auth0或remote-mcp-authkit
│
├─ 🔑 自定义认证系统/API密钥
│ └─> 从无认证模板开始,然后添加bearer认证(见步骤3)
│
└─ 🏠 内部公司工具
└─> 使用:remote-mcp-cf-access(Cloudflare Zero Trust)不确定? 从开始——你可以稍后添加认证!
remote-mcp-authlessStep 2: Create from Template
步骤2:从模板创建项目
bash
undefinedbash
undefinedReplace [TEMPLATE] with your choice from Step 1
将[TEMPLATE]替换为步骤1中你的选择
npm create cloudflare@latest -- my-mcp-server
--template=cloudflare/ai/demos/[TEMPLATE]
--template=cloudflare/ai/demos/[TEMPLATE]
npm create cloudflare@latest -- my-mcp-server
--template=cloudflare/ai/demos/[TEMPLATE]
--template=cloudflare/ai/demos/[TEMPLATE]
Example: authless template (most common)
示例:无认证模板(最常见)
npm create cloudflare@latest -- my-mcp-server
--template=cloudflare/ai/demos/remote-mcp-authless
--template=cloudflare/ai/demos/remote-mcp-authless
npm create cloudflare@latest -- my-mcp-server
--template=cloudflare/ai/demos/remote-mcp-authless
--template=cloudflare/ai/demos/remote-mcp-authless
Navigate and install
进入目录并安装依赖
cd my-mcp-server
npm install
cd my-mcp-server
npm install
Start dev server
启动开发服务器
npm run dev
**Your MCP server is now running at**: `http://localhost:8788/sse`
---npm run dev
**你的MCP服务器现在运行在**:`http://localhost:8788/sse`
---Step 3: Customize with This Skill's Patterns
步骤3:使用本技能的模式进行自定义
Now add features by copying patterns from this skill:
现在通过复制本技能中的模式添加功能:
Need Workers AI (image/text generation)?
需要Workers AI(图像/文本生成)?
bash
undefinedbash
undefinedCopy our Workers AI template
复制我们的Workers AI模板
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-with-workers-ai.ts src/my-ai-tools.ts
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-with-workers-ai.ts src/my-ai-tools.ts
Add AI binding to wrangler.jsonc:
向wrangler.jsonc添加AI绑定:
{ "ai": { "binding": "AI" } }
{ "ai": { "binding": "AI" } }
**Tools you get**: `generate_image`, `generate_text`, `list_ai_models`
---
**你将获得的工具**:`generate_image`, `generate_text`, `list_ai_models`
---Need a database (D1)?
需要数据库(D1)?
bash
undefinedbash
undefinedCopy our D1 template
复制我们的D1模板
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-with-d1.ts src/my-db-tools.ts
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-with-d1.ts src/my-db-tools.ts
Create D1 database:
创建D1数据库:
npx wrangler d1 create my-database
npx wrangler d1 create my-database
Add binding to wrangler.jsonc
向wrangler.jsonc添加绑定
**Tools you get**: `create_user`, `get_user`, `list_users`, `update_user`, `delete_user`, `search_users`
---
**你将获得的工具**:`create_user`, `get_user`, `list_users`, `update_user`, `delete_user`, `search_users`
---Need bearer token auth?
需要bearer令牌认证?
bash
undefinedbash
undefinedCopy our bearer auth template
复制我们的bearer认证模板
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-bearer-auth.ts src/index.ts
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-bearer-auth.ts src/index.ts
Add token validation (KV, external API, or static)
添加令牌验证(KV、外部API或静态验证)
**What you get**: Authorization header middleware, token validation, authenticated tools
---
**你将获得**:Authorization头中间件、令牌验证、认证工具
---Step 4: Deploy to Cloudflare
步骤4:部署到Cloudflare
bash
undefinedbash
undefinedLogin (first time only)
登录(首次使用)
npx wrangler login
npx wrangler login
Deploy to production
部署到生产环境
npx wrangler deploy
**Output shows your deployed URL**:✨ Deployment complete!
https://my-mcp-server.YOUR_ACCOUNT.workers.dev
**⚠️ CRITICAL: Note this URL - you'll need it in Step 5!**
---npx wrangler deploy
**输出将显示你的部署URL**:
**⚠️ 重要:记录此URL——你将在步骤5中需要它!**
---Step 5: Test & Configure Client
步骤5:测试与配置客户端
A. Test with curl (PREVENTS 80% OF ERRORS!)
A. 使用curl测试(可避免80%的错误!)
bash
undefinedbash
undefinedTest the exact URL you'll use in client config
测试你将在客户端配置中使用的精确URL
**Expected response**:
```json
{
"name": "My MCP Server",
"version": "1.0.0",
"transports": ["/sse", "/mcp"]
}Got 404? → Your client URL will be wrong! See "HTTP Transport Fundamentals" below.
**预期响应**:
```json
{
"name": "My MCP Server",
"version": "1.0.0",
"transports": ["/sse", "/mcp"]
}得到404? → 你的客户端URL会出错!请查看下方的“HTTP传输基础”。
B. Update Claude Desktop Config
B. 更新Claude Desktop配置
Linux/Mac:
Windows:
~/.config/claude/claude_desktop_config.json%APPDATA%/Claude/claude_desktop_config.jsonFor authless servers:
json
{
"mcpServers": {
"my-mcp": {
"url": "https://my-mcp-server.YOUR_ACCOUNT.workers.dev/sse"
}
}
}⚠️ CRITICAL: URL must match the curl command that worked in Step 5A!
With OAuth:
json
{
"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"
}
}
}
}All three URLs must use the same domain!
Linux/Mac:
Windows:
~/.config/claude/claude_desktop_config.json%APPDATA%/Claude/claude_desktop_config.json对于无认证服务器:
json
{
"mcpServers": {
"my-mcp": {
"url": "https://my-mcp-server.YOUR_ACCOUNT.workers.dev/sse"
}
}
}⚠️ 重要:URL必须与步骤5A中测试通过的curl URL完全匹配!
对于OAuth:
json
{
"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. Restart Claude Desktop
C. 重启Claude Desktop
Config only loads at startup:
- Quit Claude Desktop completely
- Reopen
- Check for your MCP server in tools list
配置仅在启动时加载:
- 完全退出Claude Desktop
- 重新打开
- 在工具列表中检查你的MCP服务器
Step 6: Verify It Works
步骤6:验证是否正常工作
Test a tool call:
- Open Claude Desktop
- Type: "List available MCP tools"
- Your server's tools should appear
- Try calling one: "Use the add tool to add 5 + 3"
If tools don't appear → See "Debugging Guide" in references/
测试工具调用:
- 打开Claude Desktop
- 输入:"列出可用的MCP工具"
- 你的服务器工具应该会显示
- 尝试调用一个工具:"使用add工具计算5 + 3"
如果工具未显示 → 请查看references/中的“调试指南”
Post-Deployment Checklist
部署后检查清单
Before declaring success, verify:
- returns server info (not 404)
curl https://worker.dev/sse - Client config URL matches curl URL exactly
- Claude Desktop restarted after config update
- Tools visible in Claude Desktop
- Test tool call succeeds
- (OAuth only) All three URLs use same domain
- No errors in logs
npx wrangler tail
All checked? 🎉 Your MCP server is live!
在宣布成功之前,请验证:
- 返回服务器信息(而非404)
curl https://worker.dev/sse - 客户端配置URL与curl URL完全匹配
- 更新配置后已重启Claude Desktop
- 在Claude Desktop中可见工具
- 测试工具调用成功
- (仅OAuth)所有三个URL使用相同域名
- 日志中无错误
npx wrangler tail
全部勾选? 🎉 你的MCP服务器已上线!
Common Next Steps
常见后续步骤
Want to add more features?
- More tools - Add to method in your McpAgent class
init() - Workers AI - Copy patterns from
mcp-with-workers-ai.ts - Database - Copy patterns from
mcp-with-d1.ts - Authentication - Copy patterns from or
mcp-bearer-auth.tsmcp-oauth-proxy.ts - Durable Objects state - Copy patterns from
mcp-stateful-do.ts
Want to avoid errors?
- Read "HTTP Transport Fundamentals" section below (prevents URL path errors)
- Read "22 Known Errors" section (prevents all common mistakes)
- Check when stuck
references/debugging-guide.md
想要添加更多功能?
- 更多工具 - 在你的McpAgent类的方法中添加
init() - Workers AI - 从复制模式
mcp-with-workers-ai.ts - 数据库 - 从复制模式
mcp-with-d1.ts - 身份验证 - 从或
mcp-bearer-auth.ts复制模式mcp-oauth-proxy.ts - Durable Objects状态 - 从复制模式
mcp-stateful-do.ts
想要避免错误?
- 阅读下方的“HTTP传输基础”部分(可避免URL路径错误)
- 阅读“22种已知错误”部分(可避免所有常见错误)
- 遇到问题时查看
references/debugging-guide.md
TL;DR - The 5-Minute Workflow
简版 - 5分钟流程
bash
undefinedbash
undefined1. Create from template (30 seconds)
1. 从模板创建(30秒)
npm create cloudflare@latest -- my-mcp
--template=cloudflare/ai/demos/remote-mcp-authless cd my-mcp && npm install
--template=cloudflare/ai/demos/remote-mcp-authless cd my-mcp && npm install
npm create cloudflare@latest -- my-mcp
--template=cloudflare/ai/demos/remote-mcp-authless cd my-mcp && npm install
--template=cloudflare/ai/demos/remote-mcp-authless cd my-mcp && npm install
2. Customize (optional, 2 minutes)
2. 自定义(可选,2分钟)
Copy patterns from this skill if needed
如有需要,从本技能复制模式
3. Deploy (30 seconds)
3. 部署(30秒)
npx wrangler deploy
npx wrangler deploy
4. Test (30 seconds)
4. 测试(30秒)
5. Configure client (1 minute)
5. 配置客户端(1分钟)
Update claude_desktop_config.json with URL from step 4
使用步骤4中的URL更新claude_desktop_config.json
Restart Claude Desktop
重启Claude Desktop
6. Verify (30 seconds)
6. 验证(30秒)
Test a tool call in Claude Desktop
在Claude Desktop中测试工具调用
**Total time**: ~5 minutes from zero to working MCP server! 🚀
---
**总耗时**:从0到可运行的MCP服务器约5分钟! 🚀
---⚠️ CRITICAL: HTTP Transport Fundamentals
⚠️ 重要:HTTP传输基础
The #1 reason MCP servers fail to connect is URL path configuration mistakes.
MCP服务器连接失败的头号原因是URL路径配置错误。
URL Path Configuration Deep-Dive
URL路径配置深入解析
When you serve an MCP server at a specific path, the client URL must match exactly.
Example 1: Serving at
/ssetypescript
// 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 });
}
};Client configuration MUST include :
/ssejson
{
"mcpServers": {
"my-mcp": {
"url": "https://my-mcp.workers.dev/sse" // ✅ Correct
}
}
}❌ WRONG client configurations:
json
"url": "https://my-mcp.workers.dev" // Missing /sse → 404
"url": "https://my-mcp.workers.dev/" // Missing /sse → 404
"url": "http://localhost:8788" // Wrong after deployExample 2: Serving at (root)
/typescript
export default {
fetch(request: Request, env: Env, ctx: ExecutionContext) {
return MyMCP.serveSSE("/").fetch(request, env, ctx); // ← Base path is "/"
}
};Client configuration:
json
{
"mcpServers": {
"my-mcp": {
"url": "https://my-mcp.workers.dev" // ✅ Correct (no /sse)
}
}
}当你在特定路径上提供MCP服务器服务时,客户端URL必须完全匹配。
示例1:在路径提供服务
/ssetypescript
// 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); // ← 基础路径为"/sse"
}
return new Response("Not Found", { status: 404 });
}
};客户端配置必须包含:
/ssejson
{
"mcpServers": {
"my-mcp": {
"url": "https://my-mcp.workers.dev/sse" // ✅ 正确
}
}
}❌ 错误的客户端配置:
json
"url": "https://my-mcp.workers.dev" // 缺少/sse → 404
"url": "https://my-mcp.workers.dev/" // 缺少/sse → 404
"url": "http://localhost:8788" // 部署后错误示例2:在(根路径)提供服务
/typescript
export default {
fetch(request: Request, env: Env, ctx: ExecutionContext) {
return MyMCP.serveSSE("/").fetch(request, env, ctx); // ← 基础路径为"/"
}
};客户端配置:
json
{
"mcpServers": {
"my-mcp": {
"url": "https://my-mcp.workers.dev" // ✅ 正确(无/sse)
}
}
}How Base Path Affects Tool URLs
基础路径如何影响工具URL
When you call , MCP tools are served at:
serveSSE("/sse")https://my-mcp.workers.dev/sse/tools/list
https://my-mcp.workers.dev/sse/tools/call
https://my-mcp.workers.dev/sse/resources/listWhen you call , MCP tools are served at:
serveSSE("/")https://my-mcp.workers.dev/tools/list
https://my-mcp.workers.dev/tools/call
https://my-mcp.workers.dev/resources/listThe base path is prepended to all MCP endpoints automatically.
当你调用时,MCP工具的服务路径为:
serveSSE("/sse")https://my-mcp.workers.dev/sse/tools/list
https://my-mcp.workers.dev/sse/tools/call
https://my-mcp.workers.dev/sse/resources/list当你调用时,MCP工具的服务路径为:
serveSSE("/")https://my-mcp.workers.dev/tools/list
https://my-mcp.workers.dev/tools/call
https://my-mcp.workers.dev/resources/list基础路径会自动添加到所有MCP端点前。
Request/Response Lifecycle
请求/响应生命周期
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/callIf client connects to (missing ):
https://my-mcp.workers.dev/ssepathname === "/" → Check fails → 404 Not Found1. 客户端连接到:https://my-mcp.workers.dev/sse
↓
2. Worker接收请求:{ url: "https://my-mcp.workers.dev/sse", ... }
↓
3. 你的fetch处理器:const { pathname } = new URL(request.url)
↓
4. pathname === "/sse" → 检查通过
↓
5. MyMCP.serveSSE("/sse").fetch() → MCP服务器处理请求
↓
6. 工具调用路由到:/sse/tools/call如果客户端连接到(缺少):
https://my-mcp.workers.dev/ssepathname === "/" → 检查失败 → 404 Not FoundTesting Your URL Configuration
测试你的URL配置
Step 1: Deploy your MCP server
bash
npx wrangler deploy步骤1:部署你的MCP服务器
bash
npx wrangler deployOutput: Deployed to https://my-mcp.YOUR_ACCOUNT.workers.dev
输出:Deployed to https://my-mcp.YOUR_ACCOUNT.workers.dev
**Step 2: Test the base path with curl**
```bash
**步骤2:使用curl测试基础路径**
```bashIf serving at /sse, test this URL:
如果在/sse路径提供服务,测试此URL:
Should return MCP server info (not 404)
应返回MCP服务器信息(而非404)
**Step 3: Update client config with the EXACT URL you tested**
```json
{
"mcpServers": {
"my-mcp": {
"url": "https://my-mcp.YOUR_ACCOUNT.workers.dev/sse" // Match curl URL
}
}
}Step 4: Restart Claude Desktop
**步骤3:使用你测试过的精确URL更新客户端配置**
```json
{
"mcpServers": {
"my-mcp": {
"url": "https://my-mcp.YOUR_ACCOUNT.workers.dev/sse" // 匹配curl URL
}
}
}步骤4:重启Claude Desktop
Post-Deployment Checklist
部署后检查清单
After deploying, verify:
- returns MCP server info (not 404)
curl https://worker.dev/sse - Client config URL matches deployed URL exactly
- No typos in URL (common: instead of
workes.dev)workers.dev - Using (not
https://) for deployed Workershttp:// - If using OAuth, redirect URI also updated
部署后,请验证:
- 返回MCP服务器信息(而非404)
curl https://worker.dev/sse - 客户端配置URL与部署的URL完全匹配
- URL中无拼写错误(常见错误:而非
workes.dev)workers.dev - 使用(而非
https://)访问已部署的Workershttp:// - 如果使用OAuth,重定向URI也已更新
Transport Selection Guide
传输协议选择指南
MCP supports two transport methods: SSE (legacy) and Streamable HTTP (2025 standard).
MCP支持两种传输方式:SSE(传统)和Streamable HTTP(2025标准)。
SSE (Server-Sent Events)
SSE(Server-Sent Events)
Best for: Wide client compatibility (2024 clients), legacy support
Serving:
typescript
MyMCP.serveSSE("/sse").fetch(request, env, ctx)Client config:
json
{
"url": "https://my-mcp.workers.dev/sse"
}Pros:
- ✅ Supported by all MCP clients (2024+)
- ✅ Easy debugging (plain HTTP)
- ✅ Works with MCP Inspector
Cons:
- ❌ Less efficient than HTTP streaming
- ❌ Being deprecated in 2025
最适合:广泛的客户端兼容性(2024版客户端)、传统支持
服务端代码:
typescript
MyMCP.serveSSE("/sse").fetch(request, env, ctx)客户端配置:
json
{
"url": "https://my-mcp.workers.dev/sse"
}优点:
- ✅ 所有MCP客户端均支持(2024+)
- ✅ 易于调试(纯HTTP)
- ✅ 可与MCP Inspector配合使用
缺点:
- ❌ 效率低于HTTP流
- ❌ 2025年将被弃用
Streamable HTTP
Streamable HTTP
Best for: Modern clients (2025+), better performance
Serving:
typescript
MyMCP.serve("/mcp").fetch(request, env, ctx)Client config:
json
{
"url": "https://my-mcp.workers.dev/mcp"
}Pros:
- ✅ More efficient than SSE
- ✅ 2025 standard
- ✅ Better streaming support
Cons:
- ❌ Newer clients only
- ❌ Less mature tooling
最适合:现代客户端(2025+)、更好的性能
服务端代码:
typescript
MyMCP.serve("/mcp").fetch(request, env, ctx)客户端配置:
json
{
"url": "https://my-mcp.workers.dev/mcp"
}优点:
- ✅ 比SSE更高效
- ✅ 2025标准
- ✅ 更好的流支持
缺点:
- ❌ 仅支持较新的客户端
- ❌ 工具链不够成熟
Support Both (Recommended)
同时支持两种(推荐)
Serve both transports for maximum compatibility:
typescript
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 });
}
};Why this works:
- SSE clients connect to
/sse - HTTP clients connect to
/mcp - Health checks available at or
//health - No transport conflicts
CRITICAL: Use to match paths correctly!
pathname.startsWith()同时提供两种传输协议以实现最大兼容性:
typescript
export default {
fetch(request: Request, env: Env, ctx: ExecutionContext) {
const { pathname } = new URL(request.url);
// SSE传输(传统)
if (pathname.startsWith("/sse")) {
return MyMCP.serveSSE("/sse").fetch(request, env, ctx);
}
// HTTP传输(2025标准)
if (pathname.startsWith("/mcp")) {
return MyMCP.serve("/mcp").fetch(request, env, ctx);
}
// 健康检查端点(可选但推荐)
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()Quick Start (5 Minutes)
快速启动(5分钟)
Now that you understand URL configuration, let's build your first MCP server.
现在你已经了解了URL配置,让我们构建你的第一个MCP服务器。
Option 1: Copy Minimal Template
选项1:复制极简模板
Use the template - the simplest working example.
mcp-http-fundamentals.tsbash
undefined使用模板——最简单的可运行示例。
mcp-http-fundamentals.tsbash
undefinedCopy minimal template
复制极简模板
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-http-fundamentals.ts src/index.ts
cp ~/.claude/skills/cloudflare-mcp-server/templates/mcp-http-fundamentals.ts src/index.ts
Install dependencies
安装依赖
npm install
npm install
Start dev server
启动开发服务器
npm run dev
npm run dev
Test connection
测试连接
Should return: {"name":"My MCP Server","version":"1.0.0",...}
应返回:{"name":"My MCP Server","version":"1.0.0",...}
undefinedundefinedOption 2: Deploy from Cloudflare Template
选项2:从Cloudflare模板部署
bash
undefinedbash
undefinedCreate new MCP server from official template
从官方模板创建新的MCP服务器
npm create cloudflare@latest -- my-mcp-server
--template=cloudflare/ai/demos/remote-mcp-authless
--template=cloudflare/ai/demos/remote-mcp-authless
cd my-mcp-server
npm install
npm run dev
Your MCP server is now running at `http://localhost:8788/sse`npm create cloudflare@latest -- my-mcp-server
--template=cloudflare/ai/demos/remote-mcp-authless
--template=cloudflare/ai/demos/remote-mcp-authless
cd my-mcp-server
npm install
npm run dev
你的MCP服务器现在运行在`http://localhost:8788/sse`Test with MCP Inspector
使用MCP Inspector测试
bash
undefinedbash
undefinedIn a new terminal
在新终端中
npx @modelcontextprotocol/inspector@latest
npx @modelcontextprotocol/inspector@latest
Click "Connect" and test tools
点击“Connect”并测试工具
undefinedundefinedDeploy to Cloudflare
部署到Cloudflare
bash
undefinedbash
undefinedDeploy
部署
npx wrangler deploy
npx wrangler deploy
Output shows your URL:
输出显示你的URL:
⚠️ REMEMBER: Update client config with this URL + /sse!
⚠️ 记住:使用此URL + /sse更新客户端配置!
---
---Core Concepts
核心概念
1. McpAgent Class
1. McpAgent类
The base class from Cloudflare's Agents SDK provides:
McpAgent- Automatic Durable Objects integration
- Built-in state management with SQL database
- Tool, resource, and prompt registration
- Transport handling (SSE + HTTP)
Basic pattern:
typescript
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" }]
})
);
}
}来自Cloudflare Agents SDK的基类提供:
McpAgent- 自动Durable Objects集成
- 内置SQL数据库状态管理
- 工具、资源和提示词注册
- 传输协议处理(SSE + HTTP)
基础模式:
typescript
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() {
// 在此注册工具
this.server.tool(
"tool_name",
"Tool description",
{ param: z.string() },
async ({ param }) => ({
content: [{ type: "text", text: "Result" }]
})
);
}
}2. Tool Definitions
2. 工具定义
Tools are functions that MCP clients can invoke. Use Zod for parameter validation.
Pattern:
typescript
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" }]
};
}
);Best practices:
- Detailed descriptions: Help LLMs understand tool purpose
- Parameter descriptions: Explain expected values and constraints
- Error handling: Return for failures
{ isError: true } - Few, focused tools: Better than many granular ones
工具是MCP客户端可以调用的函数。使用Zod进行参数验证。
模式:
typescript
this.server.tool(
"tool_name", // 工具标识符
"Tool description", // 工具用途(供LLM使用)
{ // 参数(Zod schema)
param1: z.string().describe("Parameter description"),
param2: z.number().optional()
},
async ({ param1, param2 }) => { // 处理器
// 你的逻辑
return {
content: [{ type: "text", text: "Result" }]
};
}
);最佳实践:
- 详细描述:帮助LLM理解工具用途
- 参数描述:解释预期值和约束
- 错误处理:失败时返回
{ isError: true } - 少而精的工具:比多个粒度细的工具更好
Authentication Patterns
身份验证模式
Cloudflare MCP servers support 4 authentication patterns:
Cloudflare MCP服务器支持4种身份验证模式:
Pattern 1: No Authentication
模式1:无身份验证
Use case: Internal tools, development, public APIs
Template:
templates/mcp-http-fundamentals.tsSetup: None required
Security: ⚠️ Anyone can access your MCP server
使用场景:内部工具、开发、公开API
模板:
templates/mcp-http-fundamentals.ts设置:无需任何设置
安全性:⚠️ 任何人都可以访问你的MCP服务器
Pattern 2: Token Validation (JWTVerifier)
模式2:令牌验证(JWTVerifier)
Use case: Pre-authenticated clients, custom auth systems
How it works: Client sends Bearer token, server validates
Template: Create custom JWTVerifier middleware
Setup:
typescript
import { JWTVerifier } from "agents/mcp";
const verifier = new JWTVerifier({
secret: env.JWT_SECRET,
issuer: "your-auth-server"
});
// Validate token before serving MCP requestsSecurity: ✅ Secure if tokens are properly managed
使用场景:预认证客户端、自定义认证系统
工作原理:客户端发送Bearer令牌,服务器验证
模板:创建自定义JWTVerifier中间件
设置:
typescript
import { JWTVerifier } from "agents/mcp";
const verifier = new JWTVerifier({
secret: env.JWT_SECRET,
issuer: "your-auth-server"
});
// 在处理MCP请求前验证令牌安全性:✅ 如果令牌管理得当则安全
Pattern 3: OAuth Proxy (workers-oauth-provider)
模式3:OAuth代理(workers-oauth-provider)
Use case: GitHub, Google, Azure OAuth integration
How it works: Cloudflare Worker proxies OAuth to third-party provider
Template:
templates/mcp-oauth-proxy.tsSetup:
typescript
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
});Required bindings:
jsonc
{
"kv_namespaces": [
{ "binding": "OAUTH_KV", "id": "YOUR_KV_ID" }
]
}⚠️ CRITICAL OAuth URL Configuration: When using OAuth, your redirect URIs MUST match:
json
{
"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"
}
}
}
}All URLs must use the same domain and protocol (https://).
Security: ✅✅ Secure, production-ready
使用场景:GitHub、Google、Azure OAuth集成
工作原理:Cloudflare Worker将OAuth请求代理到第三方提供商
模板:
templates/mcp-oauth-proxy.ts设置:
typescript
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) => {
// 从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
});必需的绑定:
jsonc
{
"kv_namespaces": [
{ "binding": "OAUTH_KV", "id": "YOUR_KV_ID" }
]
}⚠️ 重要OAuth URL配置:使用OAuth时,你的重定向URI必须匹配:
json
{
"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://)。
安全性:✅✅ 安全、生产就绪
Pattern 4: Remote OAuth with DCR
模式4:带DCR的远程OAuth
Use case: Full OAuth provider, custom consent screens
How it works: Your Worker is the OAuth provider
Template: See Cloudflare's demo
remote-mcp-authkitSetup: Complex, requires full OAuth 2.1 implementation
Security: ✅✅✅ Most secure, full control
使用场景:完整的OAuth提供商、自定义同意屏幕
工作原理:你的Worker作为OAuth提供商
模板:请查看Cloudflare的演示
remote-mcp-authkit设置:复杂,需要完整的OAuth 2.1实现
安全性:✅✅✅ 最安全,完全可控
Stateful MCP Servers with Durable Objects
使用Durable Objects的有状态MCP服务器
Use Durable Objects when your MCP server needs:
- Per-session persistent state
- Conversation history
- Game state (chess, tic-tac-toe)
- Cached API responses
- User preferences
当你的MCP服务器需要以下功能时,使用Durable Objects:
- 会话级持久状态
- 对话历史
- 游戏状态(国际象棋、井字棋)
- 缓存API响应
- 用户偏好
Storage API Pattern
存储API模式
Template:
templates/mcp-stateful-do.tsStore values:
typescript
await this.state.storage.put("key", "value");
await this.state.storage.put("user_prefs", { theme: "dark" });Retrieve values:
typescript
const value = await this.state.storage.get<string>("key");
const prefs = await this.state.storage.get<object>("user_prefs");List keys:
typescript
const allKeys = await this.state.storage.list();Delete keys:
typescript
await this.state.storage.delete("key");模板:
templates/mcp-stateful-do.ts存储值:
typescript
await this.state.storage.put("key", "value");
await this.state.storage.put("user_prefs", { theme: "dark" });检索值:
typescript
const value = await this.state.storage.get<string>("key");
const prefs = await this.state.storage.get<object>("user_prefs");列出键:
typescript
const allKeys = await this.state.storage.list();删除键:
typescript
await this.state.storage.delete("key");Configuration
配置
wrangler.jsonc:
jsonc
{
"durable_objects": {
"bindings": [
{
"name": "MY_MCP",
"class_name": "MyMCP",
"script_name": "my-mcp-server"
}
]
},
"migrations": [
{ "tag": "v1", "new_classes": ["MyMCP"] }
]
}IMPORTANT: Migrations are required on first deployment!
wrangler.jsonc:
jsonc
{
"durable_objects": {
"bindings": [
{
"name": "MY_MCP",
"class_name": "MyMCP",
"script_name": "my-mcp-server"
}
]
},
"migrations": [
{ "tag": "v1", "new_classes": ["MyMCP"] }
]
}重要:首次部署时需要迁移!
WebSocket Hibernation for Cost Optimization
用于成本优化的WebSocket休眠
Problem: Long-lived WebSocket connections cost CPU time
Solution: WebSocket Hibernation API suspends connections when idle
问题:长连接的WebSocket会消耗CPU时间
解决方案:WebSocket休眠API在空闲时暂停连接
Pattern
模式
Serialize metadata (preserves data during hibernation):
typescript
webSocket.serializeAttachment({
userId: "123",
sessionId: "abc",
connectedAt: Date.now()
});Retrieve on wake:
typescript
const metadata = webSocket.deserializeAttachment();
console.log(metadata.userId); // "123"Storage for persistent state:
typescript
// ❌ DON'T: In-memory state lost on hibernation
this.userId = "123";
// ✅ DO: Use storage API
await this.state.storage.put("userId", "123");序列化元数据(在休眠期间保留数据):
typescript
webSocket.serializeAttachment({
userId: "123",
sessionId: "abc",
connectedAt: Date.now()
});唤醒时检索:
typescript
const metadata = webSocket.deserializeAttachment();
console.log(metadata.userId); // "123"用于持久状态的存储:
typescript
// ❌ 不要这样做:休眠时内存状态会丢失
this.userId = "123";
// ✅ 正确做法:通过休眠保留状态
await this.state.storage.put("userId", "123");Cost Savings
成本节约
Without hibernation:
- 1000 concurrent WebSockets × 10ms CPU/sec = 10 CPU-sec/sec
- Cost: ~$0.50/day
With hibernation:
- CPU only on messages (99% idle time suspended)
- Cost: ~$0.01/day (50x reduction!)
不使用休眠:
- 1000个并发WebSocket × 10ms CPU/秒 = 10 CPU-秒/秒
- 成本:约0.50美元/天
使用休眠:
- 仅在有消息时使用CPU(99%的空闲时间被暂停)
- 成本:约0.01美元/天(减少50倍!)
Common Patterns
常见模式
API Proxy MCP Server
API代理MCP服务器
Use case: Wrap external API with MCP tools
Pattern:
typescript
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
}]
};
}
);使用场景:用MCP工具包装外部API
模式:
typescript
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
}]
};
}
);Database-Backed Tools
数据库驱动的工具
Use case: Query D1, KV, or external databases
Pattern:
typescript
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)
}]
};
}
);使用场景:查询D1、KV或外部数据库
模式:
typescript
this.server.tool(
"get_user",
"Get user details from database",
{ userId: z.string() },
async ({ userId }) => {
// 查询Durable Objects存储
const user = await this.state.storage.get<User>(`user:${userId}`);
// 或查询D1数据库
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)
}]
};
}
);Multi-Tool Coordination
多工具协作
Use case: Tools that call other tools
Pattern:
typescript
// 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");使用场景:调用其他工具的工具
模式:
typescript
// 存储第一个工具的结果
await this.state.storage.put("last_search", result);
// 第二个工具读取它
const lastSearch = await this.state.storage.get("last_search");Caching Strategy
缓存策略
Use case: Cache expensive API calls
Pattern:
typescript
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 }]
};
}
);使用场景:缓存昂贵的API调用
模式:
typescript
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);
// 检查缓存新鲜度
if (cached && Date.now() - cached.timestamp < 5 * 60 * 1000) {
return {
content: [{ type: "text", text: cached.data }]
};
}
// 获取新鲜数据
const weather = await fetchWeatherAPI(city);
// 缓存数据
await this.state.storage.put(cacheKey, {
data: weather,
timestamp: Date.now()
});
return {
content: [{ type: "text", text: weather }]
};
}
);Rate Limiting with Durable Objects
使用Durable Objects进行速率限制
Use case: Prevent abuse, respect upstream rate limits
Pattern:
typescript
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
};
}使用场景:防止滥用、遵守上游速率限制
模式:
typescript
async rateLimit(key: string, maxRequests: number, windowMs: number): Promise<boolean> {
const now = Date.now();
const requests = await this.state.storage.get<number[]>(`ratelimit:${key}`) || [];
// 删除窗口外的旧请求
const recentRequests = requests.filter(ts => now - ts < windowMs);
if (recentRequests.length >= maxRequests) {
return false; // 被速率限制
}
// 添加此请求
recentRequests.push(now);
await this.state.storage.put(`ratelimit:${key}`, recentRequests);
return true; // 允许访问
}
// 在工具中使用
if (!await this.rateLimit(userId, 10, 60 * 1000)) {
return {
content: [{ type: "text", text: "Rate limit exceeded (10 requests/minute)" }],
isError: true
};
}22 Known Errors (With Solutions)
22种已知错误(含解决方案)
1. McpAgent Class Not Exported
1. McpAgent类未导出
Error:
TypeError: Cannot read properties of undefined (reading 'serve')Cause: Forgot to export McpAgent class
Solution:
typescript
export class MyMCP extends McpAgent { ... } // ✅ Must export
export default { fetch() { ... } }错误:
TypeError: Cannot read properties of undefined (reading 'serve')原因:忘记导出McpAgent类
解决方案:
typescript
export class MyMCP extends McpAgent { ... } // ✅ 必须导出
export default { fetch() { ... } }2. Base Path Configuration Mismatch (Most Common!)
2. 基础路径配置不匹配(最常见!)
Error: or
404 Not FoundConnection failedCause: but client configured with (missing )
serveSSE("/sse")https://worker.dev/sseSolution: Match base paths exactly
typescript
// Server serves at /sse
MyMCP.serveSSE("/sse").fetch(...)
// Client MUST include /sse
{ "url": "https://worker.dev/sse" } // ✅ Correct
{ "url": "https://worker.dev" } // ❌ Wrong - 404Debug steps:
- Check what path your server uses: vs
serveSSE("/sse")serveSSE("/") - Test with curl:
curl https://worker.dev/sse - Update client config to match curl URL
错误:或
404 Not FoundConnection failed原因:但客户端配置为(缺少)
serveSSE("/sse")https://worker.dev/sse解决方案:完全匹配基础路径
typescript
// 服务器在/sse路径提供服务
MyMCP.serveSSE("/sse").fetch(...)
// 客户端必须包含/sse
{ "url": "https://worker.dev/sse" } // ✅ 正确
{ "url": "https://worker.dev" } // ❌ 错误 - 404调试步骤:
- 检查服务器使用的路径:vs
serveSSE("/sse")serveSSE("/") - 使用curl测试:
curl https://worker.dev/sse - 更新客户端配置以匹配curl URL
3. Transport Type Confusion
3. 传输协议类型混淆
Error:
Connection failed: Unexpected response formatCause: Client expects SSE but connects to HTTP endpoint (or vice versa)
Solution: Match transport types
typescript
// SSE transport
MyMCP.serveSSE("/sse") // Client URL: https://worker.dev/sse
// HTTP transport
MyMCP.serve("/mcp") // Client URL: https://worker.dev/mcpBest practice: Support both transports (see Transport Selection Guide)
错误:
Connection failed: Unexpected response format原因:客户端期望SSE但连接到HTTP端点(反之亦然)
解决方案:匹配传输协议类型
typescript
// SSE传输
MyMCP.serveSSE("/sse") // 客户端URL: https://worker.dev/sse
// HTTP传输
MyMCP.serve("/mcp") // 客户端URL: https://worker.dev/mcp最佳实践:支持两种传输协议(见传输协议选择指南)
4. pathname.startsWith() Logic Error
4. pathname.startsWith()逻辑错误
Error: Both and routes fail or conflict
/sse/mcpCause: Incorrect path matching logic
Solution: Use correctly
startsWith()typescript
// ✅ 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(...);
}错误:和路由均失败或冲突
/sse/mcp原因:路径匹配逻辑不正确
解决方案:正确使用
startsWith()typescript
// ✅ 正确
if (pathname.startsWith("/sse")) {
return MyMCP.serveSSE("/sse").fetch(...);
}
if (pathname.startsWith("/mcp")) {
return MyMCP.serve("/mcp").fetch(...);
}
// ❌ 错误:精确匹配会破坏子路径
if (pathname === "/sse") { // 破坏/sse/tools/list
return MyMCP.serveSSE("/sse").fetch(...);
}5. Local vs Deployed URL Mismatch
5. 本地与部署URL不匹配
Error: Works in dev, fails after deployment
Cause: Client still configured with localhost URL
Solution: Update client config after deployment
json
// Development
{ "url": "http://localhost:8788/sse" }
// ⚠️ MUST UPDATE after npx wrangler deploy
{ "url": "https://my-mcp.YOUR_ACCOUNT.workers.dev/sse" }Post-deployment checklist:
- Run and note output URL
npx wrangler deploy - Update client config with deployed URL
- Test with curl
- Restart Claude Desktop
错误:开发环境正常,部署后失败
原因:客户端仍配置为localhost URL
解决方案:部署后更新客户端配置
json
// 开发环境
{ "url": "http://localhost:8788/sse" }
// ⚠️ 运行npx wrangler deploy后必须更新
{ "url": "https://my-mcp.YOUR_ACCOUNT.workers.dev/sse" }部署后检查清单:
- 运行并记录输出URL
npx wrangler deploy - 使用部署的URL更新客户端配置
- 使用curl测试
- 重启Claude Desktop
6. OAuth Redirect URI Mismatch
6. OAuth重定向URI不匹配
Error:
OAuth error: redirect_uri does not matchCause: OAuth redirect URI doesn't match deployed URL
Solution: Update ALL OAuth URLs after deployment
json
{
"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"
}
}CRITICAL: All URLs must use the same protocol and domain!
错误:
OAuth error: redirect_uri does not match原因:OAuth重定向URI与部署的URL不匹配
解决方案:部署后更新所有OAuth URL
json
{
"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必须使用相同的协议和域名!
7. Missing OPTIONS Handler (CORS Preflight)
7. 缺少OPTIONS处理器(CORS预检)
Error: or
Access to fetch at '...' blocked by CORS policyMethod Not AllowedCause: Browser clients send OPTIONS requests for CORS preflight, but server doesn't handle them
Solution: Add OPTIONS handler
typescript
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
}
};When needed: Browser-based MCP clients (like MCP Inspector in browser)
错误:或
Access to fetch at '...' blocked by CORS policyMethod Not Allowed原因:浏览器客户端发送OPTIONS请求进行CORS预检,但服务器未处理
解决方案:添加OPTIONS处理器
typescript
export default {
fetch(request: Request, env: Env, ctx: ExecutionContext) {
// 处理CORS预检
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"
}
});
}
// ... 你的fetch处理器剩余部分
}
};何时需要:基于浏览器的MCP客户端(如浏览器版MCP Inspector)
8. Request Body Validation Missing
8. 缺少请求体验证
Error: or in JSON parsing
TypeError: Cannot read properties of undefinedUnexpected tokenCause: Client sends malformed JSON, server doesn't validate before parsing
Solution: Wrap request handling in try/catch
typescript
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" }
}
);
}
}
};错误:或JSON解析中的
TypeError: Cannot read properties of undefinedUnexpected token原因:客户端发送格式错误的JSON,服务器在解析前未验证
解决方案:将请求处理包装在try/catch中
typescript
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
try {
// 你的MCP服务器逻辑
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. Environment Variable Validation Missing
9. 缺少环境变量验证
Error: or silent failures (tools return empty data)
TypeError: env.API_KEY is undefinedCause: Required environment variables not configured or missing at runtime
Solution: Add startup validation
typescript
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(...);
}
}Configuration checklist:
- Development: Add to (local only, gitignored)
.dev.vars - Production: Add to
wrangler.jsonc(public) or usevars(sensitive)wrangler secret
Best practices:
bash
undefined错误:或静默失败(工具返回空数据)
TypeError: env.API_KEY is undefined原因:必需的环境变量未配置或运行时缺失
解决方案:添加启动验证
typescript
export class MyMCP extends McpAgent<Env> {
async init() {
// 验证必需的环境变量
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");
}
// 继续注册工具
this.server.tool(...);
}
}配置检查清单:
- 开发环境:添加到(仅本地,已加入git忽略)
.dev.vars - 生产环境:添加到的
wrangler.jsonc(公开)或使用vars(敏感信息)wrangler secret
最佳实践:
bash
undefined.dev.vars (local development, gitignored)
.dev.vars(本地开发,git忽略)
API_KEY=dev-key-123
DATABASE_URL=http://localhost:3000
API_KEY=dev-key-123
DATABASE_URL=http://localhost:3000
wrangler.jsonc (public config)
wrangler.jsonc(公开配置)
{
"vars": {
"ENVIRONMENT": "production",
"LOG_LEVEL": "info"
}
}
{
"vars": {
"ENVIRONMENT": "production",
"LOG_LEVEL": "info"
}
}
wrangler secret (production secrets)
wrangler secret(生产环境敏感信息)
npx wrangler secret put API_KEY
npx wrangler secret put DATABASE_URL
---npx wrangler secret put API_KEY
npx wrangler secret put DATABASE_URL
---10. McpAgent vs McpServer Confusion
10. McpAgent与McpServer混淆
Error: or
TypeError: server.registerTool is not a functionthis.server is undefinedCause: Trying to use standalone SDK patterns with McpAgent class
Solution: Use McpAgent's pattern
this.server.tool()typescript
// ❌ 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
}
}Key difference: McpAgent provides property, standalone SDK doesn't.
this.server错误:或
TypeError: server.registerTool is not a functionthis.server is undefined原因:尝试将独立SDK模式与McpAgent类一起使用
解决方案:使用McpAgent的模式
this.server.tool()typescript
// ❌ 错误:将独立SDK与McpAgent混合使用
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({ name: "My Server" });
server.registerTool(...); // 与McpAgent不兼容!
export class MyMCP extends McpAgent { /* 无server属性 */ }
// ✅ 正确:McpAgent模式
export class MyMCP extends McpAgent<Env> {
server = new McpServer({
name: "My MCP Server",
version: "1.0.0"
});
async init() {
this.server.tool("tool_name", ...); // 使用this.server
}
}关键区别:McpAgent提供属性,独立SDK不提供。
this.server11. WebSocket Hibernation State Loss
11. WebSocket休眠状态丢失
Error: Tool calls fail after reconnect with "state not found"
Cause: In-memory state cleared on hibernation
Solution: Use instead of instance properties
this.state.storagetypescript
// ❌ DON'T: Lost on hibernation
this.userId = "123";
// ✅ DO: Persists through hibernation
await this.state.storage.put("userId", "123");错误:重新连接后工具调用失败,提示"state not found"
原因:内存状态在休眠时被清除
解决方案:使用而非实例属性
this.state.storagetypescript
// ❌ 不要这样做:休眠时会丢失
this.userId = "123";
// ✅ 正确做法:通过休眠保留状态
await this.state.storage.put("userId", "123");12. Durable Objects Binding Missing
12. 缺少Durable Objects绑定
Error:
TypeError: Cannot read properties of undefined (reading 'idFromName')Cause: Forgot DO binding in wrangler.jsonc
Solution: Add binding (see Stateful MCP Servers section)
jsonc
{
"durable_objects": {
"bindings": [
{
"name": "MY_MCP",
"class_name": "MyMCP",
"script_name": "my-mcp-server"
}
]
}
}错误:
TypeError: Cannot read properties of undefined (reading 'idFromName')原因:在wrangler.jsonc中忘记DO绑定
解决方案:添加绑定(见有状态MCP服务器部分)
jsonc
{
"durable_objects": {
"bindings": [
{
"name": "MY_MCP",
"class_name": "MyMCP",
"script_name": "my-mcp-server"
}
]
}
}13. Migration Not Defined
13. 未定义迁移
Error:
Error: Durable Object class MyMCP has no migration definedCause: First DO deployment requires migration
Solution:
jsonc
{
"migrations": [
{ "tag": "v1", "new_classes": ["MyMCP"] }
]
}错误:
Error: Durable Object class MyMCP has no migration defined原因:首次DO部署需要迁移
解决方案:
jsonc
{
"migrations": [
{ "tag": "v1", "new_classes": ["MyMCP"] }
]
}14. serializeAttachment() Not Used
14. 未使用serializeAttachment()
Error: WebSocket metadata lost on hibernation wake
Cause: Not using to preserve connection metadata
serializeAttachment()Solution: See WebSocket Hibernation section
错误:WebSocket休眠唤醒后元数据丢失
原因:未使用保留连接元数据
serializeAttachment()解决方案:请查看WebSocket休眠部分
15. OAuth Consent Screen Disabled
15. OAuth同意屏幕已禁用
Security risk: Users don't see what permissions they're granting
Cause: in production
allowConsentScreen: falseSolution: Always enable in production
typescript
export default new OAuthProvider({
allowConsentScreen: true, // ✅ Always true in production
// ...
});安全风险:用户看不到他们授予的权限
原因:生产环境中
allowConsentScreen: false解决方案:生产环境中始终启用
typescript
export default new OAuthProvider({
allowConsentScreen: true, // ✅ 生产环境中始终为true
// ...
});16. JWT Signing Key Missing
16. 缺少JWT签名密钥
Error:
Error: JWT_SIGNING_KEY environment variable not setCause: OAuth Provider requires signing key for tokens
Solution:
bash
undefined错误:
Error: JWT_SIGNING_KEY environment variable not set原因:OAuth Provider需要签名密钥来生成令牌
解决方案:
bash
undefinedGenerate secure key
生成安全密钥
openssl rand -base64 32
openssl rand -base64 32
Add to wrangler secret
添加到wrangler secret
npx wrangler secret put JWT_SIGNING_KEY
---npx wrangler secret put JWT_SIGNING_KEY
---17. Tool Schema Validation Error
17. 工具Schema验证错误
Error:
ZodError: Invalid input typeCause: Client sends string, schema expects number (or vice versa)
Solution: Use Zod transforms
typescript
// 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
)错误:
ZodError: Invalid input type原因:客户端发送字符串,但Schema期望数字(反之亦然)
解决方案:使用Zod转换
typescript
// 接受字符串,转换为数字
param: z.string().transform(val => parseInt(val, 10))
// 或者:接受两种类型
param: z.union([z.string(), z.number()]).transform(val =>
typeof val === "string" ? parseInt(val, 10) : val
)18. Multiple Transport Endpoints Conflicting
18. 多个传输端点冲突
Error: returns 404 after adding
/sse/mcpCause: Incorrect path matching (missing )
startsWith()Solution: Use or exact matches correctly (see Error #4)
startsWith()错误:添加后返回404
/mcp/sse原因:路径匹配不正确(缺少)
startsWith()解决方案:正确使用或精确匹配(见错误#4)
startsWith()19. Local Testing with Miniflare Limitations
19. 使用Miniflare进行本地测试的限制
Error: OAuth flow fails in local dev, or Durable Objects behave differently
Cause: Miniflare doesn't support all DO features
Solution: Use for full DO support
npx wrangler dev --remotebash
undefined错误:本地开发中OAuth流程失败,或Durable Objects行为不同
原因:Miniflare不支持所有DO功能
解决方案:使用获得完整DO支持
npx wrangler dev --remotebash
undefinedLocal simulation (faster but limited)
本地模拟(更快但有限制)
npm run dev
npm run dev
Remote DOs (slower but accurate)
远程DO(较慢但准确)
npx wrangler dev --remote
---npx wrangler dev --remote
---20. Client Configuration Format Error
20. 客户端配置格式错误
Error: Claude Desktop doesn't recognize server
Cause: Wrong JSON format in
claude_desktop_config.jsonSolution: See "Connect Claude Desktop" section for correct format
Common mistakes:
json
// ❌ 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"
}
}
}错误:Claude Desktop无法识别服务器
原因:中的JSON格式错误
claude_desktop_config.json解决方案:请查看“连接Claude Desktop”部分获取正确格式
常见错误:
json
// ❌ 错误:缺少"mcpServers"包装
{
"my-mcp": {
"url": "https://worker.dev/sse"
}
}
// ❌ 错误:尾随逗号
{
"mcpServers": {
"my-mcp": {
"url": "https://worker.dev/sse", // ← 删除逗号
}
}
}
// ✅ 正确
{
"mcpServers": {
"my-mcp": {
"url": "https://worker.dev/sse"
}
}
}21. Health Check Endpoint Missing
21. 缺少健康检查端点
Issue: Can't tell if Worker is running or if URL is correct
Impact: Debugging connection issues takes longer
Solution: Add health check endpoint (see Transport Selection Guide)
Test:
bash
curl https://my-mcp.workers.dev/health问题:无法判断Worker是否在运行或URL是否正确
影响:调试连接问题耗时更长
解决方案:添加健康检查端点(见传输协议选择指南)
测试:
bash
curl https://my-mcp.workers.dev/healthShould return: {"status":"ok","transports":{...}}
应返回:{"status":"ok","transports":{...}}
---
---22. CORS Headers Missing
22. 缺少CORS头
Error:
Access to fetch at '...' blocked by CORS policyCause: MCP server doesn't return CORS headers for cross-origin requests
Solution: Add CORS headers to all responses
typescript
// 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"
}
});Note: OAuthProvider handles CORS automatically!
错误:
Access to fetch at '...' blocked by CORS policy原因:MCP服务器未为跨域请求返回CORS头
解决方案:为所有响应添加CORS头
typescript
// 手动CORS(如果不使用OAuthProvider)
const corsHeaders = {
"Access-Control-Allow-Origin": "*", // 或特定源
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization"
};
// 添加到响应
return new Response(body, {
headers: {
...corsHeaders,
"Content-Type": "application/json"
}
});注意:OAuthProvider会自动处理CORS!
Deployment & Testing
部署与测试
Local Development
本地开发
bash
undefinedbash
undefinedStart dev server (uses Miniflare for local DOs)
启动开发服务器(使用Miniflare进行本地DO模拟)
npm run dev
npm run dev
Start dev server with remote Durable Objects (more accurate)
启动带有远程Durable Objects的开发服务器(更准确)
npx wrangler dev --remote
**Access at**: `http://localhost:8788/sse`npx wrangler dev --remote
**访问地址**:`http://localhost:8788/sse`Test with MCP Inspector
使用MCP Inspector测试
bash
npx @modelcontextprotocol/inspector@latest- Open
http://localhost:5173 - Enter MCP server URL
- Click "Connect"
- Use "List Tools" to see available tools
- Test tool calls with parameters
bash
npx @modelcontextprotocol/inspector@latest- 打开
http://localhost:5173 - 输入MCP服务器URL
- 点击“Connect”
- 使用“List Tools”查看可用工具
- 使用参数测试工具调用
Deploy to Cloudflare
部署到Cloudflare
bash
undefinedbash
undefinedFirst time: Login
首次使用:登录
npx wrangler login
npx wrangler login
Deploy
部署
npx wrangler deploy
npx wrangler deploy
Output shows your deployed URL:
输出显示你的部署URL:
⚠️ CRITICAL: Update client config with this URL!
⚠️ 重要:使用此URL更新客户端配置!
Check deployment logs
检查部署日志
npx wrangler tail
undefinednpx wrangler tail
undefinedConnect Claude Desktop
连接Claude Desktop
~/.config/claude/claude_desktop_config.json (Linux/Mac):
json
{
"mcpServers": {
"my-mcp": {
"url": "https://my-mcp-server.YOUR_ACCOUNT.workers.dev/sse"
}
}
}%APPDATA%/Claude/claude_desktop_config.json (Windows)
With OAuth:
json
{
"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"
}
}
}
}⚠️ REMEMBER: Restart Claude Desktop after config changes!
~/.config/claude/claude_desktop_config.json(Linux/Mac):
json
{
"mcpServers": {
"my-mcp": {
"url": "https://my-mcp-server.YOUR_ACCOUNT.workers.dev/sse"
}
}
}%APPDATA%/Claude/claude_desktop_config.json(Windows)
带OAuth:
json
{
"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!
Configuration Reference
配置参考
Complete wrangler.jsonc (All Features)
完整的wrangler.jsonc(包含所有功能)
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
}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
}Complete package.json
完整的package.json
See
templates/package.json请查看
templates/package.jsonComplete claude_desktop_config.json
完整的claude_desktop_config.json
See
templates/claude_desktop_config.json请查看
templates/claude_desktop_config.jsonWorker & Durable Objects Basics
Worker与Durable Objects基础
Self-contained section for standalone use
独立使用的自包含部分
Worker Export Pattern
Worker导出模式
Workers must export a handler:
fetchtypescript
export default {
fetch(request: Request, env: Env, ctx: ExecutionContext): Response | Promise<Response> {
// Handle request
return new Response("Hello");
}
};Workers必须导出处理器:
fetchtypescript
export default {
fetch(request: Request, env: Env, ctx: ExecutionContext): Response | Promise<Response> {
// 处理请求
return new Response("Hello");
}
};Durable Objects Class Structure
Durable Objects类结构
DOs extend McpAgent (for MCP servers):
typescript
export class MyMCP extends McpAgent<Env> {
constructor(state: DurableObjectState, env: Env) {
super(state, env);
}
// Your methods here
}DOs继承自McpAgent(用于MCP服务器):
typescript
export class MyMCP extends McpAgent<Env> {
constructor(state: DurableObjectState, env: Env) {
super(state, env);
}
// 你的方法
}Bindings Configuration
绑定配置
Environment bindings give Workers access to resources:
jsonc
{
"kv_namespaces": [{ "binding": "MY_KV", "id": "..." }],
"durable_objects": {
"bindings": [{ "name": "MY_DO", "class_name": "MyDO" }]
},
"r2_buckets": [{ "binding": "MY_BUCKET", "bucket_name": "..." }]
}Access in code:
typescript
env.MY_KV.get("key");
env.MY_DO.idFromName("session-123").getStub(env);
env.MY_BUCKET.get("file.txt");环境绑定让Workers访问资源:
jsonc
{
"kv_namespaces": [{ "binding": "MY_KV", "id": "..." }],
"durable_objects": {
"bindings": [{ "name": "MY_DO", "class_name": "MyDO" }]
},
"r2_buckets": [{ "binding": "MY_BUCKET", "bucket_name": "..." }]
}在代码中访问:
typescript
env.MY_KV.get("key");
env.MY_DO.idFromName("session-123").getStub(env);
env.MY_BUCKET.get("file.txt");Additional Resources
其他资源
Official Documentation
官方文档
- Cloudflare Agents: https://developers.cloudflare.com/agents/
- MCP Specification: https://modelcontextprotocol.io/
- workers-oauth-provider: https://github.com/cloudflare/workers-oauth-provider
- Durable Objects: https://developers.cloudflare.com/durable-objects/
- Cloudflare Agents:https://developers.cloudflare.com/agents/
- MCP规范:https://modelcontextprotocol.io/
- workers-oauth-provider:https://github.com/cloudflare/workers-oauth-provider
- Durable Objects:https://developers.cloudflare.com/durable-objects/
Official Examples
官方示例
- Cloudflare AI Demos: https://github.com/cloudflare/ai/tree/main/demos
- 13 MCP Servers: https://blog.cloudflare.com/thirteen-new-mcp-servers-from-cloudflare/
Tools
工具
- MCP Inspector: https://github.com/modelcontextprotocol/inspector
- Wrangler CLI: https://developers.cloudflare.com/workers/wrangler/
- MCP Inspector:https://github.com/modelcontextprotocol/inspector
- Wrangler CLI:https://developers.cloudflare.com/workers/wrangler/
This Skill's Resources
本技能的资源
- - Deep dive on URL paths and routing
references/http-transport-fundamentals.md - - SSE vs HTTP technical details
references/transport-comparison.md - - Common connection issues + fixes
references/debugging-guide.md - - Auth patterns comparison
references/authentication.md - - GitHub, Google, Azure setup
references/oauth-providers.md - - Error troubleshooting deep-dives
references/common-issues.md - - Curated links to Cloudflare examples
references/official-examples.md
- - URL路径与路由的深入解析
references/http-transport-fundamentals.md - - SSE与HTTP的技术细节对比
references/transport-comparison.md - - 常见连接问题+解决方案
references/debugging-guide.md - - 认证模式对比
references/authentication.md - - GitHub、Google、Azure设置
references/oauth-providers.md - - 错误排查深入解析
references/common-issues.md - - Cloudflare示例的精选链接
references/official-examples.md
When NOT to Use This Skill
何时不使用本技能
Don't use this skill when:
- Building Python MCP servers (use skill instead)
fastmcp - Building local-only MCP servers (use skill)
typescript-mcp - You need non-Cloudflare hosting (AWS Lambda, GCP, etc.)
- You're working with Claude.ai web interface skills (different from MCP)
Use this skill specifically for: TypeScript + Cloudflare Workers + Remote MCP
不要在以下场景使用本技能:
- 构建Python MCP服务器(请改用技能)
fastmcp - 构建仅本地运行的MCP服务器(请改用技能)
typescript-mcp - 你需要非Cloudflare托管(AWS Lambda、GCP等)
- 你正在使用Claude.ai网页版技能(与MCP不同)
本技能专门用于:TypeScript + Cloudflare Workers + Remote MCP
Version Information
版本信息
- @modelcontextprotocol/sdk: 1.21.0
- @cloudflare/workers-oauth-provider: 0.0.13
- agents (Cloudflare Agents SDK): 0.2.20
- Last Verified: 2025-11-08
Production tested: Based on Cloudflare's official MCP servers (mcp-server-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 Efficiency
Token效率
Without this skill:
- Research scattered docs: ~10k tokens
- Debug URL path issues: ~15k tokens
- Debug other 21 errors: ~30k tokens
- Total: ~55k tokens
With this skill:
- Read skill fundamentals: ~4k tokens
- Copy templates: ~1k tokens
- Quick reference: ~1k tokens
- Total: ~6k tokens
Savings: ~88% (55k → 6k tokens)
Errors prevented: 22 (100% prevention rate)
不使用本技能:
- 分散的文档研究:~10k tokens
- 调试URL路径问题:~15k tokens
- 调试其他21种错误:~30k tokens
- 总计:~55k tokens
使用本技能:
- 阅读技能基础:~4k tokens
- 复制模板:~1k tokens
- 快速参考:~1k tokens
- 总计:~6k tokens
节省:~88%(55k → 6k tokens)
预防的错误:22种(100%预防率)