1. 为什么要在 Spring AI 里用 MCP 接天气预报
如果你正在用 Spring AI 做 Java 后端的大模型应用,大概率会遇到一个很现实的问题:模型本身不知道今天长沙多少度、明天北京下不下雨,而你又不想把天气查询逻辑硬编码进业务代码里。MCP(Model Context Protocol,模型上下文协议)就是来解决这类"外部能力接入"问题的——它把工具调用标准化,让大模型通过统一协议发现并调用你注册的工具方法,不用为每个工具写一套定制化的函数调用代码。
Spring AI 从 1.1.x 开始原生支持 MCP,服务端自动注册、客户端自动发现、工具一键绑定,Java 开发者用几个注解就能把普通业务方法变成 MCP 标准工具。这篇聚焦一个具体场景:用 Spring AI + MCP 协议做一个天气预报工具插件,同时把大模型通道统一走 TaoToken 的 Key 和 API 地址,避免在多个模型供应商之间来回切换配置。适合已经写过 Spring Boot、想快速把 MCP 工具链路跑通的 Java 后端开发者。
整篇的节奏是:先讲清楚 MCP 服务端和客户端各自要做什么,再给出 TaoToken 统一 Key 的 config.toml 配置骨架,然后是服务端工具注册、客户端调用链路的可复制配置,最后用一次本地启动验证确认插件能被正常发现和调用。你跟着做,能拿到一个可运行的天气预报 MCP 插件骨架。
2. TaoToken 前置:统一 Key 与 API 通道准备
在动手写 MCP 代码之前,先把大模型通道这块理清楚。MCP 客户端最终是要调用大模型的,而大模型调用需要一个稳定的 API 入口和 Key。TaoToken 在这里扮演的角色是统一 Key 和 API 通道——你不用为每个模型单独维护一套 base-url 和 key,而是通过一个统一的入口来管理。
你需要先拿到一个可用的 API Key。登录 TaoToken 官网(https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=),进入控制台创建 API Key:
- 控制台入口:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console
- API Keys 管理:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys
创建好 Key 之后,API 的基础地址是https://taotoken.net/api(注意这个地址不加 UTM 参数,直接用于代码里的 base-url)。这个地址兼容 OpenAI 风格的接口,所以 Spring AI 的spring-ai-starter-openai可以直接对接,只需要把 base-url 指过来、api-key 换成你的 TaoToken Key 即可。
注意:MCP 工具调用依赖大模型的 Function Calling 能力,选模型时要确认它支持函数调用,否则工具不会被触发。你可以在模型对话页面先验证一下模型是否正常响应:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat
如果你后续要做长期的编码或 Agent 类任务,可以考虑 Coding Plan,它更适合持续性的开发场景:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan
3. config.toml 配置骨架与 MCP 服务端搭建
3.1 config.toml 配置骨架
很多 MCP 客户端(包括一些 IDE 和命令行工具)用config.toml来声明 MCP 服务端。下面是一个可直接复用的骨架,把天气预报 MCP 服务端以 stdio 方式注册进去,同时把大模型通道指向 TaoToken:
# config.toml - MCP 客户端配置骨架 # 大模型通道:统一走 TaoToken [llm] provider = "openai-compatible" base_url = "https://taotoken.net/api" api_key = "sk-你的TaoTokenKey" model = "gpt-4o-mini" # 换成你账号下支持 Function Calling 的模型 temperature = 0.1 # MCP 服务端注册:天气预报插件(stdio 方式) [mcp_servers.weather] command = "java" args = [ "-Dfile.encoding=UTF-8", "-Dsun.jnu.encoding=UTF-8", "-jar", "D:/springboot-ai-mcp-server-0.0.1-SNAPSHOT.jar" ] enabled = true # 可选:SSE 方式注册(开发调试用) [mcp_servers.weather_sse] url = "http://localhost:8088/sse" enabled = false这个骨架里有两块关键信息:[llm]段负责大模型通道,base_url指向 TaoToken 的 API 地址;[mcp_servers.weather]段负责把天气预报 MCP 服务端注册进来,stdio 方式适合本地 jar 直接拉起,SSE 方式适合服务端已经独立跑起来、通过 HTTP 长连接接入的场景。
3.2 MCP 服务端 pom.xml
服务端的职责是把普通 Java 方法封装成 MCP 标准工具。先建一个 Maven 项目,pom.xml 核心依赖如下:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.5.11</version> </parent> <properties> <java.version>17</java.version> <spring-ai.version>1.1.4</spring-ai.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>版本这块要卡死:Spring Boot 3.5.11 配 Spring AI 1.1.4,JDK 17 起步。版本错配最常见的表现是自动配置类不生效,启动时看不到 MCP 相关 Bean。
3.3 服务端 application.yml
服务端支持两种传输方式,stdio 适合被客户端以子进程方式拉起,SSE 适合独立部署。SSE 方式的配置:
server: port: 8088 spring: application: name: springboot-ai-mcp-server main: web-application-type: servlet ai: mcp: server: enabled: true name: "天气预报 MCP 插件" version: "1.0.0" type: async sse-endpoint: /sse sse-message-endpoint: /mcp/message logging: level: org.springframework.ai.mcp: DEBUGstdio 方式则把web-application-type设为none,并加上stdio: true,同时把控制台日志关掉,避免日志污染 stdio 通道。
3.4 自定义 MCP 工具
核心代码就一个类,用@Tool和@ToolParam注解把方法暴露成 MCP 工具:
@Component @Slf4j public class WeatherMcpTool { private final WeatherService weatherService; public WeatherMcpTool(WeatherService weatherService) { this.weatherService = weatherService; } @Tool( name = "get_current_weather", description = """ 获取指定城市的实时天气信息,包括当前温度、湿度、风速、天气描述。 适用场景:用户询问"现在某地天气怎么样"、"某地热不热"时调用。 """ ) public String getCurrentWeather( @ToolParam(description = "城市名称,支持中文或英文,例如:北京、长沙、London") String city ) { log.info("[MCP Tool] 收到调用请求,city={}", city); WeatherResponse weather = weatherService.getWeather(city); return weather.toSummary(); } }工具描述要写清楚,大模型是靠 description 判断要不要调用、怎么传参的。描述模糊,工具大概率不会被触发。
3.5 注册工具回调
再写一个配置类,把工具对象注册成ToolCallbackProvider:
@Configuration public class McpServerConfig { @Bean public ToolCallbackProvider weatherTools(WeatherMcpTool weatherMcpTool) { return MethodToolCallbackProvider.builder() .toolObjects(weatherMcpTool) .build(); } }启动类就是标准 Spring Boot 启动类,启动后访问http://localhost:8088/sse能看到 SSE 长连接建立,说明服务端正常。
4. MCP 客户端接入与调用链路
4.1 客户端 pom.xml
客户端负责对接服务端、自动发现工具、绑定到 ChatClient。核心依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-openai</artifactId> </dependency> </dependencies>4.2 客户端 application.yml
这里把大模型通道指向 TaoToken,MCP 客户端通过 stdio 拉起服务端 jar:
server: port: 8080 spring: application: name: springboot-ai-mcp-client ai: openai: api-key: sk-你的TaoTokenKey base-url: https://taotoken.net/api chat: options: model: gpt-4o-mini temperature: 0.1 mcp: client: toolcallback: enabled: true transports: - type: stdio command: java args: - -jar - D:/springboot-ai-mcp-server-0.0.1-SNAPSHOT.jar logging: level: org.springframework.ai.mcp: DEBUG org.springframework.ai.tool: DEBUGbase-url指向 TaoToken 的 API 地址,api-key换成你在控制台创建的 Key。MCP 客户端启动时会自动连接服务端、拉取工具列表。
4.3 对话接口
写一个 Controller,把 MCP 工具回调绑定到 ChatClient:
@RestController public class WeatherController { private final ChatClient chatClient; public WeatherController(ChatClient.Builder builder, SyncMcpToolCallbackProvider mcpToolProvider) { this.chatClient = builder .defaultToolCallbacks(mcpToolProvider.getToolCallbacks()) .build(); } @GetMapping("/weather") public String queryWeather(@RequestParam String city) { return chatClient.prompt() .user(""" 查询 "%s" 的实时天气。 必须调用 get_current_weather 工具,不要用自身知识回答。 工具返回后直接原样返回结果。 """.formatted(city)) .call() .content(); } }SyncMcpToolCallbackProvider会自动把服务端发现的工具注入进来,defaultToolCallbacks绑定后,大模型在对话中就能自动判断并调用。
5. 本地启动验证与成功结果
启动顺序很重要:先起服务端,确认 8088 端口正常,再起客户端。客户端启动日志里如果能看到 MCP 工具发现相关的 DEBUG 输出,说明工具已经被拉取到了。
然后访问:
curl "http://localhost:8080/weather?city=长沙"预期返回类似:
长沙当前的天气为26℃,多云,南风3级,湿度68%。如果返回的是模型自己编的天气,说明工具没被调用。这时候去看客户端日志里有没有get_current_weather的调用记录,以及服务端日志里有没有[MCP Tool] 收到调用请求。两边日志对上了,链路就通了。
你也可以在模型对话页面单独验证模型通道是否正常:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat
6. 本篇常见错排查
工具没被调用,模型直接回答:最常见的原因是模型不支持 Function Calling,或者工具 description 写得太模糊。先确认模型支持函数调用,再把 description 写具体,明确适用场景。
客户端启动报连接失败:stdio 方式要确认 jar 路径正确、jar 已经 package 过;SSE 方式要确认服务端先起来了、端口没被占用。路径里的反斜杠在 yaml 里要注意转义。
版本冲突导致自动配置失效:Spring AI 1.1.4 必须配 Spring Boot 3.5.x,JDK 17 起步。版本不对会出现 MCP 相关 Bean 找不到的情况。
SSE 连接超时:生产环境要调整 connect-timeout 和 read-timeout,网络波动会导致长连接断开。
工具入参异常:MCP 工具方法内部要做参数校验,大模型可能传过来空值或异常格式,不校验会直接抛异常。
接入相关的文档可以在这里查:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc
7. 继续往下走
天气预报这个例子跑通之后,你可以把同样的骨架套到其他工具上——数据库查询、内部 API 调用、文件操作,都是把方法加上@Tool注解、注册成ToolCallbackProvider就行。MCP 的价值在于工具接入标准化,服务端和客户端解耦,工具换了大模型也不用改调用代码。
如果你要长期做编码或 Agent 类任务,Coding Plan 会更合适:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan
API Key 管理和接入文档分别在这里:
- API Keys:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys
- 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc
先把服务端和客户端两个项目跑起来,确认/weather?city=长沙能返回真实天气,再往里面加你自己的工具。链路通了之后,剩下的就是业务逻辑的事。