Skip to content

Commit 95d98b2

Browse files
committed
Merge fix/mcp-server-review-improvements: MCP server review P0/P1 fixes
2 parents 6040193 + b23f2bb commit 95d98b2

File tree

352 files changed

+50094
-1244
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

352 files changed

+50094
-1244
lines changed
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
---
2+
name: building-mcp-server-on-cloudflare
3+
description: |
4+
Builds remote MCP (Model Context Protocol) servers on Cloudflare Workers
5+
with tools, OAuth authentication, and production deployment. Generates
6+
server code, configures auth providers, and deploys to Workers.
7+
8+
Use when: user wants to "build MCP server", "create MCP tools", "remote
9+
MCP", "deploy MCP", add "OAuth to MCP", or mentions Model Context Protocol
10+
on Cloudflare. Also triggers on "MCP authentication" or "MCP deployment".
11+
---
12+
13+
# Building MCP Servers on Cloudflare
14+
15+
Creates production-ready Model Context Protocol servers on Cloudflare Workers with tools, authentication, and deployment.
16+
17+
## When to Use
18+
19+
- User wants to build a remote MCP server
20+
- User needs to expose tools via MCP
21+
- User asks about MCP authentication or OAuth
22+
- User wants to deploy MCP to Cloudflare Workers
23+
24+
## Prerequisites
25+
26+
- Cloudflare account with Workers enabled
27+
- Node.js 18+ and npm/pnpm/yarn
28+
- Wrangler CLI (`npm install -g wrangler`)
29+
30+
## Quick Start
31+
32+
### Option 1: Public Server (No Auth)
33+
34+
```bash
35+
npm create cloudflare@latest -- my-mcp-server \
36+
--template=cloudflare/ai/demos/remote-mcp-authless
37+
cd my-mcp-server
38+
npm start
39+
```
40+
41+
Server runs at `http://localhost:8788/mcp`
42+
43+
### Option 2: Authenticated Server (OAuth)
44+
45+
```bash
46+
npm create cloudflare@latest -- my-mcp-server \
47+
--template=cloudflare/ai/demos/remote-mcp-github-oauth
48+
cd my-mcp-server
49+
```
50+
51+
Requires OAuth app setup. See [references/oauth-setup.md](references/oauth-setup.md).
52+
53+
## Core Workflow
54+
55+
### Step 1: Define Tools
56+
57+
Tools are functions MCP clients can call. Define them using `server.tool()`:
58+
59+
```typescript
60+
import { McpAgent } from "agents/mcp";
61+
import { z } from "zod";
62+
63+
export class MyMCP extends McpAgent {
64+
server = new Server({ name: "my-mcp", version: "1.0.0" });
65+
66+
async init() {
67+
// Simple tool with parameters
68+
this.server.tool(
69+
"add",
70+
{ a: z.number(), b: z.number() },
71+
async ({ a, b }) => ({
72+
content: [{ type: "text", text: String(a + b) }],
73+
})
74+
);
75+
76+
// Tool that calls external API
77+
this.server.tool(
78+
"get_weather",
79+
{ city: z.string() },
80+
async ({ city }) => {
81+
const response = await fetch(`https://api.weather.com/${city}`);
82+
const data = await response.json();
83+
return {
84+
content: [{ type: "text", text: JSON.stringify(data) }],
85+
};
86+
}
87+
);
88+
}
89+
}
90+
```
91+
92+
### Step 2: Configure Entry Point
93+
94+
**Public server** (`src/index.ts`):
95+
96+
```typescript
97+
import { MyMCP } from "./mcp";
98+
99+
export default {
100+
fetch(request: Request, env: Env, ctx: ExecutionContext) {
101+
const url = new URL(request.url);
102+
if (url.pathname === "/mcp") {
103+
return MyMCP.serveSSE("/mcp").fetch(request, env, ctx);
104+
}
105+
return new Response("MCP Server", { status: 200 });
106+
},
107+
};
108+
109+
export { MyMCP };
110+
```
111+
112+
**Authenticated server** — See [references/oauth-setup.md](references/oauth-setup.md).
113+
114+
### Step 3: Test Locally
115+
116+
```bash
117+
# Start server
118+
npm start
119+
120+
# In another terminal, test with MCP Inspector
121+
npx @modelcontextprotocol/inspector@latest
122+
# Open http://localhost:5173, enter http://localhost:8788/mcp
123+
```
124+
125+
### Step 4: Deploy
126+
127+
```bash
128+
npx wrangler deploy
129+
```
130+
131+
Server accessible at `https://[worker-name].[account].workers.dev/mcp`
132+
133+
### Step 5: Connect Clients
134+
135+
**Claude Desktop** (`claude_desktop_config.json`):
136+
137+
```json
138+
{
139+
"mcpServers": {
140+
"my-server": {
141+
"command": "npx",
142+
"args": ["mcp-remote", "https://my-mcp.workers.dev/mcp"]
143+
}
144+
}
145+
}
146+
```
147+
148+
Restart Claude Desktop after updating config.
149+
150+
## Tool Patterns
151+
152+
### Return Types
153+
154+
```typescript
155+
// Text response
156+
return { content: [{ type: "text", text: "result" }] };
157+
158+
// Multiple content items
159+
return {
160+
content: [
161+
{ type: "text", text: "Here's the data:" },
162+
{ type: "text", text: JSON.stringify(data, null, 2) },
163+
],
164+
};
165+
```
166+
167+
### Input Validation with Zod
168+
169+
```typescript
170+
this.server.tool(
171+
"create_user",
172+
{
173+
email: z.string().email(),
174+
name: z.string().min(1).max(100),
175+
role: z.enum(["admin", "user", "guest"]),
176+
age: z.number().int().min(0).optional(),
177+
},
178+
async (params) => {
179+
// params are fully typed and validated
180+
}
181+
);
182+
```
183+
184+
### Accessing Environment/Bindings
185+
186+
```typescript
187+
export class MyMCP extends McpAgent<Env> {
188+
async init() {
189+
this.server.tool("query_db", { sql: z.string() }, async ({ sql }) => {
190+
// Access D1 binding
191+
const result = await this.env.DB.prepare(sql).all();
192+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
193+
});
194+
}
195+
}
196+
```
197+
198+
## Authentication
199+
200+
For OAuth-protected servers, see [references/oauth-setup.md](references/oauth-setup.md).
201+
202+
Supported providers:
203+
- GitHub
204+
- Google
205+
- Auth0
206+
- Stytch
207+
- WorkOS
208+
- Any OAuth 2.0 compliant provider
209+
210+
## Wrangler Configuration
211+
212+
Minimal `wrangler.toml`:
213+
214+
```toml
215+
name = "my-mcp-server"
216+
main = "src/index.ts"
217+
compatibility_date = "2024-12-01"
218+
219+
[durable_objects]
220+
bindings = [{ name = "MCP", class_name = "MyMCP" }]
221+
222+
[[migrations]]
223+
tag = "v1"
224+
new_classes = ["MyMCP"]
225+
```
226+
227+
With bindings (D1, KV, etc.):
228+
229+
```toml
230+
[[d1_databases]]
231+
binding = "DB"
232+
database_name = "my-db"
233+
database_id = "xxx"
234+
235+
[[kv_namespaces]]
236+
binding = "KV"
237+
id = "xxx"
238+
```
239+
240+
## Common Issues
241+
242+
### "Tool not found" in Client
243+
244+
1. Verify tool name matches exactly (case-sensitive)
245+
2. Ensure `init()` registers tools before connections
246+
3. Check server logs: `wrangler tail`
247+
248+
### Connection Fails
249+
250+
1. Confirm endpoint path is `/mcp`
251+
2. Check CORS if browser-based client
252+
3. Verify Worker is deployed: `wrangler deployments list`
253+
254+
### OAuth Redirect Errors
255+
256+
1. Callback URL must match OAuth app config exactly
257+
2. Check `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET` are set
258+
3. For local dev, use `http://localhost:8788/callback`
259+
260+
## References
261+
262+
- [references/examples.md](references/examples.md) — Official templates and production examples
263+
- [references/oauth-setup.md](references/oauth-setup.md) — OAuth provider configuration
264+
- [references/tool-patterns.md](references/tool-patterns.md) — Advanced tool examples
265+
- [references/troubleshooting.md](references/troubleshooting.md) — Error codes and fixes
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Project Bootstrapping
2+
3+
Instructions for creating new MCP server projects.
4+
5+
---
6+
7+
## Create Commands
8+
9+
Execute in terminal to generate a new project:
10+
11+
**Without authentication:**
12+
13+
```bash
14+
npm create cloudflare@latest -- my-mcp-server \
15+
--template=cloudflare/ai/demos/remote-mcp-authless
16+
```
17+
18+
**With GitHub login:**
19+
20+
```bash
21+
npm create cloudflare@latest -- my-mcp-server \
22+
--template=cloudflare/ai/demos/remote-mcp-github-oauth
23+
```
24+
25+
**With Google login:**
26+
27+
```bash
28+
npm create cloudflare@latest -- my-mcp-server \
29+
--template=cloudflare/ai/demos/remote-mcp-google-oauth
30+
```
31+
32+
---
33+
34+
## Additional Boilerplate Locations
35+
36+
**Main repository:** `github.com/cloudflare/ai` (check demos directory)
37+
38+
Other authentication providers:
39+
- Auth0
40+
- WorkOS AuthKit
41+
- Logto
42+
- Descope
43+
- Stytch
44+
45+
**Cloudflare tooling:** `github.com/cloudflare/mcp-server-cloudflare`
46+
47+
---
48+
49+
## Selection Matrix
50+
51+
| Goal | Boilerplate |
52+
|------|-------------|
53+
| Testing/learning | authless |
54+
| GitHub API access | github-oauth |
55+
| Google API access | google-oauth |
56+
| Enterprise auth | auth0 / authkit |
57+
| Slack apps | slack-oauth |
58+
| Zero Trust | cf-access |
59+
60+
---
61+
62+
## Platform Documentation
63+
64+
- developers.cloudflare.com/agents/model-context-protocol/
65+
- developers.cloudflare.com/agents/guides/remote-mcp-server/
66+
- developers.cloudflare.com/agents/guides/test-remote-mcp-server/
67+
- developers.cloudflare.com/agents/model-context-protocol/authorization/
68+
69+
---
70+
71+
## Commands Reference
72+
73+
**Local execution:**
74+
75+
```bash
76+
cd my-mcp-server
77+
npm install
78+
npm start
79+
# Accessible at http://localhost:8788/mcp
80+
```
81+
82+
**Production push:**
83+
84+
```bash
85+
npx wrangler deploy
86+
# Accessible at https://[worker-name].[subdomain].workers.dev/mcp
87+
```
88+
89+
**Claude Desktop setup** (modify `claude_desktop_config.json`):
90+
91+
```json
92+
{
93+
"mcpServers": {
94+
"my-server": {
95+
"command": "npx",
96+
"args": ["mcp-remote", "https://my-mcp-server.my-account.workers.dev/mcp"]
97+
}
98+
}
99+
}
100+
```
101+
102+
**Inspector testing:**
103+
104+
```bash
105+
npx @modelcontextprotocol/inspector@latest
106+
# Launch browser at http://localhost:5173
107+
# Input your server URL: http://localhost:8788/mcp
108+
```
109+
110+
---
111+
112+
## Help Channels
113+
114+
- Cloudflare Discord
115+
- GitHub discussions on cloudflare/ai repository

0 commit comments

Comments
 (0)