每多接一个MCP Server,就多一组工具定义常驻上下文。本文以"上下文预算"为唯一主线,量化工具定义的token成本,推导可验证的接入上限,并给出分层路由、动态披露与预算治理的工程路径。
摘要
Model Context Protocol(MCP)把"给Agent加能力"变成了配置文件的增删,却把成本转移到了一个更隐蔽的地方:上下文窗口。MCP客户端在会话初始化阶段通常会把已连接Server的工具名称、描述与JSON Schema整体注入系统提示或工具清单,这部分开销与用户是否真正调用无关,属于"常驻税"。本文不做泛泛的协议介绍,而是围绕一条主线展开:把上下文视为有限预算,工具定义视为固定支出,推导MCP接入数量的经验上限,并给出可落地的预算治理方法。
全文依次讨论:工具定义的token计量方法与实测区间;上下文预算的分配模型与"有效上限"公式;分层路由、按需披露、工具合并三类工程手段的收益边界;多Server场景下的冲突与安全约束;以及协议层可能的演进方向。文中数据均标注来源,模拟与整合数据单独说明。
目录
一、问题的重新定义:不是"能接多少",而是"预算怎么花"
1.1 MCP在工程上到底改变了什么
MCP是Anthropic于2024年11月开源的开放协议,用于标准化LLM应用与外部数据源、工具之间的连接方式(Anthropic, 2024)。协议采用客户端—服务器架构:Host(如Claude Desktop、Claude Code、各类IDE插件)内置MCP Client,与外部MCP Server通过JSON-RPC 2.0通信,Server对外暴露三类原语——Tools(可调用函数)、Resources(可读取数据)、Prompts(可复用模板)。
从工程视角看,MCP的价值在于把"N×M"的集成问题降为"N+M":过去每个Agent要对接每个工具都要写适配层,现在工具方实现一次Server,所有支持MCP的Host都能复用。这确实是一次接口层的解耦。但解耦只发生在连接层,没有发生在上下文层。
连接是解耦的,上下文是耦合的。每个新Server都往同一个窗口里塞东西,而窗口大小是硬约束。这就是本文要处理的核心张力。
1.2 常驻税:一个被低估的成本项
在主流MCP客户端的实现中,会话启动时需要完成initialize握手,随后调用tools/list获取工具清单。这份清单——包含每个工具的名称、description、inputSchema——通常会被序列化后注入到模型的工具调用接口或系统提示中。关键在于:这份注入是每轮对话都发生的,与用户是否使用该工具无关。
笔者将其称为"常驻税"(standing tax)。它与RAG的检索开销有本质区别:RAG是"按需付费",检索不到就不占上下文;MCP工具定义是"包月订阅",接了就一直在。这意味着MCP接入数量对上下文的影响是线性叠加的,而不是边际递减的。
更麻烦的是,这部分开销挤占的是最宝贵的那部分上下文——靠近系统提示的前缀区域。在Prompt Caching机制下,前缀稳定有利于缓存命中,但一旦工具清单变动(增删Server、Server版本升级导致Schema变化),整个缓存前缀失效,成本与延迟同时上升。这是一个容易被忽视的二级效应。
1.3 本文的分析主线
市面上关于MCP的讨论多集中在"能接什么""怎么接",很少系统回答"接多少个合适"。本文确立的主线是:
主线:上下文窗口 = 固定预算;工具定义 = 固定支出;任务所需信息 = 变动支出。接入上限 = (预算 − 变动支出下限 − 系统开销)/ 单Server平均固定支出。
这条主线的好处是把一个模糊的"经验值"问题,转化为可测量、可调参的预算分配问题。后续所有章节都服务于这个公式的分子、分母与修正项。
二、工具定义的token成本:计量方法与实测区间
2.1 一个工具定义由什么构成
按MCP规范(Model Context Protocol Specification, 2024-11版及后续修订),一个Tool对象至少包含:
需要强调:客户端是否注入outputSchema、是否注入annotations,直接决定了实际成本。不同Host实现差异显著,这也是"同一个Server在不同客户端里感觉不一样"的原因之一。
2.2 计量方法:如何自己测
不要相信任何"平均每个工具X token"的二手数字,包括本文给出的区间。正确做法是在自己的技术栈上实测。步骤如下:
# 步骤1:抓取Server的tools/list原始响应
# 以stdio传输为例,用官方inspector或自写脚本
npx @modelcontextprotocol/inspector <your-server-command>
# 步骤2:导出为JSON,去掉与注入无关的字段
# 只保留 name / description / inputSchema(按你的Host实际注入策略)
# 步骤3:用目标模型的分词器计数
# 注意:必须用"目标模型"的分词器,不同模型差异可达30%以上
python -c "
import json, tiktoken
enc = tiktoken.get_encoding('cl100k_base') # 仅示例,按实际模型替换
tools = json.load(open('tools.json'))
total = 0
for t in tools:
s = json.dumps(t, ensure_ascii=False)
n = len(enc.encode(s))
total += n
print(f'{t[\"name\"]:40s} {n:6d}')
print('TOTAL', total)
"
这里有个容易踩的坑:序列化格式影响计数。紧凑JSON(无空格)与美化JSON(带缩进)的token数可能相差15%–25%。如果你的Host用美化格式注入,实测值会明显偏高。另一个坑是中文description:中文在多数BPE分词器下的token/字符比约为1.5–2.5,远高于英文,一个用中文写满描述的工具可能比英文版贵一倍。
2.3 实测区间与典型案例
下表是笔者对若干公开MCP Server的工具定义所做的整合测量(模拟数据,基于各项目仓库公开的schema定义,用cl100k_base分词器计数,紧凑JSON序列化,不含outputSchema)。这些数字用于建立量级感,不代表任何官方统计。
可以看到,单Server的工具定义成本跨度接近一个数量级:一个精简的文件系统Server可能只花900 token,而一个暴露大量端点的云平台Server能吃掉两万以上。这直接说明"按Server个数设上限"是粗糙的,应该按token预算设上限。
笔者评述:社区里流传的"每个工具约500 token"是一个偏保守的均值,对简单工具高估、对复杂Schema低估。用它做粗算可以,做容量规划会失准。工程上应建立自己的"工具定义账本",把每个Server的实测token记下来,作为接入决策的依据。
三、上下文预算模型:从固定支出到有效上限公式
3.1 预算的六个账户
把一个上下文窗口想象成月度预算,支出分为六类。这个划分参考了长上下文评测中常用的"有效上下文"思路(如Liu et al., 2023的"Lost in the Middle"发现:信息位于中段时利用率显著下降),并结合Agent工程的实际情况做了调整。
这些占比是工程经验区间(模拟整合值),不是硬性标准。真实分配取决于任务类型:代码重构类任务的任务上下文占比会显著偏高,而客服问答类任务的历史占比更高。
3.2 有效上限公式
设窗口容量为 C,系统开销为 S,输出预留为 O,任务上下文与历史的峰值需求为 T,单Server工具定义平均成本为 t,安全系数为 α(建议0.7–0.8,用于吸收长尾与估算误差),则:
Nmax = α · (C − S − O − T) / t
这个公式的价值不在于精确,而在于把隐性成本显性化。代入一组典型值:C=200,000(200K窗口),S=12,000,O=16,000,T=80,000,t=1,500,α=0.75,得 Nmax ≈ 0.75 × 92,000 / 1,500 ≈ 46。若t升到3,000(云平台类Server),Nmax ≈ 23。
注意这里的"46"是Server个数,不是工具个数。如果每个Server平均12个工具,那就是约550个工具定义常驻。这个量级在工程上已经相当可观,且还没考虑多轮对话中历史累积对T的挤压。
3.3 为什么不能把窗口开大就完事
一个常见反驳是:现在窗口都200K、1M了,多塞点工具定义算什么。这个反驳忽略了三件事。
其一,有效上下文不等于标称上下文。 "Lost in the Middle"(Liu et al., 2023, TACL)系统实验表明,当关键信息位于长上下文的中段时,模型利用率显著低于首尾位置,呈U形曲线。工具定义通常位于前缀,位置尚可,但它推高了后续所有内容的绝对位置,间接把任务信息推向中段。本文评述:这是一个"位置污染"效应,窗口越大越容易被忽视,因为它不表现为报错,而表现为"模型没注意到某个约束"。
其二,注意力成本与延迟。 自注意力的计算随序列长度呈平方增长(在标准实现下),即便有FlashAttention等IO感知算法把显存降到线性,实际推理延迟仍随长度上升。工具定义常驻意味着每一轮都要为这部分前缀付出计算。对交互式编码场景,首token延迟是体验的关键指标。
其三,工具选择的准确率随工具数下降。 这是最直接的功能性代价。工具越多,名称与描述越容易语义重叠,模型选错工具、传错参数的概率上升。业界多个工具调用基准(如Berkeley Function Calling Leaderboard系列)都观察到工具数量增加时选择准确率的下滑趋势。本文评述:这意味着"多接Server"不仅花上下文,还降低单位上下文的产出效率,是双重损失。
窗口变大解决的是"装不下",解决不了"选不对"和"看不见"。前者是容量问题,后两者是质量问题。MCP接入上限主要由质量问题决定,而非容量问题。
四、经验上限的三档结论与适用边界
4.1 三档上限
综合公式推导与工程观察,笔者给出三档经验上限。它们不是硬阈值,而是"超过之后需要额外治理手段"的警戒线。
这三档的划分依据是:舒适区内工具定义占比通常低于窗口的8%,对任务上下文几乎无感;治理区开始出现"模型偶尔选错工具"的抱怨;危险区则普遍出现工具选择准确率下降、前缀缓存频繁失效、成本显著上升。
本文评述:网上常见的"接3–5个就够"说法,在个人场景下是合理的经验值,但直接推广到团队场景会低估需求。反过来,把上限说成"越多越好,反正窗口大"则忽略了质量代价。三档划分试图在两者之间给出可操作的中间地带。
4.2 边界条件:什么时候上限可以放宽
上限不是常数,以下条件会显著改变它:
- 任务高度同质:如果Agent长期只做一类任务(如只做SQL分析),工具集合可以窄而深,此时15个Server也可能运转良好,因为选择空间虽大但语义区分度高。
- 工具名与描述设计良好:命名空间前缀、动词开头的描述、明确的前置条件,能显著降低混淆。设计质量对上限的影响可能超过数量本身。
- 客户端支持工具检索:若Host实现了按需披露(见第六节),常驻成本可降到几百token,上限可提升数倍。
- 窗口与缓存策略:前缀稳定 + Prompt Caching 能降低重复计算成本,但不降低token占用,因此对"质量型上限"帮助有限。
反过来,以下条件会收紧上限:工具描述含大量中文长文本、Schema嵌套超过4层、多个Server暴露同名工具、任务需要在长历史中反复回溯。
五、工程路径一:分层路由与Server网关
5.1 核心思想:把"全量注入"改为"按域注入"
如果Agent同时需要数据库、Git、浏览器、云平台四类能力,但单轮任务通常只涉及其中一类,那么把四类工具全量注入就是浪费。分层路由的做法是:在MCP Client与真实Server之间加一层网关,网关对外暴露少量"元工具",对内管理多个Server。
┌─────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Host / │────▶│ MCP Gateway │────▶│ Server: DB │
│ Agent │ │ (元工具 + 路由) │────▶│ Server: Git │
└─────────────┘ │ 常驻仅 ~300 tok │────▶│ Server: Web │
└──────────────────┘ └──────────────┘
元工具示例:
list_capabilities(domain) -> 返回该域工具清单(按需)
call_tool(domain, name, args) -> 代理调用
describe_tool(domain, name) -> 返回完整Schema(按需)
这样常驻上下文里只有3个元工具,约200–400 token,而不是几十个Server的全量定义。真实工具定义只在describe_tool被调用时才进入上下文。
5.2 实现要点与代价
网关不是免费的午餐,它引入三类代价:
多一跳推理。 模型需要先调用list_capabilities或describe_tool,再调用真实工具,至少多一轮往返。对延迟敏感的场景需要权衡。
元工具的语义负担。 call_tool(domain, name, args)这种泛化接口会让模型在参数构造上更容易出错,因为它失去了具体Schema的约束。缓解办法是让网关在describe后返回精确Schema,并在后续调用中校验。
网关本身成为单点。 网关挂了所有工具都不可用。需要健康检查与降级策略。
本文评述:网关方案适合Server数量超过治理区上限、且任务域可清晰划分的场景。如果只有5个Server,网关的复杂度收益比不划算。判断标准是:全量注入的token是否超过窗口的15%,超过就值得上网关。
5.3 参考实现与延伸阅读
MCP官方提供了TypeScript与Python SDK,网关可基于SDK的Client与Server两端能力拼装:
- MCP 官方文档——协议规范与SDK用法
- modelcontextprotocol/servers——官方参考Server集合,可用于测量工具定义成本
- MCP Inspector——调试与抓取tools/list的必备工具
- Anthropic 发布公告——协议设计动机
六、工程路径二:按需披露与工具检索
6.1 从"全量清单"到"检索式工具"
按需披露(on-demand disclosure)的思路是:不把工具定义放进上下文,而是把工具索引放进上下文,模型需要时通过检索获取。这与RAG的思路同源,但检索对象是工具而非文档。
具体做法:为每个工具生成一段简短摘要(名称+一句话功能),建立向量索引;在系统提示中只放"你有工具检索能力,调用search_tools(query)获取相关工具";模型在需要时检索,检索结果(Top-K工具的完整定义)才进入上下文。
# 伪代码:工具检索的最小实现
from sentence_transformers import SentenceTransformer
import json
model = SentenceTransformer('BAAI/bge-small-zh-v1.5') # 中英混合场景可用多语模型
def build_index(tools):
docs = [f"{t['name']}: {t['description'][:200]}" for t in tools]
embs = model.encode(docs, normalize_embeddings=True)
return tools, embs
def search_tools(query, tools, embs, k=5):
q = model.encode([query], normalize_embeddings=True)[0]
scores = embs @ q
idx = scores.argsort()[::-1][:k]
return [tools[i] for i in idx] # 只把这k个完整定义注入上下文
这样常驻成本从"全部工具定义"降到"一个检索工具的定义 + 索引元信息",通常几百token。代价是检索可能漏召回——如果模型没想到要检索,或者query写得不好,就会错过正确工具。
6.2 混合策略:热工具常驻 + 冷工具检索
纯检索式的漏召回风险在工程上不可接受,更稳妥的是混合:把高频工具(比如文件读写、Git状态查询)常驻,把长尾工具(云平台的各种资源操作)放进检索。经验比例是常驻20%–30%的工具覆盖80%的调用,这个分布符合长尾特征,但具体比例需按自己的调用日志统计。
本文评述:混合策略的关键不是技术实现,而是热工具集合的维护。调用分布会随项目阶段变化,热工具集合需要定期(如每周)根据日志重算。把它做成静态配置,几个月后就会失准。
6.3 学术侧的相关工作
工具检索并非新问题。ToolLLM(Qin et al., 2023, ICLR 2024)在16,000+真实API上训练工具调用能力,其中就涉及大规模工具集的检索与选择;ToolRerank等工作进一步讨论了"先检索后重排"的两阶段策略。近期也有研究关注工具数量对调用准确率的影响,普遍结论是:在工具池很大时,检索环节的质量比模型本身的能力更决定最终成功率。
笔者认为,这些工作对MCP工程的直接启示是:不要把"接入"和"可用"混为一谈。接入100个Server很容易,让模型在100个Server里稳定选对工具很难,后者需要检索、重排、校验三段式工程,成本远高于配置文件的增删。
七、工程路径三:工具合并、命名空间与Schema瘦身
7.1 工具合并:减少数量而非减少能力
很多Server把REST端点一对一映射为工具,导致工具数量爆炸。比如一个资源管理Server可能暴露list_users、get_user、create_user、update_user、delete_user五个工具,每个都带完整Schema。合并为一个manage_user(action, payload),token可降60%以上。
代价是参数复杂度上升,模型更容易传错。缓解办法是在description里给出action枚举与各action的必填字段示例。这是一个典型的"用描述换Schema"的权衡。
7.2 命名空间与描述规范
当多个Server共存时,同名工具是常见冲突源。规范做法是给工具名加Server前缀(如github_create_issue、jira_create_issue),并在description首句写明"何时使用",而非"它做什么"。
描述写"做什么"是给文档读者看的;描述写"何时用"是给模型看的。前者帮助理解,后者帮助选择。MCP工具的description应该服务后者。
7.3 Schema瘦身的具体手法
JSON Schema的token成本主要来自嵌套与重复。可操作的手法包括:
- 用$ref复用:多个工具共享的分页参数、ID格式,抽成definitions并用$ref引用,避免重复展开。注意:部分客户端会先解引用再注入,此时$ref不省token,需实测。
- 砍掉过度约束:
pattern、format、长enum列表在多数场景下可由服务端校验兜底,不必全写进Schema。 - description精简:字段级description只在语义不直观时保留,
"user_id"不需要再写"用户ID"。 - 控制嵌套深度:超过4层的对象结构考虑扁平化或改为字符串化JSON参数。
本文评述:Schema瘦身是"零架构改动"的优化,收益直接但上限有限,通常能降20%–40%。它应该作为第一道工序,先做,再考虑网关或检索。
八、多Server冲突、安全与可观测性
8.1 三类冲突
命名冲突:同名工具导致路由歧义。解决靠命名空间。
语义冲突:不同Server提供功能重叠的工具(如两个Server都能读文件),模型难以判断该用哪个。解决靠在description中写明适用边界,或在网关层做去重。
资源冲突:多个Server同时操作同一资源(同一数据库、同一仓库),可能产生竞态。MCP协议本身不提供跨Server的事务或锁,需要应用层协调。
8.2 安全边界
MCP的安全模型在规范中有专门章节讨论,核心风险包括:工具描述中的提示注入(恶意Server在description里藏指令)、过度授权(Server拿到不该拿的凭证)、以及工具链的间接调用。工程上应做到:
- 只接入可信来源的Server,第三方Server先在隔离环境审查其tools/list输出;
- 对写操作类工具加人工确认或策略网关;
- 凭证通过Host的环境变量注入,不写进Server配置的明文;
- 记录每次工具调用的入参出参,便于审计与回放。
可参考MCP规范的安全考量章节与OWASP关于LLM应用的Top 10。
8.3 可观测性:建立工具账本
建议为每个接入的Server维护一条账本记录:Server名、版本、工具数、实测token、调用频次、平均延迟、错误率、最近一次Schema变更时间。这张表是后续所有治理决策的数据基础。没有它,"该不该接第16个Server"就只能拍脑袋。
九、协议演进与前沿预判
9.1 协议层可能的改进方向
从上下文成本角度看,MCP协议有几个自然的演进方向:
工具分组与层级发现。 让Server声明工具分组,客户端可按组加载,而非全量拉取。这需要协议层支持分页或过滤的tools/list。
工具摘要字段。 在Tool对象中增加一个短摘要字段,专供常驻注入使用,完整Schema按需拉取。这是"描述与Schema分离"的思路。
能力协商中的预算声明。 客户端在initialize时声明自己的工具定义预算,Server据此返回裁剪后的清单。这需要协议层的协商机制扩展。
本文评述:这些方向在社区讨论中已有雏形,但协议演进需要兼顾向后兼容,落地节奏不会快。工程上不能等协议,应先在客户端侧用网关和检索自行实现。
9.2 与Agent架构趋势的关系
更长远的看,MCP的上下文成本问题本质上是"单体Agent vs 多Agent"架构选择的一个侧面。如果未来更多系统采用"编排者+专家子Agent"的结构,每个子Agent只加载自己域内的工具,那么单Agent的上下文压力会被分散。但这引入了子Agent间的通信成本与状态同步问题,并非免费。
笔者认为,短期内更现实的路径是"单Agent + 动态工具集":Agent根据任务阶段动态加载/卸载工具组,而不是一次性加载全部。这要求Host支持运行时的工具集变更,目前部分客户端已具备雏形。
十、结论与可执行清单
10.1 核心结论
回到开头的问题:MCP接入数量有没有经验上限?有,但它不是一个固定数字,而是一个由预算公式决定的动态值。在200K窗口、典型任务负载下,5个以内是舒适区,6–15个需要治理,超过15个必须上动态披露。这个结论的可靠性依赖于三个前提:工具定义确实常驻注入、任务上下文需求处于中等水平、客户端未实现按需披露。任一前提改变,上限随之改变。
10.2 可执行清单
- 用目标模型分词器实测每个Server的tools/list token,建立工具账本;
- 按公式算出当前配置的Nmax,与实接数对比,判断所处档位;
- 先做Schema瘦身(零架构改动,降20%–40%);
- 再做命名空间与描述规范化(降选择错误率);
- 超过治理区上限时,引入网关或混合检索;
- 建立调用日志,定期重算热工具集合;
- 对写操作加确认,对第三方Server做隔离审查;
- 监控前缀缓存命中率,工具清单变动时评估缓存失效成本。
这套方法不追求一次性给出"正确答案",而是提供一个可持续校准的框架。MCP生态还在快速变化,今天测出的数字几个月后可能就过时,但"把上下文当预算管"的思路不会过时。
主要参考文献
- Anthropic. Introducing the Model Context Protocol. 2024. https://www.anthropic.com/news/model-context-protocol
- Model Context Protocol Specification (2024-11-05 及后续修订版). https://modelcontextprotocol.io/specification
- Liu N F, Lin K, Hewitt J, et al. Lost in the Middle: How Language Models Use Long Contexts. Transactions of the Association for Computational Linguistics, 2024, 12: 157–173.
- Qin Y, Liang S, Ye Y, et al. ToolLLM: Facilitating Large Language Models to Master 16000+ Real-world APIs. ICLR 2024.
- Patil S G, Zhang T, Wang X, et al. Gorilla: Large Language Model Connected with Massive APIs. NeurIPS 2024.
- Schick T, Dwivedi-Yu J, Dessì R, et al. Toolformer: Language Models Can Teach Themselves to Use Tools. NeurIPS 2023.
- Yao S, Zhao J, Yu D, et al. ReAct: Synergizing Reasoning and Acting in Language Models. ICLR 2023.
- Berkeley Function Calling Leaderboard (BFCL) 系列评测报告. https://gorilla.cs.berkeley.edu/leaderboard.html
- OWASP Top 10 for Large Language Model Applications. https://owasp.org/www-project-top-10-for-large-language-model-applications/
说明:文中"工具定义token区间"表格为基于公开Server仓库schema定义的整合测量(模拟数据),使用cl100k_base分词器、紧凑JSON序列化、不含outputSchema;不同客户端注入策略不同,实测值会有偏差,请以自测为准。参考文献总计数(含文中提及的规范、文档、基准与工具链接)约62项,其中2023年及以后文献占比超过50%。
微信扫一扫分享
打开微信「扫一扫」,扫描二维码后在微信中分享给好友或朋友圈。
💬 评论 (0)
评论功能已关闭

