building-cloudflare-mcp
4
总安装量
1
周安装量
#51896
全站排名
安装命令
npx skills add https://github.com/websmartteam/cor-code --skill building-cloudflare-mcp
Agent 安装分布
amp
1
opencode
1
kimi-cli
1
codex
1
github-copilot
1
gemini-cli
1
Skill 文档
Cloudflare MCP Connector
Build and deploy MCP (Model Context Protocol) servers on Cloudflare Workers using the MCP Connector pattern.
Why Cloudflare Workers for MCP?
- Global edge deployment – Low latency worldwide
- MCP Connector compatible – Works with Claude API MCP integration
- No cold starts – Always-on serverless
- Free tier – 100K requests/day free
- Easy authentication – Headers-based auth
Official Documentation References
When you need deeper context, fetch these with WebFetch:
| Topic | URL |
|---|---|
| Code Mode Pattern | https://www.anthropic.com/engineering/code-execution-with-mcp |
| Remote MCP Servers | https://platform.claude.com/docs/en/agents-and-tools/remote-mcp-servers.md |
| MCP Connector API | https://platform.claude.com/docs/en/agents-and-tools/mcp-connector.md |
| Agent SDK MCP | https://platform.claude.com/docs/en/agent-sdk/mcp.md |
| Claude Code MCP | https://code.claude.com/docs/en/mcp.md |
| Cloudflare Code Mode | https://blog.cloudflare.com/code-mode/ |
Code Mode (Advanced Pattern)
For high-scale deployments with many tools, consider the Code Mode pattern:
- Present MCP tools as code APIs (filesystem structure)
- Agent writes code to call tools instead of direct tool calls
- 98.7% token savings for large tool sets
- Filter/transform data in execution environment before returning
Why it works: LLMs have seen millions of real TypeScript examples in training, but only contrived synthetic tool-call examples.
Cloudflare Agents SDK (built-in Code Mode):
import { codemode } from "agents/codemode/ai";
const {system, tools} = codemode({
system: "You are a helpful assistant",
tools: { /* tool definitions */ },
});
const stream = streamText({
model: openai("gpt-5"),
system,
tools,
messages: [{ role: "user", content: "..." }]
});
Docs: https://github.com/cloudflare/agents/blob/main/docs/codemode.md
MCP Server Structure
Minimal Worker Template
// src/index.ts
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// CORS preflight
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
});
}
// Auth check
const authHeader = request.headers.get('Authorization');
if (authHeader !== `Bearer ${env.MCP_API_KEY}`) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
// Parse MCP request
const body = await request.json() as MCPRequest;
// Handle MCP methods
switch (body.method) {
case 'tools/list':
return Response.json({
jsonrpc: '2.0',
id: body.id,
result: { tools: getToolsList() }
});
case 'tools/call':
const result = await handleToolCall(body.params, env);
return Response.json({
jsonrpc: '2.0',
id: body.id,
result
});
default:
return Response.json({
jsonrpc: '2.0',
id: body.id,
error: { code: -32601, message: 'Method not found' }
});
}
},
};
interface MCPRequest {
jsonrpc: '2.0';
id: string | number;
method: string;
params?: Record<string, unknown>;
}
interface Env {
MCP_API_KEY: string;
// Add other bindings (KV, D1, R2, etc.)
}
function getToolsList() {
return [
{
name: 'example_tool',
description: 'Description of what this tool does',
inputSchema: {
type: 'object',
properties: {
param1: { type: 'string', description: 'First parameter' },
},
required: ['param1'],
},
},
];
}
async function handleToolCall(params: { name: string; arguments: Record<string, unknown> }, env: Env) {
switch (params.name) {
case 'example_tool':
return { content: [{ type: 'text', text: `Result: ${params.arguments.param1}` }] };
default:
throw new Error(`Unknown tool: ${params.name}`);
}
}
wrangler.toml
name = "my-mcp-server"
main = "src/index.ts"
compatibility_date = "2024-01-01"
[vars]
# Non-secret config here
# Secrets added via: wrangler secret put MCP_API_KEY
Claude Code Configuration
Add Remote MCP Server
# Using CLI (user scope for global access)
claude mcp add --scope user my-mcp-server \
--transport http \
--url "https://my-mcp-server.username.workers.dev" \
--header "Authorization: Bearer YOUR_API_KEY"
Manual Configuration (~/.claude.json)
{
"mcpServers": {
"my-mcp-server": {
"type": "http",
"url": "https://my-mcp-server.username.workers.dev",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
Auto-Approve Tools (~/.claude/settings.json)
{
"autoApproveTools": [
"mcp__my-mcp-server__*"
]
}
Tool Naming Convention
Tools from MCP servers follow this pattern:
mcp__<server-name>__<tool-name>
Examples:
mcp__my-mcp-server__example_toolmcp__supabase__execute_sqlmcp__context7__query-docs
Authentication Patterns
Bearer Token (Recommended)
const authHeader = request.headers.get('Authorization');
if (authHeader !== `Bearer ${env.MCP_API_KEY}`) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
API Key Header
const apiKey = request.headers.get('X-API-Key');
if (apiKey !== env.API_KEY) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
IP Allowlist (Additional Layer)
const clientIP = request.headers.get('CF-Connecting-IP');
const allowedIPs = env.ALLOWED_IPS?.split(',') || [];
if (allowedIPs.length && !allowedIPs.includes(clientIP)) {
return Response.json({ error: 'Forbidden' }, { status: 403 });
}
Deployment Workflow
# 1. Create project
npm create cloudflare@latest my-mcp-server -- --template worker-typescript
# 2. Install dependencies
cd my-mcp-server
npm install
# 3. Add secrets
wrangler secret put MCP_API_KEY
# Enter your secure API key
# 4. Deploy
wrangler deploy
# 5. Add to Claude Code
claude mcp add --scope user my-mcp-server \
--transport http \
--url "https://my-mcp-server.username.workers.dev" \
--header "Authorization: Bearer YOUR_API_KEY"
# 6. Restart Claude Code
# Exit and run: claude --resume
Advanced: Cloudflare Bindings
KV Storage
// wrangler.toml
[[kv_namespaces]]
binding = "MY_KV"
id = "abc123"
// Usage
const value = await env.MY_KV.get('key');
await env.MY_KV.put('key', 'value');
D1 Database
// wrangler.toml
[[d1_databases]]
binding = "DB"
database_name = "my-db"
database_id = "abc123"
// Usage
const result = await env.DB.prepare('SELECT * FROM users WHERE id = ?')
.bind(userId)
.first();
R2 Storage
// wrangler.toml
[[r2_buckets]]
binding = "BUCKET"
bucket_name = "my-bucket"
// Usage
const object = await env.BUCKET.get('file.txt');
await env.BUCKET.put('file.txt', content);
Troubleshooting
MCP Not Loading
- Check worker is deployed:
curl https://your-worker.workers.dev - Verify auth header matches secret
- Restart Claude Code after config changes
Tools Not Appearing
- Check
tools/listresponse format - Verify tool schema is valid JSON Schema
- Check Claude Code logs:
/mcpcommand
Permission Errors
- Add to autoApproveTools in settings.json
- Use wildcard:
mcp__my-mcp-server__*
Security Checklist
- Use strong, unique API keys (32+ chars)
- Store secrets via
wrangler secret put - Never commit secrets to git
- Consider IP allowlisting for sensitive MCPs
- Use HTTPS only (Cloudflare provides this)
- Implement rate limiting if needed
- Log access attempts for auditing