AI Agent全栈开发MCP实战指南
先讲几个核心观点:AI应用生态演进至今,提示词优化与Tool Calling已大幅拓展语言模型的能力边界。但工具数量激增、场景复杂度上升后,旧方案开始暴露短板——接口标准不一,模型必须硬编码工具定义。这好比厨房堆满各种制式的厨具,每件都得单独学习操作。好在MCP(模型上下文协议)正好填补了这块空白。
前言
如今,AI应用与外部系统的交互已成常态。我们从最初的提示词工程,逐步过渡到Tool Calling——让模型自主判断是否需要调用工具,以及调用哪个工具。但现实是,随着工具数量膨胀,传统Tool Calling的实现方式面临集中挑战:工具接口格式混乱,模型被迫硬编码工具定义。坦率讲,这些痛点若不解决,每新增一个工具就得修改代码,维护成本直线上升。
MCP正是为收拾这一残局而生。
什么是MCP
MCP(Model Context Protocol)模型上下文协议,核心定位并非替代Tool Calling,而是为Tool Calling搭建一套统一、可扩展的跨平台基础设施。一句话总结:MCP就是Tool Calling的管理中枢。
- Tool Calling:模型决定是否调用工具,调用哪个工具。
- MCP:规定工具的描述格式、调用方式、结果传递机制。
接入MCP后,AI只需掌握一种通信协议,剩余翻译工作全部交给MCP Server。相当于给所有厨具统一换上标准接口,厨房再混乱也能高效运转。
MCP Java SDK架构
MCP Java SDK提供了Java端的完整实现,支持同步与异步两种通信模式,确保AI模型与工具之间按照标准化流程握手。
- Client/Server:请求的发起方与接收方,类比顾客与后厨。
- Session:管理会话生命周期,相当于订单管理系统的核心。
- Transport:消息传递的底层通道,好比手机订餐加骑手配送。
Transport传输协议
MCP Java SDK支持多种“通信方式”,让AI应用(客户端)能灵活地与各类工具服务(服务器)对话。目前提供三种传输模式:
- 基于Stdio的进程间通信传输协议:通过标准输入/输出(stdin和stdout)在进程间传递消息,直接且高效。
- 基于Java HttpClient的SSE客户端传输协议:利用Java HttpClient发起HTTP请求,接收服务端持续推送的事件流。
- WebFlux SSE客户端传输协议:基于WebFlux非阻塞响应式模型处理SSE流,适用于高并发场景。
MCP Server
MCP Server是协议的服务端实现,对外暴露特定功能。你可以直接访问MCP Server社区查找所需能力——这里聚集了大量技术爱好者,资源丰富。常用社区入口:GitHub MCP Registry、MCP Flow、火山引擎MCP广场。注意,部分服务可能需要注册或申请API Key,请以官方文档为准。
MCP Client
有了服务端,代码里如何调用?答案是MCP Client。它连接开发环境与远程MCP Server。不同客户端对MCP协议的支持程度各异,可根据实际需求选择。
MCP使用
在使用MCP Client前,通常需要先启动一个或多个MCP Server实例。多数MCP Server通过npx或uv命令运行,因此需提前配置好运行环境。以下是一个典型配置,以百度地图MCP Server为例:
{
"mcpServers": {
"baidu-map": {
"command": "npx",
"args": ["-y", "@baidumap/mcp-server-baidu-map"],
"env": {
"BAIDU_MAP_API_KEY": "xxx"
}
}
}
}
配置完成后,在Cursor中可直接看到MCP Server的效果:

除了Cursor这类客户端,也可通过Spring AI代码接入。以Spring AI Alibaba为例,先引入依赖,然后在配置文件中指定MCP Server的地址与超时时间:
spring:
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY}
mcp:
client:
request-timeout: 60000
stdio:
servers-configuration: classpath:/mcp/mcp-servers-config.json
同时,将百度地图配置写入mcp/mcp-servers-config.json:
{
"mcpServers": {
"baidu-map": {
"command": "npx.cmd",
"args": ["-y", "@baidumap/mcp-server-baidu-map"],
"env": {
"BAIDU_MAP_API_KEY": "你的Key"
}
}
}
}
然后在Controller中注入ToolCallbackProvider,它会自动将MCP Server的工具注册给AI模型:
@RestController
@RequestMapping("/chat")
public class ChatController {
private ChatClient chatClient;
public ChatController(DashScopeChatModel chatModel, ToolCallbackProvider toolCallbackProvider) {
this.chatClient = ChatClient.builder(chatModel)
.defaultToolCallbacks(toolCallbackProvider)
.build();
}
@RequestMapping("/generate")
public String generate(String message) {
return chatClient.prompt().user(message).call().content();
}
}
ToolCallbackProvider是Spring AI中用于向AI模型注册可用工具的核心接口。只要MCP配置就位,它就能自动触发调用,完美解决传统Tool Calling中各工具接口不统一的问题,实现动态工具组合。
自定义MCP Server
MCP支持两种通信方式:Stdio与Streamable HTTP。早期版本使用SSE,2025年3月26日协议更新后,官方用更强大的Streamable HTTP取代了SSE(解决了SSE连接易断的痛点)。但为兼容旧版,本文仍保留SSE的实现说明。
使用Stdio自定义MCP Server
先实现一个天气查询服务:
@Service
@Slf4j
public class WeatherService {
private final Map weatherCache = new ConcurrentHashMap<>();
public WeatherService() {
weatherCache.put("北京", new WeatherInfo("晴转多云", "22~28", "南风2级", "78"));
weatherCache.put("上海", new WeatherInfo("小雨", "18~24", "东风3级", "52"));
weatherCache.put("广州", new WeatherInfo("晴朗", "25~33", "微风", "45"));
weatherCache.put("深圳", new WeatherInfo("多云", "24~30", "东北风2级", "60"));
}
@Tool(description = "查询指定城市的天气信息,返回天气状况、温度范围、风力、空气质量")
public String queryWeather(@ToolParam(description = "城市名称,如:北京、上海、广州、深圳") String city) {
log.info("[HTTP MCP] queryWeather 调用,城市: {}", city);
if (!weatherCache.containsKey(city)) {
return String.format("未找到「%s」的天气信息,支持的城市:%s", city, weatherCache.keySet());
}
WeatherInfo info = weatherCache.get(city);
return String.format("""
???? %s天气报告
─────────────────
☁️ 天气:%s
????️ 温度:%s°C
???? 风力:%s
???? AQI:%s
─────────────────
???? 更新时间:%s
""", city, info.weather, info.temp, info.wind, info.aqi,
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
record WeatherInfo(String weather, String temp, String wind, String aqi) {}
}
然后通过ToolConfig将其暴露给MCP Server:
@Configuration
public class ToolConfig {
@Bean
public ToolCallbackProvider getWeather(WeatherService weatherService) {
return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
}
}
在Stdio模式下,MCP Server是一个独立的命令行应用,无需Web容器。配置如下:
spring:
ai:
mcp:
server:
name: stdio-server
version: 0.0.1
main:
web-application-type: none
banner-mode: off
打包成jar后,客户端通过mcp-servers-config.json引用即可:
{
"mcpServers": {
"stdio-server": {
"command": "ja va",
"args": [
"-Dfile.encoding=UTF-8",
"-Dspring.ai.mcp.server.stdio=true",
"-Dlogging.pattern.console=",
"-jar",
"E:/springAI/mcp/mcp-stdio-server/target/mcp-stdio-server-1.0-SNAPSHOT.jar"
]
}
}
}
使用SSE自定义MCP Server
SSE模式的MCP Server需要运行在Web容器中。注意,不同Starter对应不同角色:
| Starter | 角色 | 被谁调用 |
|---|---|---|
spring-ai-starter-mcp-server | MCP Server | 本地MCP Client(通过Stdio) |
spring-ai-starter-mcp-server-webmvc | MCP Server | 远程MCP Client(通过HTTP/SSE) |
spring-ai-starter-mcp-server-webflux | MCP Server | 远程MCP Client(通过HTTP/SSE/WebFlux) |
spring-ai-starter-mcp-client | MCP Client | Stdio/SSE客户端 |
spring-ai-starter-mcp-client-webflux | MCP Client | WebFlux客户端 |
这里有个易踩的坑:如果在Web项目中同时引入spring-boot-starter-web和spring-ai-starter-mcp-server-webflux,会导致MCP端点(/sse)失效。原因是两个Servlet/Reactive的Dispatcher共存时,Spring Boot默认优先使用Servlet堆栈。解决方案是在配置文件中明确指定使用Reactive:
server:
port: 8081
spring:
ai:
mcp:
server:
name: sse-server
version: 0.0.1
main:
web-application-type: reactive
pom.xml需要包含WebFlux Starter:
org.springframework.boot
spring-boot-starter-web
org.springframework.ai
spring-ai-starter-mcp-server-webflux
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
Service与Config的代码与Stdio模式类似,此处不再重复。Service中的@Tool方法与Config中的MethodToolCallbackProvider充当“扫描器”,自动将工具注册给MCP Server。
启动SSE Server后,在Cursor中配置即可直接使用:
{
"mcpServers": {
"sse-server": {
"url": "http://127.0.0.1:8081/sse"
}
}
}
若要在Spring AI中作为MCP Client调用SSE Server,Controller里需注入SyncMcpToolCallbackProvider:
@RestController
@RequestMapping("/chat")
public class ChatController {
private final ChatClient chatClient;
@Autowired
public ChatController(DashScopeChatModel chatModel,
SyncMcpToolCallbackProvider mcpToolProvider) {
this.chatClient = ChatClient.builder(chatModel)
.defaultToolCallbacks(mcpToolProvider.getToolCallbacks())
.build();
}
@RequestMapping("/generate")
public String generate(String message) {
return chatClient.prompt().user(message).call().content();
}
}
完结撒花!????
从Tool Calling到MCP,本质上是将“临时拼凑的传话筒”升级为“标准化的服务总线”。MCP的出现大幅降低了AI应用与工具之间的耦合度,未来你只需专注业务逻辑,通信细节全交给协议处理。希望本文能帮你理清MCP的来龙去脉,下次写代码时,不妨亲手搭一个自定义MCP Server体验一下。







