No.05修订于 2026-08-18约 1,696 字 · 阅读 17 分钟AGENT开发 次阅读

Agent Loop 中的工具调用与 MCP 协议详解

AIAgentMCP
目录

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 架构概览

flowchart LR
    Host["LLM Host\n(管理者)"] <-- "JSON-RPC 2.0\nstdio / HTTP+SSE" --> MCP["MCP Server\n(执行者)"]
    Host -->|"LLM API 调用"| LLM["LLM 模型\n(推理引擎)"]

关键认知: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 格式
inputSchemainput_schemafunction.parameters
namenamefunction.name
descriptiondescriptionfunction.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 序列化为系统级提示词的一部分,拼入上下文窗口:

flowchart LR
    A["tools tokens\n工具定义"] --> D["统一 token 流"]
    B["system prompt tokens\n角色设定"] --> D
    C["message tokens\n用户消息和历史"] --> D
    D --> E["Transformer 模型推理"]

最终整个 token 序列输入 Transformer 模型。

4.4 tools 与 messages 的关系

flowchart LR
    subgraph Storage["客户端本地存储"]
        T[("tools\n工具配置")]
        M[("messages\n对话历史")]
    end

    subgraph Request["API 请求体"]
        Req["tools + messages"]
    end

    subgraph LLM["LLM 上下文"]
        Tokens["统一 token 流"]
    end

    T --> Req
    M --> Req
    Req --> Tokens

关键区别

维度toolsmessages
持久化在对话历史里?
每轮 API 调用都传?是(重新拼接)是(完整历史)
能被动态修改?是(随时增减工具)否(已发送的消息不能改)
上下文压缩时被截断?否(受保护)是(中间消息可能被压缩)

tools 是”能力配置”,messages 是”对话记录”,两者在客户端分开管理,每次请求时临时组装。对话历史中永远只存消息本身,不包含工具 schema。


5. Agent Loop 完整流程

5.1 流程图

flowchart TD
    A["用户输入"] --> B["Host 追加到 messages\n拼接 tools 与 messages"]
    B --> C["POST /v1/messages\n发给 LLM API"]
    C --> D["LLM 内部序列化\ntools 转 system tokens\nmessages 转 message tokens"]
    D --> E["Transformer 推理"]
    E --> F{"需要工具调用?"}
    F -->|"否"| G["返回文本给用户"]
    F -->|"是"| H["Host 解析 tool_use\n路由到对应 MCP Server"]
    H --> I["JSON-RPC tools/call\nMCP Server 执行实际逻辑"]
    I --> J["工具执行结果\ntext 或 image 或 resource"]
    J --> K["Host 追加 tool_result\n到 messages"]
    K --> L["下一轮迭代\n重新发送 tools 与 messages"]
    L --> C
    G --> UserEnd((用户))

    classDef user fill:#e1f5fe,stroke:#01579b
    classDef host fill:#fff3e0,stroke:#e65100
    classDef llm fill:#fce4ec,stroke:#880e4f
    classDef mcp fill:#e8f5e9,stroke:#1b5e20
    class A,UserEnd user
    class B,C,I,K,L host
    class D,E,F,G llm
    class H,J mcp

5.2 调用时序

sequenceDiagram
    autonumber
    participant U as 用户
    participant H as Host (Client)
    participant Msg as messages[]
    participant T as tools[]
    participant L as LLM API
    participant R as MCP Router
    participant S1 as MCP Server A

    Note over H,L: 第 N 轮对话

    U->>H: 用户输入
    H->>Msg: 追加 role user 到 messages
    H->>H: 组装请求体 tools 与 messages
    Note over H,L: tools 是独立字段,不在 messages 中

    H->>L: POST /v1/messages 携带 tools 与 messages
    Note over L: 内部序列化 system tokens + tools tokens + messages tokens
    L-->>H: 响应 文本 或 tool_use

    alt 直接回复 无需工具
        H->>Msg: 追加 role assistant 文本
        H-->>U: 返回回答
    else 需要调用工具
        H->>Msg: 追加 role assistant tool_use
        Note over H,R: Host 解析 tool_use 路由到对应 MCP Server
        H->>R: JSON-RPC tools/call 携带 name 与 arguments
        R->>S1: stdio 或 SSE 转发
        S1-->>R: 执行结果 content text
        R-->>H: JSON-RPC result
        H->>Msg: 追加 role user tool_result
        Note over H,L: 进入下一轮迭代
        H->>L: POST /v1/messages 含 tool_result
        L-->>H: 最终回答 或 继续 tool_use
        H->>Msg: 追加 assistant 回复
        H-->>U: 返回回答
    end

5.3 多 Server 场景

一个 Host 可以同时连接多个 MCP Server:

flowchart TB
    Host["Host Client\ntools 包含 read_file write_file query_db create_ticket"]
    S1["MCP Server A\n文件系统\nread_file write_file"]
    S2["MCP Server B\n数据库\nquery_db"]
    S3["MCP Server C\n工单系统\ncreate_ticket"]
    Host -->|"read_file write_file"| S1
    Host -->|"query_db"| S2
    Host -->|"create_ticket"| S3

当 LLM 返回 tool_use: read_file 时,Host 根据工具名称路由到对应的 MCP Server。


6. 关键约束与限制

约束说明
工具数量上限Anthropic 限制最多 50 个工具,OpenAI 通常限制 128 个
消耗上下文窗口工具定义会消耗 token 额度,工具越多、schema 越复杂,占用越多
每轮必传多轮对话中,tools 字段必须在每次 API 调用时都带上
影响延迟工具定义越多,输入 token 越多,首 token 延迟越高

7. 总结

MCP 本质上是 LLM 与外部世界之间的”USB 接口”:

  1. Host 从 MCP Server 获取工具 schema,转换为 LLM API 格式
  2. 工具定义作为顶层字段随每次 API 请求传入,不在对话历史中
  3. LLM 服务端将工具定义序列化为系统级提示词,拼入上下文窗口
  4. LLM 基于工具定义决策是否调用、调用哪个
  5. Host 通过 JSON-RPC 将调用请求路由到对应 MCP Server 执行
  6. 执行结果追加到对话历史,触发下一轮迭代

整个循环中,工具定义与对话历史是分开管理、临时组装的。这保证了工具列表不会因为对话变长而被压缩或截断。