返回
查看原链接原链接
Bilibili44分5秒 · —

MCP Host 与模型的通信机制:以 Claude Code 的 XML 协议为例

MCP Host 与模型的通信机制:以 Claude Code 的 XML 协议为例

Claude Code 作为 MCP Host,通过自定义的 XML 格式与语言模型进行通信,其本质是 2022 年论文提出的 ReAct 模式(Thought-Action-Observation)的一种具体实现,理解了这一点即可自行构建类似 Claude Code 的 Agent 程序。

背景与核心概念

MCP 协议的边界

  • MCP(Model Context Protocol)协议仅规定了 MCP Host 与 MCP Server 之间的通信协议,包括工具发现、调用、资源访问等。
  • MCP 协议 没有对模型(Model)的输入和输出格式提出任何要求,因此不同的 MCP Host 可能使用完全不同的格式与模型交互。
  • Claude Code 使用一种自定义的 XML 格式(x-mail) 与模型进行沟通,这是本期视频演示的核心对象。

本期目标

  1. 演示 Claude Code 与模型交互的具体细节(通过截获模型的输入和输出)。
  2. 剖析 Claude Code 使用的 XML 协议的结构。
  3. 讲解构建 Agent 常用的 ReAct 模式。
  4. 梳理 Claude Code 的 XML 协议与 ReAct 模式之间的关系。
  5. 最终目标是借学习此协议,理解如何编写一个能够与模型持续交互的 Agent 程序。

实验环境搭建:截获模型请求与返回

设计思路

  • 原始方案:Claude Code 直接与 OpenAI 兼容的模型提供商(如 DeepSeek)通信,无法直接观察到通信内容。
  • 中转方案:在 Claude Code 与模型之间插入一个本地服务器作为中间人。所有请求与响应必须经过该服务器,服务器会将内容写入日志文件,由此获取完整的交互链路。

配置 Claude Code 连接本地服务器

  • Claude Code 的 API Provider 中除了常见的 OpenAI、DeepSeek 等提供商之外,存在一种特殊选项 OpenAI compatible
  • 它的含义是:目标模型提供商虽然不是 OpenAI,但其 API 完全兼容 OpenAI 的格式规范。
  • 配置要点:
  • 选择 OpenAI compatible
  • 将 Base URL 填入本地服务器地址:http://localhost:8000
  • API Key 和 Model ID 与 OpenRouter(或目标提供商)保持一致,因为转中服务器需要将这些信息转发给上游。

本地中转服务器代码解析

中转服务器使用 Python 编写,核心基于 FastAPI 框架。代码逻辑围绕“先记录请求,再记录返回”展开。

关键组件:

变量/对象作用
app_log日志写入函数,将 message 写入指定 log 文件
appFastAPI 生成的 Web 应用实例,用于定义 POST 接口
logger基于 app_log 生成的日志记录器,负责记录模型请求和返回,输出到 lm.log 文件

接口定义:

  • 定义了一个 POST 接口,路径为 /chat/completions,Claude Code 会将模型请求放入 POST body 中请求此路径。
  • 接口内部逻辑:
  1. 获取 Claude Code 发来的请求(post body),写入日志文件。
  2. 转发请求至 OpenRouter,注意保留流式返回标志accept text/event-stream,即 SSE 协议)。
  3. 接收上游模型的流式响应,将每一行返回(line)写入日志。
  4. 将上游响应实时转发回 Claude Code。
  • 服务器监听端口为 8000。

流程图示(文字版):

Client → (1) POST请求 → 本地服务器 → (2) 记录请求日志 → (3) 转发 → OpenRouter
Client ← (7) 转发响应 ← 本地服务器 ← (6) 记录返回日志 ← (5) SSE响应 ← OpenRouter

SSE(Server-Sent Events)简介

  • 中文含义为“服务器推送事件”,是模型流式返回的专业术语(缩写为 SSE)。
  • 解决的问题:普通 HTTP 交互方式为“一去一回”,无法处理服务器连续多次响应的场景。
  • 工作原理
  1. 浏览器只需请求一次。
  2. 服务器接收到请求后连续发送多次响应,每次响应内容为数个字(token)。
  3. 浏览器接到几个字就显示几个字,实现打字机效果,提升用户体验。
  4. 所有结果发送完毕后,服务器发送一个完成标识,浏览器收到后关闭 SSE 连接,对话结束。
  • 在日志中,上游的每一条 SSE 返回均以 data: 开头,包含一段 JSON。将每条 data 中的 content 值拼接起来,即为模型的完整返回内容。
  • 如果某行以 : 开头,则该行为注释,实际内容无意义,主要作用是保持连接,防止等待期间因超时而断开连接。

启动步骤

# 1. 创建虚拟环境(防止依赖影响系统环境)
python -m venv .venv

# 2. 激活虚拟环境
source .venv/bin/activate

# 3. 安装依赖
pip install -r requirements.txt
# 依赖仅有三个:fastapi(定义接口)、uvicorn(运行服务器)、httpx(向 OpenRouter 发起 HTTP 请求)

# 4. 启动本地服务器
python lm_logger.py
# 输出显示端口为 8000

使用 Claude Code 验证

  • 在 Claude Code 中点击配置 API Provider,选择 OpenAI compatible,Base URL 填写 http://localhost:8000,保存。
  • 向 Claude Code 随便发送打招呼消息(如“嗨”),等待回复完成后,打开日志文件,可看到模型请求和模型返回两部分内容。

模型请求解析(无工具调用场景)

请求整体结构

模型请求包含以下几大核心部分:

  • model:使用的模型(如 deepseek)。
  • messages:消息列表,存放 Client 发给模型的请求以及模型的历史回答。
  • temperature:温度参数,控制模型输出的确定性。值越小,输出越稳定保守;值越大,输出越多样、富有想象力。
  • stream:代表使用 SSE 流式输出。

System Prompt 分析

第一条消息的 role 为 system,即系统提示词。其功能是设定模型需要提前感知的信息,包括:模型扮演的角色、可用的工具列表、返回结果的格式等。

基本规模数据:

  • 系统性提示词总共有 626 行(格式化后),部分行非常长。
  • 总字符数为 48671 个字符
  • 这些内容都会作为 token 发送给模型,占用上下文长度。

System Prompt 基本框架(折叠后的小标题):

  1. 工具使用格式(Tool Use Format)
  2. 工具列表(Tools)
  3. 工具使用示例(Tool Use Examples)
  4. 工具使用指南(Tool Usage Guidelines)
  5. 已连接的 MCP 服务器(Connected MCP Servers)
  6. 客户端内置函数:write_to_filereplace_in_file
  7. 工具选择的指导
  8. 自动格式化注意事项
  9. 工作流程提示
  10. 首选语言(Primary Language)

工具的分类

Claude Code 中的“工具”包含两类:

  • Claude Code 内置工具:如写入文件、替换文件内容、读取文件、运行终端命令等,用于操作本地环境和项目。
  • MCP 工具:通过 MCP 服务器提供的工具,如常用的天气预告和气象预警工具。

工具调用格式:XML 协议详解

  • Claude Code 规定客户端工具调用请求必须使用 XML 格式传递。
  • 外层标签写工具名称,内层标签写参数的名称和参数值。

读取文件工具格式示例:

外层写工具名称 read,内层写参数名 file_path(原视频中实际参数名为 paassrc,以实际内容为准),参数值即为文件路径,例如 src/index.js

模型调用工具的实现流程:

  1. 用户提出需要读取文件的问题(如“src/index.js 这个文件写了什么”)。
  2. Client 将问题发给模型。
  3. 模型发现需要调用 read 工具来获取文件内容,于是按照 system prompt 中的 XML 格式返回工具调用请求。
  4. Client 接到请求后执行读取操作,并将文件内容返回给模型。
  5. 模型自己总结答案并回复用户。

关键原则:只要模型按照 client 规定的 XML 格式返回,client 就可以帮助模型调用任何其想要调用的工具。

常用工具列表

工具名功能参数与备注
execute_command执行终端命令包含两个参数:命令内容和是否需要用户同意。一些可能影响系统的命令(如删除文件、安装文件)需用户同意。
read读取文件参数为文件路径
write_to_file写入文件内容参数为文件路径和内容
replace_in_file替换文件内容参数为文件路径和替换内容
search_files搜索文件
list_files列举当前项目目录中的文件列表
list_code_definition_names列举指定目录顶层源代码文件中使用的定义名称(类、函数、方法等)
browser_action浏览器操作

重点工具:use_mcp_tool

use_mcp_tool 是本期视频的重点,用于调用 MCP 服务器提供的工具,参数共三个:

参数名含义
server_nameMCP 服务器的名称
tool_nameMCP 工具的名称
argumentsMCP 工具的输入参数(通常以 JSON 形式)

示例:以下 XML 表示模型想要调用 weather 服务器下的 get_forecast 工具,参数为纬度 41.7128、经度 -74.006(即纽约)。

<use_mcp_tool>
  <server_name>weather</server_name>
  <tool_name>get_forecast</tool_name>
  <arguments>{"latitude": 41.7128, "longitude": -74.006}</arguments>
</use_mcp_tool>

其他重要标签

  • access_mcp_resource:用于获取 MCP 资源,需填入 MCP 服务器名称和资源 URI。本期视频暂不涉及。
  • ask_follow_up_question:模型向用户提问时使用的工具标签,用于澄清问题。
  • attempt_completion表示回答结束的标志。模型在调用一系列工具后,认为自己已完成任务或已得到答案,会将最终结论放入 attempt_completionresult 参数。Client 接到后显示结果并结束对话。
  • 另一个可选参数为 command,存储一条用于展示最终结果的命令,本期不使用。

Thinking 强制思考机制

  • Claude Code 要求模型在做任何事情之前,都必须先使用 thinking 标签进行思考,包括使用工具之前和输出最终答案之前。
  • 这是一种强制让模型“思考”的机制,有利于提高模型决策的准确率。

已连接的 MCP 服务器信息

  • Claude Code 会将用户在客户端上配置的 MCP 服务器及每个服务器包含的 MCP 工具都列举在 system prompt 中,供模型选用。
  • 包含的信息:每个 MCP 工具的用途、参数列表(帮助模型判断何时调用)、input schema(告诉模型调用工具时的参数格式)。
  • Input schema 本质上是 JSON Schema,该概念在 MCP 进阶指南中已详细讲解。

用户请求消息解析

用户请求(role 为 user)分为两部分:

  1. 用户原始问题:放在 <task> 标签内,例如 <task>嗨</task>,告诉模型这是需要完成的任务。
  2. 当前系统环境:同样以 XML 表示,放在一个长字符串中,包含当前可见的文件、打开的 tab、当前时间等信息,辅助模型做决策。

模型返回解析(无工具调用场景)

流式返回结构

  • 模型采用 SSE 方式逐量返回。日志中每一行 data: 对应一次返回。
  • 首行为注释(data: : OPENROUTER PROCESSING),以冒号开头,作用是保持连接,无有效信息。
  • 后面的每一行 data: 是 JSON 数据,其中大部分字段(如 id、provider、model)均相同。
  • 每一条消息中唯一不同的是 content 字段,其值为增量返回,将每条 content 拼接起来即为模型的完整返回。

示例

如果模型最终完整返回为“纽约明天的温度是24摄氏度”,则 SSE 返回可能包含多条 data,例如:

  • data: ...content="纽约"
  • data: ...content="明天的"
  • data: ...content="温度"
  • data: ...content="是"
  • data: ...content="24摄氏度"
  • data: ...content="[DONE]"(结束标识符)

对应展示页面

  • Claude Code 收到流式消息后逐条展示给用户。
  • Thinking 内容展示在特定区域,ask_follow_up_question 的内容展示在对应位置。

MCP 工具调用完整流程实例

实例一:仅查询天气并返回答案

场景:问“纽约明天的天气怎么样?”,Claude Code 调用 weather MCP 服务器下的 get_forecast 工具。

完整交互流程(文字版):

第一轮请求(Client → 模型):

  • System prompt(与前文分析一致,包含工具列表与格式说明)。
  • 用户问题(role 为 user,包含 task 标签与系统环境信息)。

模型第一次返回:

  • 包含两个 XML 标签:
  • <thinking> 内容:模型推理过程。
  • <use_mcp_tool> 内容:请求调用 weather 服务器的 get_forecast 工具,参数为纽约的经纬度。

第二轮请求(Client → 模型,在工具执行后):

  • 将之前的 system prompt、用户问题以及模型工具调用请求(role 为 assistant)作为历史消息重新发送给模型(因模型无记忆)。
  • 新增消息(role 为 user):
  • 第一部分:展示 MCP 工具调用的结果。
  • 第二部分:具体结果内容(如纽约明天的天气温度数据)。
  • 第三部分:当前环境信息。

模型第二次返回:

  • 同样包含两个 XML 标签:
  • <thinking> 内容:模型思考。
  • <attempt_completion> 内容:最终结论回答。

流程图示:

用户提问 → 模型返回 (thinking + use_mcp_tool) → Client 调用 MCP 工具
→ 工具结果返回给模型 → 模型返回 (thinking + attempt_completion) → 显示最终答案,结束。

实例二:查询天气并写入文件

场景:将任务改为“纽约明天的天气怎么样?把结果写入到 result.md 文件中”。

修改后的流程:

  1. 用户提问。
  2. 模型返回 thinking + use_mcp_tool(调用 get_forecast 工具)。
  3. Client 调用工具,将天气结果返回给模型。
  4. 模型第一次思考后发现任务未完成(还需要写入文件),不会使用 attempt_completion
  5. 模型再次请求调用工具,这次使用 `write_to_file`(Claude Code 内置工具),并指定文件路径和写入内容。
  6. Client 执行文件写入,将“写入成功”通知返回给模型。
  7. 模型最终返回 thinking + attempt_completion,告知任务完成。

关键认知:在每一轮工具调用中,模型可以持续调用工具直到任务完成,不限于只调用一个 MCP 工具,也可以混合使用 MCP 工具和内置工具。

ReAct 模式深度解析

ReAct 思想概述

  • ReAct 是 2022 年一篇论文中提出的概念,是 ReasoningActing 两个单词的合体。
  • 重要性:论文提出可以在不需要人干预的情况下,让模型自主思考、自主调用各类外部工具,从而完成用户诉求。
  • 符合 ReAct 模式思想的程序被称为 Agent——即能够持续思考、持续调用外部工具直至解决用户问题的一个程序。
  • Claude Code 本质上就是一个 Agent,其 Agent 流程正是基于 ReAct 思想构建的。

ReAct 三要素

中文英文含义
思考Thought模型的推理过程
行动Action获取或改变外部环境的行为(调用工具)
观察Observation行动的结果或反馈

循环模式:思考 → 行动 → 观察 → 思考 → 行动 → 观察 → ... → 最终答案

Claude Code 的 XML 标签与 ReAct 的对应关系

Claude Code 的 XML 标签ReAct 概念说明
<thinking>Thought思考
<use_mcp_tool><write_to_file><read> 等工具标签Action行动
工具执行后返回的结果消息Observation观察
<attempt_completion>Final Answer最终答案

XML 与 ReAct 的关系

  • XML 只是数据传输格式,ReAct 是思想/方法论,二者不绑定。
  • ReAct 论文原作者并未使用 XML 或 JSON,而是使用了近乎纯文本的方式实现类似效果。
  • 例如,可以使用以下纯文本格式替代:
Thought: 我需要获取纽约的天气
Action: get_forecast({"latitude": 41.7128, "longitude": -74.006})
Observation: 纽约明天的温度是24摄氏度
Thought: 任务已完成
Final Answer: 纽约明天的天气是24摄氏度。

使用 ReAct 格式复现 Claude Code 交互流程(示例)

假设将 Claude Code 的 XML 交互改为 ReAct 论文中提到的纯文本格式:

  • 模型第一个回答:Thinking: 替换为 Thought:
  • 工具调用:<use_mcp_tool> 替换为 Action: + 工具名称与参数。
  • 工具结果:替换为 Observation: + 结果内容。
  • 工具执行后再次返回 Thought:
  • 最终答案使用 Final Answer: 标记,结束对话。
  • 前提:需配套修改 system prompt,说明返回格式、工具调用示例、注意事项和工具列表。

实际演示:用开源模型 Gemma 3 演示 ReAct 格式

  • 作者使用 Ollama 启动 Google 的开源模型 Gemma 3(4B 参数)。
  • 将之前展示过的 ReAct system prompt 与用户问题“纽约明天的天气怎么样?结果写入到 result.md 文件中”合并后直接发给模型(注:正式使用时应将 system prompt 与用户问题分开传入,Ollama 设置 system prompt 略复杂,为了演示简化)。
  • 模型返回格式:包含 Thought:Action: 两部分,符合 ReAct 要求。
  • 假设调用工具完成并拿到结果,在结果前加上 Observation: 返回给模型。
  • 模型返回 Thought:Action:(要求使用 write_to_file 工具写入文件)。
  • 继续模拟写入完成,返回消息给模型。
  • 模型再次思考后,输出 Final Answer: 并结束流程。

用 DeepSeek 复现 XML 格式调用

  • 由于 Gemma 3 模型仅 4B,难以产出符合格式的 XML,因此使用 DeepSeek 演示。
  • 找到 Claude Code 的 system prompt,末尾加上问题“纽约明天的天气怎么样?结果写入到 result.md 文件中”,将整个文件内容复制给 DeepSeek。
  • DeepSeek 返回 thinkinguse_mcp_tool 标签,与 Claude Code 中见到的一致。
  • 模拟工具执行,返回结果,模型继续返回 thinkingwrite_to_file 请求。
  • 模拟写入成功,模型最终返回 attempt_completion,流程结束。
  • 注意:本示例中 DeepSeek 在 attempt_completion 之前未返回 thinking 标签,作者指出这是模型输出的小失误。

格式对比

格式优点适用场景
XML表达精确,工具参数结构化生产环境、复杂工具调用
纯文本(Thought/Action/Observation)格式简单、易于理解简单演示、轻量级 Agent
JSON结构化、易解析通用格式选项

结论:可以使用任意格式与模型通信,只要该格式遵循 ReAct 模式即可。

构建 Agent 的三要素(核心总结)

要实现一个类似 Claude Code 的 Agent 程序,需要完成以下三步:

  1. 明确告知模型返回结果的格式:可以是 XML、纯文本(Thought/Action/Observation)或 JSON,但必须明确指定。
  2. 告知模型可用的工具列表:包括工具名称、参数、用途等详细信息。
  3. 明确要求模型遵循 ReAct 模式:每次回答需先思考(Thought),随后给出工具调用请求(Action)或最终答案(Final Answer/Attempt Completion)。

将上述要求写入 system prompt,配合用户问题触发,Agent 即可运作。

局限与待确认问题

  • Claude Code 未提供修改 system prompt 的场所,XML 格式是写死在代码内部的,因此用户无法让 Claude Code 直接改用其他格式(如纯文本或 JSON)与模型交互。
  • 视频中演示的 ReAct 纯文本格式与 XML 格式的对比仅作为示例说明,前者未经过生产环境验证,其可用性需自行判断。
  • 视频作者建议优先采用 XML 格式,因为其表达精度更高;但并未给出基于实测的性能数据。
  • 关于 attempt_completion 参数中 result 的具体展示方式,以及 command 参数何时会被使用,视频未深入展开。
  • System prompt 中剩余未讲解的部分(如工具使用示例、工具使用指南、Play Mode 和 X Mode 的区别、new task 等标签)被作者以“不重要”为由跳过,具体功能与实现未详述。

关键数据与事实汇总

项目数值/事实
System Prompt 行数626 行
System Prompt 总字符数48,671 个字符
MCP 协议边界仅规定 Host 与 Server 通信,不规定与模型的格式
Claude Code 与模型的通信格式XML(x-mail)
ReAct 论文发表年份2022 年
ReAct 全称Reasoning + Acting
中转服务器端口8000
模型示例DeepSeek、Gemma 3(4B,Ollama 启动)
演示 MCP 服务器weather(官方示例,工具含 get_alerts、get_forecast)

行动清单(用于理解或复现)

  1. 克隆 GitHub 仓库(作者提供的 lm_logger.py 源码)。
  2. 执行环境搭建:创建虚拟环境 → 安装依赖(fastapi、uvicorn、httpx)→ 启动服务器。
  3. 在 Claude Code 中配置 OpenAI compatible Provider,Base URL 指向本地服务器。
  4. 发送一条简单的打招呼消息,观察日志文件(lm.log)中的模型请求与返回结构。
  5. 配置并连接 weather MCP 服务器,提问“纽约明天的天气怎么样?”,观察工具调用链路。
  6. 修改问题为“纽约明天的天气怎么样?把结果写入 result.md 文件中”,观察模型调用 mcp 工具后再调用内置 write_to_file 工具的完整流程。
  7. 使用 Ollama 启动 Gemma 3 模型,用 ReAct 纯文本格式模拟 Agent 的 thought-action-observation 循环。
  8. 使用 DeepSeek 模型(或任意 OpenAI 兼容模型)复现 XML 格式的 tool calling 流程。