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

相关推荐
likerhood1 小时前
Map的keySet()方法和entrySet()方法(java学习)
java
乐之者v1 小时前
AI编程-- codex并行开发需求
java
weixin_520649871 小时前
C#线程底层原理知识
java·开发语言
xieliyu.2 小时前
Java手搓数据结构:从零模拟实现单向无头非循环链表
java·数据结构·学习·链表
0xDevNull2 小时前
队列(Queue)实战教程:从原理到架构应用
java·开发语言·后端
再写一行代码就下班2 小时前
word模版导出(占位符方式)
java·开发语言·word
懒得起名_yyf2 小时前
AI智能体Skills全面入门指南
java
敖正炀2 小时前
集合-List-ArrayList
java