Agent Loop 中的工具调用与 MCP 协议详解
Agent Loop 中的工具调用与 MCP 协议详解
1. MCP 协议概述
MCP(Model Context Protocol)是一个基于 JSON-RPC 2.0 的标准化协议,定义了 LLM 应用(Host/Client)与外部工具/数据源(Server)之间的通信方式。
1.1 核心角色
| 角色 | 职责 | 举例 |
|---|---|---|
| Host (Client) | 建立连接、路由工具调用、管理生命周期 | Claude Code、Cursor 等 |
| MCP Server | 提供工具定义、执行实际逻辑 | 文件系统、数据库、自定义 API |
| LLM 模型 | 基于工具定义决策是否调用、调用哪个 | Claude、GPT 等 |
1.2 架构概览
关键认知:LLM 模型本身不知道 MCP Server 的存在。Host 才是真正的"连接管理者",LLM 只负责决策。
2. 传输层
MCP 支持两种传输方式:
2.1 stdio(本地场景,最常用)
Host 将 MCP Server 作为子进程启动,通过 stdin/stdout 传输 JSON-RPC 消息:
- 每条 JSON-RPC 消息占一行,
\n分隔 - stderr 保留给日志输出
- 适合本地开发、CLI 工具
2.2 HTTP + SSE(远程场景)
- Server 作为 HTTP 服务启动,暴露 SSE 端点
- Client 通过 HTTP POST 发送请求
- 通过 SSE 接收 Server 推送的响应
- 适合跨网络、跨进程的远程场景
3. 交互全流程
3.1 建立连接与初始化
连接建立后,Host 和 Server 进行能力交换:
Client 发送 initialize 请求
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": { "roots": { "listChanged": true } },
"clientInfo": { "name": "claude-code", "version": "1.0.0" }
}
}
Server 返回 initialize 响应
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": true },
"prompts": { "listChanged": true }
},
"serverInfo": { "name": "filesystem", "version": "1.0.0" }
}
}
随后 Client 发送 notifications/initialized 通知,握手完成。
3.2 能力发现
Host 查询 Server 提供了哪些能力:
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }
Server 响应:
{
"jsonrpc": "2.0", "id": 2,
"result": {
"tools": [
{
"name": "read_file",
"description": "读取文件内容",
"inputSchema": {
"type": "object",
"properties": {
"file_path": { "type": "string", "description": "文件绝对路径" }
},
"required": ["file_path"]
}
}
]
}
}
4. 工具定义如何进入 LLM 上下文
这是理解 Agent Loop 的关键环节。
4.1 格式转换
MCP Server 返回的工具定义(inputSchema)本身就是 JSON Schema,与主流 LLM API 的 tool format 高度兼容,Host 只需做简单字段映射:
| MCP 格式 | Anthropic API 格式 | OpenAI API 格式 |
|---|---|---|
inputSchema |
input_schema |
function.parameters |
name |
name |
function.name |
description |
description |
function.description |
4.2 请求体结构
工具定义作为 顶层字段 传入,与 messages 平级:
{
"model": "claude-sonnet-4-6",
"max_tokens": 4096,
"tools": [
{
"name": "read_file",
"description": "读取文件内容",
"input_schema": { ... }
}
],
"messages": [
{ "role": "user", "content": "帮我读取 /tmp/test.txt" }
]
}
4.3 内部序列化
LLM 服务端收到请求后,在内部将 tools 序列化为系统级提示词的一部分,拼入上下文窗口:
最终整个 token 序列输入 Transformer 模型。
4.4 tools 与 messages 的关系
关键区别:
| 维度 | tools | messages |
|---|---|---|
| 持久化在对话历史里? | 否 | 是 |
| 每轮 API 调用都传? | 是(重新拼接) | 是(完整历史) |
| 能被动态修改? | 是(随时增减工具) | 否(已发送的消息不能改) |
| 上下文压缩时被截断? | 否(受保护) | 是(中间消息可能被压缩) |
tools 是"能力配置",messages 是"对话记录",两者在客户端分开管理,每次请求时临时组装。对话历史中永远只存消息本身,不包含工具 schema。
5. Agent Loop 完整流程
5.1 流程图
5.2 调用时序
5.3 多 Server 场景
一个 Host 可以同时连接多个 MCP Server:
当 LLM 返回 tool_use: read_file 时,Host 根据工具名称路由到对应的 MCP Server。
6. 关键约束与限制
| 约束 | 说明 |
|---|---|
| 工具数量上限 | Anthropic 限制最多 50 个工具,OpenAI 通常限制 128 个 |
| 消耗上下文窗口 | 工具定义会消耗 token 额度,工具越多、schema 越复杂,占用越多 |
| 每轮必传 | 多轮对话中,tools 字段必须在每次 API 调用时都带上 |
| 影响延迟 | 工具定义越多,输入 token 越多,首 token 延迟越高 |
7. 总结
MCP 本质上是 LLM 与外部世界之间的"USB 接口":
- Host 从 MCP Server 获取工具 schema,转换为 LLM API 格式
- 工具定义作为顶层字段随每次 API 请求传入,不在对话历史中
- LLM 服务端将工具定义序列化为系统级提示词,拼入上下文窗口
- LLM 基于工具定义决策是否调用、调用哪个
- Host 通过 JSON-RPC 将调用请求路由到对应 MCP Server 执行
- 执行结果追加到对话历史,触发下一轮迭代
整个循环中,工具定义与对话历史是分开管理、临时组装的。这保证了工具列表不会因为对话变长而被压缩或截断。
更多推荐



所有评论(0)