← [ BACK_TO_NOTES ]

MCP 工具的有界 I/O

解释 MCP 工具为什么必须对扫描时间、返回数量、文件大小和 stdout/stderr 建立显式预算,并通过分页与 truncation 把大数据面拆成可控的小响应。

#concept #growing #ai #mcp #architecture #ops

[!info] related notes

MCP 工具的有界 I/O

一句话定义

有界 I/O 是指每个 MCP 工具都必须明确自己最多扫描多久、最多读取多少、最多返回多少,并在达到预算后返回可继续的状态,而不是无限递归或把完整结果一次塞进 response。

核心原则:

任何一次 tools/call 都应有可预测的最坏成本。

为什么文件工具也会拖垮 Agent

一个看起来很普通的:

search_files("/home/user/projects", "foo")

如果没有边界,可能递归进入:

  • .git
  • node_modules
  • .cache
  • .pnpm-store
  • dist
  • build
  • .venv
  • 大型生成目录

最终扫描几十万文件。

同样,一个:

cat huge.log

可能产生几 MB 到几百 MB stdout。

这些都不是“文件系统功能更强”,而是把不可预测的数据面塞进单次 RPC。

四类预算

1. 时间预算

递归 search/tree 必须有 deadline,例如:

default: 15s
max:     30s

达到上限后返回:

{
  "truncated": true,
  "reason": "timeout"
}

而不是继续扫。

2. 扫描预算

例如设置:

max scanned entries = 50,000

这样即使目录结构异常,也存在明确上限。

3. 结果数量预算

例如:

search default = 100
search max     = 500

“扫描多少”和“返回多少”应分别限制;否则即使扫描很快,结果本身也可能淹没模型上下文。

4. 单次 payload 预算

当前 broad-agent 实践中:

stdout <= 64 KiB
stderr <= 64 KiB

文件读取也采用分段上限,而不是整文件无条件返回。

这些数字是当前部署基线,不是 MCP 协议要求。

默认跳过重目录

对代码 Agent,通常可以默认跳过:

.git
node_modules
.cache
.pnpm-store
.yarn
.next
.nuxt
.turbo
dist
build
coverage
.venv
venv
target
.gradle
.idea

这不是因为这些目录永远没有价值,而是因为它们不应成为“普通源代码搜索”的默认成本。

如果任务确实需要,应通过显式参数扩大范围,而不是默认全扫。

Pagination 是大结果的正确协议形状

文件读取:

read(offset, max_bytes)
→ data
→ next_offset
→ truncated

Job 日志:

job_output(offset, limit)
→ chunk
→ next_offset
→ eof

相关链接:

get_related_notes(limit)
→ first N
→ total_count
→ truncated

它们本质上都是同一个设计:

单次 response 只返回一个有界窗口,并显式告诉调用者是否还有数据。

为什么 truncation 必须是协议字段

错误做法:

返回前 500 条,但不告诉调用者还有更多

这样模型会把“不完整数据”误认为“完整事实”。

正确做法至少返回:

truncated
total
next_offset / cursor
reason
scanned_count
elapsed_ms

具体字段可因工具不同而变化,但必须能表达“不完整”。

有界 I/O 与 LLM context 的关系

MCP 不只是操作系统接口,它最终服务于模型。

一个 5 MB 的日志即使网络传输成功,也会带来:

  • 序列化成本;
  • Tunnel 传输成本;
  • hosted tool result 处理成本;
  • LLM 上下文成本;
  • 关键信息被大量噪声淹没。

所以 Bounded I/O 同时是:

  • reliability 策略;
  • performance 策略;
  • context engineering 策略。

设计检查

给新工具增加以下问题:

  1. 最坏情况下会扫描多少对象?
  2. 最长允许执行多久?
  3. 最多返回多少字节/条目?
  4. 达到上限时如何表示 truncation?
  5. 调用者如何继续读取?
  6. 是否有默认应排除的重路径?
  7. 返回值是否仍足够支持模型下一步决策?

只要其中一个答案是“无限”,这个工具就还不是一个成熟的 Agent Tool。

学习检查

  1. 为什么“限制返回 500 条”仍然不能替代“限制扫描 50,000 项”?
  2. 为什么 truncation 必须显式返回?
  3. Bounded I/O 为什么既是系统可靠性问题,也是上下文工程问题?
  4. 哪些情况下应该允许显式覆盖默认 skip 目录?
  5. Pagination 与 Job Manager 的日志读取为什么属于同一设计思想?
创建于 2026/10/1 更新于 2026/10/1
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本