example-mcp-server-streamable-http-stateless
example-mcp-server-streamable-http-stateless
README
Calculator Learning Demo - Streamable HTTP (Stateless) Transport
<div align="center">
</div>
🎯 Overview
This repository provides a reference implementation of an MCP calculator server using Streamable HTTP transport in a truly stateless mode. It is architected for maximum scalability and is optimized for serverless and edge computing environments.
The core design principle is that the server holds zero state between requests. Every incoming request is atomic and self-contained. This design choice enables perfect horizontal scaling and eliminates an entire class of state-related complexities and vulnerabilities.
Key Characteristics
- Zero State Persistence: The server retains no memory of past requests. No sessions, no history.
- Per-Request Lifecycle: A new MCP server instance is created for every HTTP request and is destroyed immediately after the response stream closes.
- Infinite Scalability: Since no state is shared, any server instance in a cluster can handle any request, making load balancing trivial (e.g., round-robin).
- No Resumability: By design, if a connection is lost, the client must initiate a completely new request. There is no session to resume.
- Ideal Use Case: Edge functions (Vercel, Cloudflare), serverless computing (AWS Lambda), and any application where horizontal scalability is paramount.
📊 Transport Comparison
This table compares the four primary MCP transport mechanisms. The implementation in this repository is highlighted.
| Dimension | STDIO | SSE (Legacy) | Streamable HTTP (Stateful) | Streamable HTTP (Stateless) |
|---|---|---|---|---|
| Transport Layer | Local Pipes (stdin/stdout) |
2 × HTTP endpoints (GET+POST) |
Single HTTP endpoint /mcp |
✅ Single HTTP endpoint /mcp |
| Bidirectional Stream | ✅ Yes (full duplex) | ⚠️ Server→Client only | ✅ Yes (server push + client stream) | ✅ Yes (within each request) |
| State Management | Ephemeral (Process Memory) | Ephemeral (Session Memory) | Persistent (Session State) | ❌ None (Stateless) |
| Resumability | ❌ None | ❌ None | ✅ Yes (Last-Event-Id) |
❌ None (by design) |
| Scalability | ⚠️ Single Process | ✅ Multi-Client | ✅ Horizontal (Sticky Sessions) | ♾️ Infinite (Serverless) |
| Security | 🔒 Process Isolation | 🌐 Network Exposed | 🌐 Network Exposed | 🌐 Network Exposed |
| Ideal Use Case | CLI Tools, IDE Plugins | Legacy Web Apps | Enterprise APIs, Workflows | ✅ Serverless, Edge Functions |
📐 Architecture and Flow
The stateless transport treats every request as a new, independent interaction. A fresh MCP server instance is created for each incoming request and destroyed once the response is complete. This eliminates the need for session management and allows any server in a cluster to handle any request.
sequenceDiagram
participant Client
participant Load Balancer
participant Server A
participant Server B
Note over Client,Server B: No Session Handshake Required
Client->>Load Balancer: POST /mcp (Request 1)
Load Balancer->>Server A: Route to any available server
Server A-->>Load Balancer: Process and respond
Load Balancer-->>Client: 200 OK with response stream
Note over Client,Server B: Next request can go to a different server
Client->>Load Balancer: POST /mcp (Request 2)
Load Balancer->>Server B: Route to any available server
Server B-->>Load Balancer: Process and respond independently
Load Balancer-->>Client: 200 OK with response stream
The core of this architecture is the handleMCPRequest function in stateless-production-server.ts, which performs the following for every call:
- Creates a new
McpServerinstance using thecreateMCPServerfactory. - Creates a new
StreamableHTTPServerTransportconfigured for stateless operation (sessionIdGenerator: undefined). - Connects the server and transport.
- Processes the HTTP request and streams the response.
- Listens for the
response.on('close', ...)event to tear down and garbage-collect both the server and transport instances.
✨ Feature Compliance
This server implements a minimal, stateless version of the MCP Latest Standard. Features requiring state are explicitly not implemented.
| Name | Status | Implementation |
|---|---|---|
calculate |
Core ✅ | Basic arithmetic with optional streaming progress. |
batch_calculate |
Not Implemented | Returns error -32601, as this is not part of the stateless demo. |
advanced_calculate |
Not Implemented | Returns error -32601, not included in this build. |
demo_progress |
Extended ✅ | Emits 5 SSE progress events, then the final result. |
explain-calculation |
Core ✅ | Returns a stateless Markdown explanation. |
generate-problems |
Core ✅ | Returns stateless Markdown practice problems. |
calculator-tutor |
Core ✅ | Returns stateless Markdown tutoring content. |
solve_math_problem |
Stub | Returns error -32004 Available in extended build. |
explain_formula |
Stub | Returns error -32004 Available in extended build. |
calculator_assistant |
Stub | Returns error -32004 Available in extended build. |
calculator://constants |
Core ✅ | Resource for static mathematical constants. |
calculator://history/{id} |
Not Implemented | Always returns a 404 Not Found error. |
calculator://stats |
Core ✅ | Resource for process uptime only; no request counters. |
formulas://library |
Extended ✅ | Resource for a static list of mathematical formulas. |
request://current |
Extended ✅ | Debug resource that echoes current request info. |
🚀 Getting Started
Prerequisites
- Node.js (v20.x or higher)
- npm or yarn
Installation
# Clone the repository
git clone https://github.com/modelcontextprotocol/mcp-server-examples.git
cd mcp-server-examples/streamable-http-stateless
# Install dependencies
npm install
# Build the project
npm run build
Running the Server
# Start the stateless server on port 1071
npm run start:stateless
# Or, run in development mode with auto-reload
npm run dev
Testing with MCP Inspector
You can interact with the running server using the official MCP Inspector CLI. Ensure the server is running first.
# The CLI will connect to the server and list its capabilities
npx @modelcontextprotocol/inspector http://localhost:1071/mcp
📋 API Usage Examples
All requests are made to the single /mcp endpoint. No session headers are required.
Basic Calculation
curl -X POST http://localhost:1071/mcp \
-H 'Content-Type: application/json' \
-d '[{
"jsonrpc": "2.0",
"id": "req-1",
"method": "tools/call",
"params": {
"name": "calculate",
"arguments": { "a": 100, "b": 5, "op": "divide", "precision": 4 }
}
}]'
# Response:
# {"jsonrpc":"2.0","id":"req-1","result":{"content":[{"type":"text","text":"DIVIDE: 100 ÷ 5 = 20\n\nSteps:\nInput: 100 divide 5\nDivision: 100 ÷ 5 = 20\nFinal result (4 decimal places): 20"}],"metadata":{...}}}
Streaming Progress Demonstration
Use the -N (no-buffering) flag with curl to see the Server-Sent Events (SSE) as they arrive.
curl -N -X POST http://localhost:1071/mcp \
-H 'Content-Type: application/json' \
-d '[{
"jsonrpc": "2.0",
"id": "req-2",
"method": "tools/call",
"params": {
"name": "demo_progress",
"arguments": {}
}
}]'
# Expected SSE stream output (events arrive over 1 second):
# event: progress
# data: {"progressToken":"...","progress":0.2,"level":"info","data":"Progress step 1 of 5"}
#
# event: progress
# data: {"progressToken":"...","progress":0.4,"level":"info","data":"Progress step 2 of 5"}
#
# event: progress
# data: {"progressToken":"...","progress":0.6,"level":"info","data":"Progress step 3 of 5"}
#
# event: progress
# data: {"progressToken":"...","progress":0.8,"level":"info","data":"Progress step 4 of 5"}
#
# event: progress
# data: {"progressToken":"...","progress":1,"level":"info","data":"Progress step 5 of 5"}
#
# event: data
# data: {"jsonrpc":"2.0","id":"req-2","result":{"content":[{"type":"text","text":"Progress demonstration completed with 5 steps"}]}}
🧠 State Management Model
This server is explicitly stateless. All state required to process a request must be contained within the request itself. The server does not and cannot retain information between requests.
What IS NOT Stored Server-Side
- ❌ Calculation History: The server has no memory of past calculations.
- ❌ User Sessions: There is no concept of a user session.
- ❌ Request Correlation: The server does not link multiple requests together.
What IS Available (Per-Process or Per-Request)
- ✅ Process Uptime: Accessible via the
calculator://statsresource. This is global to the Node.js process, not a specific request. - ✅ Static Resources: The
calculator://constantsandformulas://libraryresources are read from static definitions on each call. - ✅ Request Context: The server has access to the current HTTP request headers and body, but only for the duration of that single request.
🛡️ Security Model
A stateless architecture changes the security model by eliminating session-based vulnerabilities.
- No Session Hijacking: Since there are no sessions, they cannot be hijacked.
- Per-Request Authentication: Security is handled on a per-request basis. In a production scenario, you would add middleware to validate an
Authorizationheader containing a stateless token (e.g., JWT) on every call. - Reduced Attack Surface: The absence of server-side state storage reduces the potential for state-based attacks like data corruption or information leakage between sessions.
- Input Validation: All parameters are rigorously validated on every request using Zod schemas, preventing malformed data from propagating.
🎓 Educational Tool (Optional)
For learning purposes, the server supports an optional educational echo tool via the SAMPLE_TOOL_NAME environment variable:
# Start server with educational tool
SAMPLE_TOOL_NAME=educational_echo npm run start:stateless
# Test the educational tool
curl -X POST http://localhost:1071/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"educational_echo","arguments":{"message":"Hello MCP!"}},"id":1}'
# Response: Sample tool "educational_echo" received: Hello MCP!
When set, the educational tool appears first in the tools list. When unset, only standard calculator tools are available.
🧪 Testing
This project includes a test suite verifying its stateless behavior.
# Run all available tests
npm test
# Run tests with a code coverage report
npm run test:coverage
# Run tests in watch mode for development
npm run test:watch
Production-Ready Features
This server includes several features designed for observability in a production environment.
Structured Logging
All console output is structured JSON, including a unique requestId to correlate all logs associated with a single HTTP request. This is essential for debugging in a distributed, serverless environment.
Example Log Entry:
{"timestamp":"2023-10-27T18:30:00.000Z","level":"info","message":"Created fresh MCP server instance","context":{"requestId":"..."}}
Monitoring & Health Checks
The server exposes several endpoints for monitoring and health checks:
| Endpoint | Method | Description |
|---|---|---|
/health |
GET |
A simple health check, returns status healthy. |
/health/detailed |
GET |
Provides detailed system, application, and characteristic info. |
/metrics |
GET |
Exposes basic metrics in a Prometheus-compatible format. |
Example Health Check:
curl -s http://localhost:1071/health | jq
{
"status": "healthy",
"timestamp": "2023-10-27T18:35:00.000Z",
"pattern": "stateless",
"uptime": 300.123,
"memory": { "rss": 50123456, ... },
"version": "1.0.0"
}
📚 Official Resources
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。