ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

大模型开发 - 33 MCP:深入理解 Model Context Protocol(MCP)及其在 Spring AI 中的实践指南|TaoToken 统一 Key 接入

大模型开发 - 33 MCP:深入理解 Model Context Protocol(MCP)及其在 Spring AI 中的实践指南|TaoToken 统一 Key 接入 1. 为什么 Java 开发者需要认真对待 MCP如果你正在用 Spring AI 做大模型开发大概率已经踩过这样的坑模型想查一下订单状态你得在代码里写死一个Tool方法模型想读一份本地文档你又得手动塞进 Prompt 里。工具越接越多代码越来越乱换一个模型厂商还得重写一遍适配层。Model Context ProtocolMCP就是为了解决这个问题出现的——它把「模型调用外部能力」这件事从业务代码里抽出来变成一套标准协议。MCP 全称 Model Context Protocol直译是「模型上下文协议」你可以把它理解成大模型世界里的 USB-C 接口。以前每个工具都要给模型单独做一根线现在统一成一个插口谁实现了 MCP谁就能被模型发现和调用。它基于 JSON-RPC 2.0支持 stdio、SSE、WebSocket 等多种传输方式核心能力包括工具发现、资源读取、提示模板管理以及能力协商。这套东西适合谁我认为有三类 Java 开发者值得花时间第一类是做企业级 AI 应用的需要把内部系统安全地暴露给模型第二类是做 Agent 的工具数量多到Tool注解已经管不过来第三类是想让自己的 Java 服务被 Claude Desktop、Cline 这类客户端直接调用的。Spring AI 从 1.0.0-M5 开始提供了 MCP 的 Boot Starter客户端和服务端都能开箱即用这也是我下面要带你跑通的最小实践路径。需要提前说明的是MCP 本身只解决「协议怎么通信」不解决「模型从哪来」。你仍然需要一个兼容 OpenAI 协议的大模型服务端点。我这边统一用 TaoToken 的 API 作为模型入口它的 Base URL 是https://taotoken.net/api兼容 OpenAI 的/v1/chat/completions格式Spring AI 的 OpenAI Starter 可以直接对接。这样你的 MCP 工具链路和模型调用链路就能在同一个工程里跑通排查问题时也不会互相干扰。2. TaoToken 前置准备Key、Base URL 与模型 ID在动手写 MCP 代码之前先把模型这一侧的凭证准备好。很多同学卡在第一步不是因为 MCP 难而是因为 Key 没配对、Base URL 写错、模型 ID 不存在结果报了一堆看不懂的错。我建议你按下面的顺序来。首先登录 TaoToken 控制台创建 API Key。地址是https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai进去之后在 API Keys 页面新建一个 Key复制出来保存好。这个 Key 只会完整显示一次丢了就只能重建。如果你还没决定用哪个模型可以先去模型对话页面试一下https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai看看当前可用的模型列表记下你打算用的 Model ID比如gpt-4o-mini或者claude-3-5-sonnet这类。这里有个关键点TaoToken 的 API 地址是https://taotoken.net/api注意不要加 UTM 参数也不要加/v1后缀Spring AI 的 OpenAI Starter 会自动拼接/v1/chat/completions。如果你手动写 HTTP 请求那完整路径就是https://taotoken.net/api/v1/chat/completions。这个细节我在第一次接入时踩过坑多写了一个/v1导致 404排查了半小时。环境变量建议这样设置避免把 Key 硬编码进代码export TAOTOKEN_API_KEYsk-你的实际Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api如果你用的是 Windows PowerShell对应命令是$env:TAOTOKEN_API_KEYsk-你的实际Key $env:TAOTOKEN_BASE_URLhttps://taotoken.net/api接下来确认你的 Spring AI 版本。MCP 的 Starter 在 1.0.0-M5 之后才比较稳定我建议直接用 1.0.0-M6 或更高。在pom.xml里通过 BOM 统一管理版本dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version1.0.0-M6/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement同时确认你的 Spring Boot 版本在 3.2 以上JDK 17 以上。MCP Java SDK 0.8.0 之后引入了 Session 会话模型所有通信都要经过McpSession不再直接操作 Transport这个变更在写代码时要注意构造McpClient和McpServer都要用 Builder 模式。如果你打算长期跑 Agent 类任务比如让模型连续调用多个工具完成一个复杂流程可以考虑 TaoToken 的 Coding Plan地址是https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai它在长上下文和连续调用场景下更划算。不过对于下面这个最小实践普通 API Key 就够了。3. 可复制配置application.yml 与 Java SDK 片段这一节是整篇文章的核心我会给出完整的application.yml、Maven 依赖和 Java 代码你直接复制到工程里就能跑。先说明整体结构我们做一个 MCP 服务端暴露一个「查询天气」的工具再做一个 MCP 客户端通过 Spring AI 的 ChatClient 调用这个工具而 ChatClient 背后的模型走 TaoToken。先看服务端的依赖。如果你用 WebFlux 做 SSE 传输加这个dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server-webflux/artifactId /dependency服务端的application.yml配置如下server: port: 8080 spring: ai: mcp: server: name: weather-mcp-server version: 1.0.0 protocol: SSE sse-endpoint: /mcp capabilities: tool: true resource: false prompt: false logging: level: org.springframework.ai.mcp: DEBUG这里sse-endpoint: /mcp表示客户端通过http://localhost:8080/mcp建立 SSE 连接。capabilities.tool: true表示这个服务端只暴露工具能力不暴露资源和提示模板按需开启即可。服务端的工具注册代码注意 MCP Java SDK 0.8.0 之后工具要通过ToolProvider接口注册package com.example.mcp.server; import org.springframework.ai.mcp.server.ToolProvider; import org.springframework.ai.mcp.server.annotation.ToolMethod; import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; Component public class WeatherToolProvider implements ToolProvider { Override public ListMapString, Object getTools() { return List.of( Map.of( name, getWeather, description, 获取指定城市的当前天气, inputSchema, Map.of( type, object, properties, Map.of( city, Map.of( type, string, description, 城市名称例如 北京 ) ), required, List.of(city) ) ) ); } ToolMethod(getWeather) public String getWeather(String city) { // 真实场景这里调用天气 API这里用模拟数据 return 当前 city 的天气是晴气温 25°C湿度 40%。; } }启动类就是标准的 Spring Boot 启动类package com.example.mcp.server; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication public class McpWeatherServerApplication { public static void main(String[] args) { SpringApplication.run(McpWeatherServerApplication.class, args); } }启动后你会看到日志里输出 SSE 端点注册成功的信息。用浏览器访问http://localhost:8080/mcp会保持连接不返回这是正常的SSE 是长连接。再看客户端。客户端依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-client-webflux/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency客户端的application.yml是重点这里同时配置了 MCP 连接和 TaoToken 模型入口server: port: 8081 spring: ai: openai: api-key: ${TAOTOKEN_API_KEY} base-url: ${TAOTOKEN_BASE_URL} chat: options: model: gpt-4o-mini temperature: 0.7 mcp: client: name: weather-mcp-client version: 1.0.0 transport: type: SSE sse: uri: http://localhost:8080/mcp toolcallback: enabled: true logging: level: org.springframework.ai.mcp: DEBUG org.springframework.ai.openai: DEBUG注意base-url写的是https://taotoken.net/api不要带/v1。toolcallback.enabled: true让 Spring AI 自动把 MCP 发现的工具注册成 ChatClient 可用的 ToolCallback这样你就不用手动写Tool了。客户端的调用代码package com.example.mcp.client; import org.springframework.ai.chat.client.ChatClient; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; Component public class WeatherRunner implements CommandLineRunner { private final ChatClient chatClient; public WeatherRunner(ChatClient.Builder builder) { this.chatClient builder.build(); } Override public void run(String... args) { String answer chatClient.prompt() .user(帮我查一下北京现在的天气用工具查) .call() .content(); System.out.println(模型回答: answer); } }这段代码里模型会先判断需要调用getWeather工具Spring AI 通过 MCP 客户端向服务端发起tools/call请求拿到结果后再交给模型生成自然语言回答。整条链路是ChatClient → TaoToken 模型 → 工具调用决策 → MCP Client → MCP Server → 工具执行 → 结果回传 → 模型总结。4. 验证请求从启动日志到工具调用链路连通配置写完之后怎么确认整条链路真的通了我一般分三步验证每一步都有明确的成功标志。第一步单独启动 MCP 服务端观察日志。成功的话你会看到类似这样的输出Registered SSE endpoint at /mcp MCP Server initialized: weather-mcp-server v1.0.0 Capabilities: toolstrue, resourcesfalse, promptsfalse如果看到Capabilities: toolstrue说明工具能力已经暴露。这时候可以用 curl 手动发一个 JSON-RPC 请求测试MCP 的 SSE 端点需要先建立连接再发消息用 curl 不太方便我建议直接用客户端验证。第二步启动客户端观察 MCP 连接日志。成功标志是看到工具发现的结果MCP Client connected to http://localhost:8080/mcp Discovered tools: [getWeather] Registered ToolCallback: getWeather看到Discovered tools: [getWeather]就说明协议握手、能力协商、工具发现都成功了。这一步如果卡住通常是服务端没启动或者端口不对。第三步看模型调用结果。客户端启动后会执行WeatherRunner控制台应该输出模型回答: 北京当前天气是晴气温 25°C湿度 40%。同时服务端日志里会出现tools/call的请求记录客户端日志里会出现对 TaoToken 的/v1/chat/completions请求。如果你在客户端日志里看到两次模型请求那是正常的第一次模型决定调用工具第二次模型根据工具结果生成最终回答。为了更直观地验证你可以把WeatherRunner改成多轮对话连续问两个城市String answer1 chatClient.prompt() .user(查一下上海天气) .call() .content(); System.out.println(上海: answer1); String answer2 chatClient.prompt() .user(再查一下广州天气) .call() .content(); System.out.println(广州: answer2);如果两次都能正确返回说明 MCP 会话保持正常工具可以重复调用。这时候你可以打开 TaoToken 的模型对话页面https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai对比一下同样的 Prompt 在纯对话模式下模型是没法查天气的只有接了 MCP 工具才能拿到实时数据这个对比能帮你确认工具调用确实生效了。还有一个验证技巧把服务端的getWeather方法改成返回一个随机数比如当前 city 温度 (20 new Random().nextInt(10)) °C然后连续调用几次如果每次温度不同说明工具是真的被执行了而不是模型在编答案。5. 本篇常见错排查401、local proxy failed 与 choices 解析异常这一节我整理了几个真实遇到的报错基本都是配置问题对照着改就能解决。报错一401 Unauthorizedorg.springframework.web.reactive.function.client.WebClientResponseException$Unauthorized: 401 Unauthorized这个几乎都是 Key 的问题。检查三件事TAOTOKEN_API_KEY环境变量有没有生效可以在代码里打印System.getenv(TAOTOKEN_API_KEY)确认Key 有没有多余空格复制的时候容易带上换行Key 是不是已经被删除或过期。另外确认base-url写的是https://taotoken.net/api如果误写成https://taotoken.net/api/v1请求路径会变成/api/v1/v1/chat/completions虽然可能返回 404 而不是 401但也一并检查。报错二local proxy failed 或 Connection refusedjava.net.ConnectException: Connection refused: localhost:8080这个通常是 MCP 服务端没启动或者端口被占用。先确认服务端进程在跑netstat -an | grep 8080看一下端口监听状态。如果服务端启动失败检查spring-ai-starter-mcp-server-webflux依赖有没有加对WebFlux 和 WebMVC 的 Starter 不能混用混用会导致端点注册冲突。还有一种情况是客户端配置的uri写成了http://localhost:8080少了/mcp路径SSE 握手会失败。报错三Error reading choices 或 choices 为空java.lang.NullPointerException: Cannot invoke java.util.List.get(int) because choices is null这个报错说明模型返回的 JSON 结构不符合 OpenAI 格式Spring AI 解析choices数组时拿到 null。常见原因有两个一是base-url配错请求打到了非 OpenAI 兼容的端点二是模型 ID 写错服务端返回了错误信息而不是正常的 chat completion。解决办法是打开 DEBUG 日志看原始响应体logging: level: org.springframework.web.reactive.function.client: DEBUG如果响应体里是{error: model not found}这类信息那就是 Model ID 的问题去 TaoToken 模型列表确认可用模型名。如果响应体是 HTML说明 URL 打到了网页而不是 API检查base-url有没有多写路径。报错四OAuth 或认证方式不匹配OAuth2 authentication failed / invalid_clientMCP 的 SSE 传输在某些实现里会走 OAuth 流程但 Spring AI 的 Starter 默认用简单连接。如果你在服务端配置了额外的安全拦截客户端又没带对应凭证就会报这个。最小实践阶段建议先关掉服务端的 Spring Security或者放行/mcp路径Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(auth - auth .requestMatchers(/mcp/**).permitAll() .anyRequest().authenticated()); return http.build(); }报错五工具被发现但模型不调用日志里显示Discovered tools: [getWeather]但模型回答里没有调用工具直接编了一个天气。这种情况通常是 Prompt 不够明确模型觉得不需要工具。把用户输入改成「必须使用 getWeather 工具查询北京天气」或者在系统提示里强调「所有天气问题必须调用工具」。另外确认toolcallback.enabled: true生效了如果这个开关没开工具虽然被发现但不会注册给 ChatClient。排查的时候记住一个原则先看 MCP 层日志再看模型层日志。MCP 层确认工具发现和调用是否正常模型层确认请求是否到达 TaoToken 以及返回结构是否正确。两层分开看问题定位会快很多。6. 把 MCP 工具链路接到 TaoToken 的长期实践建议跑通最小实践之后你可能会想把它用到真实项目里。我分享几个实际落地时的经验。第一工具粒度要控制。MCP 工具不是越多越好一个服务端暴露 5 到 10 个高内聚的工具比较合适。工具太多会导致模型选择困难也会让tools/list的响应变大每次对话都要传输一遍。我一般按业务域拆分服务端比如订单服务端、用户服务端、文档服务端客户端按需连接。第二传输方式按场景选。本地 CLI 工具用 stdioWeb 应用之间用 SSE高并发场景用 WebFlux 的 SSE。stdio 的好处是不占端口、进程隔离适合把 Python 脚本包装成 MCP 工具SSE 的好处是跨网络、支持多客户端适合微服务架构。如果你不确定先用 SSE调试方便。第三模型入口统一管理。MCP 解决的是工具协议模型调用仍然需要一个稳定的端点。我建议把 TaoToken 的 Base URL 和 Key 放在配置中心或环境变量里不要散落在各个服务的application.yml中。这样换模型、换 Key 的时候只改一处。如果你同时跑多个 Agent 任务Coding Plan 的额度管理会比按量计费更清晰具体可以看https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai。第四日志要分级。开发阶段把org.springframework.ai.mcp开到 DEBUG能看到完整的 JSON-RPC 请求响应生产环境调到 INFO只记录工具调用次数和耗时。MCP 的结构化日志里会带sessionId排查多客户端并发问题时很有用。第五注意 SDK 版本升级。MCP Java SDK 从 0.7.0 到 0.8.0 引入了 Session 模型工具注册从直接实现接口改成了ToolProvider资源访问从ResourceHandler改成了ResourceProvider。升级前一定要看 Migration Guide否则编译都过不了。Spring AI 的 Starter 版本要和 SDK 版本对齐BOM 里统一管理最省心。最后说一个我自己的用法把 MCP 服务端做成独立的 Spring Boot 应用部署在内网客户端通过 SSE 连接。这样工具的执行环境是隔离的模型只能通过协议调用不能直接访问数据库或文件系统。安全边界清晰审计也方便。客户端这边只负责模型交互和工具编排不碰具体业务逻辑。这套结构跑下来新增一个工具只需要在服务端加一个ToolMethod客户端不用改代码重启服务端就能被发现。如果你还没创建 Key现在可以去https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai建一个然后按上面的配置把服务端和客户端跑起来。接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai里面有完整的 API 说明和示例。遇到问题先看 DEBUG 日志大部分配置错误在日志里都能直接看到原因。
返回列表