MCP 是什么
MCP,全称是 Model Context Protocol(模型上下文协议)。它是由 Anthropic 开源,旨在解决大模型与外部世界"沟通不畅"的问题。
它不是一个具体的框架或技术,而是一个通用开源标准协议,用于安全、高效地连接智能体应用与外部工具。其核心理念就是赋予智能体应用类似 USB 接口的功能:只需遵守统一的协议,就能标准化地调用各种外部工具,从而实现即插即用。你完全可以把 MCP 理解为是智能体连接外部工具的 USB 接口
比如,以前如果你想让大模型读取你的数据库,你必须为这个特定的智能体写一段专门的 function call 代码。如果你换一个智能体,这代码可能就得重新写一遍。现在有了 MCP 后,你只需要把数据库的一些列操作包装成一个 MCP Server。任何支持 MCP 的客户端(如 Claude Desktop, Cursor,Cline等)都能直接连接上这个server使用工具,无需重复造轮子。
借助MCP,工具都遵循统一的调用协议,智能体则能够更加丝滑地与外部工具交互。社区中已经公开了大量可用的 MCP Server 工具,而这些工具的功能和能力,将直接决定智能体在实际任务中的执行效果。
MCP的工作流程

第一阶段:初始化(工具说明获取) 智能体初始化的时候,会通过 MCP 协议向所有连接的 MCP Server 使用JSON-RPC 协议请求工具说明书。MCP Server 负责提供并确保这些说明书是标准化的JSON格式。
第二阶段:决策(大模型规划) 智能体将用户的原始问题和获取到的所有标准化工具说明,一同发送给大模型。大模型根据这些信息进行规划,并返回一个清晰的工具调用指令。
第三阶段:调用(执行与结果回传) 智能体接收到指令后,立即通过 MCP 协议请求对应的 MCP Server 执行工具操作。MCP Server 完成实际的工具逻辑(如数据库查询),并将原始执行结果返回给智能体。
第四阶段:总结(生成最终回复) 智能体将用户原始问题+工具执行的最终结果+完整的对话历史,再次发回给大模型。大模型基于这个结果进行总结,生成一段自然语言回复,输出给用户
spring ai 开发MCP server
stdio 方式
依赖
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
<!--webflux 应用 使用这个,和webmvc 包冲突,两个只能用一个-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.ai</groupId>-->
<!-- <artifactId>spring-ai-starter-mcp-server-webflux</artifactId>-->
<!-- </dependency>-->
定义tools
java
package com.lujia.ai.springaimcpserver.service;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;
@Service
public class WeatherMcpService {
/**
* 定义天气查询工具
*
* @param city
* @return
*/
@Tool(name = "getWeather", description = "根据城市名称查询天气信息")
public String getWeather(String city) {
//模拟查询天气
return switch (city) {
case "广州" -> "广州: 晴, 25°C";
case "郑州" -> "郑州: 多云, 22°C";
case "深圳" -> "深圳: 小雨, 28°C";
default -> city + ": 下雪, -20°C";
};
}
}
定义ToolCallbackProvider 来注册toolObjects
java
@Configuration
public class McpConfiguration {
/**
* ToolCallbackProvider ,会扫描 WeatherService 里面的@Tool的方法,
* @param weatherService
* @return
*/
@Bean
public ToolCallbackProvider weatherTools(WeatherMcpService weatherService) {
return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
}
}
配置
yaml
spring:
main:
# 非web应用
web-application-type: none
# 关闭banner
banner-mode: off
ai:
mcp:
server:
name: mcp-server
version: 1.0.0
# 这里有三种 类型定义MCP server ,代表交互方式的不同 stdio 表示通过控制台输入输出交互
stdio: true
enabled: true
type: SYNC
# 控制台不打印日志
logging:
level:
root: OFF
使用
这里使用 vs code 插件cline ,
首先编译打包我们的jar 包,在cline mcp 注册配置中,添加一下配置,args 里面填写你的jar 包绝对路径,保存即可注册mcp server,之后就可以使用了

效果如下:

sse 方式
SSE(Server-Sent Events)模式基于 HTTP,采用双端点架构:sse-message-endpoint 是 MCP Client 用来向服务器发送请求、调用工具的接口,客户端通过约定的 JSON-RPC 协议将参数传入并获取响应。sse-endpoint 则是 MCP Client 用来监听服务器主动推送消息的通道,比如工具列表更新、状态变更等。二者配合构成了 MCP SSE 的核心通信机制,使客户端既能主动发起操作,也能实时接收服务器推送的变化,实现双向互动和高效协作,
目前官方已经不推荐使用这种方式
sse 和stdio 代码都一样,只是配置修改即可
yaml
server:
port: 8080
# context-path: /test
spring:
application:
name: mcp-weather-sse
ai:
mcp:
server:
enabled: true
name: weather-sse-server
version: 1.0.0
type: SYNC
capabilities:
tool: true
resource: false
prompt: false
completion: false
sse-message-endpoint: /mcp/messages # 客户端向 MCP Server 发送指令("写信")
sse-endpoint: /sse # 客户端订阅服务器推送消息("听收音机")
servlet:
encoding:
force: true
charset: UTF-8
enabled: true
启动服务,在cline mcp配置中添加下面就可以使用
json
{
"mcpServers": {
"weather-sse": {
"type": "sse",
//mcp服务暴露的端口地址
"url": "http://127.0.0.1:8080/sse",
"autoApprove": [],
"timeout": 60,
"disabled": false
}
}
}
streamable http
StreamableHTTP 是MCP在2025年3月26日正式提出的最新官方传输标准,用来改进传统 SSE 在长连接、大数据流和双端点管理上的局限。它通过 单一 HTTP 端点实现请求发送与流式响应接收,支持 断续重连和未确认消息重发,保证长时间任务或增量输出的稳定可靠,同时简化了客户端与服务器的交互模型,是官方推荐替代SSE的方案
代码还还是一样,只需要修改配置文件即可
yaml
server:
port: 8080
spring:
application:
name: mcp-weather-streamable
ai:
mcp:
server:
## 这个地方改成STATELESS,就是无状态模式
protocol: STREAMABLE
name: streamable-mcp-server
version: 1.0.0
type: SYNC
instructions: "这个服务是用来查询城市天气的。"
resource-change-notification: true
tool-change-notification: true
prompt-change-notification: true
streamable-http:
mcp-endpoint: /api/mcp
keep-alive-interval: 30s
servlet:
encoding:
charset: UTF-8
force: true
enabled: true
protocol:STREAMABLE 表示开启 Streamable HTTP 模式;
instructions:用于定义 MCP Server 的提示词,指导模型行为;
streamable-http.mcp-endpoint:指定服务的端口路径,与SSE的不同,这边一个端口就可以实现双向通信;keep-alive-interval:设置 HTTP 连接心跳间隔,保证长连接稳定。
其中protocol 还可以直接切换成 STATELESS。在 无状态模式下,MCP Server 不会在内存中保存客户端会话,也不会分配或要求 Mcp-Session-Id。每个请求都是独立处理的,服务器不会记录多轮对话历史或流式事件状态。这种模式适合 单次调用、无历史依赖的工具或 API,例如一次性计算、查询数据库、或者获取即时信息的场景,不需要断点重连或多轮交互。
由于无状态模式无法保留上下文或中途恢复,它不适合依赖会话连续性的多轮交互、长连接流式推送或复杂工具链操作;但它的优势是 简单、易扩展、适合 serverless 或微服务架构
启动服务,在vscode cline 中配置即可使用
json
{
"mcpServers": {
"weather-streamable": {
"url": "http://127.0.0.1:8080/api/mcp",
"type": "streamableHttp",
"timeout": 60,
"disabled": false
}
}
}
spring ai 开发 mcp client
client 依赖
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>
配置client
yaml
spring:
ai:
deepseek:
api-key: 你的apikey
base-url: https://api.deepseek.com/
mcp:
client:
enabled: true
name: my-mcp-client
version: 1.0.0
request-timeout: 60s
type: SYNC
stdio:
connections:
weather-stdio:
command: java
args:
- -jar
- "D:\\ideafile\\springAI\\spring-ai-mcp-server\\target\\spring-ai-mcp-server-0.0.1-SNAPSHOT.jar"
sse:
connections:
weather-sse:
url: http://127.0.0.1:8003
sse-endpoint: /sse
streamable-http:
connections:
weather-streamable:
url: http://127.0.0.1:8004/
endpoint: api/mcp
使用
java
@RestController
@RequestMapping("/test")
public class TestController {
// 官网上也可以这样注入
@Autowired
private List<McpSyncClient> mcpSyncClients; // For sync client
// OR
// 官网上也可以这样注入
@Autowired
private List<McpAsyncClient> mcpAsyncClients; // For async client
@Autowired
private SyncMcpToolCallbackProvider toolCallbackProvider;
@Autowired
private DeepSeekChatModel chatModel;
private ChatClient chatClient;
@PostConstruct
public void init() {
/**
* 将MCP Client的工具注入到 ChatClient
*/
ToolCallback[] toolCallbacks = toolCallbackProvider.getToolCallbacks();
this.chatClient = ChatClient.builder(chatModel).defaultTools(Arrays.asList(toolCallbacks)).build();
}
/**
* 智能体调用
*/
@GetMapping("/chat")
public String chat(String userMessage) {
return chatClient.prompt().user(userMessage).call().content();
}
}