1. 为什么 Java 开发者现在要盯紧 MCP
如果你是一名 Java 后端,最近大概率被两个词反复刷屏:MCP 和 Claude。MCP 全称 Model Context Protocol,模型上下文协议,说白了就是给大模型和各种工具、数据源之间定了一套统一的“插座标准”。以前你想让大模型查个数据库、调个地图 API、操作一下 Git 仓库,得自己写一堆胶水代码,每个模型厂商的对接方式还不一样;现在只要你的服务实现了 MCP 协议,任何支持 MCP 的客户端都能直接把它当工具用。
这对 Java 开发者意味着什么?意味着你手里那些 Spring Boot 服务、内部管理系统、数据查询接口,不用大改就能被 AI 智能体调用。你不需要去学 Python 生态那一套,Spring AI Alibaba 已经把 MCP 的客户端和服务端能力封装好了,注解一加、Bean 一注册,你的 Java 方法就变成了大模型可以调用的工具。
这篇文章我按真实接入链路来写:先在 Claude 桌面端跑通一个本地 MCP Server,确认工具能被正确加载和触发;再把同样的能力迁移到 Spring AI Alibaba 生态里,用 Java 代码作为 MCP Client 去调用它。中间会给出 Claude 配置文件骨架、MCP Server 注册步骤、Spring AI Alibaba 侧的依赖和 Bean 配置片段,最后做一次端到端调用验证,确认工具调用和模型响应都正常。适合有 Spring Boot 基础、想快速把 MCP 落到 Java 项目里的同学。
2. 前置准备:TaoToken 与模型接入
在动手写 MCP Server 之前,得先把模型调用这条链路打通。MCP 负责的是“工具怎么被调用”,但真正决定要不要调用工具、怎么组织参数的,还是背后的大模型。所以你需要一个能稳定调用 Claude 等模型的入口。
我这边用的是 TaoToken 来做模型接入,它的 API 地址是 https://taotoken.net/api ,兼容常见的调用方式,Java 侧用 Spring AI 的 OpenAI 兼容客户端就能直接对接。先去控制台创建一个 API Key,地址在 https://taotoken.net/api-keys ,创建完复制出来,后面配置里要用。
如果你只是想先验证模型对话是否正常,可以打开模型对话页面 https://taotoken.net/models 直接试一句,确认 Key 有效、模型有响应。这一步别跳过,因为后面 MCP 工具调用失败时,你得能区分是模型链路的问题还是 MCP 配置的问题。
对于长期要做编码、跑 Agent 任务的场景,可以考虑 Coding Plan https://taotoken.net/coding-plan ,额度更划算。接入文档在 https://taotoken.net/doc ,里面有各语言的调用示例,Java 侧照着改 base_url 和 api_key 就行。
把 Key 准备好之后,我们进入正题:先写一个能被 Claude 桌面端识别的 MCP Server。
3. 第一步:用 Spring AI 写一个 stdio 模式的 MCP Server
MCP Server 有两种主流传输方式:stdio 和 SSE。stdio 是标准输入输出,适合本地进程,Claude 桌面端直接以子进程方式启动它;SSE 是 HTTP 长连接,适合独立部署、多客户端远程调用。我们先做 stdio 版本,因为它最容易在 Claude 里验证。
3.1 添加依赖
新建一个 Spring Boot 项目,在 pom.xml 里加入 MCP Server 的 starter:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId> </dependency>这个 starter 会把 MCP 服务端的自动配置、工具扫描、stdio 通信都带进来。版本跟随你项目里的 Spring AI BOM 即可。
3.2 配置 application.yml
stdio 模式下,应用不能以 Web 方式启动,否则会占用端口、干扰标准输入输出。配置如下:
spring: main: web-application-type: none banner-mode: off ai: mcp: server: stdio: true name: my-weather-server version: 0.0.1web-application-type: none是关键,少了它启动会报错或者卡住。banner-mode: off是为了避免 banner 输出污染 stdio 通道,这个坑我踩过,Claude 那边会解析失败。
3.3 用 @Tool 注解暴露工具方法
写一个 Service,用@Tool标记要被大模型调用的方法,用@ToolParameter描述参数。这里用 Open-Meteo 这个免费天气 API 做示例,不需要申请 Key:
@Service public class WeatherService { private final WebClient webClient; public WeatherService(WebClient.Builder builder) { this.webClient = builder.baseUrl("https://api.open-meteo.com/v1").build(); } @Tool(description = "根据经纬度获取当前天气和未来预报") public String getWeather( @ToolParameter(description = "纬度,例如 39.9042") String latitude, @ToolParameter(description = "经度,例如 116.4074") String longitude) { try { return webClient.get() .uri(uri -> uri.path("/forecast") .queryParam("latitude", latitude) .queryParam("longitude", longitude) .queryParam("current", "temperature_2m,wind_speed_10m") .queryParam("timezone", "auto") .build()) .retrieve() .bodyToMono(String.class) .block(); } catch (Exception e) { return "获取天气失败:" + e.getMessage(); } } }description写清楚很重要,大模型就是靠这段文字判断什么时候该调用这个工具。参数描述也一样,写得越具体,模型填参数越准。
3.4 注册 ToolCallbackProvider
在启动类里把工具注册成 Bean:
@SpringBootApplication public class McpServerApplication { public static void main(String[] args) { SpringApplication.run(McpServerApplication.class, args); } @Bean public ToolCallbackProvider weatherTools(WeatherService weatherService) { return MethodToolCallbackProvider.builder() .toolObjects(weatherService) .build(); } }打包成 jar:
mvn clean package -DskipTests记下 jar 的完整路径,下一步 Claude 配置里要用绝对路径。
4. 第二步:在 Claude 桌面端接入并验证
Claude 桌面端通过一个 JSON 配置文件来管理 MCP Server。找到配置文件:
macOS 路径是~/Library/Application Support/Claude/claude_desktop_config.json,Windows 是%APPDATA%\Claude\claude_desktop_config.json。如果文件不存在就新建一个。
4.1 配置文件骨架
{ "mcpServers": { "weather": { "command": "java", "args": [ "-Dspring.ai.mcp.server.stdio=true", "-Dspring.main.web-application-type=none", "-Dlogging.pattern.console=", "-jar", "/绝对路径/target/mcp-server-0.0.1.jar" ], "env": {} } } }几个要点:-jar后面必须是 jar 的绝对路径,相对路径 Claude 解析不到;-Dlogging.pattern.console=把控制台日志格式清空,避免日志混进 stdio 通道;-Dspring.main.web-application-type=none再显式声明一次,双保险。
4.2 重启并确认工具加载
保存配置后完全退出 Claude 再重新打开。在输入框附近能看到工具图标,点开应该能看到getWeather这个工具,说明 MCP Server 被成功拉起、工具被正确注册。
4.3 触发一次真实调用
输入提示词:“帮我查一下北京现在的天气”。Claude 会判断需要调用getWeather,自动填入北京对应的经纬度,然后返回天气数据。如果能看到温度、风速这些字段,说明整条链路通了:Claude 发起工具调用 → stdio 传给 Java 进程 → Java 调 Open-Meteo → 结果回传 → 模型组织成自然语言。
这一步验证通过,说明你的 Java MCP Server 是合格的。接下来把它迁移到 Spring AI Alibaba 生态,让 Java 应用自己当客户端。
5. 第三步:Spring AI Alibaba 作为 MCP Client 调用
现在换个角色:不再是 Claude 来调你的服务,而是你的 Java 应用去调 MCP Server。Spring AI Alibaba 提供了 stdio 和 SSE 两种客户端 starter。
5.1 添加客户端依赖
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId> </dependency>5.2 配置模型与 MCP 服务器
spring: ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: claude-3-5-sonnet mcp: client: stdio: servers-configuration: classpath:/mcp-servers-config.jsonbase-url指向 TaoToken 的 API 地址,api-key从环境变量注入,别硬编码在文件里。模型名按你实际可用的填。
5.3 mcp-servers-config.json
在src/main/resources下建这个文件,内容和 Claude 那份类似:
{ "mcpServers": { "weather": { "command": "java", "args": [ "-Dspring.ai.mcp.server.stdio=true", "-Dspring.main.web-application-type=none", "-Dlogging.pattern.console=", "-jar", "/绝对路径/target/mcp-server-0.0.1.jar" ], "env": {} } } }5.4 注入工具并调用
@SpringBootApplication public class ClientApplication { public static void main(String[] args) { SpringApplication.run(ClientApplication.class, args); } @Bean public CommandLineRunner run(ChatClient.Builder builder, ToolCallbackProvider tools, ConfigurableApplicationContext ctx) { return args -> { ChatClient chatClient = builder.defaultTools(tools).build(); String answer = chatClient.prompt("北京的天气怎么样?").call().content(); System.out.println(">>> " + answer); ctx.close(); }; } }defaultTools(tools)这一行就是把 MCP Server 提供的工具挂到 ChatClient 上,Spring AI Alibaba 会自动完成工具描述到模型 function calling 格式的适配。
启动:
mvn spring-boot:run日志里会看到 MCP 客户端向服务端发起tools/list请求,拿到工具列表,然后模型决定调用getWeather,返回天气数据。控制台打印出结果,说明 Java 作为 MCP Client 的链路也通了。
6. 常见报错与排查清单
接入过程中最容易卡在几个地方,我按出现频率排一下。
工具重复注册报错:如果你用 SSE 模式,可能遇到Multiple tools with the same name。这是 Spring AI 的自动配置类SseHttpClientTransportAutoConfiguration和SseWebFluxTransportAutoConfiguration同时加载导致的,两个都去申请了同一批工具。解决办法是在启动类上排除掉其中一个:
@SpringBootApplication(exclude = { org.springframework.ai.autoconfigure.mcp.client.SseHttpClientTransportAutoConfiguration.class })Claude 里看不到工具:先确认 jar 路径是绝对路径,再确认web-application-type: none配了,最后看日志有没有输出到 stdout 污染通道。把logging.pattern.console=设成空能解决大部分问题。
模型不调用工具:检查@Tool的 description 是不是太模糊,模型判断不出该不该用。把描述写具体,比如“根据经纬度获取当前天气和未来预报”就比“获取天气”好很多。
API Key 无效:确认 base-url 是 https://taotoken.net/api ,Key 从 https://taotoken.net/api-keys 创建,别把控制台登录态和 API Key 搞混。模型对话页面 https://taotoken.net/models 可以先单独验证 Key。
SSE 模式连不上:确认服务端真的在对应端口启动了,url配置里别漏了协议头。SSE 服务端需要独立部署,不能和 stdio 混在一个进程里。
7. 继续往下走
到这一步,你已经跑通了 Java MCP 的完整链路:写 Server、Claude 验证、Spring AI Alibaba 当 Client 调用。接下来可以做的方向很多,比如把内部的数据查询接口用@Tool包一层,让智能体能直接查业务数据;或者把 SSE 模式的 Server 部署到内网,多个 Agent 共享同一批工具。
如果你要长期跑编码类、Agent 类任务,建议把模型调用切到 Coding Plan https://taotoken.net/coding-plan ,额度更稳。接入细节和更多示例看文档 https://taotoken.net/doc ,控制台在 https://taotoken.net/console ,API Key 管理在 https://taotoken.net/api-keys 。Claude Code 相关的接入说明在 https://taotoken.net/claude-code ,Anthropic 兼容接入在 https://taotoken.net/anthropic 。
MCP 的价值不在于协议本身多复杂,而在于它把“工具接入”这件事标准化了。你写的 Java 方法,加个注解就能被任何支持 MCP 的智能体调用,这才是对 Java 开发者最实在的收益。