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

相关推荐
星子落怀aa4 分钟前
Java 反复报错?Gemini助力修复
java
半夜修仙7 分钟前
RabbitMQ中如何保证消息的可靠性传输
java·分布式·中间件·rabbitmq·github·java-rabbitmq
Flittly9 分钟前
【AgentScope Java新手村系列】(3)工具系统
java·spring boot·spring
吴声子夜歌12 分钟前
Java——多线程编程技巧
java·多线程
AI行业学习25 分钟前
CC-Switch v3.16.1 官方下载 | 安装配置详细教程【2026.6.10】
java·开发语言·vue.js·python·mysql·eclipse·html
不负岁月无痕1 小时前
C++ 模板核心内容与高频面试题汇总
java·开发语言·c++
Flittly1 小时前
【AgentScope Java新手村系列】(2)第一个Agent-基础对话
java·spring boot·spring·ai
摇滚侠1 小时前
Spring MVC 不是一个单独的框架,是 Spring 框架的一个模块
java·spring·mvc
阿正的梦工坊1 小时前
【Rust】04-借用、引用与切片
java·数据库·rust
devilnumber2 小时前
静态代理 & 动态代理:实战运用 + 场景区别 + 怎么选
java·开发语言·代理模式