文章类型技术长文 所属专栏Agent 网络通信 预计阅读56 分钟 文档状态已发布
返回

Claude Code 网络层深度解析——模型流、MCP 与工具出网

沿一次真实编码任务,拆解 Claude Code 的模型流、Agent Loop、工具并发、MCP 传输、企业代理、沙箱出网与故障恢复。

开始阅读全文11196 字 · 56 分钟 查看系列目录Agent 网络通信
关键词 Claude CodeAgentSSEMCP网络通信工具调用沙箱
栏目 AgentNetworking;专栏 Agent 网络通信;标签 Claude Code、Agent、SSE、MCP、网络通信、工具调用、沙箱

Claude Code 表面上是一个运行在终端里的编码 Agent,网络上却不是“CLI 发一个请求,模型返回一个答案”这么简单。一次完整任务至少会同时经过三条相互独立的通信面:

  1. 模型通信面:Claude Code 向 Claude 模型服务持续发送上下文,并通过流式响应接收文本、thinking 和 tool_use
  2. 工具通信面:本地工具在进程内或子进程中执行,远程能力则可能通过 MCP 的 stdio、Streamable HTTP 或兼容性 SSE 接入;
  3. 执行出网面:Bash、测试程序、包管理器、浏览器和其他子进程从沙箱内访问文件系统与网络。

此外还有一条横跨三者的控制面:模型路由、认证、企业代理、LLM Gateway、权限规则、沙箱策略、取消信号与遥测。

这几条链路的故障语义不同。模型 SSE 中断,并不等于 MCP 断线;MCP 工具返回错误,也不等于 Bash 子进程没有执行;上下文超长,更不是网络不可达。只有先把边界拆开,才能理解 Claude Code 为什么能够连续工作,以及它在什么位置恢复、重试或停止。

资料与证据边界

本文使用两类资料:

  • 官方契约:Anthropic 的 Claude Code、Claude API 和 MCP 官方文档,用于确认公开协议、配置项与用户可依赖的行为;
  • 实现分析how-claude-code-works 仓库对特定 Claude Code 构建快照的源码分析,用于解释 QueryEnginequery()StreamingToolExecutor、压缩流水线和错误扣留等内部结构。

该仓库 README 明确声明它是独立研究与教育性分析,并非 Anthropic 官方设计说明。因此,文中凡涉及内部类名、精确调度顺序和恢复分支,都会标注为“仓库分析”,不把它们写成跨版本稳定的产品契约。1

核心结论#

在进入细节前,可以先记住六点:

  1. Claude Code 的主模型流本质上是一次次 HTTPS/SSE 请求,而不是一个无限延续的单请求会话。
  2. 模型只生成工具调用意图,真正的文件写入、命令执行与外部 API 副作用由本地 Claude Code 或 MCP Server 完成。
  3. 每一轮工具执行都会把 tool_result 写回消息历史,再发起下一次模型请求。
  4. 仓库分析显示,Claude Code 可以在整体模型响应尚未结束时,提前执行已经完整解析的工具调用;但这属于实现优化,不是 Messages API 的协议保证。
  5. MCP 远程 HTTP/SSE 连接与本地 stdio 进程采用不同恢复策略:前者自动退避重连,后者不会自动重启。
  6. 企业正向代理、LLM Gateway 与 Bash 沙箱代理是三层不同设施,不能互相替代。

1. Claude Code 网络拓扑#

Claude Code 网络拓扑总览

1.1 本地 CLI 进程#

Claude Code 的 CLI 不是一个薄客户端,而是 Agent 的本地运行时。官方文档将 Claude Code 描述为可以直接读取代码库、编辑文件、运行命令并接入开发工具的 Agentic Coding Tool;终端只是入口,任务循环和工具副作用主要发生在本地。2

从网络职责看,本地进程至少包含以下逻辑模块:

模块主要职责是否直接产生网络流量
输入与界面层接收用户消息、显示流式文本、权限弹窗、进度和结果间接
会话层保存消息历史、使用量、工作目录与任务状态通常否
模型客户端组装 Messages 请求,连接 Anthropic 或第三方模型上游
Agent Loop判断继续、执行工具、回填结果或停止间接
MCP Client管理 MCP Server、能力发现、OAuth、工具调用可能
工具执行器调度 Read、Edit、Bash、MCP 等工具可能
沙箱管理器限制 Bash 及其子进程的文件与网络访问
权限与策略层allow/deny/ask、工作区信任、企业策略通常否

how-claude-code-works 将会话外壳还原为 QueryEngine,将单次模型—工具循环还原为 query() 异步生成器。这个分层非常有解释力:

  • QueryEngine 关注会话生命周期、消息持久化、预算、最终结果和权限拒绝;
  • query() 关注上下文压缩、模型流、工具执行以及本轮继续或终止。3

因此,“一次用户输入”与“一次模型 API 请求”不是同一件事。一个用户任务可能只对应一次 submitMessage(),却在 query() 内部发起多次模型请求。

1.2 Claude 模型服务#

在直接 Anthropic API 路径上,Claude Code 使用 Messages API 的流式能力。请求设置 stream: true 后,服务端通过 SSE 连续发送结构化事件,包括:

  • 文本块增量;
  • thinking / reasoning 增量;
  • tool_use 块及其参数增量;
  • usage、stop reason 与最终完成事件;
  • 流内部错误。4

模型服务做的是推理与决策,不是本地副作用执行。例如,模型可以返回:

{
"type": "tool_use",
"id": "toolu_xxx",
"name": "Read",
"input": {
"file_path": "src/payment.ts"
}
}

但它不会直接打开用户磁盘上的文件。Read 的实际执行发生在 Claude Code 本地工具系统;如果是 MCP 工具,则由对应 MCP Server 执行。

这条边界十分关键:

模型返回的是“调用什么工具、传什么参数”,本地运行时决定“是否允许、何时执行、执行结果如何回填”。

因此,网络层和权限层并不是模型服务的附属功能,而是 Agent Runtime 自己的责任。

1.3 Amazon Bedrock 等模型上游#

Claude Code 不只支持直连 Anthropic API。官方文档还提供 Amazon Bedrock、Google Vertex AI 和 Microsoft Foundry 等第三方部署路径。不同上游共享相近的 Agent 语义,但认证、端点、模型标识和底层 API 不同。

上游主要认证方式模型标识关键差异
Anthropic APIClaude 账号或 ANTHROPIC_API_KEYAnthropic 模型名或别名直接使用 Anthropic Messages 协议
Amazon BedrockAWS SDK 默认凭证链、IAM、SSO、Bedrock API Keyinference profile ARN / Bedrock model IDClaude Code 使用 Bedrock Invoke API,不使用 Converse API
Google Vertex AIApplication Default Credentials、Service Account、Workload IdentityVertex 版本名受项目、区域、配额和 Model Garden 可用性约束
Microsoft FoundryAPI Key 或 Entra ID 默认凭证链deployment name认证与部署绑定在 Azure 资源上
企业 LLM Gateway企业自定义 token、mTLS 或代理认证网关映射的模型名由网关决定上游路由、审计和配额

Bedrock 路径依赖 AWS 默认凭证链,并允许通过 IAM、SSO Profile、环境变量或 Bedrock API Key 认证。官方文档还明确指出标准 Bedrock 路径使用 Invoke API。5

Vertex AI 路径则使用 Google Cloud 的标准凭证体系,端点与可用模型还受项目、区域和配额影响。6

这里要区分两个配置概念:

  • 模型选择决定“由哪个模型回答”;
  • Base URL / Provider 选择决定“请求发到哪里”。

官方模型配置文档明确指出,ANTHROPIC_BASE_URL 只改变请求端点,并不自动改变模型选择。7

1.4 企业 LLM Gateway#

LLM Gateway 是位于 Claude Code 与模型上游之间的应用层代理。它一般承担:

  • 集中保存 API Key 或云凭证;
  • 按团队、项目或环境统计使用量;
  • 实施预算、速率限制和模型白名单;
  • 记录审计日志;
  • 在 Anthropic、Bedrock、Vertex 等上游间路由;
  • 对 Header、模型名和请求格式进行转换。

官方文档强调,Gateway 必须正确透传 Claude Code 使用的请求格式与能力 Header;否则新模型能力、beta 功能、工具搜索或 prompt caching 可能失效。8

LLM Gateway 只覆盖模型流量。它默认不会替 Claude Code 管理:

  • 本地 Bash 子进程访问 GitHub 或 npm;
  • MCP Server 的 HTTP 连接;
  • 本地 stdio MCP 进程;
  • WebFetch 与其他工具的独立网络路径。

把 LLM Gateway 当成“所有 Agent 网络流量的总入口”是常见误区。

1.5 本地和远程 MCP Server#

MCP 是 Claude Code 的第二条网络主干。它把外部系统能力标准化为:

  • Tools;
  • Resources;
  • Prompts;
  • 通知与动态能力变化。

本地 MCP Server 常通过 stdio 运行,由 Claude Code 启动子进程;远程 MCP Server 则主要通过 Streamable HTTP 接入,旧式 HTTP+SSE 仍作为兼容路径存在。Claude Code 官方文档还支持 WebSocket 扩展,但 MCP 标准传输的核心仍是 stdio 与 Streamable HTTP。910

how-claude-code-works 的工具系统分析显示,MCP 工具最终会被桥接为与内置工具相同的统一 Tool 接口,进入同一套:

  1. 工具查找;
  2. Schema 验证;
  3. 权限检查;
  4. 执行;
  5. 结果格式化;
  6. tool_result 回填。

这使 MCP 不是“外挂脚本”,而是 Claude Code 工具池的一部分。11

1.6 Shell 与沙箱子进程#

Shell 工具打开的是第三条网络面。一个 Bash 命令可能继续派生:

  • git
  • gh
  • npm / pnpm
  • curl
  • 测试进程;
  • 浏览器驱动;
  • 容器或基础设施 CLI。

这些子进程可能访问与模型服务完全无关的主机。Claude Code 的 Bash 沙箱使用操作系统级机制限制文件系统与网络访问,并将约束施加到 Bash 及其所有子进程。macOS 使用 Seatbelt;Linux/WSL2 依赖 bubblewrap,并通过外部代理控制出网。12


2. 一次模型请求如何构造#

一次 Claude 模型请求的构造

Claude 模型在每次 API 请求之间不会自动记住上一轮。Claude Code 必须把当前推理需要的内容重新组装进请求。官方 prompt caching 文档明确说明:每个新 turn 都会再次发送系统提示词、项目上下文、历史消息、工具调用和结果;缓存只是让服务端避免重复计算相同前缀,并没有省略这些语义内容。13

一个高度简化的请求结构如下:

{
"model": "claude-...",
"max_tokens": 16000,
"system": [
{"type": "text", "text": "..."}
],
"tools": [
{
"name": "Read",
"description": "...",
"input_schema": {"type": "object", "properties": {}}
}
],
"messages": [
{"role": "user", "content": "..."},
{"role": "assistant", "content": []},
{"role": "user", "content": []}
],
"stream": true
}

实际请求还可能包含 thinking、effort、cache control、service tier、beta headers 与 provider 特定配置。

2.1 System Prompt#

System Prompt 定义 Claude Code 作为编码 Agent 的行为边界,包括:

  • 核心操作原则;
  • 工具使用规则;
  • 安全约束;
  • 当前环境信息;
  • 输出风格;
  • 用户追加的系统指令。

官方 context window 文档确认,系统指令、CLAUDE.md、auto memory、skills、MCP 工具名、文件内容和命令输出都会进入 Claude 可见上下文,但不同机制的加载时机和压缩后恢复方式不同。14

仓库分析进一步给出了一种具体快照布局:

  • 稳定核心指令放在较前位置;
  • 动态系统内容位于后部;
  • CLAUDE.md、日期、记忆、技能或 MCP 增量可能以消息附件形式注入;
  • Git 状态、平台、Shell 等环境信息被纳入请求上下文。15

这里最重要的工程约束不是“提示词应该写多长”,而是稳定前缀。Prompt cache 按精确前缀匹配,修改前部内容会使后续层全部失效。Claude API 的缓存层级是:

tools → system → messages

因此:

  • 工具定义变化会使 tools、system 和 messages 缓存全部失效;
  • system 变化会使 system 与 messages 层失效;
  • 只在消息尾部追加新 turn,通常可以继续命中前缀缓存。16

这也是 Claude Code 尽量保持工具顺序、系统提示词和会话启动上下文稳定的原因。

2.2 对话历史#

对话历史不仅包含用户与模型的文本,还包括完整的 Agent 轨迹:

User message
→ Assistant text / thinking / tool_use
→ User tool_result
→ Assistant next reasoning / tool_use
→ User tool_result
→ ...

官方文档把会话上下文描述为:

  • 对话历史;
  • 已读取文件;
  • 命令输出;
  • CLAUDE.md;
  • auto memory;
  • skills;
  • 系统指令。17

对于工具调用,Messages API 使用一条 assistant 消息承载 tool_use,随后由一条 user 消息承载与 tool_use_id 对应的 tool_result。工具结果之所以使用 user role,并不表示它是用户手工输入,而是协议把“客户端环境返回给模型的数据”放在 user turn 中。

当一次 assistant turn 生成多个并行工具调用时,推荐将所有对应 tool_result 放在同一条 user 消息中,否则会降低模型后续继续并行调用工具的概率。18

2.3 工具定义#

工具定义至少包括:

  • 唯一名称;
  • 描述;
  • JSON Schema;
  • 可选的缓存或延迟加载标记。

模型依据工具定义生成 tool_use,Claude Code 再根据本地实现决定权限与执行方式。

仓库分析中的统一 Tool 接口还包含:

  • isConcurrencySafe(input)
  • isReadOnly(input)
  • isDestructive(input)
  • validateInput()
  • checkPermissions()
  • call()
  • UI 渲染函数。11

特别需要注意:

只读与并发安全不是同一个概念。

只读操作通常适合并行,但并不自动意味着并发安全;真正决定调度的应是工具对当前输入的并发安全声明。

为了减少上下文占用并维持缓存稳定,Claude Code 默认延迟加载 MCP 工具定义。官方文档说明,开始时可以只加载工具名;当模型通过 Tool Search 发现某个工具后,再以 tool_reference 形式把完整定义追加到历史中,从而不破坏前部缓存。1419

仓库分析还指出,内置工具与 MCP 工具会分区排序:内置工具保持稳定前缀,MCP 工具放在后缀,以降低 MCP 连接变化对缓存键的影响。这个精确排序属于实现分析,但其背后的目标与官方 prompt caching 规则一致。11

2.4 上下文压缩结果#

当上下文接近上限时,Claude Code 不会简单丢弃整个会话。官方公开行为是:

  1. 优先清理较旧的工具输出;
  2. 仍不够时,对对话历史生成结构化摘要;
  3. 重新注入需要长期保留的系统提示词、项目根 CLAUDE.md 与 auto memory;
  4. 某些按路径加载的规则或嵌套 CLAUDE.md,会在后续重新读取匹配文件时再次加载。1420

how-claude-code-works 对特定快照还原出更细的入口流水线,例如:

Tool Result Budget
→ History Snip
→ Microcompact
→ Context Collapse
→ Autocompact
→ Build API Request

这些阶段的共同目的,是在下一次网络请求发出前控制消息体积。315

这里必须严格区分:

问题本质典型处理
Prompt Too Long请求语义内容超过上下文能力裁剪、折叠、摘要、重新构造请求
Request Too LargeHTTP 请求字节数超限减少附件、消息或工具定义
网络超时连接或读取阶段失败退避重试、重新建连
SSE 流中断已开始响应但未完成处理部分流,视内容类型决定恢复
Max Output Tokens当前输出被截断提高上限或生成续写 turn

把 Prompt Too Long 当作普通网络错误反复重试,只会重复发送同一个过大的请求。

2.5 Base URL、认证和模型路由#

Claude Code 的“发到哪里”“如何认证”和“选择哪个模型”是三个独立维度。

直接 Anthropic API#

常见配置包括:

  • ANTHROPIC_API_KEY:作为 X-Api-Key
  • ANTHROPIC_AUTH_TOKEN:作为 Bearer Token;
  • ANTHROPIC_BASE_URL:覆盖 API Endpoint;
  • model / --model / /model:选择模型。217

Amazon Bedrock#

认证来自 AWS SDK 默认凭证链,可使用 Profile、SSO、环境变量、角色或 Bedrock API Key;模型名则是 Bedrock 的 inference profile 或 model ID。5

Google Vertex AI#

认证来自 Google Cloud ADC,模型路由还依赖 Project、Region 与可用模型版本。6

Microsoft Foundry#

可以使用 Foundry API Key 或 Microsoft Entra ID 默认凭证链,模型选择对应 Azure 中的 deployment name。22

企业 LLM Gateway#

ANTHROPIC_BASE_URL 可把请求转发到企业网关,但网关仍需要理解并转发:

  • Messages API 请求体;
  • streaming 响应;
  • anthropic-version
  • 必要的 beta headers;
  • 模型别名或自定义映射;
  • request/session/agent 追踪 Header。8

3. Claude API 流式响应处理#

3.1 SSE 事件序列#

Messages API 的流式响应不是“一个 JSON 被切成很多段”,而是由多个有名称的 SSE 事件组成。官方事件顺序为:

  1. message_start
  2. 对每个内容块:
    • content_block_start
    • 零个或多个 content_block_delta
    • content_block_stop
  3. 一个或多个 message_delta
  4. message_stop4

中间还可能出现:

  • ping
  • error
  • 新增的未知事件类型。

因此,客户端必须按事件类型和内容块 index 维护状态,而不能只把所有 data: 字段拼成字符串。

3.2 文本块增量#

文本内容通过:

{
"type": "content_block_delta",
"index": 0,
"delta": {
"type": "text_delta",
"text": "..."
}
}

持续到达。

CLI 可以即时渲染这些片段,改善首字延迟。但渲染层需要理解:

  • 当前文本只是部分结果;
  • 后面可能继续出现新的内容块;
  • 当前请求可能最终以 tool_use 而不是普通文本完成;
  • 流中错误可能发生在已经显示部分文本之后。

文本增量适合做“尽早展示”,不适合当作本轮已完成的事务提交信号。

3.3 Tool Use 块增量#

工具调用的参数以 input_json_delta 形式到达,其中 partial_json 是 JSON 字符串片段:

{
"type": "content_block_delta",
"index": 1,
"delta": {
"type": "input_json_delta",
"partial_json": "{\"file_path\":\"src/pay"
}
}

标准处理方式是:

  1. 按内容块 index 累积 partial_json
  2. 等待 content_block_stop
  3. 解析完整 JSON;
  4. 用工具 Schema 再次验证;
  5. 只有验证成功后,才进入权限与执行流水线。4

Claude API 还提供 fine-grained tool streaming,可减少服务端对工具参数的缓冲,从而更早返回大参数片段。但官方明确提醒,这种模式可能产生不完整或无效 JSON;若输出因 max_tokens 结束,工具参数甚至可能被截断在中间。23

因此:

“收到工具参数增量”不等于“工具可以执行”;完整内容块边界与 Schema 验证才是安全调度点。

3.4 流完成与流中错误#

完成一条内容块和完成整个消息是两个不同事件:

  • content_block_stop:某一个 text、thinking 或 tool_use block 完成;
  • message_stop:整个模型响应完成。

message_delta 会更新顶层字段,包括 stop reason 和累计 usage。一次典型工具调用响应的 stop reason 是 tool_use;普通答案可能是 end_turn;输出上限则可能是 max_tokens

流中还可能出现:

event: error
data: {"type":"error","error":{"type":"overloaded_error", ...}}

这类错误不是普通 HTTP 非 2xx 响应,而是已经建立 SSE 连接后由事件流传回的错误。4

3.5 HTTP 200 后为什么仍可能失败#

HTTP 200 只表示:

  • 请求已被接受;
  • 响应 Header 已返回;
  • SSE 流开始建立。

它不表示:

  • 模型已经完成生成;
  • 所有内容块已经闭合;
  • 工具 JSON 一定完整;
  • 服务端不会在后续过载;
  • 中间代理不会断开长连接。

Anthropic 官方错误文档明确说明,SSE 可以在初始 HTTP 200 之后出现错误,此时不能沿用普通 HTTP 状态码错误处理。24

这会形成四种不同结果:

结果是否有 HTTP 200是否有部分内容是否有 message_stop
正常完成
流中服务错误可能
网络中断可能
客户端取消是或否可能

因此,Claude Code 必须把 message_stop 或等价的完整消息状态当作“本轮网络响应完成”的边界,而不是仅依赖 HTTP 200。


4. 流式响应如何驱动 Agent Loop#

流式响应驱动 Agent Loop

4.1 QueryEngine 与查询循环#

how-claude-code-works 将 Claude Code 的主循环还原为双层结构:3

QueryEngine
└── submitMessage()
└── query()
├── 压缩与上下文构造
├── 调用模型
├── 消费流事件
├── 调度工具
├── 拼接 tool_result
└── 继续下一轮或终止

这个分层的价值在于区分两种生命周期:

维度QueryEnginequery()
管理对象一次用户交互与会话外壳当前模型—工具循环
关注点消息持久化、预算、最终结果、权限拒绝压缩、模型流、工具执行、恢复
状态范围会话级turn / loop 级
主要输出面向 CLI/SDK 的消息和最终 Result流事件、assistant、tool result 等中间消息

这不是 Anthropic 对外保证的类结构,而是仓库对特定构建的实现分析。但它非常适合解释为什么 Claude Code 可以在一个用户任务内多次调用模型。

4.2 异步生成器消费事件#

仓库分析中的 query()async function*。异步生成器在 Agent Loop 中有三个优势:

线性控制流#

恢复分支可以写成普通的:

更新状态
→ continue

而不必把每种情况拆成复杂回调。

自然背压#

消费方只有处理完当前 yield 的事件,才继续拉取下一事件。相比无界 EventEmitter,这更容易避免 UI、日志和工具结果队列失控。

取消传播#

生成器退出时可以清理底层流、取消 pending task 和释放资源。官方交互文档也把 Ctrl+C 定义为取消当前操作,把 Esc 定义为停止当前响应或工具调用。25

4.3 Tool Call 完成后的调度#

模型流里可能同时出现文本块和多个工具块。安全的调度顺序应是:

input_json_delta
→ 累积参数
→ content_block_stop
→ JSON 解析
→ Schema 验证
→ 查找工具
→ 权限检查
→ 入执行队列

仓库分析中的 StreamingToolExecutor 为每个工具维护:

queued → executing → completed → yielded

当一个 tool_use 块完整解析后,它就可以被加入队列,不必等待整个 assistant message 的 message_stop3

这一步的关键是“完整块”,不是“看到工具名称”或“收到一部分 JSON”。

4.4 模型继续输出时提前执行工具#

这是 Claude Code 网络层最有价值、也最需要准确表述的优化。

Messages API 只规定事件如何到达,不规定客户端何时执行工具。官方通用工具文档也明确表示,多个工具是并行还是串行,由客户端根据副作用和依赖自行决定。18

how-claude-code-works 对其分析快照的结论是:

当某个 tool_use block 已完整解析,StreamingToolExecutor 会立即尝试调度;模型可以继续输出后面的 token 或其他工具块。

时间线上表现为:

模型流: [ text ][ tool A 完成 ][ text ][ tool B 完成 ][ message_stop ]
工具 A: [----------执行----------]
工具 B: [---执行---]

而不是:

模型流: [----------------完整响应----------------]
工具 A: [执行]
工具 B: [执行]

这一优化将部分工具耗时覆盖在模型尾部生成时间里。但必须强调:

  • 它是仓库还原出的内部实现,不是 Claude API 的公共兼容性承诺;
  • 只有完整、验证通过且权限已允许的调用才能提前执行;
  • 对写操作和存在顺序依赖的调用,调度器仍需要独占或延迟;
  • fine-grained tool streaming 的原始 JSON 片段不能直接执行。

4.5 Tool Result 回填和下一轮请求#

工具执行后,Claude Code 把结果转换为 tool_result 内容块:

{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_xxx",
"content": "..."
}
]
}

然后发起下一次模型请求:

工具失败同样应该返回结构化结果,而不是让整个进程直接崩溃。仓库分析把这一原则概括为“错误是数据”:Schema 错误、权限拒绝、执行异常和 MCP 错误都会被封装为带错误标记的 tool_result,让模型决定是否修正参数、换工具或停止。11


5. Claude Code 的工具并发机制#

5.1 只读工具并行#

官方通用工具文档指出,彼此独立的只读操作通常适合并行,而有副作用、共享状态或顺序要求的工具更适合串行。API 本身不规定执行顺序。18

仓库分析显示,Claude Code 的实际门控字段是:

isConcurrencySafe(input)

而不是单纯的 isReadOnly(input)。典型可并发操作包括:

  • 读取不同文件;
  • Grep / Glob 搜索;
  • 无副作用的 MCP 查询;
  • 彼此独立的状态读取。

调度器会将连续出现的并发安全调用组成一批并行执行,同时保留模型给出的整体顺序。

5.2 写操作串行#

典型需要串行或独占的操作包括:

  • Edit / Write
  • 会修改仓库状态的 Bash 命令;
  • 创建分支、提交或 PR;
  • 会改变共享服务状态的 MCP 工具;
  • 对前一个工具结果存在依赖的调用。

原因并不仅是“写操作危险”,还包括:

  • 两个编辑可能基于同一旧文件版本;
  • mkdir 与后续写文件存在顺序关系;
  • git checkout 会改变后续所有命令的工作树视图;
  • PR 创建依赖 push 已经成功;
  • 外部服务可能不支持幂等重试。

仓库分析中的 fail-closed 默认值是:新工具默认视为不可并发、非只读,只有工具显式声明安全时才进入并行批次。11

5.3 兄弟工具取消#

这一节需要区分“通用协议”与“实现策略”。

官方工具协议要求:即使某个调用最终没有执行,也应为它返回一个 is_error: truetool_result,解释未执行原因。18

仓库分析进一步指出,在其观察到的 Claude Code 实现中,某些 Bash 工具失败后会触发 siblingAbortController,取消正在并行执行的兄弟工具。设计动机是 Bash 调用之间经常存在隐式依赖:

mkdir build
→ cd build
→ cmake ..

如果第一步失败,继续执行后两步没有意义。

但这个行为不能泛化为“任何工具失败都会取消所有并行工具”:

  • 独立 Read/Grep 失败通常不需要取消其他读取;
  • MCP 查询之间可能彼此独立;
  • 是否级联取消取决于工具类型和调度批次;
  • 这是版本相关内部策略,不是公开 API 合约。3

正确抽象应是:

并发批次需要显式的失败域,而不是一刀切地全取消或全继续。

5.4 流式窗口如何隐藏工具延迟#

假设模型完整响应耗时为 TmT_m,一批只读工具耗时为 TrT_r,后续串行写工具耗时为 TwT_w

传统等待完整响应后执行:

TserialTm+Tr+TwT_{\text{serial}} \approx T_m + T_r + T_w

若只读工具在模型尾部生成期间提前启动:

ToverlapTprefix+max(Tmodel-tail,Tr)+TwT_{\text{overlap}} \approx T_{\text{prefix}} + \max(T_{\text{model-tail}}, T_r) + T_w

可节省的时间近似为:

ΔTmin(Tmodel-tail,Tr)\Delta T \approx \min(T_{\text{model-tail}}, T_r)

这种优化最适合:

  • 读取文件;
  • 搜索仓库;
  • 查询 issue;
  • 无副作用的 MCP 数据获取。

不适合:

  • 尚未完整解析的参数;
  • 需要用户批准的危险命令;
  • 有强顺序依赖的写操作;
  • 可能被后续模型输出撤销或修正的副作用操作。

6. MCP 网络链路#

MCP 链路与企业网络控制

6.1 本地 stdio MCP#

stdio MCP Server 是 Claude Code 启动的本地子进程。协议消息通过标准输入和标准输出传输:

Claude Code
├── stdin ── JSON-RPC request ──> MCP Server
├── stdout <─ JSON-RPC response ── MCP Server
└── stderr <─ 日志与诊断信息 ───── MCP Server

特点:

  • 不需要监听端口;
  • 不暴露网络服务;
  • 权限继承自本地进程环境;
  • 进程崩溃即连接终止;
  • stdout 必须保持协议纯净,普通日志应写 stderr。

Claude Code 官方文档明确说明,stdio server 是本地进程,断开后不会自动重连。9

“不会自动重连”的实际含义是:Claude Code 不会把一个已退出的本地 Server 当成远程网络抖动反复重启。需要修正命令、依赖或配置,再显式重新连接。

6.2 Remote Streamable HTTP#

当前 MCP 标准推荐远程 Server 使用 Streamable HTTP。它通常在单一 MCP Endpoint 上承载 JSON-RPC 请求,并可以返回普通 JSON 或 SSE 流。10

从 Claude Code 视角,Remote Streamable HTTP 适合:

  • 企业 SaaS;
  • Issue Tracker;
  • 代码托管平台;
  • 监控系统;
  • 数据库网关;
  • 内部知识与权限服务。

相比 stdio,它增加了:

  • DNS / TCP / TLS;
  • HTTP 代理;
  • OAuth 或 Header 认证;
  • 服务端会话;
  • 超时与重连;
  • 负载均衡和多实例路由。

如果服务端启用 MCP Session,后续请求还需要携带对应 Session ID;服务端返回会话失效时,客户端需要重新初始化,而不是继续使用旧状态。

6.3 兼容性 SSE#

旧式 HTTP+SSE MCP 传输曾使用:

  • SSE 作为服务端到客户端通道;
  • 独立 HTTP POST 作为客户端到服务端通道。

当前 MCP SDK 文档将它标为 deprecated,只建议用于旧客户端兼容;新的远程 Server 应优先使用 Streamable HTTP。26

Claude Code 仍支持添加 SSE Server,是为了兼容已有生态,而不是表示 SSE 仍是新 MCP 服务的首选架构。

需要避免把两种 SSE 混淆:

SSE 用途含义
Claude Messages SSE模型服务向 Claude Code 推送生成事件
旧 MCP SSEMCP Server 向 MCP Client 推送 JSON-RPC 消息

它们都是 SSE,但协议、端点、状态机和错误语义完全不同。

6.4 初始化与能力协商#

MCP 建连后,不能立即随意调用工具。官方规范要求初始化阶段先完成:

  1. Client 发送 initialize
    • 支持的 protocol version;
    • client capabilities;
    • clientInfo;
  2. Server 返回:
    • 选定的 protocol version;
    • server capabilities;
    • serverInfo;
    • 可选 instructions;
  3. Client 发送 notifications/initialized
  4. 进入正常 Operation;
  5. 再调用 tools/listresources/listprompts/list 等。27

能力协商解决的是“双方能做什么”,不是单纯的握手形式。例如,Server 是否支持:

  • tools;
  • resources;
  • prompts;
  • logging;
  • list change notifications;
  • subscriptions。

Claude Code 还支持 MCP list_changed 通知。当 Server 的工具、Prompt 或 Resource 发生变化时,可以动态刷新能力,而不必重启整个会话。官方文档说明,刷新失败时,当前版本会保留上次成功发现的能力,等待后续刷新。9

6.5 OAuth 和请求头#

远程 HTTP MCP 可以使用 OAuth。Claude Code 官方文档覆盖:

  • 自动 OAuth 登录;
  • Token 安全存储与自动刷新;
  • 固定 callback port;
  • Dynamic Client Registration;
  • 预配置 client ID / secret;
  • OAuth metadata discovery;
  • scope pinning;
  • 无浏览器 SSH 环境下复制回调 URL。28

如果企业认证不是 OAuth,例如:

  • Kerberos;
  • 短期内部 Token;
  • 自定义 SSO;
  • 动态服务身份;

可以使用 headersHelper 在连接时生成 Header。官方当前行为是:

  • 每次新连接和重连都重新运行 helper;
  • 动态 Header 覆盖同名静态 Header;
  • 401/403 时可重新获取 Header、重连并重试一次;
  • project/local 级 helper 只有在接受工作区信任后才执行。29

这说明 MCP 认证本身也有生命周期:

获取凭证
→ 建连
→ 初始化
→ 调用工具
→ 401/403
→ 刷新 Header / OAuth
→ 重连
→ 重试

6.6 MCP 连接中断与重连#

Claude Code 官方文档给出了明确的远程 MCP 恢复策略:

  • HTTP 或 SSE 在会话中断开:
    • 最多重连 5 次;
    • 初始等待 1 秒;
    • 每次翻倍;
    • 重连期间 /mcp 显示 pending;
    • 失败后标记 failed,可手工重试;
  • stdio Server:
    • 不自动重连;
  • 初始连接的瞬时错误:
    • 最多重试 3 次;
  • 认证错误与 not found:
    • 不做盲重试,需要修改配置;
  • 成功建连后的 capability discovery:
    • 对瞬时网络和服务端错误最多重试 3 次。30

仓库分析中的 Pending / Connected / NeedsAuth / Failed / Disabled 状态与官方用户可见行为基本对应,但具体内部枚举仍应视为版本实现。11


7. 企业代理和工具出网#

企业环境里最容易混淆的三种代理如下:

代理什么主要作用
LLM GatewayClaude 模型请求模型路由、预算、审计、凭证集中化
Corporate Forward ProxyClaude Code 进程发出的 HTTP(S) 流量网络出口、认证、TLS Inspection、防火墙
Sandbox ProxyBash 与子进程的出网域名 allowlist、凭证注入、OS 级隔离

7.1 LLM Gateway#

LLM Gateway 位于模型应用协议层。它知道:

  • 模型名;
  • Messages 请求;
  • streaming;
  • usage;
  • provider;
  • API key;
  • token 与成本。

它适合解决模型治理,但不自动替代企业正向代理,也不自动控制子进程访问 github.comregistry.npmjs.org 或内网服务。

7.2 HTTP_PROXYHTTPS_PROXYNO_PROXY#

Claude Code 当前官方网络配置支持:

Terminal window
export HTTPS_PROXY=https://proxy.example.com:8080
export HTTP_PROXY=http://proxy.example.com:8080
export NO_PROXY="localhost,192.168.1.1,example.com,.example.com"

也支持 NO_PROXY="*" 绕过全部代理。31

工程上需要明确:

  • HTTPS_PROXY 常是最主要配置;
  • NO_PROXY 应包含本地服务、内网 MCP Endpoint 和不应穿过企业代理的地址;
  • 带用户名密码的代理 URL 需要避免落入脚本和日志;
  • NTLM、Kerberos 等高级认证更适合由企业代理助手或 Gateway 处理;
  • 环境变量必须在 Claude Code 启动时可见。

不要假设主进程配置代理后,所有 Shell 工具都会得到同一网络行为。是否继承、是否被沙箱改写、目标是否在 allowlist,仍取决于 Bash 执行路径。

7.3 自定义 CA 与 TLS Inspection#

企业 TLS Inspection 会由代理重新签发服务端证书。Claude Code 若不信任企业根 CA,会出现:

  • unknown issuer;
  • self-signed certificate;
  • certificate verification failed。

当前原生 Claude Code 默认信任 bundled Mozilla CA 与操作系统 CA Store;也可以通过:

Terminal window
export CLAUDE_CODE_CERT_STORE="bundled,system"
export NODE_EXTRA_CA_CERTS=/path/to/enterprise-ca.pem

显式加入企业 CA。31

这里不应通过:

Terminal window
NODE_TLS_REJECT_UNAUTHORIZED=0

关闭证书验证。那会把“信任指定企业 CA”变成“信任任何证书”,直接破坏 TLS 安全边界。

7.4 mTLS#

如果企业 Gateway 要求客户端证书,Claude Code 支持:

Terminal window
export CLAUDE_CODE_CLIENT_CERT=/path/to/client-cert.pem
export CLAUDE_CODE_CLIENT_KEY=/path/to/client-key.pem
export CLAUDE_CODE_CLIENT_KEY_PASSPHRASE="..."

mTLS 在普通服务端证书验证之外,再让服务端验证客户端身份。31

因此一次完整建连可能包含:

TCP
→ TLS Server Certificate 验证
→ Client Certificate 提交
→ 企业 Gateway 身份映射
→ HTTP Authentication
→ Messages API 请求

任意一层失败,都可能在用户侧只表现为“Unable to connect”。

7.5 沙箱 Domain Allowlist#

Bash 沙箱的网络访问通过外部代理控制。官方文档说明:

  • Bash 和所有子进程受相同 OS 级网络约束;
  • 第一次访问新域名可触发批准;
  • allowedDomains 控制允许访问的域名;
  • deniedDomains 可覆盖更宽的 allow wildcard;
  • allowManagedDomainsOnly 可阻止开发者扩大管理员策略;
  • 内置 WebFetch 的权限规则与 Bash sandbox 是不同路径。12

示意配置:

{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": [
"github.com",
"api.github.com",
"registry.npmjs.org"
],
"deniedDomains": [
"metadata.internal"
]
}
}
}

需要特别注意:

  • 允许 github.com 不一定自动允许 api.github.com
  • wildcard 范围过大会扩大数据外泄面;
  • 沙箱内置代理默认不解密 TLS,因此能按域名控制,但不能检查加密内容;
  • 若启用凭证 masking 与注入,则可能需要显式启用 TLS termination,由代理完成安全替换。12

7.6 Shell 子进程的网络权限#

Bash 子进程最终有效权限由多层共同决定:

企业防火墙
∩ Corporate Proxy
∩ NO_PROXY
∩ Sandbox allowedDomains
∩ deniedDomains
∩ 文件系统权限
∩ 凭证可见性
∩ Claude Code permission rules

例如,gh pr create 成功需要同时满足:

  1. Bash 工具被允许执行;
  2. 命令可访问当前仓库和 Git 配置;
  3. api.github.com 在沙箱网络允许范围内;
  4. GitHub Token 对子进程可见,或由 sandbox credential masking 安全注入;
  5. 企业代理信任 GitHub TLS;
  6. GitHub API 权限足以创建 PR。

任何一项失败,都可能表现为工具错误。故障定位不能只看“Claude Code 能否连模型”。


8. Claude Code 的故障恢复路径#

8.1 模型请求失败#

模型请求在收到响应 Header 前失败时,可按 HTTP 与 SDK 错误类型处理。

Anthropic 官方 SDK 默认会对以下瞬时错误自动重试两次,并使用短指数退避:

  • connection error;
  • HTTP 408;
  • HTTP 409;
  • HTTP 429;
  • HTTP 5xx;
  • 服务端明确要求重试的情况。2432

重试时应记录:

  • request ID;
  • provider;
  • model;
  • attempt;
  • error type;
  • retry-after;
  • 是否经过 Gateway;
  • connect / TLS / first-byte 时间。

以下错误不应盲重试:

  • 400 参数错误;
  • 401 无效认证;
  • 403 权限不足;
  • 413 请求过大;
  • 模型在当前 provider 不存在;
  • mTLS 证书错误。

8.2 SSE 流中断#

SSE 中断发生时,模型可能已经输出:

  • 部分文本;
  • 完整文本块;
  • thinking 块;
  • 半截工具参数;
  • 已完整的一个工具调用;
  • 多个工具调用中的一部分。

官方流恢复建议指出:

  • 文本块可以把已有部分作为上下文,构造 continuation request;
  • tool_use 与 extended thinking 不能安全地做通用“半块续接”;
  • 应从最近完整文本边界恢复,而不是假设半截工具 JSON可继续。4

Claude Code 层还需要检查:

  1. 是否已经执行过某个完整 tool call;
  2. 是否已经把 tool result 写入本地会话;
  3. 重试会不会再次触发副作用;
  4. 前端已经展示的文本是否会重复;
  5. 当前请求是否有稳定的最终 assistant message。

仓库分析提到“可恢复错误扣留”:某些错误先保留在内部,不立刻向上层发射,只有恢复失败才暴露给 UI。这个机制适合避免前端看到“错误—恢复—继续”的噪声,但属于版本相关内部实现。3

8.3 Prompt Too Long 与网络错误的区别#

二者的判定应尽量靠错误类型,而不是用户感觉“卡住了”。

Prompt Too Long#

特征:

  • 请求已到达服务端;
  • 输入语义长度超限;
  • 同样请求重试仍会失败;
  • 正确动作是压缩、裁剪或改变请求结构。

仓库分析中的恢复顺序是:

尝试提交已有 Context Collapse
→ 反应式全量压缩
→ 重新构造请求
→ 仍失败才返回错误

网络错误#

特征:

  • DNS、TCP、TLS、代理或连接读取失败;
  • 原请求本身可能合法;
  • 可能通过重新建连或退避恢复;
  • 不应自动改变上下文语义。

把网络错误错误地归类为 Prompt Too Long,会无谓损失上下文;把 Prompt Too Long 当网络错误重试,则会形成重复失败循环。

8.4 MCP 连接失败#

MCP 故障要先区分阶段:

阶段典型故障处理
启动stdio command 不存在修改本地配置,不自动重试
建连DNS / refused / timeout / 5xxHTTP/SSE 瞬时重试
认证401/403、OAuth scope 不足刷新凭证或重新授权
初始化protocol version 不兼容更新 Client/Server
能力发现tools/list 暂时失败短退避重试,保留旧能力
运行中Session 过期或流断开重连并重新初始化
调用工具业务错误返回 tool_result(is_error=true)

如果 GitHub MCP 断开,Claude Code 不应该假装“GitHub 工具不存在”。当前官方行为在启用 Tool Search 时会把连接失败信息传给 Claude,使模型可以明确告诉用户能力不可用或尝试替代路径。30

8.5 工具执行失败#

工具失败分为四类:

  1. 输入错误:Schema 或业务验证失败;
  2. 权限错误:规则拒绝、用户拒绝或工作区不可信;
  3. 执行错误:文件不存在、命令非零退出、网络调用失败;
  4. 副作用不确定:远程服务可能已执行,但结果响应丢失。

前三类通常可以作为错误 Tool Result 回填,让模型调整。第四类最危险,例如:

gh pr create 已把请求发给 GitHub
→ 本地连接超时
→ Claude Code 没拿到 PR URL

此时不能直接再次创建 PR。应先查询当前分支是否已有对应 PR,再决定是否补发。这属于副作用幂等问题,不能仅靠网络重试解决。

仓库分析还显示,大工具结果可能被截断或落盘,模型得到路径与摘要,再按需读取。这样可以防止一次工具输出把下一次模型请求挤爆。11

8.6 用户中断#

官方交互文档支持:

  • Ctrl+C:取消当前操作;
  • Esc:停止当前响应或工具调用,同时保留已经完成的工作;
  • Ctrl+X Ctrl+K:终止后台子 Agent。25

仓库分析中的异步生成器与 AbortController 解释了取消如何向下传播:

用户中断
→ QueryEngine 停止消费
→ query() 生成器退出
→ 模型流 abort
→ pending tool / child process 取消
→ 清理资源
→ 保留已完成消息与文件变更

但取消不是回滚:

  • 已经写入的文件不会自动还原;
  • 已经创建的 PR 不会自动删除;
  • 已经发出的外部请求可能仍在服务端执行;
  • 后台进程需要独立终止。

因此,用户中断语义应理解为“停止继续推进”,而不是“恢复到任务开始前”。


9. 完整案例时序#

从 Issue 到 Pull Request 的完整网络时序

下面用一个完整任务串起所有网络边界:

读取 GitHub Issue,分析代码,修改文件,执行测试,创建 Pull Request,并返回结果。

9.1 正常路径#

9.2 每一步的网络边界#

阶段网络或进程边界主要状态失败后能否直接重试
用户提交任务终端输入 → Claude CodeSession / Turn可以
Request 1CLI → 模型 ProviderModel request瞬时错误可以
SSE 返回Provider → CLIStream / content blocks取决于已完成内容
读取 IssueCLI → MCP → GitHubMCP Session / Tool Call只读,通常可以
搜索文件本地工具Tool Call通常可以
编辑文件本地文件系统副作用应检查当前文件版本
执行测试Bash → 子进程Process / Tool Call通常可重跑,但有成本
创建 PRMCP / gh → GitHub外部副作用不能盲重试
最终回答CLI UIDelivery可重新渲染,不应重跑任务

9.3 四个典型故障插入点#

故障 A:模型 Request 2 收到 529#

处理:

  1. SDK 按退避策略重试;
  2. 保留 Issue Tool Result;
  3. 不重新读取 Issue;
  4. 若重试失败,向用户暴露 Provider 错误和 request ID。

故障 B:模型已完整生成 Read,但后续 SSE 中断#

处理:

  1. 检查该 tool_use 是否已经完整解析;
  2. 若内部实现已经执行 Read,记录 tool call ID 与结果;
  3. 不再次执行同一调用;
  4. 使用已完成消息边界或重建当前 turn;
  5. 不尝试续接半截 tool JSON。

故障 C:GitHub MCP 会话中断#

处理:

  1. Remote HTTP/SSE 按官方策略退避重连;
  2. 重新初始化并发现能力;
  3. 对只读 get_issue 可安全重试;
  4. 若是 create_pull_request,先查询是否已经创建。

故障 D:测试进程无法访问依赖仓库#

排查顺序:

  1. Bash 命令是否在沙箱内;
  2. 目标域名是否在 allowedDomains
  3. 企业代理变量是否传给进程;
  4. NO_PROXY 是否误配置;
  5. 企业 CA 是否被信任;
  6. Token 是否被 deny、mask 或未继承;
  7. 是否需要用户批准 unsandboxed retry。

9.4 这条时序揭示了什么#

完整任务不是一个长请求,而是多个事务边界组成的轨迹:

模型请求
→ 工具决策
→ 权限与调度
→ 本地 / MCP 副作用
→ 结果回填
→ 新模型请求

每个边界都需要自己的:

  • ID;
  • 超时;
  • 取消语义;
  • 重试策略;
  • 日志;
  • 幂等判断;
  • 恢复状态。

将所有失败都归结为“Agent 出错”,会失去可诊断性;将所有恢复都归结为“再调用一次模型”,则会引入重复副作用。


结语:Claude Code 网络层的真正设计重点#

Claude Code 的网络层并不以某一种协议取胜。它的核心是把不同性质的通信统一进一个可持续推进的 Agent Loop:

  • Messages SSE 提供低延迟模型事件;
  • tool_use / tool_result 把模型决策与真实执行分开;
  • QueryEngine 与 query() 分离会话生命周期和当前循环;
  • StreamingToolExecutor 尝试重叠模型生成与安全工具执行;
  • isConcurrencySafe 区分并行读取与串行副作用;
  • MCP 把外部系统接入统一工具流水线;
  • Corporate Proxy、LLM Gateway 与 Bash Sandbox 分别治理不同网络面;
  • Prompt compaction 解决语义容量问题,网络重试解决传输问题;
  • 用户取消停止后续工作,但不假装回滚已经发生的副作用。

如果只在模型 API 外面包一层超时和重试,就还没有真正实现 Agent 网络层。生产级实现必须知道:当前断的是哪条链路、丢的是哪一段状态、已经发生了什么副作用,以及下一步能否安全重放。


参考资料#

Anthropic 与 Claude Code 官方资料#

MCP 官方规范#

how-claude-code-works 实现分析#

Footnotes#

  1. How Claude Code Works — README 与免责声明, Windy3f3f3f3f.

  2. Claude Code overview, Anthropic.

  3. 第 2 章:系统主循环, how-claude-code-works. 2 3 4 5 6

  4. Streaming messages, Anthropic. 2 3 4 5

  5. Claude Code on Amazon Bedrock, Anthropic. 2

  6. Claude Code on Google Vertex AI, Anthropic. 2

  7. Model configuration, Anthropic. 2

  8. LLM gateway configuration, Anthropic. 2

  9. Connect Claude Code to tools via MCP, Anthropic. 2 3

  10. MCP Transports, Model Context Protocol. 2

  11. 第 4 章:工具系统, how-claude-code-works. 2 3 4 5 6 7

  12. Configure the sandboxed Bash tool, Anthropic. 2 3

  13. How Claude Code uses prompt caching, Anthropic.

  14. How Claude Code works — Context window, Anthropic. 2 3

  15. 第 3 章:上下文工程, how-claude-code-works. 2

  16. Prompt caching, Anthropic.

  17. How Claude Code works, Anthropic.

  18. Parallel tool use, Anthropic. 2 3 4

  19. Tool use with prompt caching, Anthropic.

  20. Explore the context window, Anthropic.

  21. Environment variables, Anthropic.

  22. Claude Code on Microsoft Foundry, Anthropic.

  23. Fine-grained tool streaming, Anthropic.

  24. Claude API errors, Anthropic. 2

  25. Interactive mode and Keybindings, Anthropic. 2

  26. MCP TypeScript SDK — Server transports, Model Context Protocol.

  27. MCP Lifecycle, Model Context Protocol.

  28. Claude Code MCP — Authenticate with remote MCP servers, Anthropic.

  29. Claude Code MCP — Dynamic headers, Anthropic.

  30. Claude Code MCP — Automatic reconnection, Anthropic. 2

  31. Enterprise network configuration, Anthropic. 2 3

  32. TypeScript SDK — retries and request IDs, Anthropic.

Claude Code 网络层深度解析——模型流、MCP 与工具出网
https://jupiter-ws.cn/posts/agent-networking/02-claude-code-network-layer/
作者
Jupiter
发布于
2026-08-05
许可协议
CC BY-NC-SA 4.0