从零开始用Java搭建Spring AI MCP Server:STDIO模式配置与验证指南

发布时间:2026/9/27 20:11:49

从零开始用Java搭建Spring AI MCP Server:STDIO模式配置与验证指南 1. 为什么 Java 开发者需要一个 STDIO 模式的 MCP Server如果你正在用 Spring Boot 写业务系统又想让自己写的工具方法被 Claude、Cursor、TRAE 这类支持 MCP 的客户端直接调用那么 Spring AI 提供的 MCP Server Boot Starter 就是最省事的路径。MCP 全称 Model Context Protocol它做的事情可以类比成「给大模型装 USB 接口」你按协议把工具暴露出去客户端就能发现并调用不用为每个模型单独写适配层。STDIO 模式是四种传输方式里门槛最低的一种。它不走 HTTP、不占端口客户端启动一个子进程通过标准输入输出收发 JSON-RPC 消息。适合命令行工具、桌面应用内嵌服务、本地单机场景。你写完一个 jar客户端配置里写一行java -jar握手成功就能用。这篇聚焦 STDIO 这一条链路从依赖坐标、application.yml 骨架、Tool工具定义到打包、客户端 config.toml 配置、握手验证和工具调用目标是一次跑通。模型侧统一走 TaoToken 的 Key 和 API 通道这样客户端和 Server 的鉴权配置可以收敛到一处不用在多个平台之间来回切换。适合谁看有 Java 基础、用过 Spring Boot、想快速把本地能力接进 AI 客户端的开发者。不需要你提前懂 MCP 协议细节跟着配置走即可。2. 前置准备TaoToken Key 与 Spring AI 版本对齐2.1 拿到统一 KeyTaoToken 的定位是给 AI 应用提供统一的模型调用入口。你只需要在控制台创建一个 API Key后续客户端里配置 base-url 和 api-key 就能调用模型。地址如下官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 通道https://taotoken.net/api控制台创建 Keyhttps://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteKey 管理页https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite创建完把 Key 存到环境变量里别硬编码进代码export TAOTOKEN_API_KEYsk-你的key2.2 版本矩阵Spring AI 的 MCP 支持在 1.1.x 才比较完整STDIO starter 的坐标和早期版本有差异务必对齐组件版本要求说明JDK17Spring AI 1.1 最低要求推荐 21Spring Boot3.2与 Spring AI 1.1 兼容Spring AI BOM1.1.0-M2 或更高统一管理 starter 版本Maven3.8构建工具注意如果你之前用过spring-ai-mcp-server-spring-boot-starter这种旧坐标1.1.x 已经改成spring-ai-starter-mcp-server写错会直接报找不到依赖。3. 可复制配置STDIO MCP Server 骨架3.1 父工程 BOM先建一个父 pom把版本收口子模块不用重复写版本号?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.5.6/version relativePath/ /parent groupIdcom.example/groupId artifactIdmcp-parent/artifactId version0.0.1-SNAPSHOT/version packagingpom/packaging modules modulestdio-mcp/module /modules properties java.version21/java.version spring-ai.version1.1.0-M2/spring-ai.version /properties dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version${spring-ai.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement /project3.2 子模块依赖STDIO 模式只需要一个 starter不要引入 web 相关依赖否则会启动 Tomcat 破坏标准输入输出通道?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdcom.example/groupId artifactIdmcp-parent/artifactId version0.0.1-SNAPSHOT/version relativePath../pom.xml/relativePath /parent artifactIdstdio-mcp/artifactId dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server/artifactId /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build /project3.3 application.yml 骨架STDIO 模式的关键是关掉 web 容器、关掉 banner、关掉控制台日志因为 stdout 要留给协议消息任何多余输出都会污染握手spring: main: banner-mode: off web-application-type: none ai: mcp: server: enabled: true stdio: true name: stdio-time-server version: 1.0.0 type: SYNC capabilities: tool: true resource: true prompt: true request-timeout: 30s logging: pattern: console: file: name: ./logs/stdio-mcp.log注意logging.pattern.console:后面留空是故意的表示不向控制台输出日志。日志改写到文件方便排查又不干扰协议。3.4 定义工具用Tool注解标记方法Spring AI 会自动生成 JSON Schema 并注册到 MCP 能力列表package com.example.stdiomcp.tools; import org.springframework.ai.tool.annotation.Tool; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; Service public class TimeToolService { Tool(description 获取当前本地时间返回时间戳、可读时间和星期信息) public String getTime() { LocalDateTime dateTime LocalDateTime.now(ZoneId.of(Asia/Shanghai)); long timestamp System.currentTimeMillis(); DateTimeFormatter formatter DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss); String formatted dateTime.format(formatter); int dayOfWeek dateTime.getDayOfWeek().getValue(); int dayOfYear dateTime.getDayOfYear(); return String.format(时间戳: %d, 时间: %s, 星期%d, 本年第%d天, timestamp, formatted, dayOfWeek, dayOfYear); } }3.5 注册工具回调光有Tool还不够需要显式注册ToolCallbackProvider否则客户端tools/list拿到的是空列表package com.example.stdiomcp.config; import com.example.stdiomcp.tools.TimeToolService; import org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.ai.tool.method.MethodToolCallbackProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class ToolsConfig { Bean public ToolCallbackProvider timeTools(TimeToolService timeToolService) { return MethodToolCallbackProvider.builder() .toolObjects(timeToolService) .build(); } }3.6 打包mvn -pl stdio-mcp -am clean package -DskipTests产物在stdio-mcp/target/stdio-mcp-0.0.1-SNAPSHOT.jar记住这个绝对路径客户端配置要用。4. 客户端 config.toml 与握手验证4.1 客户端侧配置不同客户端的配置文件格式略有差异但核心字段一致command、args、env。以通用 JSON 形式举例Claude Desktop 用的是claude_desktop_config.jsonCursor 和 TRAE 用mcp.json字段结构相同{ mcpServers: { stdio-time-server: { command: java, args: [ -Dspring.ai.mcp.server.stdiotrue, -Dlogging.pattern.console, -jar, /absolute/path/to/stdio-mcp-0.0.1-SNAPSHOT.jar ], env: { TAOTOKEN_API_KEY: sk-你的key } } } }如果你用的是支持 TOML 的客户端等价写法[mcp_servers.stdio-time-server] command java args [ -Dspring.ai.mcp.server.stdiotrue, -Dlogging.pattern.console, -jar, /absolute/path/to/stdio-mcp-0.0.1-SNAPSHOT.jar ] [mcp_servers.stdio-time-server.env] TAOTOKEN_API_KEY sk-你的key注意-jar后面必须是绝对路径。相对路径在客户端启动子进程时工作目录不确定会直接报找不到 jar。4.2 手动握手验证在接入客户端之前建议先用命令行手动验证一次确认 Server 能正常响应 initialize 请求。MCP 的 STDIO 传输是每行一个 JSON-RPC 消息你可以用管道喂进去printf %s\n \ {jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2024-11-05,capabilities:{},clientInfo:{name:cli-test,version:1.0}}} \ | java -Dspring.ai.mcp.server.stdiotrue -Dlogging.pattern.console \ -jar /absolute/path/to/stdio-mcp-0.0.1-SNAPSHOT.jar正常返回类似{jsonrpc:2.0,id:1,result:{protocolVersion:2024-11-05,capabilities:{tools:{listChanged:true}},serverInfo:{name:stdio-time-server,version:1.0.0}}}看到serverInfo里有你的服务名说明握手成功。4.3 验证工具列表接着发tools/list确认工具被正确注册printf %s\n \ {jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2024-11-05,capabilities:{},clientInfo:{name:cli-test,version:1.0}}} \ {jsonrpc:2.0,method:notifications/initialized} \ {jsonrpc:2.0,id:2,method:tools/list,params:{}} \ | java -Dspring.ai.mcp.server.stdiotrue -Dlogging.pattern.console \ -jar /absolute/path/to/stdio-mcp-0.0.1-SNAPSHOT.jar返回里应该能看到getTime这个工具带 description 和 inputSchema。4.4 验证工具调用最后发tools/call实际执行一次printf %s\n \ {jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2024-11-05,capabilities:{},clientInfo:{name:cli-test,version:1.0}}} \ {jsonrpc:2.0,method:notifications/initialized} \ {jsonrpc:2.0,id:3,method:tools/call,params:{name:getTime,arguments:{}}} \ | java -Dspring.ai.mcp.server.stdiotrue -Dlogging.pattern.console \ -jar /absolute/path/to/stdio-mcp-0.0.1-SNAPSHOT.jar返回的content数组里会带上格式化后的时间字符串。到这一步STDIO 链路就完整跑通了。5. 本篇常见错误排查5.1 客户端报「server disconnected」或握手超时最常见的原因是 stdout 被日志污染。检查三处banner-mode: off是否生效、logging.pattern.console:是否留空、有没有引入spring-boot-starter-web。任何一行非 JSON 输出都会让客户端解析失败。5.2 tools/list 返回空数组Tool方法所在类没有加Service或Component或者没有注册ToolCallbackProviderBean。两个条件缺一不可。另外确认spring.ai.mcp.server.capabilities.tool是 true。5.3 启动报 web 容器相关异常说明 classpath 里有 web 依赖。STDIO 模式必须web-application-type: none同时 pom 里不能有spring-boot-starter-web或spring-boot-starter-webflux。如果确实需要 HTTP 能力应该改用 SSE 或 Streamable-HTTP 模式而不是在 STDIO 里混用。5.4 中文返回乱码客户端和 Server 的编码不一致。在启动参数里加-Dfile.encodingUTF-8并确认Tool返回的字符串本身是 UTF-8。5.5 工具调用报「method not found」tools/call里的name必须和tools/list返回的完全一致大小写敏感。如果你改了方法名客户端缓存可能还是旧的重启客户端即可。6. 下一步把模型通道也接上STDIO Server 本身只负责暴露工具真正让模型「用起来」还需要客户端侧配置模型通道。如果你希望客户端调用模型时也走统一入口可以在客户端配置里把 base-url 指向 TaoToken 的 API 地址api-key 用同一个 Key模型对话调试入口https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite长期编码 / Agent 场景https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite这样工具调用和模型推理共用一套鉴权排查问题时只需要看一个 Key 的用量和日志。STDIO 这条链路跑通之后再切到 SSE 或 Streamable-HTTP 只是换 starter 和 yml 的事工具代码可以原样复用。
延伸阅读

更多相关文章

2026/9/27 20:06:48

游戏网站域名选型与部署的5个最佳实践

游戏网站域名选型与部署的5个最佳实践 想做个游戏官网,手抖得厉害?别慌。 很多创始人卡在第一步: 自己不会代码,却想做网站 。 其实,域名选对,技术门槛就砍掉一半。 今天聊点实操。不整虚的,直接上 最佳实践 。 一、 目标定死,指标先行…

2026/9/27 20:06:48

3步修复wordpress主题蓝色被黑漏洞的保姆级建站教程

3步修复wordpress主题蓝色被黑漏洞的保姆级建站教程 你的wordpress主题蓝色站点突然弹满赌博广告,后台密码改不动,是不是懵了?别慌,这是典型的被挂马攻击。很多站长遇到这事只会重装系统,结果三天后又被黑,根本不知道问题出在哪。今…

2026/9/27 21:01:54

5G EPS FB掉2G通话聚集排查:gNB重定向优先级与邻区配置优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/27 21:01:54

CCS入门到烧录:DSP开发三大关键操作详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/27 21:01:54

高精度相机标定棋盘格图:光学、算法与物理三重验证标准

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/27 21:01:53

展开网站建设全流程对比评测:3步搞定域名服务器不踩坑

展开网站建设全流程对比评测:3步搞定域名服务器不踩坑 域名选错、服务器配烂,90%的新手站长第一步就输给了技术门槛。别被那些花哨的营销词忽悠,展开网站建设的核心,就是要把“域名”和“服务器”这两个地基打牢。…

2026/9/27 0:00:45

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/27 0:00:45

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/27 0:00:45

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/27 0:00:45

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/27 0:00:45

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/27 0:00:45

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/25 20:55:38

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/26 19:58:38

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/25 18:34:56

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑