MCP协议详解
# 什么是 MCP 协议?一文彻底搞懂 AI 工具调用背后的通信标准
🧭 适合读者:AI 应用开发者 / 研究人员 / 工程师 / 无代码工具集成者
📍 关键词:MCP、Cursor、LangChain、Function Calling、Agent、工具调用、协议标准
# 🧩 01. 背景:为什么需要 MCP?
在现代 AI 应用中,很多时候我们希望模型不仅仅回答问题,还能执行操作,比如:
- 获取天气信息;
- 查询数据库;
- 打开网页或文档;
- 执行某个 Python 函数……
这就引出了 “工具调用(Tool Calling)” 的需求。
# 🤖 02. 问题:AI 怎么调用工具?
OpenAI、Anthropic 等大模型已经支持 function_call
(函数调用)功能,它可以:
- 理解你的问题;
- 自动决定需要调用哪个工具;
- 返回结构化参数,让你去实际调用那个工具。
但它本身不会真正执行工具调用,这就需要一个协议,让 AI 调用你定义的工具服务,并返回结果。
# 🚀 03. 解决方案:MCP(Model Context Protocol)
MCP 是一个专门为工具调用设计的 开放协议,它定义了:
- 工具如何注册;
- 工具调用的参数结构;
- 服务之间如何通信;
- 请求与响应的格式;
- 会话(session)如何维持。
# ✅ MCP 不是模型、不是平台,它是一个协议标准 + 实现规范
# 🧱 04. MCP 架构全景图(通俗理解)
[你在 Cursor 中输入问题]
│
▼
┌─────────────────────┐
│ MCP 客户端(如 Cursor) │
│ - 调用模型 │
│ - 管理对话 │
│ - 发起工具请求 │
└─────────────────────┘
│
向你写的 MCP 服务发送请求
▼
┌─────────────────────┐
│ MCP 服务端(你写的) │
│ - 注册工具 schema │
│ - 接收调用请求 │
│ - 执行真实逻辑 │
└─────────────────────┘
│
返回执行结果给 Cursor
▼
[结果呈现在对话中,继续交互]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 📦 05. MCP 各方职责一览表
角色 | 说明 | 示例 |
---|---|---|
🧠 MCP 客户端 | 构建 prompt、调用模型、解析 function_call 并发送工具请求 | Cursor / LangChain / Spring AI |
🛠️ MCP 服务端 | 接收工具请求、注册工具 schema、实现工具逻辑 | 你基于 MCP SDK 实现的服务 |
🧬 大模型(LLM) | 理解 prompt、选择工具、生成 function_call | GPT-4 / Claude / Gemini 等 |
# 🔍 06. 具体流程详解(Cursor + OpenAI + 你写的工具)
# 🔄 从输入到执行,完整调用流程如下:
sequenceDiagram
participant U as 用户
participant C as Cursor (MCP 客户端)
participant M as 模型 (GPT-4 / Claude)
participant S as 你写的 MCP 服务 (使用 MCP SDK)
U->>C: “北京今天天气如何?”
C->>S: 请求工具 schema(工具描述)
S-->>C: 返回工具 schema(如 getWeather)
C->>M: 提交 prompt + tools(function schema)
M-->>C: 返回 function_call(调用 getWeather)
C->>S: 发出工具调用请求(getWeather("北京"))
S-->>C: 返回工具执行结果(如 "北京今天多云 22°C")
C-->>U: 显示最终响应结果
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 🧭 全流程总览:Cursor 如何调用 MCP 工具
🧠 AI Agent 逻辑 📡 MCP 协议交互
┌────────────────────────────────────┐ ┌────────────────────────────┐
│ Cursor 启动时读取配置的 MCP 地址 │────GET──▶│ MCP 服务:返回 tool schema │
└────────────────────────────────────┘ └────────────────────────────┘
│
▼
┌────────────────────────────────────┐
│ 构造 prompt,附带 tool schema(function)│
└────────────────────────────────────┘
│
▼
┌────────────────────────────────────┐
│ 调用 LLM,得到 function_call 响应 │
└────────────────────────────────────┘
│
▼
┌────────────────────────────────────┐ ┌──────────────────────────────┐
│ 解析 function_call,发送给 MCP 服务 │────POST──▶│ MCP 服务调用工具,返回结果 │
└────────────────────────────────────┘ └──────────────────────────────┘
│
▼
┌────────────────────────────────────┐
│ 插入工具执行结果,继续对话流程 │
└────────────────────────────────────┘
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 🔹 1. Cursor 启动时向 MCP 服务发送“工具列表”请求
请求内容(标准化):
GET /schema
或者通过 MCP stdio/stream 协议(更常见):
{
"type": "schema_request"
}
2
3
# 🔸 2. MCP 服务端返回工具定义(McpSchema 列表)
例如:
{
"type": "schema_response",
"tools": [
{
"name": "getWeather",
"description": "获取指定城市的天气",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "要查询的城市名称"
}
},
"required": ["city"]
}
},
{
"name": "runShellCommand",
"description": "执行一个 shell 命令",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string"
}
},
"required": ["command"]
}
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
MCP SDK 通过 McpSchema
定义这些 schema,Cursor 会自动读取并转换为 LLM function 调用 schema。
# 🔹 3. Cursor 构造带 Tool schema 的 prompt 并发给 LLM
Prompt(隐藏系统提示)会包含:
- tool 的名称
- tool 的参数 JSON schema
- 所有 tool 的描述
- 用户输入的问题(例如:“北京今天天气如何?”)
🔄 传给 LLM 的结构(例如 OpenAI):
{
"model": "gpt-4",
"messages": [
{ "role": "user", "content": "北京今天天气如何?" }
],
"functions": [ // function calling 的 tool 列表
{
"name": "getWeather",
"description": "获取指定城市的天气",
"parameters": { ... }
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
# 🔸 4. LLM 返回 function_call(选中了某个工具)
返回示例:
{
"message": {
"role": "assistant",
"content": null,
"function_call": {
"name": "getWeather",
"arguments": "{ \"city\": \"北京\" }"
}
}
}
2
3
4
5
6
7
8
9
10
# 🔹 5. Cursor 将该调用发送给 MCP 服务执行(MCP-Client)
{
"type": "tool_request",
"tool": "getWeather",
"arguments": {
"city": "北京"
}
}
2
3
4
5
6
7
# 🔸 6. MCP 服务执行工具逻辑,返回响应:(MCP-server)
{
"type": "tool_response",
"tool": "getWeather",
"result": "北京今天多云,气温 22 度。"
}
2
3
4
5
# ✅ 小结:Cursor 是一个完整的 MCP 客户端 + AI Agent
能力 | 实现位置 |
---|---|
工具 discovery 请求 | MCP 协议客户端逻辑 |
prompt 构造、附加 tool schema | Agent 层(Cursor 内部) |
function_call 解析 | Agent 层(Cursor) |
工具调用请求发送 | MCP 协议客户端(MCP-Client) |
工具执行逻辑 | MCP 服务端(MCP-server) |
工具 schema 注册 | MCP SDK(服务端初始化注册) |
# 🔧 07. 那 MCP SDK 到底做了什么?
MCP SDK 是 MCP 协议的官方 Java 实现,主要作用是帮助你快速实现一个MCP 服务端。它帮你完成了:
能力 | 是否 SDK 提供 |
---|---|
接收 Cursor 的工具请求 | ✅ |
注册工具 + 参数 schema | ✅ |
解析工具请求 + 封装响应 | ✅ |
实现工具逻辑(如查天气) | ❌(由你实现) |
调用 LLM / 构造 prompt | ❌(不是 SDK 作用) |
自动优化提示词 / Function Selection | ❌(由客户端做) |
✅ 总结一句话:MCP SDK 是协议实现,不是 AI 调度器,也不是模型调用器。
# MCP Java SDK架构原理图
+-----------------------------------------------------------------------------------------------------------+
| 应用层 (Agent/用户代码) |
| |
| +------------------------+ +------------------------+ +------------------------+ |
| | LLM输出JSON解析转换器 | | 业务逻辑处理 | | 结果处理逻辑 | |
| +------------------------+ +------------------------+ +------------------------+ |
+-----------------------------------------------------------------------------------------------------------+
| | |
v v ^
+-----------------------------------------------------------------------------------------------------------+
| MCP SDK API层 |
| +------------------------+ +------------------------+ +------------------------+ |
| | McpClient (工厂类) |---->| McpSyncClient接口 |---->| McpAsyncClient接口 | |
| +------------------------+ +------------------------+ +------------------------+ |
+-----------------------------------------------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------------------------------------------+
| MCP Client Session层 |
| |
| +------------------------+ +------------------------+ +------------------------+ |
| | McpClientSession |<--->| RequestResponseHandler |<--->| 消息序列化/反序列化 | |
| +------------------------+ +------------------------+ +------------------------+ |
+-----------------------------------------------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------------------------------------------+
| Transport传输层 |
| |
| +---------------------------+ +---------------------------+ |
| | HttpClientSseClientTransport | | StdioClientTransport | |
| | (远程SSE服务连接) | | (本地命令行服务连接) | |
| +---------------------------+ +---------------------------+ |
| | | |
| +---------------------------+ +---------------------------+ |
| | FlowSseClient | | ServerParameters (配置) | |
| +---------------------------+ +---------------------------+ |
| | | |
| +---------------------------+ +---------------------------+ |
| | HTTP请求/响应处理 | | 进程I/O流管理 | |
| +---------------------------+ +---------------------------+ |
+-----------------------------------------------------------------------------------------------------------+
| |
v v
+-----------------------------------------------------------------------------------------------------------+
| MCP协议消息格式 |
| |
| +------------------------+ +------------------------+ +------------------------+ |
| | 初始化/Ping消息 |---->| 工具调用请求/响应 |---->| 资源和提示模板消息 | |
| +------------------------+ +------------------------+ +------------------------+ |
| |
| +------------------------------------------------------------------------------------+ |
| | McpSchema (协议规范类) | |
| | +-------------------+ +-------------------+ +-------------------+ | |
| | | 请求类定义 | | 响应类定义 | | 工具Schema定义 | | |
| | +-------------------+ +-------------------+ +-------------------+ | |
| +------------------------------------------------------------------------------------+ |
+-----------------------------------------------------------------------------------------------------------+
| | |
v v v
+-----------------------------------------------------------------------------------------------------------+
| MCP服务层 |
| |
| +------------------------+ +------------------------+ +------------------------+ |
| | 远程SSE MCP服务 | | 本地命令行MCP服务 | | 其他MCP服务实现 | |
| +------------------------+ +------------------------+ +------------------------+ |
+-----------------------------------------------------------------------------------------------------------+
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
graph TD
subgraph "MCP Java SDK 架构"
subgraph "核心组件"
McpClient["McpClient (接口)"]
McpSyncClient["McpSyncClient (同步客户端)"]
McpAsyncClient["McpAsyncClient (异步客户端)"]
end
subgraph "传输层"
Transport["ClientTransport (接口)"]
HttpTransport["HttpClientSseClientTransport"]
StdioTransport["StdioClientTransport"]
ServerParams["ServerParameters"]
end
subgraph "规范层"
McpSchema["McpSchema"]
ToolRequest["CallToolRequest"]
ToolResult["CallToolResult"]
Tool["Tool"]
end
subgraph "服务类型"
RemoteServices["远程SSE服务"]
LocalServices["本地命令行服务"]
end
end
McpClient --> McpSyncClient
McpClient --> McpAsyncClient
McpSyncClient --> Transport
McpAsyncClient --> Transport
Transport --> HttpTransport
Transport --> StdioTransport
StdioTransport --> ServerParams
McpSyncClient --> McpSchema
McpAsyncClient --> McpSchema
McpSchema --> ToolRequest
McpSchema --> ToolResult
McpSchema --> Tool
HttpTransport --> RemoteServices
StdioTransport --> LocalServices
RemoteServices --> |"例如"| FetchService["fetch服务"]
LocalServices --> |"例如"| MongoService["MongoDB服务"]
LocalServices --> |"例如"| MySQLService["MySQL服务"]
LocalServices --> |"例如"| BrowserService["浏览器工具服务"]
LocalServices --> |"例如"| ClickHouseService["ClickHouse服务"]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 工作流程详解
初始化流程
应用代码 → 创建Transport实现 → 构建McpClient → 调用initialize() → 建立与MCP服务连接 → 发送初始化消息 → 等待服务就绪
工具调用流程
LLM输出 → JSON解析 → 参数Map转换 → 创建CallToolRequest → McpClientSession发送请求 → Transport层传输 → MCP服务处理 → 返回CallToolResult → 应用处理结果
SSE连接细节
HttpClientSseClientTransport → 基础URL+SSE端点 → 创建HTTP连接 → 设置SSE请求头 → 建立长连接 → FlowSseClient管理事件流 → 监听服务器事件 → 处理消息回调
本地命令行连接细节
ServerParameters配置 → StdioClientTransport → 启动子进程 → 管理标准输入/输出流 → 发送JSON消息到stdin → 从stdout读取响应 → 解析为MCP消息
错误处理流程
异常发生 → Transport层捕获 → 创建McpError → 通过CompletableFuture传播 → McpClientSession处理 → 返回给应用层 → 应用决定重试或失败处理
# MCP配置提示词模板流程
sequenceDiagram
participant User as 用户
participant Cursor as Cursor IDE
participant MCP as MCP 服务
participant LLM as 大语言模型
User->>Cursor: 输入查询
Cursor->>MCP: 请求可用prompt模板 (listPrompts)
MCP-->>Cursor: 返回可用prompt模板列表
Cursor->>MCP: 获取特定prompt模板 (getPrompt)
MCP-->>Cursor: 返回prompt模板结构
Cursor->>Cursor: 将用户输入套入prompt模板
Cursor->>LLM: 发送完整prompt请求
LLM-->>Cursor: 将LLM结果返回给客户端
Cursor-->>User: 显示回答
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 🛠️ 08.MCP SDK (JAVA版)实战
/**
* MCP客户端示例类,展示如何使用SDK API连接不同类型的MCP服务
*/
public class McpClientExample {
/**
* 连接到SSE远程服务示例
*/
public static void connectToSseService() {
System.out.println("=== 连接到SSE远程服务 ===");
// 1. 创建SSE Transport
String sseUrl = "https://mcp.api-inference.modelscope.cn/sse/83945a7d864c4d"; // 替换为你的SSE服务URL
// 正确分离基础URL和SSE端点
String baseUrl = "https://mcp.api-inference.modelscope.cn"; // 基础URL
String sseEndpoint = "/sse/83945a7d864c4d"; // SSE端点路径
McpSyncClient client = null;
try {
System.out.println("尝试连接SSE服务...");
System.out.println("基础URL: " + baseUrl);
System.out.println("SSE端点: " + sseEndpoint);
// 首先测试URL是否可以访问
try {
System.out.println("测试URL可访问性...");
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) new java.net.URL(sseUrl).openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "text/event-stream");
connection.setConnectTimeout(5000);
connection.connect();
int responseCode = connection.getResponseCode();
System.out.println("URL测试响应码: " + responseCode);
if (responseCode != 200) {
System.out.println("警告: URL直接访问返回非200状态码");
}
connection.disconnect();
} catch (Exception e) {
System.out.println("URL可访问性测试失败: " + e.getMessage());
}
// 使用SDK提供的Transport实现
var transport = HttpClientSseClientTransport.builder(baseUrl)
.sseEndpoint(sseEndpoint)
.build();
// 2. 创建MCP客户端
client = McpClient.sync(transport)
.requestTimeout(Duration.ofSeconds(60)) // 增加超时时间
.build();
// 3. 初始化客户端
System.out.println("正在初始化客户端...");
client.initialize();
System.out.println("客户端初始化成功");
// 4. 列出可用工具
McpSchema.ListToolsResult toolsResult = client.listTools(null);
List<Tool> tools = toolsResult.tools();
System.out.println("可用工具列表:");
for (Tool tool : tools) {
System.out.println(" - " + tool.name() + ": " + tool.description());
}
// 5. 调用工具 (fetch)
CallToolRequest request = new CallToolRequest(
"fetch",
Map.of("url", "https://www.example.com", "max_length", 1000)
);
System.out.println("\n调用fetch工具...");
CallToolResult result = client.callTool(request);
System.out.println("工具调用结果: " + result.content().get(0));
} catch (Exception e) {
System.err.println("连接SSE服务出错: " + e.getMessage());
e.printStackTrace();
} finally {
// 6. 关闭客户端
if (client != null) {
client.closeGracefully();
System.out.println("客户端已关闭");
}
}
}
/**
* 连接到本地命令行服务示例
*/
public static void connectToLocalService() {
System.out.println("\n=== 连接到本地命令行服务 ===");
// 1. 创建命令行服务参数 (修改为你的服务配置)
String command = "npx";
List<String> args = List.of("-y", "mcp-mongo-server", "mongodb://root:123456@localhost:12710/");
Map<String, String> env = Map.of(); // 环境变量
System.out.println("命令: " + command);
System.out.println("参数: " + args);
try {
// 使用SDK提供的ServerParameters和StdioClientTransport
ServerParameters params = ServerParameters.builder(command)
.args(args).env(env)
.build();
var transport = new StdioClientTransport(params);
// 2. 创建MCP客户端
McpSyncClient client = McpClient.sync(transport)
.requestTimeout(Duration.ofSeconds(30))
.build();
try {
// 3. 初始化客户端
System.out.println("正在初始化客户端...");
client.initialize();
System.out.println("客户端初始化成功");
// 4. 列出可用工具
McpSchema.ListToolsResult toolsResult = client.listTools(null);
List<Tool> tools = toolsResult.tools();
System.out.println("MongoDB工具列表:");
for (Tool tool : tools) {
System.out.println(" - " + tool.name() + ": " + tool.description());
}
// 5. 调用示例工具 (假设有个count工具)
CallToolRequest countRequest = new CallToolRequest("count", Map.of("collection", "users"));
CallToolResult countResult = client.callTool(countRequest);
System.out.println("计数结果: " + countResult.content().get(0));
} finally {
// 6. 关闭客户端
client.closeGracefully();
System.out.println("客户端已关闭");
}
} catch (Exception e) {
System.err.println("连接本地服务出错: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 展示更多API用法
*/
public static void exploreMoreApis() {
System.out.println("\n=== 探索更多API用法 ===");
// 使用SSE服务作为示例
String sseBaseUrl = "https://mcp.api-inference.modelscope.cn"; // 替换为你的URL
String endpoint = "/sse/83945a7d864c4d";
var transport = HttpClientSseClientTransport.builder(sseBaseUrl).sseEndpoint(endpoint).build();
McpSyncClient client = McpClient.sync(transport)
.requestTimeout(Duration.ofSeconds(30))
.build();
try {
client.initialize();
System.out.println("客户端初始化成功");
// 测试ping服务
client.ping();
System.out.println("Ping成功");
// 列出资源
McpSchema.ListResourcesResult resources = client.listResources(null);
System.out.println("可用资源数量: " + resources.resources().size());
if (!resources.resources().isEmpty()) {
// 读取第一个资源
McpSchema.Resource resource = resources.resources().get(0);
System.out.println("资源: " + resource.name() + " (" + resource.uri() + ")");
McpSchema.ReadResourceResult readResult = client.readResource(resource);
System.out.println("资源内容长度: " + readResult.contents().size());
}
// 列出提示模板
McpSchema.ListPromptsResult prompts = client.listPrompts(null);
System.out.println("可用提示模板数量: " + prompts.prompts().size());
if (!prompts.prompts().isEmpty()) {
// 获取第一个提示模板
McpSchema.Prompt prompt = prompts.prompts().get(0);
System.out.println("提示模板: " + prompt.name() + " - " + prompt.description());
try {
McpSchema.GetPromptResult promptResult =
client.getPrompt(new McpSchema.GetPromptRequest(prompt.name(), Map.of()));
System.out.println("提示模板消息数量: " + promptResult.messages().size());
} catch (Exception e) {
System.err.println("获取提示模板详情失败: " + e.getMessage());
}
}
} catch (Exception e) {
System.err.println("API调用出错: " + e.getMessage());
e.printStackTrace();
} finally {
client.closeGracefully();
System.out.println("客户端已关闭");
}
}
/**
* 主方法 - 运行所有示例
*/
public static void main(String[] args) {
System.out.println("MCP客户端示例程序启动");
// 启用详细HTTP和连接调试日志
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "DEBUG");
System.setProperty("reactor.netty.http.client.HttpClient", "DEBUG");
try {
// 连接到SSE远程服务
// connectToSseService();
// 连接到本地命令行服务
// 注意:取消注释下行来运行本地服务示例,需要确保本地有对应的服务
connectToLocalService();
// 探索更多API用法
//exploreMoreApis();
} catch (Exception e) {
System.err.println("示例执行出错: " + e.getMessage());
e.printStackTrace();
}
System.out.println("\nMCP客户端示例程序结束");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# 📌 09. 如何落地 MCP?
作为开发者或研究人员,你可以从以下几个方面入手:
- 使用 MCP SDK 开发你的工具服务(如 Java 服务端);
- 在工具中注册 MCP Schema,定义输入参数;
- 用 Cursor 等工具作为 MCP 客户端;
- 让它调用你提供的工具,接入你的模型或业务系统。