Spring AI MCP协议实战:一行代码接入几百个外部工具
你正在开发一个AI客服系统。产品经理说,用户问"帮我查一下订单状态"时,AI要能直接查数据库;用户说"这个商品降价了通知我"时,AI要能设置一个价格监控任务;用户说"帮我退掉上周买的那个耳机"时,AI要能调用售后系统发起退款。你心想,这不就是要让AI调用一堆后端API嘛,我写几个 Function Calling 就行了。
写着写着不对劲了——订单服务要一个 Tool,售后要一个 Tool,物流要一个 Tool,优惠券要一个 Tool,用户画像要一个 Tool……你写了几十个 @Tool 注解的方法,散布在十几个微服务里。更离谱的是,每接入一个新的外部系统(比如企业微信、飞书、Slack),你都得重新写一遍 Tool 定义。你开始怀疑:难道没有一个标准化的方式,让AI工具可以像 USB 接口一样即插即用吗?
还真有。2024年底 Anthropic 提出的 MCP(Model Context Protocol,模型上下文协议)就是干这个的。而 Spring AI 2.0 已经把它完整地落了地。
一、这个问题到底是什么
MCP 要解决的核心问题一句话就能说清楚:让AI应用和外部工具/数据源之间的连接,从"每个都要手写适配代码"变成"遵循同一套协议自动对接"。
不理解?打个比方。在没有 USB 之前,你买个鼠标要装驱动,买个键盘要装驱动,买个打印机要装驱动,而且不同品牌、不同型号的驱动还不一样。MCP 就是 AI 世界的 USB 协议——工具提供方按 MCP 规范暴露接口,AI 应用按 MCP 规范消费工具,双方不需要知道对方的实现细节。
在 Spring AI 引入 MCP 之前,你想让 AI 调用一个外部 API,通常的做法是这样:写一个类,在方法上加 @Tool 注解,描述这个方法的功能和参数,然后注册到 ChatClient 里。这个方法内部你要自己处理 HTTP 调用、参数序列化、异常处理、结果格式化,等等。如果一个公司有 50 个内部微服务,每个服务暴露 5 个接口想给 AI 调用,你就要手写 250 个 @Tool 方法。
而 MCP 的思路完全反过来:每个服务自己实现一个 MCP Server,把自己能做的事情通过标准协议暴露出来。AI 应用只需要一个 MCP Client,就能自动发现和调用所有注册的 MCP Server 上的工具。新服务上线,只要它实现了 MCP Server,AI 应用不需要改一行代码就能用上它的能力。
具体到 Java 开发者的日常工作里,以前你可能会写这样的代码:
@Tool(description = "查询用户订单")
public Order queryOrder(String orderId) {
return orderService.findById(orderId);
}
@Tool(description = "取消订单")
public void cancelOrder(String orderId) {
orderService.cancel(orderId);
}
@Tool(description = "查询物流状态")
public Logistics queryLogistics(String trackingNumber) {
return logisticsService.findByTrackingNumber(trackingNumber);
}
三个服务,三个 @Tool。三十个服务呢?三百个 @Tool。而且每个服务升级了接口参数,你还得同步改这边的 Tool 定义。维护成本随着服务数量线性增长。
而 MCP 模式下,订单服务、物流服务各自启动自己的 MCP Server,AI 应用通过 MCP Client 自动发现:"哦,有个订单服务,它提供了 query_order 和 cancel_order 两个工具;还有个物流服务,提供了 query_logistics 工具。"你不需要在 AI 应用里写任何 @Tool 注解了。
这不仅仅是少写代码的问题,更重要的是职责分离。订单服务的开发团队最清楚自己的接口怎么用、参数怎么传,由他们来定义 MCP Tool 最合适。AI 应用的开发团队不需要了解订单服务的内部细节,只需要信任 MCP 协议。这跟微服务架构里"服务自治"的理念完全一致。
MCP 协议的标准化还带来了一个额外的好处:生态复用。Anthropic 官方维护了一个 MCP Server 仓库,里面有几百个现成的 Server,覆盖了文件系统、数据库、搜索引擎、云服务、办公套件等各种场景。你用 Spring AI 的 MCP Client 连上去就能用,一行代码都不用写。想想之前你要接入 Google Drive 得翻多少文档、写多少适配代码,现在直接启动对应的 MCP Server,完事。
二、底层原理到底怎么回事
MCP 协议基于 JSON-RPC 2.0,通信层可以选择标准输入输出(stdio)或者 HTTP + SSE(Server-Sent Events)。客户端和服务端之间通过这两种传输方式交换 JSON 格式的请求和响应。Spring AI 2.0 在 spring-ai-mcp 和 spring-ai-starter-mcp-client 两个模块中封装了完整的 MCP 客户端实现。
MCP 协议定义了三种核心能力,这三种能力分别对应 AI 应用中最常见的三个需求场景。
第一种是 Tool(工具)。这是最直观的——让 AI 模型能够调用外部函数。MCP Server 声明自己有哪些工具、每个工具的参数 schema 是什么,MCP Client 获取这些信息后,自动转换成 AI 模型能理解的 Function Calling 格式。当模型决定调用某个工具时,Client 把调用请求发给 Server,Server 执行后返回结果,Client 再把结果传回给模型。
第二种是 Resource(资源)。这个比 Tool 抽象一点,但它解决了 RAG 场景中一个很实际的问题:AI 需要读取的外部文档、知识库、配置文件等,在哪里、怎么访问?MCP 把数据源也标准化了。Server 可以暴露自己的资源列表(比如:“我有一个产品手册,URI 是 docs://product-manual”),Client 可以通过标准方式读取这些资源内容。这样你的 RAG 应用不需要为每个文档源写不同的接入代码,MCP 协议帮你统一了。
第三种是 Prompt Template(提示词模板)。Server 可以提供预定义的 Prompt 模板,Client 获取后可以直接使用。这在团队协作中很有用——比如安全团队可以提供一个"安全审查"的 Prompt 模板,所有 AI 应用通过 MCP 就能拿到这个模板,确保安全审查的标准一致。
这三种能力是可选的。一个 MCP Server 可以只提供 Tool,也可以同时提供 Tool + Resource + Prompt Template。Spring AI 的 MCP Client 会自动探测 Server 支持哪些能力,按需使用。
接下来看数据流。从 AI 模型发起调用到底层工具执行完毕,完整链路是这样的:
第一步,用户发送消息给 ChatClient。第二步,ChatClient 检查当前有哪些可用的 MCP Tool,将这些 Tool 的元信息(名称、描述、参数 schema)拼接到请求的 tools 字段里,发给大模型。第三步,大模型分析用户意图,如果决定调用某个工具,返回一个 tool_call 指示。第四步,ChatClient 收到 tool_call 后,找到对应的 MCP Server,通过 JSON-RPC 发送 tools/call 请求。第五步,MCP Server 执行对应的逻辑,返回结果。第六步,ChatClient 把工具返回结果作为新的消息上下文,再次发给大模型,让大模型生成最终的自然语言回复。
这里面有几个值得关注的细节。
**Tool 发现是动态的。**每次对话开始前(或者在每次请求前),Client 都会调用 tools/list 方法获取当前可用的工具列表。这意味着你可以在运行时启动新的 MCP Server,Client 下一次请求就能感知到新工具,不需要重启应用。
**MCP 支持 stdio 和 HTTP 两种传输方式。**stdio 模式下,Client 以子进程方式启动 Server,通过标准输入输出通信。这种方式部署简单、延迟低,适合同机器的场景。HTTP+SSE 模式下,Server 是一个独立的 HTTP 服务,Client 通过 HTTP 请求调用。这种方式支持跨机器部署,适合微服务架构。Spring AI 2.0 对两种方式都有支持,你可以通过配置轻松切换。
**连接是惰性建立的。**Client 不会在应用启动时就连接所有 Server,而是在第一次需要调用时建立连接。这避免了启动时的连接风暴,对于有几十个 MCP Server 的大型应用来说是个很实用的设计。
**异常处理有完整的回退机制。**如果 MCP Server 不可达,Client 会抛出 McpException,你可以选择跳过这个工具、返回一个预设的兜底回复、或者让模型重新规划。Spring AI 2.0 还提供了重试策略配置,可以对瞬时故障进行自动重试。
还有一个很多人问的问题:MCP 和传统的 Function Calling 是什么关系?简单说,MCP 是 Function Calling 的上层封装和标准化。在 Spring AI 里,MCP 的 Tool 最终会被转换成 ChatModel 能识别的 ToolCallback,所以底层还是走了 Function Calling 的通道。区别在于,这些 Tool 不需要在你的应用代码里定义,而是从远端的 MCP Server 动态获取的。你可以把 MCP 理解成 Function Calling 的"工厂模式"——你不再需要手动 new 每一个 Tool 对象,工厂(MCP Client)帮你自动获取和注册。
三、实战:手把手写代码
接下来通过两个完整的示例,演示如何在 Spring Boot 应用中使用 MCP Client 接入外部工具。
示例一:用 MCP Client 接入 Braze 搜索引擎,让AI自动查资料
这个示例展示的是最经典的 MCP Client 使用场景——启动一个现成的 MCP Server,AI 应用自动获取它提供的搜索工具。
先创建 Spring Boot 项目,添加以下 Maven 依赖。版本使用 Spring AI 2.0.0(这是我写文章时 Maven Central 上的最新正式版):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>mcp-demo</artifactId>
<version>1.0.0</version>
<name>mcp-demo</name>
<description>Spring AI MCP Client Demo</description>
<properties>
<java.version>21</java.version>
<spring-ai.version>2.0.0</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>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring AI OpenAI Starter(使用 OpenAI 兼容接口) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<!-- Spring AI MCP Client -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
然后配置 application.yml,声明要连接哪些 MCP Server 以及 OpenAI 的 API Key:
spring:
application:
name: mcp-demo
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com
chat:
options:
model: gpt-4o-mini
mcp:
client:
enabled: true
connections:
# Braze 搜索引擎的 MCP Server(以 stdio 方式运行)
bravesearch:
type: STDIO
command: npx
args:
- "-y"
- "@anthropic/mcp-server-brave-search"
env:
BRAVE_API_KEY: ${BRAVE_API_KEY}
server:
port: 8080
接下来写一个 REST Controller,让用户可以通过 HTTP 接口与 AI 对话。Spring AI 2.0 的 MCP Client 会自动从配置的 Server 中获取所有可用工具,并注册到 ChatClient 里。代码里你不需要显式地写任何 Tool 注册:
package com.example.mcpdemo;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
public class ChatController {
private final ChatClient chatClient;
public ChatController(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
@GetMapping("/chat")
public Mono<String> chat(@RequestParam(defaultValue = "今天有什么科技新闻?") String message) {
return Mono.fromCallable(() -> chatClient.prompt()
.user(message)
.call()
.content());
}
}
启动类就是一个标准的 Spring Boot 入口:
package com.example.mcpdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class McpDemoApplication {
public static void main(String[] args) {
SpringApplication.run(McpDemoApplication.class, args);
}
}
启动应用后,访问 http://localhost:8080/chat?message=最近关于Spring AI有什么新闻。AI 会通过 MCP Client 自动发现 Braze Search 工具,调用搜索引擎查询相关文章,然后用自然语言回答你。你在 Controller 里没有写任何关于搜索的代码——工具发现、参数构造、结果解析全是 MCP 自动完成的。
示例二:手写 MCP Server,暴露自定义业务工具
第一个示例用的是社区现成的 MCP Server。实际工作中,你更可能需要把自己公司的内部服务通过 MCP 暴露出去。这里演示如何用 Spring AI 2.0 的 spring-ai-starter-mcp-server 写一个 MCP Server。
先看 Maven 依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>order-mcp-server</artifactId>
<version>1.0.0</version>
<name>order-mcp-server</name>
<properties>
<java.version>21</java.version>
<spring-ai.version>2.0.0</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</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
MCP Server 的配置很简单。使用 HTTP+SSE 模式暴露,这样其他微服务可以通过 HTTP 调用:
spring:
application:
name: order-mcp-server
ai:
mcp:
server:
enabled: true
transport: http
sse-endpoint: /mcp/sse
sse-message-endpoint: /mcp/message
server:
port: 8081
核心代码——用 @Tool 注解定义 MCP 工具。注意这里用的是 org.springframework.ai.mcp.server.annotation.Tool,不是之前 Function Calling 那个 Tool 注解:
package com.example.orderserver;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.ai.mcp.server.annotation.Tool;
import org.springframework.ai.mcp.server.annotation.ToolParam;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;
@SpringBootApplication
public class OrderMcpServerApplication {
public static void main(String[] args) {
SpringApplication.run(OrderMcpServerApplication.class, args);
}
}
@Component
class OrderToolService {
private final Map<String, Order> orderStore = new ConcurrentHashMap<>();
public OrderToolService() {
// 初始化几条模拟数据
orderStore.put("ORD-001", new Order("ORD-001", "user-123", "iPhone 16 Pro",
new BigDecimal("8999.00"), "已发货", "SF1234567890"));
orderStore.put("ORD-002", new Order("ORD-002", "user-123", "AirPods Pro 2",
new BigDecimal("1899.00"), "已完成", "SF9876543210"));
orderStore.put("ORD-003", new Order("ORD-003", "user-456", "MacBook Pro 14",
new BigDecimal("14999.00"), "待付款", null));
}
@Tool(description = "根据订单ID查询订单详情,包含商品名称、金额、状态和物流单号")
public Order queryOrder(
@ToolParam(description = "订单ID,格式为ORD-开头后跟三位数字") String orderId) {
Order order = orderStore.get(orderId);
if (order == null) {
throw new RuntimeException("订单不存在: " + orderId);
}
return order;
}
@Tool(description = "根据用户ID查询该用户的所有订单列表")
public String queryUserOrders(
@ToolParam(description = "用户ID") String userId) {
StringBuilder result = new StringBuilder("用户 " + userId + " 的订单列表:\n");
boolean found = false;
for (Order order : orderStore.values()) {
if (order.userId().equals(userId)) {
result.append(" - ").append(order.orderId())
.append(":").append(order.productName())
.append(",金额").append(order.amount()).append("元")
.append(",状态:").append(order.status()).append("\n");
found = true;
}
}
if (!found) {
result.append(" 暂无订单");
}
return result.toString();
}
@Tool(description = "根据物流单号查询物流状态信息")
public Logistics queryLogistics(
@ToolParam(description = "物流单号,通常以SF开头") String trackingNumber) {
// 模拟物流查询
return new Logistics(trackingNumber, "运输中",
"预计送达时间:" + LocalDateTime.now().plusDays(2).toString(),
"当前所在城市:上海转运中心");
}
}
record Order(String orderId, String userId, String productName,
BigDecimal amount, String status, String trackingNumber) {
}
record Logistics(String trackingNumber, String status,
String estimatedDelivery, String currentLocation) {
}
这个 Server 启动后,MCP 协议会自动暴露三个工具:queryOrder、queryUserOrders、queryLogistics。任何实现了 MCP Client 的应用(不限于 Java、不限于 Spring AI),只要能通过网络访问 http://localhost:8081/mcp/sse,就能自动发现并调用这三个工具。
接下来在之前的 MCP Client Demo 中新增一个 HTTP 连接配置,接入我们自己写的订单 MCP Server。修改 Client 的 application.yml:
spring:
application:
name: mcp-demo
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai.com
chat:
options:
model: gpt-4o-mini
mcp:
client:
enabled: true
connections:
bravesearch:
type: STDIO
command: npx
args:
- "-y"
- "@anthropic/mcp-server-brave-search"
env:
BRAVE_API_KEY: ${BRAVE_API_KEY}
# 新增:连接我们自己的订单 MCP Server
order-service:
type: HTTP
url: http://localhost:8081/mcp/sse
server:
port: 8080
就这样。Client 端不需要改任何 Java 代码。启动 Server(端口 8081)和 Client(端口 8080),访问 http://localhost:8080/chat?message=帮我查一下用户user-123的所有订单。AI 会自动通过 MCP 调用订单 Server 的 queryUserOrders 工具,然后给你漂亮的回复。
示例三:同一个 Client 连接多个不同类型的 MCP Server
这个示例展示 MCP 最强大的能力——异构工具的自动编排。你可以同时接入一个搜索引擎 Server、一个数据库查询 Server、一个邮件发送 Server,AI 可以根据用户意图自动选择合适的工具组合。
在 application.yml 里继续追加配置就好:
spring:
ai:
mcp:
client:
enabled: true
connections:
bravesearch:
type: STDIO
command: npx
args: ["-y", "@anthropic/mcp-server-brave-search"]
env:
BRAVE_API_KEY: ${BRAVE_API_KEY}
order-service:
type: HTTP
url: http://localhost:8081/mcp/sse
# 文件系统 MCP Server(可以读写本地文件)
filesystem:
type: STDIO
command: npx
args: ["-y", "@anthropic/mcp-server-filesystem", "/tmp/mcp-data"]
# PostgreSQL MCP Server(可以直接查数据库)
postgres:
type: STDIO
command: npx
args: ["-y", "@anthropic/mcp-server-postgres"]
env:
DATABASE_URL: ${POSTGRES_URL}
用户问"帮我搜索一下最近关于iPhone 16的新闻,整理成要点保存到文件"——AI 先调用 Braze Search 获取新闻,再调用 filesystem 写入文件。整个过程 ChatClient 自动编排,Controller 代码完全不变。这就是 MCP 标准化的威力。
四、踩坑经验和最佳实践
**stdio 模式在 Docker 容器里容易出问题。**npx 启动的 Node.js 进程需要完整的运行环境,而很多 Docker 基础镜像(比如 eclipse-temurin:17-jre)不带 Node.js。如果你的 Spring Boot 应用跑在容器里,要么换用 -jdk 镜像,要么把 Node-based 的 MCP Server 改用 HTTP 模式单独部署。生产环境强烈建议 HTTP 模式——每个 MCP Server 作为独立服务运行,Client 通过网络调用,职责清晰、可独立扩缩容。
**Tool 的 description 要写得足够具体。**LLM 根据 description 判断该调用哪个工具,如果 description 模糊,就容易选错。好的 description 应该包含:这个工具做什么、什么场景下用、输入参数的含义。差例子:“查询订单”;好例子:“根据订单ID查询订单详情,返回商品名称、金额、物流状态和快递单号。适用于用户询问某个具体订单信息的场景”。
**工具返回结果不要太大。**LLM 的上下文窗口有限,工具返回的数据越精简越好。比如查询用户订单,不要返回订单对象的所有字段(包括内部的 JSON 嵌套),只返回用户关心的那几个字段。如果你的工具要查询大量数据(比如一个包含 100 条订单的列表),考虑先做分页或摘要,让模型决定是否需要进一步查询详情。
**MCP Server 需要做好鉴权。**默认情况下,任何人能访问你的 MCP Server 端点就能调用你的工具。HTTP 模式的 MCP Server 跟普通 REST API 一样需要加鉴权——可以用 Spring Security 加 API Key 验证,或者放在内网用服务网格做 mTLS。Spring AI 2.0 的 MCP Client 支持在连接配置中设置 HTTP Headers,你可以通过这个传递认证信息。
**多个 MCP Server 有同名工具时要注意。**如果两个 Server 都提供了一个叫 search 的工具,Client 会以最后注册的为准还是两个都保留?答案是两个都保留,但工具名称会加上 Server 前缀做区分,比如 bravesearch_search 和 filesystem_search。不过尽量不要让工具重名——命名时加上业务前缀是个好习惯,比如 order_query 而不是 query。
**开发阶段用 MCP Inspector 调试。**Anthropic 提供了一个 MCP Inspector 工具(开源,npm 可安装),可以可视化地查看 MCP Server 的工具列表、参数 schema,还能手动发起调用验证结果。写 MCP Server 的时候先走一遍 Inspector 确认没问题,再接 Client,能少走很多弯路。
**不要把所有业务逻辑都塞进 MCP Server。**MCP 解决的是"AI 怎么调用工具"的问题,不是"业务逻辑怎么写"的问题。MCP Server 应该是一个薄层,收到 Tool 调用请求后,转发给真正的业务服务去执行。如果你的 MCP Server 里写了大量业务逻辑,那它就成了一个新的单体,违背了微服务架构的原则。
五、性能对比和技术选型
先说延迟。stdio 模式因为是在同机器上通过进程间通信,一次 Tool 调用的额外开销通常在 10-50 毫秒。HTTP 模式因为要走网络,延迟会增加 5-100 毫秒(取决于网络状况)。但这点延迟相对于 LLM 本身的推理时间(通常 1-5 秒)来说,基本可以忽略。所以性能不是你选择 stdio 还是 HTTP 的首要考虑因素——架构需求更重要。
连接数方面,每个 MCP Server 连接会占用一个 TCP 连接或一个子进程。stdio 模式下,一个 Client 实例对每个 Server 类型只维护一个进程(长连接),所以就算并发 1000 个请求,也只是复用同一个 Server 进程。HTTP 模式下,Client 和 Server 之间的连接池由底层 HTTP 客户端控制,Spring AI 2.0 默认使用 Spring 的 WebClient,支持连接复用和连接池。
关于 MCP 和传统 Function Calling 怎么选,这里给一个简单的决策树:
- 工具数量少于 5 个,且都在同一个应用里 → 直接用 Function Calling(@Tool 注解),别上 MCP。不值得为了几个简单的工具引入额外的架构复杂度。
- 工具分散在多个微服务里,或者工具数量超过 10 个 → 上 MCP。标准化带来的收益远大于搭建成本。
- 需要接入社区已有的工具(搜索、文件系统、数据库等)→ 直接用 MCP Server 社区生态。不要重复造轮子。
- 工具需要被多个不同的 AI 应用共享 → 上 MCP。一次暴露,到处可用。
Spring AI 2.0 的 MCP 实现还有一个不错的特性:它和原有的 Function Calling 是兼容的。你可以在同一个 ChatClient 里同时使用 MCP Tool 和传统的 @Tool 注解方法,两者会合并到一起发送给模型。这意味着你可以渐进式迁移,不需要一次性把所有 @Tool 都改造成 MCP Server。
六、总结
MCP 不是一个复杂的概念。它只是把"AI 调用外部工具"这件事标准化了——Server 端定义工具,Client 端自动发现和调用,中间走 JSON-RPC 协议。简单到你觉得"这不是理所应当的吗",但在此之前整个行业确实没这么做。
Spring AI 2.0 对 MCP 的支持做到了开箱即用。几个 starter 依赖加几行 YAML 配置,你就能接入几百个社区现成的工具,或者把自己公司的微服务改造成 MCP Server。对于正在用 Spring 技术栈的 Java 团队来说,这可能是目前最平滑的 AI 工具调用标准化方案。
回到开头那个客服系统的例子。有了 MCP,订单服务团队维护自己的 MCP Server,物流团队维护自己的,售后团队维护自己的。AI 客服应用只需要配好 MCP Client,指向这几个 Server 的地址。新加一个优惠券服务?运维部署完,AI 应用自动感知。订单接口升级了参数?订单团队改自己的 Server,AI 应用无感知。这才是微服务架构下 AI 工具调用该有的样子。
最后提醒一句:MCP 还在快速发展中,协议规范可能会有不兼容的变更,生产环境注意锁定版本。但方向是对的——标准化永远比各自为战强。
更多推荐

所有评论(0)