news 2026/6/24 11:11:33

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 能力(否则必翻车)

正确配置

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 日志
数据库连接池启动日志

错误表现

Unexpected token '�' not valid JSON Unexpected non-whitespace character after JSON

必须做的事情

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

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

<configuration><propertyname="LOG_FILE"value="logs/mcp-server.log"/><appendername="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><rootlevel="INFO"><appender-refref="FILE"/></root><loggername="org.springframework.ai.mcp"level="DEBUG"/><!-- 关闭 Spring Boot 自带的启动 INFO --><loggername="org.springframework.boot.StartupInfoLogger"level="OFF"/><loggername="org.springframework.boot.autoconfigure.logging"level="OFF"/></configuration>

或者直接:

<configuration><rootlevel="OFF"/></configuration>

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


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

典型错误

"��ѯˮ����Ϣ��时间�?"

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

正确做法(TRAE 启动参数)

{"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

建议

spring:profiles:active:dev

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

--spring.profiles.active=dev

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

不推荐的返回方式

@ToolpublicReservoirInfogetReservoirInfo(Stringname)

问题可能来自:

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

推荐做法(最佳实践)

@ToolpublicMap<String,Object>getReservoirInfo(Stringname){ReservoirInfoinfo=service.findByName(name);if(info==null){returnnull;}Map<String,Object>result=newHashMap<>();result.put("name",info.getName());result.put("code",info.getCode());result.put("location",info.getLocation());returnresult;}

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


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

错误示例(非常常见)

System.out.println("查询水库信息:"+name);

后果

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

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


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

application.yml(推荐基线)

spring:main:web-application-type:none# 设置为非Web应用类型banner-mode:off# 关闭 Spring Boot 启动横幅ai:mcp:server:enabled:truename:demo-aiversion:1.0.0stdio:truelogging: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 就会变得非常稳定、非常可靠


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/24 10:14:31

PaddlePaddle Knowledge Distillation:蒸馏压缩大模型

PaddlePaddle 知识蒸馏&#xff1a;让大模型“瘦身”也能聪明如初 在今天的AI产品开发中&#xff0c;我们常常面临一个矛盾&#xff1a;一方面&#xff0c;像ERNIE、PP-YOLO这样的大模型在精度上表现惊艳&#xff1b;另一方面&#xff0c;它们动辄数百MB的体积和毫秒级以上的推…

作者头像 李华
网站建设 2026/6/21 23:05:11

PaddlePaddle输入输出定价:请求与响应Token统计

PaddlePaddle输入输出定价&#xff1a;请求与响应Token统计 在AI服务逐渐走向产品化、商业化的今天&#xff0c;一个看似技术细节的问题正变得越来越关键——一次API调用到底该收多少钱&#xff1f; 尤其当企业开始将大模型集成到客服系统、文档处理平台或智能助手时&#xf…

作者头像 李华
网站建设 2026/6/13 22:43:24

使用Vitis进行RTL核集成:手把手操作指南

手把手教你用Vitis集成RTL核&#xff1a;从Verilog到C调用的完整实战路径你有没有遇到过这种情况&#xff1f;手头有一个性能出色的Verilog写的图像滤波器&#xff0c;已经通过了时序收敛和功能仿真&#xff0c;但一想到要把它塞进Zynq系统里、还能被Linux上的C程序调用&#x…

作者头像 李华
网站建设 2026/6/20 17:41:56

告别审美黑洞!手把手教你用 NotebookLM 给 PPT “一键美颜”

你是否也经历过这样的崩溃时刻&#xff1a; 内容写好了&#xff0c;但配色怎么调都像 10 年前的汇报。想找几张高质量配图&#xff0c;结果在图库里耗掉了两个小时。做出来的 PPT 被老板评价为“没有商务感”、“不够严谨”。 其实&#xff0c;最近大火的 AI 神器 NotebookLM…

作者头像 李华
网站建设 2026/6/20 22:50:45

全球表迁移:轻松跨区域迁移DynamoDB表

在处理数据库迁移时,尤其是在AWS环境中,如何在不中断服务的情况下将数据从一个区域迁移到另一个区域是一个常见问题。本文将通过一个实际案例,详细介绍如何利用DynamoDB的全球表功能来实现这种迁移。 背景 假设你有一组DynamoDB表,目前这些表存储在一个特定的AWS区域。你…

作者头像 李华
网站建设 2026/6/23 6:24:04

Ktor中的Blob处理:用户头像的存储与传输

引言 在现代网络应用中,用户头像的处理是一个常见但又复杂的任务。特别是在使用Ktor框架时,如何高效地存储和传输这些头像数据成为了一个需要深入探讨的问题。本文将通过一个实际的例子,展示如何在Ktor中使用Blob来存储和传输用户头像数据。 背景 Ktor是一个基于Kotlin的…

作者头像 李华