文章目录
- [Spring AI + FastMCP 跨语言 MCP 集成踩坑实录:为什么 SSE 一直报错?](#Spring AI + FastMCP 跨语言 MCP 集成踩坑实录:为什么 SSE 一直报错?)
- 一、目标架构
- [二、FastMCP SSE Server](#二、FastMCP SSE Server)
- [三、Spring AI 配置](#三、Spring AI 配置)
- 四、诡异错误
- 五、问题根源
- 六、为什么会这样?
- [七、后来又试了 Streamable HTTP](#七、后来又试了 Streamable HTTP)
- 八、生产环境怎么做?
-
- [方案1:Java MCP Gateway](#方案1:Java MCP Gateway)
- [方案2:纯 REST](#方案2:纯 REST)
- 九、现在到底推荐什么?
- 十、总结
Spring AI + FastMCP 跨语言 MCP 集成踩坑实录:为什么 SSE 一直报错?
最近在研究 MCP(Model Context Protocol)生态时,尝试做了一个:
text
Spring AI MCP Client
->
Python FastMCP Server
的跨语言 Demo。
目标很简单:
- Python 使用 FastMCP 提供 Tool
- Spring AI 自动发现并调用 Tool
- 使用 SSE 或 HTTP 方式通信
原以为会很顺利,结果一路踩坑。
尤其是:
text
Spring AI + FastMCP SSE Transport
兼容问题。
这篇文章就把整个排查过程、原理、以及最终可行方案整理一下,希望能帮大家少踩坑。
一、目标架构
最开始想实现的是:
text
Spring AI MCP Client
|
| HTTP/SSE
|
Python FastMCP Server
Python 提供一个用户查询 Tool:
python
@mcp.tool()
def get_user_info(user_id: str):
return {
"id": user_id,
"name": "Tom"
}
Spring AI 自动调用。
二、FastMCP SSE Server
Python 端代码:
python
from fastmcp import FastMCP
mcp = FastMCP("user-service")
@mcp.tool()
def get_user_info(user_id: str):
return {
"id": user_id,
"name": "Tom"
}
if __name__ == "__main__":
mcp.run(
transport="sse",
host="0.0.0.0",
port=8081
)
启动后:
text
http://localhost:8081/sse
访问:
bash
curl http://localhost:8081/sse
返回:
text
event: endpoint
data: /messages/
说明 SSE Server 正常。
三、Spring AI 配置
Spring Boot:
yaml
spring:
ai:
mcp:
client:
enabled: true
sse:
connections:
user-service:
url: http://localhost:8081
endpoint: /sse
看起来没问题。
但是启动后直接报错。
四、诡异错误
日志:
text
ValidationError: Invalid JSON: EOF while parsing a value
核心报错:
text
POST /messages/?session_id=xxx 400 Bad Request
FastMCP 收到:
text
body = b''
也就是:
text
空请求体
而 FastMCP 的 SSE Server:
要求:
http
POST /messages/
Content-Type: application/json
body 必须是:
json
{
"jsonrpc":"2.0",
"method":"initialize"
}
结果 Spring AI 发了一个:
text
空 POST
于是直接:
text
400 Bad Request
五、问题根源
最开始以为:
- endpoint 写错
- session 有问题
- trailing slash
- Spring AI 配置错误
后来发现:
真正问题是:
text
Spring AI 与 FastMCP 的 SSE 协议实现并不完全兼容
虽然都叫:
text
MCP SSE Transport
但:
两边实际上:
- SDK 不同
- 生命周期不同
- session 机制不同
- probe 行为不同
尤其:
Spring AI 在建立连接时:
会先发送一个:
text
empty POST body
作为连接探测。
而 FastMCP:
严格要求必须是 JSON-RPC body。
于是协议直接冲突。
六、为什么会这样?
因为 MCP 生态目前还在快速演进。
现在实际上有几套实现:
| 生态 | 实现 |
|---|---|
| Spring AI | Java MCP SDK |
| FastMCP | Python MCP SDK |
| Claude Desktop | Anthropic MCP |
| FastAPI-MCP | OpenAPI Adapter |
虽然都叫:
text
MCP
但:
Transport 细节还没完全统一。
尤其:
text
SSE / Streamable HTTP
仍然存在兼容问题。
七、后来又试了 Streamable HTTP
Spring AI 1.1 已支持:
yaml
streamable-http:
理论上:
text
POST /mcp
会比 SSE 更标准。
但实际测试:
FastMCP 这边仍然不够稳定。
跨语言场景:
text
Spring AI ↔ Python MCP
目前还是容易踩坑。
八、生产环境怎么做?
目前比较稳的做法其实是:
方案1:Java MCP Gateway
text
Spring AI Client
->
Java MCP Server
->
Python REST API
即:
text
MCP 只在 Java 层
Python 不直接参与 MCP。
方案2:纯 REST
text
Spring AI Tool
->
HTTP
->
FastAPI
其实很多企业最终还是:
text
REST API
因为:
- 成熟
- 稳定
- 网关友好
- K8s 友好
九、现在到底推荐什么?
目前我的建议:
| 场景 | 推荐 |
|---|---|
| 学习 MCP | stdio |
| 本地开发 | stdio |
| Claude Desktop | stdio |
| Java 全栈 | Spring AI MCP |
| Python Tool | FastMCP |
| 跨语言 HTTP | 暂时谨慎 |
| 企业生产 | REST / Java MCP Gateway |
十、总结
这次踩坑最大的感受:
text
MCP 的理念非常先进
但:
text
跨语言 transport 生态
还没有完全成熟
尤其:
text
Spring AI ↔ Python MCP
目前:
stdio 依然是最稳定方案。
如果你只是:
- 学习 MCP
- 做本地 Agent
- Tool 实验
那么:
text
stdio 足够了
如果要:
- 微服务
- 云原生
- 跨机器
建议暂时:
text
REST API
或者:
text
Java MCP Gateway
会更稳一些。