Spring Boot MCP(stdio)工具实现的注意事项(踩坑总结)

Spring Boot MCP(stdio)工具实现的注意事项(踩坑总结)

随着 MCP(Model Context Protocol)的普及,越来越多的人开始使用 Spring Boot + MCP 来给 AI 工具(如 TRAE、Claude Desktop )扩展能力。

stdio 模式的 MCP 和我们熟悉的 Web Spring Boot 完全不是一回事,稍不注意就会出现:

  • Tool 调用返回 null
  • MCP Client 报 JSON 解析错误
  • 工具列表加载失败
  • 中文参数直接乱码

本文结合 真实踩坑经验 ,总结 Spring Boot 实现 MCP(stdio)工具时的关键注意事项


一、首先要明确:stdio MCP ≠ Web 服务

MCP(stdio)本质是什么?

  • MCP Client(如 TRAE)启动你的程序
  • 通过 stdin / stdout 与之通信
  • stdout 是协议通道,不是控制台

👉 你必须把 Spring Boot 当成:

一个"命令行工具程序",而不是 HTTP 服务


二、必须关闭 Web 能力(否则必翻车)

正确配置

yaml 复制代码
spring:
  main:
    web-application-type: none

如果不关:

  • Tomcat 会启动
  • 控制台输出大量日志
  • stdout 被污染
  • MCP 直接无法解析

三、stdout 只能输出 MCP JSON(这是第一铁律)

常见 stdout 污染来源

来源 是否致命
Spring Boot Banner
log.info / log.debug
System.out.println
MyBatis SQL 日志
数据库连接池启动日志

错误表现

text 复制代码
Unexpected token '�'
not valid JSON
Unexpected non-whitespace character after JSON

必须做的事情

yaml 复制代码
spring:
  main:
    banner-mode: off
2️⃣ 关闭所有 stdout 日志
yaml 复制代码
logging:
  level:
    root: OFF
3️⃣ 提供 logback-spring.xml(推荐)

建议只输出MCP的日志其他日志写入到文件里:

xml 复制代码
<configuration>
    <property name="LOG_FILE" value="logs/mcp-server.log"/>

    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_FILE}</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="FILE"/>
    </root>

    <logger name="org.springframework.ai.mcp" level="DEBUG"/>
    <!-- 关闭 Spring Boot 自带的启动 INFO -->
    <logger name="org.springframework.boot.StartupInfoLogger" level="OFF"/>
    <logger name="org.springframework.boot.autoconfigure.logging" level="OFF"/>
</configuration>

或者直接:

xml 复制代码
<configuration>
    <root level="OFF"/>
</configuration>

MCP stdio 模式下,宁可没有日志,也不要 stdout 日志


四、Windows 下一定要强制 UTF-8(否则中文必炸)

典型错误

text 复制代码
"��ѯˮ����Ϣ��时间�?"

这是 GBK 输出 + UTF-8 解析 的经典乱码。

正确做法(TRAE 启动参数)

json 复制代码
{
  "command": "java",
  "args": [
    "-Dfile.encoding=UTF-8",
    "-Dspring.output.ansi.enabled=NEVER",
    "-jar",
    "xxx.jar"
  ]
}

📌 这一步不做,中文参数 100% 出问题


五、Tool 能调用 ≠ Spring 容器正常

一个非常迷惑人的现象是:

  • Tool 能被 TRAE 识别
  • 简单 Tool(时间、字符串)正常
  • 一查数据库就返回 null

常见原因

  1. 没有指定 profile
  2. 数据源指向了"空库"
  3. Mapper 没被扫描
  4. Service 实际上是 null

建议

yaml 复制代码
spring:
  profiles:
    active: dev

或在启动参数中显式指定:

text 复制代码
--spring.profiles.active=dev

六、MCP Tool 返回值要"简单、干净"

不推荐的返回方式

java 复制代码
@Tool
public ReservoirInfo getReservoirInfo(String name)

问题可能来自:

  • 懒加载代理
  • 循环引用
  • Jackson 序列化失败
  • LocalDateTime / BigDecimal

推荐做法(最佳实践)

java 复制代码
@Tool
public Map<String, Object> getReservoirInfo(String name) {
    ReservoirInfo info = service.findByName(name);
    if (info == null) {
        return null;
    }

    Map<String, Object> result = new HashMap<>();
    result.put("name", info.getName());
    result.put("code", info.getCode());
    result.put("location", info.getLocation());
    return result;
}

👉 MCP Tool = 接口协议,不是领域模型暴露


七、严禁在 Tool 中使用 System.out

错误示例(非常常见)

java 复制代码
System.out.println("查询水库信息:" + name);

后果

  • stdout 被污染
  • MCP JSON 被截断
  • Client 报解析错误

📌 stdio MCP 下,System.out = 自杀按钮


八、最小可用 MCP(stdio)配置模板

application.yml(推荐基线)

yaml 复制代码
spring:
  main:
    web-application-type: none    # 设置为非Web应用类型
    banner-mode: off              # 关闭 Spring Boot 启动横幅
    
  ai:
    mcp:
      server:
        enabled: true
        name: demo-ai
        version: 1.0.0
        stdio: true

logging:
  level:
    root: OFF

九、MCP stdio 的五条"生存铁律"

  1. stdout 只能输出 MCP JSON
  2. 禁止 Banner
  3. 禁止 stdout 日志
  4. 强制 UTF-8
  5. Tool 返回值尽量简单

只要违反一条,问题一定以 JSON 解析错误的形式出现


十、总结

Spring Boot 实现 MCP(stdio)工具时,最大的误区在于:

用 Web Spring Boot 的思维,去写一个"协议型命令行程序"

一旦你真正把它当成:

  • 没有控制台
  • 没有日志
  • stdout 只服务协议

👉 MCP 就会变得非常稳定、非常可靠


相关推荐
爬山算法37 分钟前
Hibernate(85)如何在持续集成/持续部署(CI/CD)中使用Hibernate?
java·ci/cd·hibernate
菜鸟233号1 小时前
力扣647 回文子串 java实现
java·数据结构·leetcode·动态规划
Charlie_lll1 小时前
力扣解题-[3379]转换数组
数据结构·后端·算法·leetcode
qq_12498707531 小时前
基于Java Web的城市花园小区维修管理系统的设计与实现(源码+论文+部署+安装)
java·开发语言·前端·spring boot·spring·毕业设计·计算机毕业设计
h7ml1 小时前
查券返利机器人的OCR识别集成:Java Tesseract+OpenCV优化图片验证码的自动解析方案
java·机器人·ocr
野犬寒鸦1 小时前
从零起步学习并发编程 || 第五章:悲观锁与乐观锁的思想与实现及实战应用与问题
java·服务器·数据库·学习·语言模型
Volunteer Technology2 小时前
Sentinel的限流算法
java·python·算法
VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue云租车平台系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
岁岁种桃花儿2 小时前
SpringCloud从入门到上天:Nacos做微服务注册中心
java·spring cloud·微服务
jdyzzy2 小时前
什么是 JIT 精益生产模式?它与传统的生产管控方式有何不同?
java·大数据·人工智能·jit