mcp-stateless-http-demo
A minimal stateless HTTP MCP server demonstrating the 2026-07-28 protocol era, with tools for arithmetic, order and user queries, resources, prompts, and MCP Apps, featuring caching and W3C trace context.
README
mcp-stateless-http-demo
基于 MCP 2.0 SDK 的 无状态 Streamable HTTP 最小可运行示例,并落地了 2026-07-28 协议大版本 的关键新特性。
约束遵循
项目开发文档.md(SDD):无 stdio、无 SSE、无 session-id、无 LLM。
一、项目定位:新版本要解决什么
MCP 协议在 2026-07-28 迎来了一次大版本升级(协议 era 从 2024/2025 演进到 2026-07-28)。本项目是这次升级的最小落地示范,用一套可运行的 Server + Client 验证"现代协议时代"的完整交互流程,重点回答三件事:
- 协议怎么变 —— 移除
initialize握手、改走server/discover,请求自动携带协议版本头; - 架构怎么变 —— 从"有状态会话"变为"无状态请求自包含",服务端零会话存储;
- 生产能力补了什么 —— 工具列表缓存、W3C Trace Context 分布式追踪、单行请求/响应日志、MCP Apps 交互式 UI。
| 能力 | 解决的问题 | 以前 MCP(传统模式) | 新方向(Server/Capability 模式) | 对 Agent / Planner 的影响 | ChatBI 示例 |
|---|---|---|---|---|---|
| 1. 动态发现(Dynamic Discovery) | 工具和服务越来越多,不想全部写死 | Client 先知道有哪些 Server,然后调用 tools/list 获取工具 |
Client 可以先发现业务能力 / Server,再发现 Server 下的 Tool | Planner 不需要维护所有工具清单,可以根据任务找到对应能力 | 用户问“分析销售下降原因”,先发现 Sales Analytics Server,再选择 analyze_growth |
| 核心变化 | 发现范围扩大 | Server → Tools |
Capability → Server → Tools |
从“找工具”变成“找解决问题的能力” | 从找 query_sales,变成找“销售分析能力” |
| 2. Server 自描述能力增强(Server Self Description) | Agent 不知道一个 Server 能干什么 | Tool 有 name、description、inputSchema |
Server 自己描述领域、业务对象、能力范围、权限、工具集合 | Planner 可以理解业务边界,不只是看到工具名字 | Sales MCP Server 描述:负责销售领域,支持收入、订单、客户分析 |
| 核心变化 | 描述粒度提升 | Tool 级描述 | Server / Domain 级描述 | LLM 可以先理解“这个服务适合解决什么问题” | 不只是看到 query_sales,而知道“这是销售分析领域能力” |
| 3. 对 Agent Planner 更友好(Planner-oriented) | Tool 数量爆炸,Prompt 塞不下 | Planner Prompt 中维护大量工具列表 | Planner 根据当前任务加载相关能力和工具 | Planner 从“工具选择”升级为“能力选择 + 工具选择” | 先选择 Sales Analytics 能力,再选择 query_sales、analyze_growth |
一句话总结新版本的价值:
旧版本演示"MCP 怎么跑起来";新版本演示"MCP 在 2026-07-28 时代该怎么设计"——无状态、可观测、可缓存、可交互。
二、新版本特性总览(功能 + 意义)
| 能力 | 说明 | 意义 |
|---|---|---|
| MCP Server / Client | 分别位于 server/ 与 client/ |
一个仓库同时示范两端,闭环验证协议 |
| Streamable HTTP | http://localhost:8000/mcp,仅 POST |
单一 HTTP 端点,对网关/防火墙友好 |
| Stateless(无状态) | 服务端不保存 session、不产生 mcp-session-id,每个请求自包含 |
无共享状态 → 天然支持水平扩展、容器化/边缘部署,故障恢复简单 |
| 现代协议 era(2026-07-28) | 客户端用 server/discover 握手,移除 initialize,自动发送 Mcp-Method / Mcp-Name / Mcp-Protocol-Version 头 |
单请求完成握手、请求自描述,连接更快、更贴近 REST 语义 |
| Tools | add multiply query_order list_orders get_user semantic_query |
覆盖算术、业务查询、语义查询(§13 Phase 2 预览) |
| Resource | resource://company/profile(静态)、resource://orders/{order_id}(模板) |
数据资源化访问,支持动态参数 |
| Prompt | welcome、order_analysis(order_id) |
提示词模板化,便于复用 LLM 引导 |
| MCP Apps(2026-07-28) | orders_table 工具绑定 ui://orders/table HTML 资源 |
工具输出从"纯文本"升级为"可交互界面" |
| tools/list 缓存(2026-07-28) | 响应带 _meta.ttlMs / cacheScope |
减少重复拉取,降低 LLM 应用的延迟与带宽 |
| W3C Trace Context(2026-07-28) | OpenTelemetry 分布式追踪,客户端 span 跨进程级联到服务端 | 端到端链路可观测,生产排障必备 |
| 请求/响应日志 | 每个 JSON-RPC 请求打印 [REQ] / [RESP](单行、可 grep) |
审计友好,无需额外中间件即可排查问题 |
三、与旧版本对比:优势一目了然
旧时代 = 2024/2025 协议(基于
initialize+ 会话);现代时代 = 2026-07-28 协议。
| 维度 | 旧时代(2024/2025) | 现代时代(2026-07-28) | 新版本优势 |
|---|---|---|---|
| 握手方式 | initialize 协商,需维护握手状态 |
server/discover 单请求完成 |
少一轮往返、更简单,接近普通 HTTP 调用 |
| 会话模型 | 有状态,携带 mcp-session-id |
无状态,每个请求自包含 | 可水平扩展、部署/运维简化、无粘性会话需求 |
| 传输格式 | 默认 SSE 流式响应 | Streamable HTTP,支持 json_response=True 返回纯 JSON |
客户端实现简单,任何 HTTP 栈都能对接 |
| 方法路由 | 靠请求体 method 字段识别 |
自动带 Mcp-Method / Mcp-Name / Mcp-Protocol-Version 头 |
网关/代理可直接按头路由,无需解析 body |
| 工具列表 | 每次全量拉取 | ttlMs / cacheScope 缓存提示 |
减少重复请求,LLM 应用首屏响应更快 |
| UI 能力 | 仅文本/结构化输出 | MCP Apps(ui:// 交互式 HTML) |
工具结果可渲染成可操作界面,而非静态文本 |
| 可观测性 | 无标准追踪 | W3C Trace Context(OTel) | 跨进程分布式追踪,一个 trace_id 贯穿两端 |
| 请求审计 | 无 | [REQ] / [RESP] 单行中间件 |
可直接 grep、可审计,无需额外部署 |
核心结论:新版本不是在旧模型上打补丁,而是把 MCP 的传输层、握手层、能力层全部升级——从"会话式 RPC"变成"无状态可观测的 HTTP 风格协议",这让 MCP Server 可以像普通 Web 服务一样部署、扩容、排障。
目录结构
.
├── 项目开发文档.md # SDD 规范(§5/6/7/8 为实现依据)
├── pyproject.toml # 依赖(mcp[cli]>=2.0.0、fastapi、uvicorn、opentelemetry-sdk)
├── README.md
├── server/ # MCP Server
│ ├── main.py # 入口 + McpServerLauncher 启动类
│ ├── tools.py # 工具 / 资源 / 提示词 / MCP Apps 定义
│ ├── logging_middleware.py # 请求/响应日志中间件(ServerMiddleware)
│ └── tracing.py # OpenTelemetry 追踪配置(Console/OTLP 导出)
└── client/ # MCP Client
├── main.py # discover → list → call 流程演示
└── tracing.py # 客户端追踪 + W3C traceparent 注入
快速开始
环境:Python 3.12+,包管理用 uv。
# 1. 安装依赖
uv sync
# 2. 启动服务端(终端 1)
.venv/bin/python server/main.py
# -> Uvicorn running on http://127.0.0.1:8000
# 或使用启动类自定义端口:
# .venv/bin/python -c "from server.main import McpServerLauncher; McpServerLauncher(port=9000).run()"
# 3. 运行客户端(终端 2)
.venv/bin/python client/main.py
客户端预期输出:
[Connected] modern protocol, supported=2026-07-28
client root span: 337fa235c2870945c7d857160f4dd58b
[Available Tools] orders_table, add, multiply, query_order, list_orders, get_user, semantic_query
[cache] tools/list ttlMs=300000 cacheScope=public
[Available Resources] ui://orders/table, resource://company/profile
[Available Prompts] welcome, order_analysis
[call] add(10, 20) -> 30
[call] query_order('10001') -> {...}
[resource] company/profile -> ...
[mcp-app] ui://orders/table -> <!DOCTYPE html>...
[prompt] order_analysis('10003') -> ...
[error] unknown tool -> is_error=True: Unknown tool: unknown
注意输出中的 [cache] tools/list ttlMs=300000 cacheScope=public 和 [mcp-app] ui://orders/table——这两行就是 2026-07-28 新特性(缓存提示、MCP Apps)的实际效果。
架构与协议流程
MCP Client(modern era)
│ discover(server/discover) ── Mcp-Method / Mcp-Protocol-Version 头,无会话
│ list_tools / call_tool / read_resource / get_prompt
▼ (每个请求自包含:capabilities/clientInfo 放 _meta,带 traceparent)
MCP Server(stateless_http=True, json_response=True)
│ OpenTelemetryMiddleware 提取 traceparent 建 span
│ RequestResponseLoggingMiddleware 打印 [REQ]/[RESP]
▼
Tools / Resources / Prompts / MCP Apps(MCPServer 注册)
协议时代说明:SDK 2.0 支持"双时代"——首个请求是 initialize 走旧协议(2024/2025 版本),
首个请求是 server/discover(或带 2026 封装的请求)则进入现代 era(2026-07-28)。
本 demo 客户端显式走现代 era。
2026-07-28 新特性实现细节
1. 无状态化 + 移除 initialize 握手
- 服务端:
streamable_http_app(stateless_http=True)—— 每次请求新建 transport,零会话存储。 - 客户端:
session.discover()替代session.initialize()—— 请求自动携带Mcp-Protocol-Version/Mcp-Method/Mcp-Name头。 - 验证:裸
curl -D无mcp-session-id响应头;连续请求各自独立。
2. tools/list 缓存(ttlMs / cacheScope)
server/tools.py 中:
cache_hints={
"tools/list": CacheHint(ttl_ms=300_000, scope="public"),
"server/discover": CacheHint(ttl_ms=60_000, scope="public"),
}
响应会带上 cacheScope/ttlMs;客户端可据此缓存 tools/list 结果 5 分钟。
3. MCP Apps(交互式 HTML 工具)
apps = Apps()
@apps.tool(resource_uri="ui://orders/table")
async def orders_table() -> list[dict]: ...
apps.add_html_resource("ui://orders/table", html, ...)
mcp = MCPServer(..., extensions=[apps])
宿主(如 Claude Desktop)在沙箱 iframe 渲染 ui:// HTML,经 postMessage + JSON-RPC
双向通信,把工具返回的数据渲染成可交互表格。本 demo 是文本客户端,只能读取 HTML 源文件,
不渲染界面。
4. W3C Trace Context(OTel)
- 服务端:SDK 内置
OpenTelemetryMiddleware为每个请求建 span (mcp.method.name/mcp.protocol.version/gen_ai.tool.name)。 - 客户端:
trace_meta()用opentelemetry.propagate.inject把traceparent写进每个请求的_meta,服务端extract出上下文 → 服务端 span 挂到客户端 span 下。 - 观察:客户端与服务端日志中 span 共享同一
trace_id,且parent_id指向客户端对应请求 span。 - 导出器:默认
ConsoleSpanExporter(打印 span);设置环境变量OTEL_EXPORTER_OTLP_ENDPOINT可切换为 OTLP(需另装opentelemetry-exporter-otlp-proto-http)。
请求/响应日志
server/logging_middleware.py 基于 SDK 的 ServerMiddleware 协议实现,
在每个 JSON-RPC 请求前后记录方法与参数/结果(单行、长内容截断到 500 字符):
08/01 15:54:43 INFO [REQ ] id=5 method=tools/call params={"name": "add", "arguments": {"a": 10, "b": 20}, "_meta": {...}}
08/01 15:54:43 INFO [RESP] id=5 method=tools/call result={"content": [{"text": "30", "type": "text"}], "isError": false, ...}
处理失败时记 [RESP] ... error=... 后原样抛出。
验证清单(AC)
- [x] AC-001 服务端启动:
python server/main.py→Uvicorn running on http://127.0.0.1:8000 - [x] AC-002 客户端连接:
[Connected] ... - [x] AC-003 工具发现:
add, multiply, query_order, list_orders, get_user, semantic_query(+orders_table) - [x] AC-004 工具调用:
add(10, 20) -> 30 - [x] AC-005 无状态验证:无
mcp-session-id,连续请求独立 - [x] §10 错误场景:未知工具/非法参数以
is_error=True结果返回 - [x] 2026 新特性:现代协议 era、tools/list 缓存、MCP Apps、W3C Trace Context
注意事项
- 文本客户端无法渲染 MCP Apps 界面;想看交互式 UI 需使用支持 MCP Apps 的宿主。
- OTel span 由
BatchSpanProcessor异步导出,打印可能晚于请求执行。 - 客户端 span 输出会混在演示输出里(结尾统一 flush),属正常现象。
_ORDERS/_USERS为只读演示数据(相当于 mock 数据库),不违反无状态要求。
推荐服务器
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 模型以安全和受控的方式获取实时的网络信息。