Skip to content

Commit 4337e31

Browse files
docs: add stateless MCP server guide and update MCP documentation
This commit documents the new stateless MCP server approach introduced in PR #752 (Upgrade MCP SDK to v1.25.1). Changes: - Add new stateless-mcp-server.mdx guide demonstrating WebStandardStreamableHTTPServerTransport usage - Update MCP index page to explain both stateless and McpAgent-based approaches - Update remote-mcp-server guide to clarify it uses McpAgent and link to stateless option - Document the simplest way to create MCP servers on Cloudflare Workers The new example (examples/mcp-server) uses the MCP SDK directly without the agents package, providing a zero-config stateless option that is simpler for basic use cases. Related PR: cloudflare/agents#752
1 parent b09c50e commit 4337e31

File tree

3 files changed

+244
-2
lines changed

3 files changed

+244
-2
lines changed

src/content/docs/agents/guides/remote-mcp-server.mdx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ import { Details, Render, PackageManagers } from "~/components";
1111

1212
## Deploy your first MCP server
1313

14-
This guide will show you how to deploy your own remote MCP server on Cloudflare, with two options:
14+
This guide will show you how to deploy your own remote MCP server on Cloudflare using the `McpAgent` class, which provides built-in state management and authentication support. This approach is best when you need to maintain state between requests or implement complex authentication flows.
15+
16+
:::note[Looking for a simpler stateless option?]
17+
If you do not need state management and want the simplest possible MCP server, see the [Build a stateless MCP server](/agents/guides/stateless-mcp-server/) guide. That approach uses the MCP SDK directly without the `McpAgent` wrapper.
18+
:::
19+
20+
You can deploy an MCP server with two options:
1521

1622
- **Without authentication** — anyone can connect and use the server (no login required).
1723
- **With [authentication and authorization](/agents/guides/remote-mcp-server/#add-authentication)** — users sign in before accessing tools, and you can control which tools an agent can call based on the user's permissions.
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
---
2+
pcx_content_type: tutorial
3+
title: Build a stateless MCP server
4+
tags:
5+
- MCP
6+
sidebar:
7+
order: 3
8+
---
9+
10+
import { Details, Render, PackageManagers, WranglerConfig, TypeScriptExample } from "~/components";
11+
12+
This guide demonstrates the simplest way to build a stateless MCP server on Cloudflare using the `@modelcontextprotocol/sdk` package directly. This approach is ideal when you do not need to maintain state between requests.
13+
14+
## What you will build
15+
16+
You will create a simple MCP server that:
17+
18+
- Runs on Cloudflare Workers
19+
- Uses `WebStandardStreamableHTTPServerTransport` for HTTP-based communication
20+
- Exposes a single tool that returns a greeting
21+
- Requires no authentication
22+
- Maintains no state between requests
23+
24+
## Prerequisites
25+
26+
- A Cloudflare account ([sign up for free](https://dash.cloudflare.com/sign-up))
27+
- Node.js and npm installed
28+
- Basic familiarity with TypeScript
29+
30+
## Set up your project
31+
32+
First, create a new directory for your MCP server and initialize it:
33+
34+
```sh
35+
mkdir my-stateless-mcp
36+
cd my-stateless-mcp
37+
npm init -y
38+
```
39+
40+
Install the required dependencies:
41+
42+
<PackageManagers
43+
type="install"
44+
pkg="@modelcontextprotocol/sdk zod"
45+
/>
46+
47+
Install Wrangler as a dev dependency:
48+
49+
<PackageManagers
50+
type="install"
51+
pkg="wrangler --save-dev"
52+
/>
53+
54+
## Create the MCP server
55+
56+
Create a `src` directory and add your server code:
57+
58+
```sh
59+
mkdir src
60+
```
61+
62+
Create `src/index.ts` with the following code:
63+
64+
<TypeScriptExample>
65+
66+
```ts title="src/index.ts"
67+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
68+
import { z } from "zod";
69+
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
70+
71+
const server = new McpServer({
72+
name: "Hello MCP Server",
73+
version: "1.0.0"
74+
});
75+
76+
server.registerTool(
77+
"hello",
78+
{
79+
description: "Returns a greeting message",
80+
inputSchema: { name: z.string().optional() }
81+
},
82+
async ({ name }) => {
83+
return {
84+
content: [
85+
{
86+
text: `Hello, ${name ?? "World"}!`,
87+
type: "text"
88+
}
89+
]
90+
};
91+
}
92+
);
93+
94+
const transport = new WebStandardStreamableHTTPServerTransport();
95+
server.connect(transport);
96+
97+
const corsHeaders = {
98+
"Access-Control-Allow-Origin": "*",
99+
"Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
100+
"Access-Control-Allow-Headers":
101+
"Content-Type, Accept, mcp-session-id, mcp-protocol-version",
102+
"Access-Control-Expose-Headers": "mcp-session-id",
103+
"Access-Control-Max-Age": "86400"
104+
};
105+
106+
function withCors(response: Response): Response {
107+
for (const [key, value] of Object.entries(corsHeaders)) {
108+
response.headers.set(key, value);
109+
}
110+
return response;
111+
}
112+
113+
export default {
114+
fetch: async (request: Request, _env: Env, _ctx: ExecutionContext) => {
115+
if (request.method === "OPTIONS") {
116+
return new Response(null, { headers: corsHeaders });
117+
}
118+
return withCors(await transport.handleRequest(request));
119+
}
120+
};
121+
```
122+
123+
</TypeScriptExample>
124+
125+
## Configure Wrangler
126+
127+
Create a `wrangler.jsonc` configuration file:
128+
129+
<WranglerConfig>
130+
131+
```jsonc
132+
{
133+
"compatibility_date": "2025-01-08",
134+
"compatibility_flags": ["nodejs_compat"],
135+
"main": "src/index.ts",
136+
"name": "my-stateless-mcp",
137+
"observability": {
138+
"logs": {
139+
"enabled": true
140+
}
141+
}
142+
}
143+
```
144+
145+
</WranglerConfig>
146+
147+
Create a basic `tsconfig.json`:
148+
149+
```json title="tsconfig.json"
150+
{
151+
"compilerOptions": {
152+
"target": "ES2022",
153+
"module": "ES2022",
154+
"lib": ["ES2022"],
155+
"moduleResolution": "bundler",
156+
"types": ["@cloudflare/workers-types"]
157+
}
158+
}
159+
```
160+
161+
## Test locally
162+
163+
Start the development server:
164+
165+
```sh
166+
npx wrangler dev
167+
```
168+
169+
Your MCP server is now running locally. You can test it using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector):
170+
171+
```sh
172+
npx @modelcontextprotocol/inspector@latest
173+
```
174+
175+
Open the inspector in your browser at `http://localhost:5173` and connect to your local server (usually `http://localhost:8787`).
176+
177+
## Deploy to Cloudflare
178+
179+
Deploy your MCP server to Cloudflare:
180+
181+
```sh
182+
npx wrangler deploy
183+
```
184+
185+
After deployment, your MCP server will be available at:
186+
187+
```
188+
https://my-stateless-mcp.your-account.workers.dev
189+
```
190+
191+
You can now connect to this URL from any MCP client that supports the `streamable-http` transport, such as:
192+
193+
- [AI Playground](https://playground.ai.cloudflare.com/)
194+
- [MCP Inspector](https://github.com/modelcontextprotocol/inspector)
195+
- [Claude Desktop](/agents/guides/connect-mcp-client/) (via the `mcp-remote` proxy)
196+
197+
## Understanding the code
198+
199+
### WebStandardStreamableHTTPServerTransport
200+
201+
The `WebStandardStreamableHTTPServerTransport` class from the MCP SDK handles the HTTP transport layer. It supports the [streamable-http transport](https://spec.modelcontextprotocol.io/specification/draft/basic/transports/#http-with-sse) which uses HTTP POST for requests and Server-Sent Events (SSE) for streaming responses.
202+
203+
This transport is stateless by default - each request is independent and does not maintain session state between requests.
204+
205+
### CORS headers
206+
207+
The CORS headers are required to allow browser-based MCP clients to connect to your server. The configuration above allows all origins (`*`), but you can restrict this to specific domains in production.
208+
209+
### Tool registration
210+
211+
The `server.registerTool()` method registers a tool with your MCP server. Each tool has:
212+
213+
- A unique name (`hello`)
214+
- A description that helps AI models understand when to use the tool
215+
- An input schema defined using [Zod](https://zod.dev/)
216+
- An async handler function that processes requests and returns results
217+
218+
## Next steps
219+
220+
Now that you have a basic stateless MCP server running:
221+
222+
- Add more tools to expand your server's capabilities
223+
- Learn how to [build a remote MCP server](/agents/guides/remote-mcp-server/) with the `McpAgent` class for stateful interactions
224+
- Add [authentication and authorization](/agents/model-context-protocol/authorization/) to secure your server
225+
- Explore [MCP tools best practices](/agents/model-context-protocol/tools/) for designing effective tools
226+
227+
## Related resources
228+
229+
- [Model Context Protocol documentation](https://modelcontextprotocol.io/)
230+
- [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
231+
- [Example code on GitHub](https://github.com/cloudflare/agents/tree/main/examples/mcp-server)

src/content/docs/agents/model-context-protocol/index.mdx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,9 @@ The MCP standard supports two modes of operation:
3737

3838
### Get Started
3939

40-
Go to the [Getting Started](/agents/guides/remote-mcp-server/) guide to learn how to build and deploy your first remote MCP server to Cloudflare.
40+
Cloudflare offers two approaches for building MCP servers:
41+
42+
- **[Stateless MCP servers](/agents/guides/stateless-mcp-server/)**: The simplest approach using the MCP SDK directly. Best for servers that do not need to maintain state between requests.
43+
- **[McpAgent-based servers](/agents/guides/remote-mcp-server/)**: Uses the `McpAgent` class for built-in state management, authentication, and Durable Objects integration. Best for complex servers that need session state or advanced features.
44+
45+
Start with the [stateless approach](/agents/guides/stateless-mcp-server/) if you are new to MCP or need a simple server. Upgrade to the [McpAgent approach](/agents/guides/remote-mcp-server/) when you need state management or authentication.

0 commit comments

Comments
 (0)