实测 MCP 工具定义占用多少上下文
作者用官方 SDK 构建不同工具数量的测试服务器,并用 tiktoken 的 cl100k 编码统计工具定义的令牌量,再对照官方文件系统服务器。其测试中五十个工具约占 6,132 个令牌,但这一结果取决于定义内容和统计口径。
AI 深度解读
MCP 工具还没被调用,就已经占用上下文。作者用官方 SDK 搭建测试服务器,又检查了官方 filesystem server:50 个合成工具的定义占 6,132 tokens,16 个真实工具占 4,204 tokens。开销确实存在,但离「接一个服务器就挤爆上下文」还很远。
这组实验更有用的地方,是把单次窗口占用和多轮输入开销分开了。对日常 AI 编程来说,先弄清宿主实际发送哪些定义,再决定断开连接、精简描述还是拆分工具,比单纯数工具更靠谱。
50 个工具为什么可能比想象中便宜
作者测试了两组对象:一组是自己搭建的服务器,模拟文件读写、目录列表、网页搜索、数据库查询、GitHub issues 和聊天消息;另一组是未经修改的官方 filesystem server,提供 16 个工具。
下面是作者用 tiktoken 的 cl100k 分词方式统计紧凑 JSON 的结果:
tools-synthetic-1.json: 1 tools | compact 470 bytes = 101 tokens
tools-synthetic-10.json: 10 tools | compact 5626 bytes = 1208 tokens
tools-synthetic-50.json: 50 tools | compact 28226 bytes = 6132 tokens
tools-real-filesystem-server.json: 16 tools | compact 19369 bytes = 4204 tokens
要看最后一行:真实服务器只有 16 个工具,定义体积却已经接近 50 个合成工具。
作者给出的合成工具均值约为每个 121 至 123 tokens,真实工具则约为 263 tokens。因此,标题里的「50 个工具只需 6,132 tokens」不能直接拿来估算自己的环境。这个真实样本更接近每个工具 260 tokens,但它也只是一个服务器的测量结果。
工具之间的差异同样明显。edit_file 占 408 tokens,directory_tree 为 387,search_files 为 376,read_media_file 为 319,read_text_file 为 312;另一端的 copy_file 为 205,get_file_info 为 197,list_allowed_directories 为 154。
最重和最轻相差约 2.6 倍。逐个工具相加是 4,202 tokens,列表括号和逗号另占 2 tokens。
工具数量只能粗估开销,描述和 schema 的复杂度才决定实际重量。
工具没有执行,为什么也会占上下文
模型要先知道有哪些工具、各自做什么、参数怎么填,才能决定是否调用。工具定义就是提前交给模型的使用说明。
真实服务器的 list_directory 占 214 tokens。它不仅介绍目录列表功能,还说明条目会标记为 [FILE] 或 [DIR],需要大小信息时应使用 list_directory_with_sizes,需要递归视图时应使用 directory_tree,并交代允许访问的目录范围。
这些信息有助于模型选对工具,但都需要 tokens。除此之外,还有 title、inputSchema、outputSchema,以及重复出现的 JSON Schema draft 2020-12 标识。annotations 里还有 readOnlyHint、destructiveHint、idempotentHint、openWorldHint 四个标志。
没有参数也不等于免费。list_allowed_directories 不接收参数,名称、描述等内容仍然占了 154 tokens。
格式也会影响统计。同样的 16 个工具,紧凑 JSON 为 4,204 tokens,带缩进和换行的格式化 JSON 为 6,010 tokens,多出约 43%。不过,这个结果成立的前提是宿主确实把对应格式的文本发给模型,不能看到日志打印得漂亮,就认定请求也多花了这些 tokens。
作者还提出,描述缩短一半,大约可以减少该工具三分之一的开销。这个比例更适合作为优化线索:原文没有展示足够多的删改前后对照,无法保证所有工具都符合。
每轮重复发送,会不会把窗口越挤越小
这里要分清两个账本。
按作者讨论的完整定义随请求发送的方式,filesystem server 每次请求占 4,204 tokens。在 200k 上下文窗口里,约为 2.1%。对话进行了 20 轮,并不会因为这些定义重复发送,就在当前窗口里堆出 20 份副本。
但累计输入量会增加。20 次请求对应 84,080 tokens 的工具定义;三个同等规模的服务器,每次请求就是 12,612 tokens,约占 200k 窗口的 6.3%,还没有算对话、代码和工具返回内容。
窗口占用看单次请求,累计开销看发送次数,两者不能混算。
作者按每百万输入 tokens 1.50 美元举例,4,204 tokens 每次约花 0.006 美元,20 次约 0.13 美元。这只是原文选用的价格示例,文中没有交代对应模型,也没有纳入缓存计费等条件,不能当作通用报价。
作者认为,200k 或 1M 窗口接一两个服务器通常无须焦虑,接到四五个,或者任务很长时,才更值得管理。这个边界是经验判断,不是实验验证过的阈值。窗口多大、每个服务器多重、工具返回多少内容,都会改变结论。
更关键的是,作者只测了工具定义,没有测工具结果。搜索命中、大文件内容、数据库查询结果是另一笔开销,作者认为它们通常更大,但没有给出本次实验的对照数据。
我的判断
这篇最有价值的地方,是用可核对的数字缩小了争论范围。它证明了这个 filesystem server 的定义有多重,也展示了合成测试可能低估真实工具;它没有证明所有 MCP 宿主、模型和服务器都遵循同一种发送方式。
作者用的是 cl100k。原文称其他模型的分词结果通常可能上下浮动约 10% 至 20%,但没有展示跨模型测量。宿主也可能包装、转换或筛选定义,因此,客户端列出的 JSON 不一定等于最终送进模型的内容。
优化顺序上,断开不用的服务器很合理,因为它能直接移除整组定义。精简描述也值得做,但匹配规则、路径约束、返回格式往往关系到调用是否正确。删掉这些文字省下的 tokens,可能被一次错误调用和后续重试抵消;原文没有测量这种取舍。
拆分服务器则需要条件。把 50 个工具拆成两组 25 个,只有每次按需连接其中一组,才能减少当轮定义。两组都连着,收益就没有了。作者说拆分「没有额外构建成本」,这个判断偏乐观,普通团队还要处理配置和维护。
相比按服务器拆分,宿主若支持按需加载工具定义,也能更细致地控制输入。原文没有比较这些方案,所以它提供的是一套排查方向,还不是经过完整对照的最优配置。
能拿来做什么
- 先盘点 AI 编程环境里实际启用的服务器及发送方式。处理前端组件时,如果数据库、聊天等工具长期闲置,可以先断开,并确认宿主确实停止发送它们的定义。
- 维护 Node 编写的 MCP server 时,优先检查冗长描述、重复示例和相互重叠的说明。保留参数约束与关键语义,再观察精简后是否影响工具选择和调用成功率。
- 排查长任务的上下文消耗时,把工具定义、对话历史和工具结果分别统计。不要把累计发送的 84,080 tokens 当成当前窗口占用,也不要漏掉读取文件和搜索结果产生的内容。
- 只有工具能按任务分组启用时,再考虑拆分大型服务器。先验证日常工作是否经常只用其中一组,避免拆完以后仍然全部连接。