MCP 接入 Pi Agent 的背景与核心变革
Pi Agent 是一个运行在终端里的极简可扩展 AI Agent,其核心理念是保持核心小巧,通过扩展工具和配置适配不同工作流。在 Pi 0.99 版本之前,官方对 MCP(Model Context Protocol)的态度非常明确:不支持。团队成员曾在播客和文章中多次解释为何不喜欢 MCP,认为其存在诸多问题。然而,Pi 0.99 版本不仅引入了对 MCP 的支持,更将其直接加进到了 Pi 的核心。这并非简单的兼容性更新,而是重新设计了模型看到这些工具的方式。
“Pi 以前对 MCP 的态度非常明确,官网直接写着不支持MCP。但到了 Pi 0.99 MCP不但来了,而且直接加进到了 Pi 的核心。”
本次更新的重点不在于“终于支持 MCP”,而在于把连接方式和暴露方式分开来。传统的 MCP 实现往往将 Server 提供的所有工具定义(名称、描述、参数 Schema)全部放入模型上下文,导致 Token 消耗巨大。Pi 通过三种不同的 Exposure(暴露模式)——Direct、Deferred 和 Code Mode,来解决上下文膨胀、工具组合困难以及中间数据污染对话历史等问题。为了验证这些模式,博主将本地 Pi 更新到 0.99.2 版本,并安装了官方的 Filesystem MCP Server。该服务器提供 14个工具(包括读取/写入文件、列目录、搜索等),被限制在一个仅包含 projects.json 和 notes.txt 的临时演示目录中,以确保测试环境的纯净和安全。
Direct 模式:传统 MCP Harness 的直接映射
Direct 是最接近传统 MCP Harness 的工作方式。在这种模式下,Pi 在第一次模型调用中就会加入该 Server 全部的工具定义。以 Filesystem Server 为例,模型的上下文中会直接出现所有 14个工具的完整名称、说明和 JSON Schema。模型可以直接调用如 mcp__demo_files__read_text_file 这样的函数,无需搜索或进入特定的 Code Mode。
“Direct... Pi 在第一次模型调用中加入了全部的14个工具,每个工具都有名称、说明和 JSON Schema。”
这种模式的优势在于调用路径最短,最为直接。模型无需额外的步骤即可发现并使用工具。然而,其代价也非常明显:无论当前任务是否需要这些工具,完整的定义都会进入上下文。如果同时连接多个大型 MCP Server,工具定义的 Token 消耗会迅速膨胀,导致模型在开始工作前就占用大量上下文窗口。这是用户在传统 MCP 使用中感到头痛的主要原因之一,而 Direct 模式并未解决这一问题。
Deferred 模式:按需加载与上下文优化
Deferred(延迟)模式旨在解决启动时的上下文膨胀问题。在此模式下,Pi 在首轮请求中不会把 MCP 工具交给模型。相反,模型只能看到一个名为 tool_search 的工具以及系统提示词中的 Server Index(索引)。
“Deferred... Pi首轮不会把 14个MCP工具交给模型,模型只看到一个 tool_search。”
工作流程如下:首先,模型使用自然语言搜索需要的工具。tool_search 的参数仅包含查询文本和可选的数量上限,返回结果并非孤立的工具名列表,而是类似 Loaded N tools 的文本描述。此时,Pi 内部系统消息中会出现一个名为 toolsAdded 的内部字段,保存这一刻新增的完整工具定义(名称、说明、Schema)。注意:toolsAdded 不会以原样 JSON 发给模型,而是由 Pi 在 Provider 适配层转换为目标 API 的传输格式(如 OpenAI Responses 中的 additional_tools)。
在实测中,从 14个工具 中加载了 8个相关工具。Pi 将这次变化记录到 SystemMessage.toolsAdded,但当前轮次不能立即使用这些工具。模型在下一轮请求中才能真正看到这 8份 Schema,并执行如 read_multiple_files 的操作。Deferred 模式通过多一次模型的往返(搜索+加载),换取了更小的初始上下文。它没有改变工具调用本身,加载后的 MCP 工具调用和返回内容仍会写入 Agent 主循环维护的对话消息。
Code Mode:沙箱内的工具编排与组合能力
Code Mode 是 Pi 0.99.2 连接 MCP Server 的默认方式,也是本期重点介绍的模式。需要区分的是,Pi 有一个全局设置 codemode.mode: "only",但本文仅讨论 MCP 工具如何通过 Code Mode 暴露。在首轮请求中,主模型看不到独立的 MCP 工具列表,而是通过一个名为 codemode 的顶层工具访问所有能力。
“Code Mode... Pi原本的内置工具是否直接可见不属于这项MCP exposure控制的范围,主模型只通过一个叫 codemode 这样的工具访问。”
codode 的参数 Schema 非常简单,仅包含一个字符串字段 code。模型将一段 JavaScript 源码作为参数传入,Pi 的 Harness 侧会创建一个新的 QuickJS 运行环境执行该代码。关键点在于:QuickJS 不是另一个 Agent,它只是按代码执行的沙箱;语义判断和工具选择由主模型在生成代码时完成。
虽然 MCP 工具不作为顶层声明,但 codemode 的 description 中会提供沙箱辅助函数、MCP Namespace 以及预算内(约 3000个 Token)的工具声明。模型先阅读这些信息,理解任务,选择工具,再编写 JavaScript 调用流程。脚本中可以使用 searchTools(基于 BM25 的文本相关性排名,非 LLM 调用)和 describeTool。真正的读取、解析、筛选(如并发读两个文件、JSON 解析、按 Issues 排序)都在同一段 JavaScript 内部完成。
“关键并不只是少了几个工具定义,读取两个文件、解析筛选和排序都发生在了一次 Code Mode 调用内部。”
最终结果(如“cedar 11个 issue”)由脚本控制返回。Pi 收集 JavaScript 中的 text、image 及顶层 return 作为 Content,并自动附加执行元数据(如调用名称、耗时)到 details。MCP 工具的完整返回不会逐条写进主对话消息,从而避免了中间数据污染。这种模式将 CLI 式的组合能力(过滤、聚合)带入了 MCP,显著减少了 Agent Loop 的往返次数。
Hidden 模式与配置管理细节
除了上述三种主要模式,Pi 还提供了 Hidden(隐藏)选项。在此模式下,Server 保持连接但不向当前 Agent 暴露工具。这适合由其他扩展或控制逻辑进行管理的场景,实现了更细粒度的权限隔离。
MCP 的配置通过全局 ~/.pi/agent/mcp.json 或项目级 .pi/mcp.json 文件读取。Exposure 是 mcpServers 下每个 Server 自己的属性,可选值为 direct、deferred、codemode 和 hidden。用户也可以在 Pi 会话中输入 /mcp 命令交互式修改 Server 的 Exposure,配置会自动写回 JSON 文件。博主建议使用 pi mcp list --json 检查每个 Server 实际生效的模式,确保配置正确应用。
“Exposure不是整个 MCP 配置的一个全局开关,而是 mcpServers下面每个Server自己的属性。”
这种设计允许用户根据任务需求灵活切换。例如,对于小型 Server 且工具较少时,Direct 最简单;当工具很多但每次只用少数几个时,Deferred 更合适;而当任务需要组合多个工具、处理结构化结果且在意上下文成本时,Code Mode 是最佳选择。这种可配置的暴露方式标志着 Pi 对 MCP 支持的核心价值:将工具的发现、组合与执行边界从协议层剥离,交由 Harness 侧管理。
实际测试中的三个代表性问题与局限
在真实运行环境中,博主遇到了三个具有代表性的问题,揭示了当前实现的局限性:
- Namespace 命名陷阱:系统提示词中规范化的 Namespace(如
mcp__demo_files)与配置文件中的命名可能不一致。博主尝试使用配置中的demo-files导致找不到 Namespace。这说明按需发现虽然节省上下文,但命名和描述的准确性直接影响可靠性。 - 工具过滤的副作用:博主尝试使用
--tools codemode参数来限制主模型只能调用 Code Mode,结果发现该参数不仅关闭了主模型的直接工具访问,也一并过滤掉了供 Code Mode 调用的嵌套 MCP 工具。正确做法是保持正常配置,并在任务提示中明确要求只使用 MCP。 - 路径安全边界的现实挑战:在 macOS 上,
/tmp实际指向/private/tmp。Filesystem Server 授权的是规范路径,因此字面上的/tmp被判定为允许目录之外,导致调用失败。这直观地说明了 MCP Server 的文件边界不是提示词约束,而是实际的访问控制逻辑。
“这个错误反而提供了一个很直观的例子:它说明MCP Server的文件边界不是一句提示词,而是Server实际执行的访问控制。”
这些问题表明,Pi 的更新并未自动解决 MCP Server 本身的质量、安全边界或输出结构化问题。如果 Server 返回难以解析的大段文本,JavaScript 脚本也只能继续处理这种低质量数据。协议本身不会替你决定哪些操作应该被允许,高权限 Server 依然是高风险工具。
MCP 痛点解决程度与架构意义分析
回到最初的问题:Pi 的方案解决了 MCP 的哪些问题?
- 上下文膨胀:Direct 未解决;Deferred 按需加入顶层 Schema,显著减少初始占用;Code Mode 避免逐个注册工具,仅在 Description 中携带预算内信息。当工具数量庞大时,Code Mode 的优势最为明显。
- 工具组合:Direct 和 Deferred 仍受限于 Agent Loop,每次调用需往返;Code Mode 在 JavaScript 沙箱内完成循环、并发、条件判断和解析聚合,实现了类似 CLI 的组合能力。这是 Code Mode 最大的改进点。
- 模型往返次数:Deferred 增加了发现步骤,导致额外延迟;Code Mode 将多个内部调用合并为一次主模型工具调用,显著减少了往返次数。
- 中间结果污染对话历史:Direct 和 Deferred 会将每一步的中间数据写入主循环消息;Code Mode 允许脚本过滤后再返回少量内容,仅留下调用摘要和最终输出,明显减少了对话历史的污染。但需注意,调用的元数据(如耗时、状态)仍会保留在
details中。 - Server 输出质量与安全:这两点并未自动解决。Output quality 取决于 Server 端是否返回结构化数据;安全方面,Pi 提供了沙箱和 Exposure 选择,但高权限 MCP Server 依然是高风险工具。Pi 修正的是“MCP 工具进入 Agent 的方式”,而非修复 MCP 协议本身的安全缺陷。
“Pi 0.99最有价值的变化,倒不是说工具列表里多了MCP,而是把工具的暴露方式变成了可配置的选项。”
Pi 的 Code Mode 实际上是将 CLI(命令行界面)的组合能力引入了 MCP。过去,CLI 因模型可组合命令、过滤输出而优于远程函数调用;现在,Pi 让 MCP 也能实现这种组合。但这并不意味着 CLI 不再重要或每个 Server 都应采用 Code Mode。它意味着我们可以将“Server如何提供能力”与“Agent如何看见和调用能力”分开讨论。
结论
Pi Agent 0.99 对 MCP 的支持并非简单的协议兼容,而是一次暴露机制的重构。通过引入 Direct、Deferred 和 Code Mode 三种模式,Pi 针对性地解决了传统 MCP 实现中上下文膨胀、工具组合困难和对话历史污染等核心痛点。
其中,Code Mode 通过引入 JavaScript 沙箱和工具编排器,实现了类似 CLI 的复杂逻辑处理能力,显著降低了 Token 消耗并减少了模型往返次数。然而,这种架构并未自动解决 MCP Server 本身的质量问题、安全边界或输出结构化挑战。Pi 修正的是工具进入 Agent 的方式,而非 MCP 协议本身的缺陷。对于用户而言,应根据 Server 规模、工具使用频率及任务复杂度(是否需要组合逻辑)灵活选择 Exposure 模式。这一更新让 MCP 更接近“Agent 原生工具”,而非仅仅是一套远程函数调用接口,为未来更复杂的 Agent 工作流奠定了基础。