项目地址:https://github.com/xuezha/mcp-server-demo/
项目结构
~/mcp-server-demo/
├── pom.xml # Maven 配置,Spring Boot 3.5 + Spring AI MCP Starter
├── src/main/java/com/example/mcp/
│ ├── McpServerApplication.java # 启动类
│ ├── tool/CalculatorTool.java # Tool: 四则运算计算器
│ ├── resource/SystemInfoResource.java # Resource: 系统运行时信息
│ └── prompt/CodeReviewPrompt.java # Prompt: 代码审查模板
└── src/main/resources/
└── application.yml # StreamableHTTP 配置,端口 8080,endpoint /mcp
环境准备
你需要先安装:
brew install openjdk@17 maven
然后设置 JAVA_HOME:
export JAVA_HOME=(/usr/libexec/javahome−v172>/dev/null∣∣echo"/opt/homebrew/opt/openjdk@17")exportPATH="(/usr/libexec/java_home -v 17 2>/dev/null || echo "/opt/homebrew/opt/openjdk@17") export PATH="(/usr/libexec/javahome−v172>/dev/null∣∣echo"/opt/homebrew/opt/openjdk@17")exportPATH="JAVA_HOME/bin:$PATH"
构建 & 运行
cd ~/mcp-server-demo
mvn clean package -DskipTests
java -jar target/mcp-server-demo-1.0.0.jar
验证测试
服务启动后,用 curl 测试 StreamableHTTP 端点:
1. Initialize 握手
curl -X POST http://localhost:8080/mcp
-H "Content-Type: application/json"
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
2. 列出工具
curl -X POST http://localhost:8080/mcp
-H "Content-Type: application/json"
-H "Mcp-Session-Id: <从 initialize 响应头获取>"
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
3. 调用计算器
curl -X POST http://localhost:8080/mcp
-H "Content-Type: application/json"
-H "Mcp-Session-Id: "
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"calculate","arguments":{"operation":"multiply","a":6,"b":7}}}'
4. 列出资源
curl -X POST http://localhost:8080/mcp
-H "Content-Type: application/json"
-H "Mcp-Session-Id: "
-d '{"jsonrpc":"2.0","id":4,"method":"resources/list"}'
5. 读取系统信息
curl -X POST http://localhost:8080/mcp
-H "Content-Type: application/json"
-H "Mcp-Session-Id: "
-d '{"jsonrpc":"2.0","id":5,"method":"resources/read","params":{"uri":"system://info"}}'
6. 获取 Prompt 模板
curl -X POST http://localhost:8080/mcp
-H "Content-Type: application/json"
-H "Mcp-Session-Id: "
-d '{"jsonrpc":"2.0","id":6,"method":"prompts/get","params":{"name":"code-review","arguments":{"language":"Java","code":"int x = 1/0;"}}}'
三个 MCP 能力:
- calculate Tool --- 四则运算,支持 add/subtract/multiply/divide
- system://info Resource --- 返回 OS、Java 版本、内存等运行时信息
- code-review Prompt --- 参数化代码审查模板,接收 language 和 code 参数
装好 JDK 17 和 Maven 后就可以直接构建运行了。
7. MCP服务整条链路
这个MCP demo把MCP服务发布成StreamableHTTP,核心工作全由 Spring AI 的 starter 自动完成。整条链路如下:
关键入口:一个 starter 依赖
org.springframework.ai spring-ai-starter-mcp-server-webmvc
这个 starter 做了三件事:
- 引入 WebMVC StreamableHTTP Transport
starter 内部依赖了 WebMvcStreamableServerTransportProvider,它本质上是一个 Spring MVC 的 @Controller,在指定路径(默认 /mcp)上注册了 HTTP 端点:
- POST /mcp --- 接收客户端的 JSON-RPC 请求(initialize、tools/call、resources/read 等),返回 JSON 响应或 SSE 流
- GET /mcp --- 可选的 SSE 通道,用于服务端主动推送通知
- DELETE /mcp --- 客户端关闭会话
- 自动装配 MCP Server
Spring Boot 的 auto-configuration 扫描到你注册的 Bean:
- MethodToolCallbackProvider → 自动发现 @Tool 方法,注册为 MCP tools
- SyncResourceSpecification → 注册为 MCP resources
- SyncPromptSpecification → 注册为 MCP prompts
然后用这些 Bean 构建出 McpSyncServer,绑定到 transport provider 上。
- 会话管理
transport 层自动处理 Mcp-Session-Id 请求头。客户端第一次 initialize 时,服务端生成 session ID 放在响应头里返回;后续请求带上这个 header,服务端就能关联到同一个会话状态。
数据流走向
Client Spring MVC MCP Server
│ │ │
│── POST /mcp (initialize) ─────>│ │
│ │── JSON-RPC dispatch ────────>│
│ │<── ServerInfo + capabilities ─│
│<── 200 + Mcp-Session-Id ───────│ │
│ │ │
│── POST /mcp (tools/call) ─────>│ │
│ + Mcp-Session-Id header │── route to tool handler ───>│
│ │<── CallToolResult ───────────│
│<── 200 JSON ───────────────────│ │
配置驱动
application.yml 里的这段配置控制行为:
spring:
ai:
mcp:
server:
type: SYNC # 同步模式(vs ASYNC 用 Reactor)
streamable-http:
enabled: true # 启用 StreamableHTTP transport
endpoint: /mcp # HTTP 端点路径
enabled: true 是触发 StreamableHTTP auto-configuration 的开关。如果设为 false 或不配置,starter 会退回到 legacy SSE transport。
和旧 SSE 方式的区别
旧 SSE 需要两个端点(/sse 长连接 + /messages 接收请求),客户端必须先建立 SSE 连接才能通信。StreamableHTTP 统一成单个 /mcp 端点,普通 POST 请求就能完成交互,SSE
只在需要流式推送时可选使用。对负载均衡、代理、CORS 都更友好。
所以总结就是:你写业务逻辑(Tool/Resource/Prompt),starter 负责把它们通过 WebMVC 暴露为 StreamableHTTP 端点,中间的 transport 层、JSON-RPC 解析、会话管理全是自动的。