Spring AI MCP Server接入百炼问题排查

Spring AI MCP Server接入百炼问题排查

问题背景

在将基于Spring AI的MCP(Model Context Protocol)服务接入阿里云百炼平台时,遇到一个奇怪的问题:MCP服务在trae客户端上可以正常工作,但在百炼平台上却无法正常使用。具体表现为百炼平台发送第二个请求时,服务端接收不到请求体,导致请求失败。

公司有个AI对话智能体的需求,作为负责这个需求的后端开发,开发阶段被这个问题困扰了好久,不过最终还是然我找到原因了。所以写一篇博客分享一下,避免大家后续使用Spring MCP Server 接入百炼时踩坑!

问题现象

正常情况(trae客户端)

trae客户端每个请求都创建新的连接:

  1. 第一个连接发送initialize请求 → 响应后关闭连接
  2. 第二个连接发送notifications/initialized请求 → 响应后关闭连接
  3. 第三个连接发送tools/list请求 → 正常处理

异常情况(百炼平台)

百炼一直会提示:"获取工具异常,请确认MCP是否正常运行"

复制代码
"获取工具异常,请确认MCP是否正常运行
错误码:11200001
RequestId: dce6eab1-b35c-4471-bc97-d764639dff73

分析日志后发现是由于百炼平台会尝试复用连接导致的:

  1. 第一个连接发送initialize请求 → 响应后服务器关闭连接
  2. 在同一个连接上尝试发送第二个请求 → 但是此时MCP服务端Netty已经关闭链接了,这时候即使收到请求头,但是Netty的channel可能已经半关闭了,无法再继续接收请求内容,也无法正常响应内容。百炼那边等待超时就抛出异常了!

日志分析

从服务端日志可以看到关键信息:

log 复制代码
# 第一个请求正常处理
2025-12-13T11:43:58.745+08:00 INFO  REQUEST_BODY_DEBUG : MCP Request Body (207 bytes): {"jsonrpc":"2.0","method":"initialize","id":"3fe559ae-0",...}

# 服务器响应后关闭连接
2025-12-13T11:43:58.750+08:00 DEBUG r.n.http.server.HttpServerOperations : Last HTTP packet was sent, terminating the channel

# 第二个请求到达,但请求体为空
2025-12-13T11:44:58.805+08:00 INFO  REQUEST_BODY_DEBUG : MCP Request Body (0 bytes): 
2025-12-13T11:44:58.808+08:00 ERROR WebFluxStreamableServerTransportProvider : Failed to deserialize message: No content to map due to end-of-input

问题定位

通过深入分析日志,我们发现问题出现在几个方面:

1. HTTP/1.1连接复用问题

  • 服务器在发送完第一个响应后立即关闭了连接(terminating the channel)
  • 百炼平台认为连接仍然可用,尝试复用连接发送第二个请求
  • 由于连接已关闭,第二个请求的请求体无法被正确传输

2. 客户端-服务器行为不一致

  • trae:为每个请求创建新连接,符合服务器预期
  • 百炼:尝试复用连接以提升性能,但与服务器行为冲突

3. 协议处理差异

  • trae使用协议版本:2025-06-18
  • 百炼使用协议版本:2025-03-26
  • trae的capabilities为空对象
  • 百炼的capabilities包含roots.listChanged=true

排查过程

第一阶段:基础排查

  1. 检查协议兼容性:确认两个协议版本都支持
  2. 检查日志级别:启用DEBUG级别日志
  3. 对比请求差异:分析trae和百炼的请求头、请求体差异

第二阶段:深入分析

  1. 添加请求体调试过滤器:
java 复制代码
@Component
@Order(1)
public class RequestBodyDebugFilter implements WebFilter {
    // 记录请求头和请求体内容
}
  1. 发现关键证据:
  • 第二个请求的Content-Length: 54,但实际接收到的body是0字节
  • 请求在开始处理后等待60秒超时
  1. 排除可能性:
  • 排除100-continue问题(百炼没有发送Expect头)
  • 排除缓冲区大小问题
  • 排除JSON解析问题

第三阶段:问题根源确认

通过对比分析和日志追踪,确认问题是:
服务器在HTTP/1.1连接上过早关闭连接,但客户端仍尝试复用该连接

解决方案

最终解决方案:响应头中告诉百炼,链接已经关闭

java 复制代码
@Component
@Order(Integer.MIN_VALUE)
public class ForceConnectionCloseFilter implements WebFilter {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        
        if (path.equals("/mcp")) {
            // 在响应头中强制设置Connection: close
            exchange.getResponse().getHeaders().set("Connection", "close");
            log.info("Forcing connection close for MCP request on connection: {}", 
                     exchange.getRequest().getId());
        }
        
        return chain.filter(exchange);
    }
}

方案原理

  1. 显式通信 :通过Connection: close头明确告诉客户端不要复用连接
  2. 客户端适配:百炼平台看到这个头后会为每个请求创建新连接
  3. 消除歧义:避免客户端和服务器对连接状态的理解不一致

其他尝试方案(未成功)

  1. 调整Netty配置尝试保持连接
  2. 修改HTTP解码器参数
  3. 添加Expect: 100-continue处理
  4. 调整连接超时时间

技术要点总结

1. HTTP/1.1连接管理

  • 默认情况下,HTTP/1.1支持连接复用(keep-alive)
  • 服务器可以通过Connection: close头显式关闭连接
  • Spring WebFlux/Netty在特定情况下可能过早关闭连接

2. Spring WebFlux行为

  • Reactive编程模型对连接管理有特殊处理
  • Netty默认配置可能不适合所有客户端
  • 需要显式配置来处理连接复用

3. 客户端差异

  • 不同HTTP客户端对连接复用的实现策略不同
  • 有些客户端更激进地尝试复用连接
  • 服务器需要能够处理各种客户端行为

经验教训

  1. 不要假设客户端行为一致:不同的HTTP客户端实现可能有显著差异
  2. 连接管理要显式:模糊的连接管理容易导致问题
  3. 日志是最好的调试工具:详细的日志可以快速定位问题
  4. 简单方案往往最有效 :复杂的配置调整不如简单的Connection: close
  5. 理解底层协议:对HTTP协议的理解有助于解决这类问题

结论

通过添加ForceConnectionCloseFilter,我们成功地解决了Spring AI MCP Server接入百炼平台的问题。这个问题的核心在于客户端和服务器对HTTP/1.1连接复用的行为不一致。解决方案虽然简单,但背后涉及对HTTP协议、Spring WebFlux连接管理和客户端兼容性的深入理解。

相关推荐
xiwc2 小时前
我用 MCP + 多 Agent 搭了一条自动化内容发布流水线
人工智能·mcp
蓝胖的四次元口袋2 小时前
MCP知识梳理(1)
mcp
EatFan3 小时前
「失控AI智能体」首遭FTC立案:英伟达Agent安全体系落地,AI智能体合规设计如何前置
大数据·人工智能·安全·ai智能体·mcp·agent安全·ftc
EatFan4 小时前
MCP 从概念到落地:Java(Spring AI Alibaba)与 .NET 双栈接入实操对比
java·人工智能·后端·spring·.net·java后端·mcp
EatFan18 小时前
从“框架混战“到“运行时收敛“:2026 年 AI Agent 开发框架的三条路线之争
java·数据库·人工智能·多智能体·ai agent·mcp·agent 框架
诺伦1 天前
AI Agent编排实战:用四层架构搭建增长运营垂类Agent系统 | RiseClaw玄策
人工智能·ai agent·mcp·agent编排·增长运营
大连好光景1 天前
MCP协议与Function Calling的区别?
functioncalling·mcp
EatFan1 天前
从云原生到AI原生:2026后端架构“三驾马车”(事件驱动、虚拟线程、AI Agent内嵌)演进解析
spring boot·云原生·架构·虚拟线程·ai-native·ai agent·spring ai
Patrick在香港1 天前
MCP 的 initialize 握手真的没了?67 行标准库实测 2026-07-28 规范
python·agent·claude·mcp·json-rpc
EatFan2 天前
AI Agent 进入工程化下半场:从多智能体编排走向治理、标准化与运行沙箱
人工智能·多智能体·ai agent·开源框架·mcp·agents.md