【免费下载链接】opencodex
Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code
在 opencodex 的 Cursor 桥接(Browser-under-Cursor)场景中,代理需要把 Codex / Responses 侧的工具注入到 Cursor 模型的可调用目录中。本文基于 devlog/_fin/260711_cursor_browser_bridge/004_fix_mcp_tools_channel.md 这一修复记录,完整还原"工具注入失败 → 误判通道不兼容 → 重新定位为编码形状错误 → 修复并线上验证"的全过程。读完你将掌握:Cursor AgentRunRequest 协议中mcp_tools(McpTools包装)与RequestContext.tools两条工具广告通道的区别、protobuf 序列化形状错误(wire type 7)如何让通道被误判废弃,以及如何通过隔离第二代理进行可复现的线上实验。
问题症状:模型"看不见"注入的工具
在 Cursor 客户端下,opencodex 需要把自身的客户端工具(如exec_command、read_file、apply_patch等 Responses 风格工具)注入给模型调用,以驱动浏览器等操作。修复前的表现非常明确:
- 无论注入时使用裸名称、
mcp_前缀名称、provider 标识符opencodex,还是通过mcp_instructions附带匹配的 serverName,模型都zero tool calls——不发起任何工具调用; - 模型直接报告工具不可用,并回退使用 Cursor 原生的 Shell 工具;
- 唯一的例外是:当注入发生在
AgentRunRequest.mcp_tools顶层通道(McpTools包装)时,工具才真正进入模型的可调用目录。
线上端到端验证(纯生产代码、无脚手架)确认了两个模型家族都能命中注入工具:
cursor/gpt-5.6-luna -> FINAL function_call run_probe {"note":"hi"} cursor/claude-4.5-sonnet -> FINAL function_call run_probe {"note":"hi"}也就是说,根因不是provider 身份、不是工具命名、不是mcp_instructions,而是:opencodex 此前只通过 native-exec 的requestContextArgs(RequestContext.tools)广告客户端工具,而 Cursor不会把该通道的工具注册进模型的可调用目录。
根因:为什么 RequestContext.tools 通道不够
opencodex 的 Cursor 适配器有两条工具广告路径:
RequestContext.tools(native-exec requestContextArgs):随 native exec 的requestContextArgs携带,用于声明代理侧可执行的原生工具(文件、Shell、MCP、网络等)。该通道对 Cursor 原生工具有效,但对 Responses 客户端工具注入无效——Cursor 不会将RequestContext.tools中的条目注册进模型的可调用目录。AgentRunRequest.mcp_tools(McpTools包装):AgentRunRequest的顶层字段(protobuf 中为 field 4McpTools包装),Cursor 会据此把注入工具注册为可调用。这是本次修复补上的通道。
修复后的策略是双通道并存:RequestContext.tools广告保留(作为第二通道),同时把同一份工具定义镜像进mcp_tools。从源码结构看,live-transport.ts中buildCursorToolDefinitions(cursorVisibleTools, activeRequest.toolChoice)(live-transport.ts)负责生成 native-exec 侧的工具定义,而请求编码器 protobuf-request.ts 复用同一套工具定义构造mcp_tools。
历史误判:Phase 45 为何错误废弃了这个通道
修复记录揭示了一个典型的排障陷阱——通道本身没有被协议拒绝,而是序列化形状错了。
此前 Phase 42 也尝试过把工具镜像进AgentRunRequest.mcp_tools,但线上 Cursor 解析器直接崩溃:
parse binary: illegal tag: field no 13 wire type 7wire type 7 在 protobuf 二进制编码中是非法 wire type(合法类型只有 0/1/2/3/4/5),这明确指向序列化缺陷:字段被以错误的形状赋值,编码出的二进制非法。但当时的 RCA 结论(见 devlog/_fin/350_cursor-provider-add/129_phase45-cursor-tool-wire-compat-live-rca.md)把现象误读为"顶层mcp_tools镜像对此客户端路径不兼容",于是做出了保守决策:不发送顶层mcp_tools,仅保留RequestContext.tools广告,并加了一条断言run.mcpTools toBeUndefined。
本次修复推翻了这一结论:这是错误形状的赋值,而非通道被拒绝。用正确的McpToolsSchema包装编码:
create(McpToolsSchema, { mcpTools: mcpToolDefs })即可产出合法的请求——在 gpt-5.6-luna 和 claude-4.5-sonnet 上均无解析崩溃。独立的佐证来自真实 Cursor 客户端确实读取该通道:agent-vibes 的 sol 搜索器 Poincare 解析AgentRunRequest.mcp_tools(Tier 2 事实)。
修复实现:正确填充 mcp_tools 通道
修复已合入 src/adapters/cursor/protobuf-request.ts 的buildPreparedCursorRunRequest(encodeCursorRunRequest为其返回裸字节的兼容包装,见 protobuf-request.ts)。核心逻辑位于 protobuf-request.ts:
// 提升到 mcp_tools spread 之外,让 token 估算读到与 wire 相同的一份过滤后定义 const mcpToolDefs = buildCursorToolDefinitions(visibleTools, request.toolChoice);随后在构造AgentRunRequest时(protobuf-request.ts):
// 将客户端(Responses)工具定义镜像进顶层 AgentRunRequest.mcp_tools 通道。 // 仅通过 native-exec requestContextArgs(RequestContext.tools)广告是不够的: // cursor 模型会把这些工具报告为不可用并回退到原生工具。 // 填充 mcp_tools 才能把它们注册进模型的可调用目录(线上验证: // gpt-5.6-luna 与 claude-4.5-sonnet 均实际调用了注入工具)。 // Phase 42 尝试过但用错形状赋值导致 Cursor 二进制解析器崩溃 // ("illegal tag");正确的 McpTools 包装是 wire 兼容的(两个模型家族均无解析崩溃)。 ...(mcpToolDefs.length > 0 || request.suppressDefaultCursorToolCatalog === true ? { mcpTools: create(McpToolsSchema, { mcpTools: mcpToolDefs }) } : {}),几个实现要点:
- 过滤后的同一份定义:
mcp_tools使用与RequestContext.tools及事件状态clientToolNames相同的cursorToolsForActivePrompt过滤后的可见集合。若直接使用原始request.tools,会让mcp_tools暴露事件状态不认识的工具——模型一旦调用就会被当作未知 Responses 工具拒绝。 - 空包装的语义:
mcpToolDefs.length === 0时,显式空McpTools包装(针对裸 API 调用者)会抑制 Cursor 默认原生目录;字段缺失则让已识别的 Codex 会话保留默认目录(protobuf-request.ts)。 - 工具定义构建:tool-definitions.ts 的
buildCursorToolDefinitions按toolChoice过滤(cursorToolAllowedByChoice),为每个工具产出McpToolDefinition:name/toolName使用线名(tool-naming.ts),providerIdentifier统一为OCX_RESPONSES_TOOL_PROVIDER(值opencodex-responses,tool-naming.ts),inputSchema由encodeCursorInputSchema编码为 protobufValue。 - 线名规则:Cursor 侧展示给模型的 MCP 显示名为
mcp_<providerIdentifier>_<toolName>(如mcp_opencodex-responses_exec_command),而广告的短名可能被模型原样调用,因此normalizeCursorWireName会把显示前缀折叠回广告线名,避免"工具未找到"(tool-naming.ts)。
排障方法学:隔离第二代理上的可复现实验
修复记录详细说明了如何在不动线上代理的前提下安全实验:
- 在一次性第二代理(端口 10199)上运行,使用隔离的
OPENCODEX_HOME/CODEX_HOME副本,实验后删除令牌; - 实验驱动的是真实
/v1/responses请求构建路径,而非手写 mock; - 通过环境变量门控(env-gated)的脚手架逐个验证假设,提交前全部移除脚手架;
- Tier-2 的 protobuf 事实由 sol cxc-search 子代理(Socrates、Poincare)提供:
mcp_tools= field 4McpTools包装;RequestContext.mcp_instructions= field 14;以及可用的opencode-cursor桥接的线形状。
这种"隔离环境 + 环境变量门控脚手架 + 真实请求路径"的做法,让开发者可以自由改变 wire 形状、验证假设而不影响用户正在运行的 10100 代理会话。
验证:单测断言更新 + 线上端到端
单元测试断言从 phase45 的run.mcpTools toBeUndefined反转为正向断言。在 tests/providers/cursor/cursor-blob.test.ts 中:
// 客户端 Responses 工具被镜像进顶层 AgentRunRequest.mcp_tools 载荷 // (McpTools 包装),使 cursor 模型将其注册为可调用。仅通过 native exec // RequestContext.tools 广告会让模型看不到工具。包装形状 wire 兼容 // (此前的崩溃是错误形状赋值,现已修正)。 expect(run?.mcpTools?.mcpTools.length).toBe(1); expect(run?.mcpTools?.mcpTools[0]?.toolName).toBe("mcp__fs__read_file");同时 tests/providers/cursor/cursor-native-exec.test.ts 继续断言RequestContext.tools通道仍携带mcp__fs__read_file——双通道均有测试覆盖。工具选择语义(buildCursorToolDefinitions对auto/required/allowedTools的过滤)由 tests/providers/cursor/cursor-tool-choice.test.ts 与 tests/providers/cursor/cursor-tool-definitions.test.ts 守护。
验证矩阵:
bunx tsc --noEmit # exit 0 bun test tests/cursor-blob.test.ts tests/cursor-request-builder.test.ts \ tests/cursor-tool-definitions.test.ts tests/cursor-native-exec.test.ts # 44 pass 线上端到端:gpt-5.6-luna 与 claude-4.5-sonnet 均调用注入工具(run_probe)残余风险与注意事项
- 覆盖范围:
mcp_tools通道仅在 gpt-5.6-luna 与 claude-4.5-sonnet 上线上验证。其他模型家族对(现已正确编码的)该通道未测试;包装是标准 protobuf,崩溃概率低,但发布前建议在 Cursor 全产品线做一次宽泛的线上冒烟。 - 运行中代理:用户的线上代理(10100)需要重启后才生效,运行中的会话不会自动获得修复。
- 返回路径未变:工具结果回传路径不变(既有客户端工具桥:
function_call浮出 -> Codex 执行 -> 结果作为历史在下一轮回放)。一次完整的多轮浏览器往返(node_repl-> 结果 -> 下一次调用)值得单独冒烟,但返回路径没有代码改动。 - 提交卫生:修复提交在
claudecode分支上,脚手架被完全移除(native-exec.ts/tool-definitions.ts恢复到干净基线;被卷入另一会话提交 7f80b053 的OCX_CURSOR_PROBE_*脚手架也在此移除)。
总结
AgentRunRequest.mcp_tools通道的修复是 opencodex Cursor 桥接中工具注入正确性的关键一环:RequestContext.tools只对 Cursor 原生工具有效,客户端(Responses)工具必须镜像进mcp_tools的McpTools包装才会进入模型可调用目录。而 Phase 45 的"通道不兼容"误判提醒我们,protobuf 的illegal tag / wire type错误首先指向编码形状缺陷,而非通道本身被拒绝——用正确 schema 包装后重新实验,才能得出可靠结论。
【免费下载链接】opencodex
Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code
相关推荐
OpenCodex Cursor 路由下 Browser 插件失效的根因分析与修复:打通 AgentRunRequest.mcp_tools 工具注册通道
OpenCodex Cursor 路由下 Browser 插件失效的根因分析与修复:打通 AgentRunRequest.mcp_tools 工具注册通道 导读
opencodex Cursor 路由下 Browser 插件不可用根因分析:从合成 Provider 广告到 AgentRunRequest.mcp_tools 通道修复
opencodex Cursor 路由下 Browser 插件不可用根因分析:从合成 Provider 广告到 AgentRunRequest.mcp_tool
opencodex Cursor 桥接 mcp_tools 工具通告通道加固实战:channel 一致性缺陷修复与回归验证
opencodex Cursor 桥接 mcp_tools 工具通告通道加固实战:channel 一致性缺陷修复与回归验证 本指南围绕 opencodex(Un
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考