使用 java 搭建一个基于 StreamableHTTP 的 MCP 服务

项目地址: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 做了三件事:

  1. 引入 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 --- 客户端关闭会话
  1. 自动装配 MCP Server

Spring Boot 的 auto-configuration 扫描到你注册的 Bean:

  • MethodToolCallbackProvider → 自动发现 @Tool 方法,注册为 MCP tools
  • SyncResourceSpecification → 注册为 MCP resources
  • SyncPromptSpecification → 注册为 MCP prompts

然后用这些 Bean 构建出 McpSyncServer,绑定到 transport provider 上。

  1. 会话管理

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 解析、会话管理全是自动的。

相关推荐
噢,我明白了18 小时前
表单的完整 CRUD 练习【极简个人记账本】(含前端后端链接mySQL)
java·前端·数据库·mysql
通往曙光的路上18 小时前
mysql1
java
Tigshop开源商城1 天前
『物流设置+SEO优化』Tigshop开源商城系统 JAVA v5.8.26 版本更新!
java·开源商城系统·tigshop
Tigshop开源商城1 天前
『订单税率+收货地址校验国家字段』功能上新|跨境运营更高效,Tigshop开源商城系统 JAVA v5.8.23 版本更新
java·开源商城系统·tigshop
REDcker1 天前
C++变量存储与ELF段布局详解 从const全局到rodata与nm_readelf验证实践
java·c++·面试
kobesdu1 天前
【ROS2实战笔记-19】ROS2 生命周期节点的启动顺序、状态转换陷阱与热备方案
java·前端·笔记·机器人·ros·ros2
neo_Ggx231 天前
Maven 版本管理详解:SNAPSHOT、Release 与 Nexus 仓库的区别和影响
java·maven
matlabgoodboy1 天前
软件开发定制小程序APP帮代做java代码代编写C语言设计python编程
java·c语言·小程序
江离w1 天前
新版vibecoding项目初始化指令
java
tongluowan0071 天前
Spring MVC 底层工作流程+源码分析
java·spring·mvc