
1. 为什么 Java 开发者需要关注 Spring AI MCP ServerMCPModel Context Protocol模型上下文协议解决的是一个很实际的问题大模型本身只会“说”不会“做”。你问它今天杭州天气如何它只能凭训练数据猜你让它查一下订单表里某个用户的状态它也无从下手。MCP 的出现相当于给模型装了一双能伸进业务系统的手——通过标准化协议把外部工具、数据库、内部 API 暴露成模型可以调用的能力。Spring AI 从 1.0 版本开始正式提供 MCP Server 的官方支持这对 Java 生态来说是个不小的变化。以前想给模型接工具多数方案绕不开 Python 的 LangChain 或自己手写 HTTP 适配层现在用 Spring Boot 的注解和自动配置就能把服务暴露成 MCP 工具SSE 传输、工具注册、参数描述这些都有现成 starter 兜底。这篇文章面向的是已经在写 Spring Boot、想快速把内部能力接给大模型调用的 Java 开发者。我会用一个可运行的加法工具做例子把工程搭建、application.yml 配置、MCP Server 注册、SSE 连通性验证、以及模型调用通道用 TaoToken 统一 Key 接入串成一条完整链路。你跟着做下来能拿到一个本地能跑、能被 MCP 客户端连上的服务端。需要提前说清楚的是MCP Server 负责“暴露工具”模型调用负责“让模型决定调哪个工具”这两件事是分开的。很多新手卡住的地方就在于工具写好了但模型侧没配好于是对话里模型永远不调用工具。所以本文会把模型接入这一段也讲透用 TaoToken 的 OpenAI 兼容通道作为统一入口避免你在多个厂商 Key 之间来回切换。核心检索词先摆出来Spring AI MCP Server 是什么、能做什么、适合谁。它适合三类人——想把公司内部系统接给 AI 的 Java 后端、在做 AI Agent 需要工具编排的工程师、以及不想引入 Python 技术栈的 Spring 团队。下面从零开始。2. TaoToken 前置准备统一 Key 与 API 通道在写 MCP Server 之前先把模型调用这条线准备好。原因很简单MCP Server 只是工具提供方真正发起对话、决定调用哪个工具的是模型客户端。如果你用 Chatbox 这类客户端直连那客户端需要填一个模型 API如果你自己写 MCP Client 做端到端测试那代码里也要有模型通道。与其每个环节各配一套 Key不如统一走一个兼容 OpenAI 协议的入口。TaoToken 在这里扮演的就是统一接入层的角色。它提供 OpenAI 兼容的 API 形态也就是说你原来用spring-ai-openai-spring-boot-starter写的代码只需要把 base-url 和 api-key 换掉其余调用方式不变。对 Java 项目来说这点很关键——Spring AI 的 OpenAI 模型实现是现成的不用为了换供应商重写模型层。具体操作路径访问官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册账号进入控制台。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 在里面创建 API Key。创建完记得立刻复制保存页面刷新后完整 Key 不会再显示。拿到 Key 之后你需要记住两个地址API 基础地址https://taotoken.net/api 注意这个地址不加任何查询参数模型对话入口https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite如果你打算长期做编码类 Agent 或需要稳定的工具调用额度可以看下 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。它更适合高频调用场景比按量计费更可控。这里有个容易踩的坑很多人把 base-url 写成https://taotoken.net/api/v1然后在 Spring AI 里又自动拼了/v1结果变成/api/v1/v1/chat/completions直接 404。正确做法是 base-url 只写到https://taotoken.net/api让框架自己补路径。这个细节后面排障章节还会展开。Key 的权限方面建议按项目分 Key不要一个 Key 到处用。控制台的 API Keys 页面可以管理多个 Key出问题能快速定位是哪个项目超限或泄露。文档入口在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 遇到参数不确定时优先查文档而不是猜。准备工作做完你手上应该有三样东西一个可用的 API Key、base-urlhttps://taotoken.net/api、以及一个想接入的模型 ID比如常见的对话模型标识。这三样就是后面配置里的三件套缺一不可。3. 可复制配置application.yml 与 MCP Server 注册代码这一节是全文的技术核心我会给出可以直接复制的配置和代码。工程用 Spring Boot 3.5、Java 17依赖通过 start.spring.io 生成勾选spring-ai-starter-mcp-server-webmvc和spring-ai-starter-model-openai。先看 pom.xml 里需要的关键依赖版本以你生成时为准这里只列坐标dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server-webmvc/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency然后是 application.yml。这里同时配了两块MCP Server 的 SSE 端点和模型调用通道。注意缩进YAML 对空格敏感。server: port: 8080 spring: ai: openai: # 统一接入通道只写到 /api不要带 /v1 base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: gpt-4o-mini temperature: 0.7 mcp: server: name: math-mcp-server version: 1.0.0 # SSE 传输方式webmvc 场景下使用 protocol: SSE sse-endpoint: /api/v1/sse sse-message-endpoint: /api/v1/mcp/message关于api-key我强烈建议用环境变量注入不要硬编码在 yml 里。启动前设置export TAOTOKEN_API_KEY你的KeyWindows PowerShell 用$env:TAOTOKEN_API_KEY你的Key。接下来写工具类。Spring AI 用Tool注解描述工具能力方法参数就是模型要填的参数package com.example.mcp.tool; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; public class MathTool { Tool(description 计算两个整数相加的结果) public int addNumbers( ToolParam(description 第一个加数) int a, ToolParam(description 第二个加数) int b) { return a b; } Tool(description 计算两个整数相乘的结果) public int multiplyNumbers( ToolParam(description 第一个乘数) int a, ToolParam(description 第二个乘数) int b) { return a * b; } }注意description写清楚很重要模型是靠这段文字判断什么时候调用这个工具的。写“两个数字相加”比写“add”效果好得多。最后是注册配置类把工具暴露给 MCP Serverpackage com.example.mcp.config; import com.example.mcp.tool.MathTool; 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 McpServerConfig { Bean public ToolCallbackProvider mathToolCallbackProvider() { return MethodToolCallbackProvider.builder() .toolObjects(new MathTool()) .build(); } }启动类保持默认即可。跑起来之后SSE 端点就是http://localhost:8080/api/v1/sse。这里的三件套对应关系是Base URL 用https://taotoken.net/apiKey 用环境变量里的值Model ID 用 yml 里的gpt-4o-mini按你实际可用的模型替换。这三样在 MCP Client 或 Chatbox 里配置时同样适用。4. 验证请求SSE 连通性与工具调用实测配置写完先别急着接客户端用 curl 验证 SSE 端点是否活着。打开终端执行curl -N http://localhost:8080/api/v1/sse-N表示禁用缓冲你会看到类似这样的输出并且连接保持不关闭event: endpoint data: /api/v1/mcp/message?sessionId8f3a1c2e-...看到event: endpoint就说明 SSE 通道建立成功服务端把消息回传地址也告诉你了。如果这里卡住没有任何输出或者直接连接被拒先检查端口和启动日志。接着验证模型通道。单独测一下 TaoToken 的对话接口确认 Key 和 base-url 没问题curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: 你好}] }返回里能看到choices数组和content字段就说明模型通道通了。这一步很关键因为后面 MCP 工具调用失败时你要能区分是工具侧问题还是模型侧问题。两端都通之后用 Chatbox 做端到端测试。在 Chatbox 里添加 MCP ServerURL 填http://localhost:8080/api/v1/sse传输方式选 SSE。然后在对话里问“帮我算一下 12 加 30 等于多少”。正常情况下模型会先发起工具调用服务端执行addNumbers再把结果 42 返回给模型最终回复你“12 加 30 等于 42”。实测下来最容易出问题的是模型没有触发工具调用直接自己编了个答案。这通常是因为工具描述不够清晰或者模型本身对 function calling 支持不好。换一个工具调用能力强的模型 ID 往往能解决。如果你要自己写 MCP Client 做自动化测试核心是先用 SSE 建立连接拿到 sessionId再往 message 端点发 JSON-RPC 请求。Spring AI 的 Client 侧 starter 已经封装了这些不建议手写协议细节。5. 常见报错排查清单401、连接失败与工具不触发这一节按真实报错来对照遇到问题直接查。401 Unauthorized。最常见的原因是 Key 没注入成功或写错。先确认环境变量在当前 shell 生效echo $TAOTOKEN_API_KEY。如果为空说明 export 没执行或换了终端窗口。另一个原因是 base-url 写成了带/v1的形式导致鉴权头被发到错误路径。记住 base-url 只写https://taotoken.net/api。还有一种是 Key 被控制台禁用或额度耗尽去 console 页面确认状态。local proxy failed / Connection refused。这个报错通常出现在 MCP Client 侧意思是连不上你的 SSE 端点。检查三件事服务是否真的启动了看日志有没有Tomcat started on port 8080、端口是否被占用、防火墙是否拦截。如果你在容器里跑localhost 在容器内指向容器自己要用宿主 IP 或服务名。reading choices 相关报错。这类错误一般出现在解析模型响应时说明返回体结构和预期不符。常见诱因是模型 ID 写错或者请求打到了非 OpenAI 兼容的路径。用第 4 节的 curl 单独测模型通道能快速定位。如果 curl 正常但代码报错检查 Spring AI 版本和 starter 是否匹配。OAuth / 鉴权流程报错。如果你用的是需要 OAuth 的客户端比如某些 Claude Code 场景注意 MCP Server 本身不负责 OAuth鉴权是在客户端和模型服务之间完成的。Claude Code 接入时Anthropic 相关配置入口在 https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentClaudeCodeAnthropicutm_campaignrewrite 按文档填 Base URL、Key、Model ID 三件套即可。工具不触发。模型回复正常但从不调用工具排查顺序工具description是否清晰、参数是否标了ToolParam、ToolCallbackProvider是否被 Spring 扫描到加个日志确认 Bean 创建了、模型是否支持 function calling。我踩过的坑是工具类没加进toolObjects服务起来了但工具列表是空的。SSE 连接建立后立刻断开。多半是sse-message-endpoint配错客户端拿到的回传地址无效。对照第 3 节 yml 里的两个端点路径确保和客户端配置一致。6. 把这条链路用起来从本地验证到长期编码走到这里你已经有了一个能跑的 Spring AI MCP ServerSSE 通道验证过模型调用通道也通了。接下来怎么用取决于你的场景。如果只是本地验证和偶尔测试用 Chatbox 连本地 SSE 端点就够了模型侧走 TaoToken 的模型对话入口 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 选一个工具调用能力强的模型即可。如果你要把这套东西用在日常编码或 Agent 工作流里调用频率会上来建议用 Coding Plan 管理额度避免按量计费时突然超支。配置方式不变还是那三件套Base URLhttps://taotoken.net/api、控制台创建的 Key、以及你选定的 Model ID。最后给一个实用建议把工具按业务域拆成多个ToolCallbackProvider不要把所有工具塞进一个类。工具数量多了之后模型选择准确率会下降描述也会互相干扰。按订单、用户、报表这种维度分开注册需要哪个挂哪个维护起来清爽很多。代码能跑通只是第一步真正省时间的是把排障清单存下来。下次再遇到 401 或工具不触发直接翻第 5 节对照比重新搜一遍快得多。