)
1. 为什么 Java 开发者需要一个能查天气的 AI 助手如果你写过 Spring Boot大概率经历过这样的场景想让 AI 回答一句“纬度 20 经度 20 现在什么天气”结果模型一本正经地回你“我无法获取实时天气信息”。这不是模型笨而是它手里没有工具。Spring AI 加 MCP 协议解决的正是这件事——让模型在对话过程中主动调用你写好的 Java 方法把真实数据拿回来再组织成自然语言。这篇内容面向已经会写 Controller、会配 application.yml 的 Java 开发者目标是从一个空项目开始跑通“用户提问 → 模型识别意图 → 调用 MCP 天气工具 → 返回结构化结果”的完整链路。全程只需要一个统一 Key 来驱动模型不用在多个平台之间来回切换账号。我会把 MCP Server 的配置骨架、客户端的接入参数、以及一次真实查询的验证命令都贴出来你照着改路径就能跑。需要提前说明的是MCPModel Context Protocol在这里扮演的是“工具注册与发现”的角色。你可以把它理解成一份通讯录客户端知道有哪些工具可用模型知道什么时候该翻通讯录找人帮忙。Spring AI 则负责把这份通讯录翻译成模型能理解的 function calling 格式。两者配合Java 生态里就能做出可对话、可调用外部能力的智能体雏形。2. TaoToken 统一 Key 的前置准备在动手写代码之前先把模型调用这一层理顺。我试过在本地同时维护好几套模型配置改一个参数要翻三个文件后来统一走 TaoToken 的 API 入口客户端里只认一个 base-url 和一个 Key切换模型只改 model 名就行。你需要先拿到一个 API Key。打开 https://taotoken.net/api-keys 创建复制出来存到环境变量里别硬编码进代码。接着确认两件事一是模型对话入口在 https://taotoken.net/api 下二是 Spring AI 的 OpenAI 兼容 starter 可以直接指向这个地址。如果你还没决定用哪个模型可以先到模型对话页面试几句确认返回正常再写进配置。这里有个细节Spring AI 的 OpenAI starter 默认会拼接/v1/chat/completions所以 base-url 填到域名加/api即可不要自己再补/v1。Key 的传递方式走标准的Authorization: Bearer头Spring AI 会自动处理。把这两项确认好后面 MCP Server 和 Client 的配置才有稳定的模型后端。3. 可复制的 MCP Server 与 Client 配置骨架先建 MCP Server 模块。它的职责很单一暴露一个带Tool注解的方法通过 stdio 与客户端通信。核心服务类长这样Service public class WeatherService { Tool(description Get weather forecast for a specific latitude/longitude) public String getWeatherByLocation(int latitude, int longitude) { if (latitude 10 longitude 10) { return The forecast for latitude 10 and longitude 10 is rainy; } if (latitude 20 longitude 20) { return The forecast for latitude 20 and longitude 20 is stormy; } return The forecast is sunny; } }Tool里的 description 不是写给人看的是写给模型看的。模型靠这句话判断“用户问天气时我该不该调这个方法”。描述里带上 latitude/longitude 这类关键词命中率会明显提高。Server 的 application.yml 只需要三行关键配置spring: application: name: spring-ai-mcp-server ai: mcp: server: stdio: true server: port: 9998stdio: true表示这个服务不靠 HTTP 端口对外而是通过标准输入输出被客户端拉起。端口号在这里只是占位实际通信不走它。Client 模块的依赖需要两个 starterMCP 客户端和 OpenAI 兼容的模型 starter。dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-client/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependencyClient 的 application.yml 把模型指向 TaoToken同时声明 MCP 工具回调开启spring: ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: gpt-4o-mini mcp: client: toolcallback: enabled: true type: SYNC stdio: servers-configuration: classpath:/mcp-servers-config.jsontype: SYNC表示同步调用调试阶段比异步好排查。servers-configuration指向的 JSON 文件告诉客户端怎么启动 Server{ mcpServers: { spring-ai-mcp-weather: { command: java, args: [ -Dspring.ai.mcp.server.stdiotrue, -jar, /absolute/path/to/spring-ai-mcp-server-0.0.1-SNAPSHOT.jar ] } } }路径一定用绝对路径。相对路径在 IDE 里跑和命令行里跑的工作目录不一样很容易出现“明明文件在却找不到”的情况。4. 验证请求与成功结果配置写完后先编译打包 Server./mvnw clean package -pl spring-ai-mcp-server -am然后启动 Client./mvnw spring-boot:run -f spring-ai-mcp-client/pom.xmlClient 启动时会自动按 JSON 里的命令拉起 Server 进程。如果控制台出现 MCP 工具注册成功的日志说明通讯录已经加载。接着发一次真实查询curl -G http://localhost:8080/chat \ --data-urlencode query纬度20经度20的天气怎样预期返回类似纬度20经度20的天气预报是暴风雨天气。再换英文问一次确认多语言都能命中同一个工具curl -G http://localhost:8080/chat \ --data-urlencode queryWhats the weather at latitude 20 longitude 20?返回The forecast for latitude 20 and longitude 20 is stormy就说明整条链路通了。这里的关键不是天气数据本身而是模型确实调用了你写的 Java 方法而不是凭空编造。5. 本篇常见错误排查中文提问时模型不调工具直接说无法获取天气。这是系统提示词没覆盖中文关键词。在defaultSystem里显式列出“天气、纬度、经度、预报”等词并加上 MUST use tools 的强制指令命中率会从“偶尔”变成“稳定”。MCP Server 启动失败日志报找不到 jar。九成是 JSON 里的路径问题。用pwd确认当前目录把 jar 的绝对路径填进去。另外确认打包产物名和 JSON 里写的一致版本号写错也会找不到。Client 启动报 401 或模型调用失败。检查TAOTOKEN_API_KEY环境变量是否真的注入到了运行进程里。IDE 里配的环境变量和终端里的不是同一份建议在启动命令前显式 export 一次再验证。工具被调用了但返回结果不对。检查Tool方法的参数类型。模型传过来的是 JSON 数字如果方法签名写成 String反序列化会失败。latitude/longitude 用 int 或 double 都行但别用 String 接。改了 Server 代码但 Client 还是旧行为。MCP Server 是被 Client 以子进程方式拉起的改了 Server 必须重新 package否则 JSON 里指向的还是旧 jar。养成“改 Server 先打包”的习惯。6. 下一步把天气助手接进真实场景跑通这个最小闭环之后你可以做两件事让它更像一个真项目。第一把WeatherService里的假数据换成真实天气 API 的调用Tool方法内部发 HTTP 请求拿实时数据模型侧完全不用改。第二如果你打算长期跑编码类或 Agent 类任务可以了解下 Coding Plan 的额度方式比按次调用更适合高频调试。接入文档在 https://taotoken.net/doc 有更细的参数说明遇到模型侧报错可以先翻那里。整个链路的核心其实就一句话模型负责理解意图MCP 负责暴露工具Spring AI 负责把两者接起来。你把工具写对、描述写清楚剩下的交给协议就行。