Skip to content

Commit 8806c0e

Browse files
committed
examples readme improvements
1 parent 16df308 commit 8806c0e

File tree

1 file changed

+245
-85
lines changed

1 file changed

+245
-85
lines changed

src/examples/README.md

Lines changed: 245 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -4,134 +4,294 @@ This directory contains example implementations of MCP clients and servers using
44

55
## Table of Contents
66

7-
- [Streamable HTTP Servers - Single Node Deployment](#streamable-http---single-node-deployment-with-basic-session-state-management)
8-
- [Simple Server with Streamable HTTP](#simple-server-with-streamable-http-transport-serversimplestreamablehttpts)
9-
- [Server Supporting SSE via GET](#server-supporting-with-sse-via-get-serverstandalonessewithgetstreamablehttpts)
10-
- [Server with JSON Response Mode](#server-with-json-response-mode-serverjsonresponsestreamablehttpts)
11-
- [Client Example - Streamable HTTP](#client-clientsimplestreamablehttpts)
12-
- [Useful bash commands for testing](#useful-commands-for-testing)
7+
- [Client Implementations](#client-implementations)
8+
- [Streamable HTTP Client](#streamable-http-client)
9+
- [Backwards Compatible Client](#backwards-compatible-client)
10+
- [Server Implementations](#server-implementations)
11+
- [Single Node Deployment](#single-node-deployment)
12+
- [Streamable HTTP Transport](#streamable-http-transport)
13+
- [Deprecated SSE Transport](#deprecated-sse-transport)
14+
- [Backwards Compatible Server](#streamable-http-backwards-compatible-server-with-sse)
15+
- [Multi-Node Deployment](#multi-node-deployment)
16+
- [Backwards Compatibility](#testing-streamable-http-backwards-compatibility-with-sse)
17+
18+
## Client Implementations
19+
20+
### Streamable HTTP Client
21+
22+
A full-featured interactive client that connects to a Streamable HTTP server, demonstrating how to:
23+
24+
- Establish and manage a connection to an MCP server
25+
- List and call tools with arguments
26+
- Handle notifications through the SSE stream
27+
- List and get prompts with arguments
28+
- List available resources
29+
- Handle session termination and reconnection
30+
- Support for resumability with Last-Event-ID tracking
31+
32+
```bash
33+
npx tsx src/examples/client/simpleStreamableHttp.ts
34+
```
35+
36+
### Backwards Compatible Client
37+
38+
A client that implements backwards compatibility according to the [MCP specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#backwards-compatibility), allowing it to work with both new and legacy servers. This client demonstrates:
1339

14-
## Streamable HTTP - single node deployment with basic session state management
40+
- The client first POSTs an initialize request to the server URL:
41+
- If successful, it uses the Streamable HTTP transport
42+
- If it fails with a 4xx status, it attempts a GET request to establish an SSE stream
1543

16-
Multi node with state management example will be added soon after we add support.
44+
```bash
45+
npx tsx src/examples/client/streamableHttpWithSseFallbackClient.ts
46+
```
47+
48+
## Server Implementations
49+
50+
### Single Node Deployment
1751

52+
These examples demonstrate how to set up an MCP server on a single node with different transport options.
1853

19-
### Simple server with Streamable HTTP transport (`server/simpleStreamableHttp.ts`)
54+
#### Streamable HTTP Transport
2055

21-
A simple MCP server that uses the Streamable HTTP transport, implemented with Express. The server provides:
56+
##### Simple Streamable HTTP Server
2257

23-
- A simple `greet` tool that returns a greeting for a name
24-
- A `greeting-template` prompt that generates a greeting template
25-
- A static `greeting-resource` resource
58+
A server that implements the Streamable HTTP transport (protocol version 2025-03-26).
2659

27-
#### Running the server
60+
- Basic server setup with Express and the Streamable HTTP transport
61+
- Session management with an in-memory event store for resumability
62+
- Tool implementation with the `greet` and `multi-greet` tools
63+
- Prompt implementation with the `greeting-template` prompt
64+
- Static resource exposure
65+
- Support for notifications via SSE stream established by GET requests
66+
- Session termination via DELETE requests
2867

2968
```bash
3069
npx tsx src/examples/server/simpleStreamableHttp.ts
3170
```
3271

33-
The server will start on port 3000. You can test the initialization and tool listing:
72+
##### JSON Response Mode Server
73+
74+
A server that uses Streamable HTTP transport with JSON response mode enabled (no SSE).
75+
76+
- Streamable HTTP with JSON response mode, which returns responses directly in the response body
77+
- Limited support for notifications (since SSE is disabled)
78+
- Proper response handling according to the MCP specification for servers that don't support SSE
79+
- Returning appropriate HTTP status codes for unsupported methods
80+
81+
```bash
82+
npx tsx src/examples/server/jsonResponseStreamableHttp.ts
83+
```
84+
85+
##### Streamable HTTP with server notifications
3486

35-
### Server supporting SSE via GET (`server/standaloneSseWithGetStreamableHttp.ts`)
87+
A server that demonstrates server notifications using Streamable HTTP.
3688

37-
An MCP server that demonstrates how to support SSE notifications via GET requests using the Streamable HTTP transport with Express. The server dynamically adds resources at regular intervals and supports notifications for resource list changes (server notifications are available through the standalone SSE connection established by GET request).
89+
- Resource list change notifications with dynamically added resources
90+
- Automatic resource creation on a timed interval
3891

39-
#### Running the server
4092

4193
```bash
4294
npx tsx src/examples/server/standaloneSseWithGetStreamableHttp.ts
4395
```
4496

45-
The server will start on port 3000 and automatically create new resources every 5 seconds.
97+
#### Deprecated SSE Transport
4698

47-
### Server with JSON response mode (`server/jsonResponseStreamableHttp.ts`)
99+
A server that implements the deprecated HTTP+SSE transport (protocol version 2024-11-05). This example only used for testing backwards compatibility for clients.
100+
101+
- Two separate endpoints: `/mcp` for the SSE stream (GET) and `/messages` for client messages (POST)
102+
- Tool implementation with a `start-notification-stream` tool that demonstrates sending periodic notifications
103+
104+
```bash
105+
npx tsx src/examples/server/simpleSseServer.ts
106+
```
48107

49-
A simple MCP server that uses the Streamable HTTP transport with JSON response mode enabled, implemented with Express. The server provides a simple `greet` tool that returns a greeting for a name.
108+
#### Streamable Http Backwards Compatible Server with SSE
50109

51-
_NOTE: This demonstrates a server that does not use SSE at all. Note that this limits its support for MCP features; for example, it cannot provide logging and progress notifications for tool execution._
110+
A server that supports both Streamable HTTP and SSE transports, adhering to the [MCP specification for backwards compatibility](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#backwards-compatibility).
52111

53-
#### Running the server
112+
- Single MCP server instance with multiple transport options
113+
- Support for Streamable HTTP requests at `/mcp` endpoint (GET/POST/DELETE)
114+
- Support for deprecated SSE transport with `/sse` (GET) and `/messages` (POST)
115+
- Session type tracking to avoid mixing transport types
116+
- Notifications and tool execution across both transport types
54117

55118
```bash
56-
npx tsx src/examples/server/jsonResponseStreamableHttp.ts
119+
npx tsx src/examples/server/sseAndStreamableHttpCompatibleServer.ts
57120
```
58121

122+
### Multi-Node Deployment
59123

60-
### Client (`client/simpleStreamableHttp.ts`)
124+
When deploying MCP servers in a horizontally scaled environment (multiple server instances), there are a few different options that can be useful for different use cases:
125+
- **Stateless mode** - No need to maintain state between calls to MCP servers. Useful for simple API wrapper servers.
126+
- **Persistent storage mode** - No local state needed, but session data is stored in a database. Example: an MCP server for online ordering where the shopping cart is stored in a database.
127+
- **Local state with message routing** - Local state is needed, and all requests for a session must be routed to the correct node. This can be done with a message queue and pub/sub system.
61128

62-
A client that connects to the server, initializes it, and demonstrates how to:
129+
#### Stateless Mode
63130

64-
- List available tools and call the `greet` tool
65-
- List available prompts and get the `greeting-template` prompt
66-
- List available resources
131+
The Streamable HTTP transport can be configured to operate without tracking sessions. This is perfect for simple API proxies or when each request is completely independent.
67132

68-
#### Running the client
133+
##### Implementation
69134

70-
```bash
71-
npx tsx src/examples/client/simpleStreamableHttp.ts
135+
To enable stateless mode, configure the `StreamableHTTPServerTransport` with:
136+
```typescript
137+
sessionIdGenerator: () => undefined
72138
```
73139

74-
Make sure the server is running before starting the client.
140+
This disables session management entirely, and the server won't generate or expect session IDs.
75141

142+
- No session ID headers are sent or expected
143+
- Any server node can process any request
144+
- No state is preserved between requests
145+
- Perfect for RESTful or stateless API scenarios
146+
- Simplest deployment model with minimal infrastructure requirements
76147

77-
### Useful commands for testing
148+
```
149+
┌─────────────────────────────────────────────┐
150+
│ Client │
151+
└─────────────────────────────────────────────┘
152+
153+
154+
┌─────────────────────────────────────────────┐
155+
│ Load Balancer │
156+
└─────────────────────────────────────────────┘
157+
│ │
158+
▼ ▼
159+
┌─────────────────┐ ┌─────────────────────┐
160+
│ MCP Server #1 │ │ MCP Server #2 │
161+
│ (Node.js) │ │ (Node.js) │
162+
└─────────────────┘ └─────────────────────┘
163+
```
78164

79-
#### Initialize
80-
Streamable HTTP transport requires to do the initialization first.
81165

82-
```bash
83-
# First initialize the server and save the session ID to a variable
84-
SESSION_ID=$(curl -X POST \
85-
-H "Content-Type: application/json" \
86-
-H "Accept: application/json" \
87-
-H "Accept: text/event-stream" \
88-
-d '{
89-
"jsonrpc": "2.0",
90-
"method": "initialize",
91-
"params": {
92-
"capabilities": {},
93-
"protocolVersion": "2025-03-26",
94-
"clientInfo": {
95-
"name": "test",
96-
"version": "1.0.0"
97-
}
98-
},
99-
"id": "1"
100-
}' \
101-
-i http://localhost:3000/mcp 2>&1 | grep -i "mcp-session-id" | cut -d' ' -f2 | tr -d '\r')
102-
echo "Session ID: $SESSION_ID
103166

167+
#### Persistent Storage Mode
168+
169+
For cases where you need session continuity but don't need to maintain in-memory state on specific nodes, you can use a database to persist session data while still allowing any node to handle requests.
170+
171+
##### Implementation
172+
173+
Configure the transport with session management, but retrieve and store all state in an external persistent storage:
174+
175+
```typescript
176+
sessionIdGenerator: () => randomUUID(),
177+
eventStore: databaseEventStore
104178
```
105-
Once a session is established, we can send POST requests:
106179

107-
#### List tools
108-
```bash
109-
# Then list tools using the saved session ID
110-
curl -X POST -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
111-
-H "mcp-session-id: $SESSION_ID" \
112-
-d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":"2"}' \
113-
http://localhost:3000/mcp
180+
All session state is stored in the database, and any node can serve any client by retrieving the state when needed.
181+
182+
- Maintains sessions with unique IDs
183+
- Stores all session data in an external database
184+
- Provides resumability through the database-backed EventStore
185+
- Any node can handle any request for the same session
186+
- No node-specific memory state means no need for message routing
187+
- Good for applications where state can be fully externalized
188+
- Somewhat higher latency due to database access for each request
189+
190+
191+
```
192+
┌─────────────────────────────────────────────┐
193+
│ Client │
194+
└─────────────────────────────────────────────┘
195+
196+
197+
┌─────────────────────────────────────────────┐
198+
│ Load Balancer │
199+
└─────────────────────────────────────────────┘
200+
│ │
201+
▼ ▼
202+
┌─────────────────┐ ┌─────────────────────┐
203+
│ MCP Server #1 │ │ MCP Server #2 │
204+
│ (Node.js) │ │ (Node.js) │
205+
└─────────────────┘ └─────────────────────┘
206+
│ │
207+
│ │
208+
▼ ▼
209+
┌─────────────────────────────────────────────┐
210+
│ Database (PostgreSQL) │
211+
│ │
212+
│ • Session state │
213+
│ • Event storage for resumability │
214+
└─────────────────────────────────────────────┘
114215
```
115216

116-
#### Call tool
117217

118-
```bash
119-
# Call the greet tool using the saved session ID
120-
curl -X POST \
121-
-H "Content-Type: application/json" \
122-
-H "Accept: application/json" \
123-
-H "Accept: text/event-stream" \
124-
-H "mcp-session-id: $SESSION_ID" \
125-
-d '{
126-
"jsonrpc": "2.0",
127-
"method": "tools/call",
128-
"params": {
129-
"name": "greet",
130-
"arguments": {
131-
"name": "World"
132-
}
133-
},
134-
"id": "2"
135-
}' \
136-
http://localhost:3000/mcp
218+
219+
#### Streamable HTTP with Distributed Message Routing
220+
221+
For scenarios where local in-memory state must be maintained on specific nodes (such as Computer Use or complex session state), the Streamable HTTP transport can be combined with a pub/sub system to route messages to the correct node handling each session.
222+
223+
1. **Bidirectional Message Queue Integration**:
224+
- All nodes both publish to and subscribe from the message queue
225+
- Each node registers the sessions it's actively handling
226+
- Messages are routed based on session ownership
227+
228+
2. **Request Handling Flow**:
229+
- When a client connects to Node A with an existing `mcp-session-id`
230+
- If Node A doesn't own this session, it:
231+
- Establishes and maintains the SSE connection with the client
232+
- Publishes the request to the message queue with the session ID
233+
- Node B (which owns the session) receives the request from the queue
234+
- Node B processes the request with its local session state
235+
- Node B publishes responses/notifications back to the queue
236+
- Node A subscribes to the response channel and forwards to the client
237+
238+
3. **Channel Identification**:
239+
- Each message channel combines both `mcp-session-id` and `stream-id`
240+
- This ensures responses are correctly routed back to the originating connection
241+
242+
```
243+
┌─────────────────────────────────────────────┐
244+
│ Client │
245+
└─────────────────────────────────────────────┘
246+
247+
248+
┌─────────────────────────────────────────────┐
249+
│ Load Balancer │
250+
└─────────────────────────────────────────────┘
251+
│ │
252+
▼ ▼
253+
┌─────────────────┐ ┌─────────────────────┐
254+
│ MCP Server #1 │◄───►│ MCP Server #2 │
255+
│ (Has Session A) │ │ (Has Session B) │
256+
└─────────────────┘ └─────────────────────┘
257+
▲│ ▲│
258+
│▼ │▼
259+
┌─────────────────────────────────────────────┐
260+
│ Message Queue / Pub-Sub │
261+
│ │
262+
│ • Session ownership registry │
263+
│ • Bidirectional message routing │
264+
│ • Request/response forwarding │
265+
└─────────────────────────────────────────────┘
137266
```
267+
268+
269+
- Maintains session affinity for stateful operations without client redirection
270+
- Enables horizontal scaling while preserving complex in-memory state
271+
- Provides fault tolerance through the message queue as intermediary
272+
273+
274+
## Backwards Compatibility
275+
276+
### Testing Streamable HTTP Backwards Compatibility with SSE
277+
278+
To test the backwards compatibility features:
279+
280+
1. Start one of the server implementations:
281+
```bash
282+
# Legacy SSE server (protocol version 2024-11-05)
283+
npx tsx src/examples/server/simpleSseServer.ts
284+
285+
# Streamable HTTP server (protocol version 2025-03-26)
286+
npx tsx src/examples/server/simpleStreamableHttp.ts
287+
288+
# Backwards compatible server (supports both protocols)
289+
npx tsx src/examples/server/sseAndStreamableHttpCompatibleServer.ts
290+
```
291+
292+
2. Then run the backwards compatible client:
293+
```bash
294+
npx tsx src/examples/client/streamableHttpWithSseFallbackClient.ts
295+
```
296+
297+
This demonstrates how the MCP ecosystem ensures interoperability between clients and servers regardless of which protocol version they were built for.

0 commit comments

Comments
 (0)