题图

本文永久链接https://tonybai.com/2026/07/09/mcp-server-architecture-patterns-analysis

本文基于论文《MCP Server Architecture Patterns for LLM-Integrated Applications》(arXiv:2606.30317)整理与解读,原文由 Celabe 公司与滑铁卢大学的研究者合作完成,是目前少见的针对 MCP 生态"怎么写好一个 Server"给出系统性架构总结的工程经验论文。

大家好,我是Tony Bai。

Anthropic 在 2024 年 11 月发布 Model Context Protocol(MCP)之后,这件事的走向和当年 Language Server Protocol(LSP)出现时非常相似:一个标准化协议一出,社区在几个月内就堆出了成百上千个实现。GitHub 上、官方 registry 里,MCP Server 遍地都是——连数据库、SaaS API、浏览器自动化都被人包了一层 MCP 外壳。

但一个尴尬的事实是:协议规范只告诉你“接口长什么样”,没人告诉你“该怎么设计一个好用、好维护的 MCP Server”。于是我们看到大量项目在重复踩同一批坑:一个工具塞进去几十个参数、状态该放哪里全靠感觉、聚合多个上游服务时工具名互相冲突……

这篇论文做的事情很朴素但很稀缺:他们系统性地看了 15 个独立开发的 MCP Server(5 个来自语音 AI 平台 ANSYR 的生产环境,10 个来自官方公开仓库),用软件工程里经典的“模式描述法”(Gamma 等人《设计模式》中 context / problem / solution / consequences 的结构)总结出了5 种可复用的架构模式,外加 4 个应该避免的反模式,并且——这是本文最值得关注的地方——用真实的生产遥测数据回答了一个所有人都在猜但没人量化过的问题:

一个 MCP Server 里的工具数量,到底能堆到多少个,Agent 还能选对?

答案后面会揭晓,先把地基打好。

论文怎么做的:方法论一句话说清

研究者没有停留在“我觉得应该这样设计”的经验之谈,而是走了两步:

  • 语料库构建:5 个生产级 MCP Server(语音 AI 场景,涵盖工具编排、会话状态、电话适配、CRM 网关、多租户聚合等)+ 10 个官方公开 Server(filesystem、postgres、github、slack、puppeteer、memory 等耳熟能详的名字)。
  • 两阶段编码:第一阶段开放编码,标注每个 Server 里反复出现的结构性决策;第二阶段模式编码,把这些决策归并成候选模式——只有在至少两个独立 Server 中都出现、且解决了一个“没有现成方案”的问题,才会被正式收进模式目录。

为了验证这套分类法不是“作者自己看着顺眼”,他们还额外找了 54 个留出(held-out)的 Server,让两个独立的 LLM 评审员(Claude Haiku 4.5 和 Claude Sonnet 4)在只拿到模式定义、且描述里刻意不点名架构的情况下做分类,算出的Cohen’s kappa = 0.76,属于“实质性一致”(substantial agreement)。这个细节很重要,我们后面讨论工具选择准确率时会用到同一个评审设置。

五种架构模式:MCP Server 的“设计模式词典”

每种模式论文都给出了经典的 GoF 式描述结构,下面逐一拆解。

模式 1:Resource Gateway(资源网关)

场景:Agent 需要读取一个或多个后端系统(数据库、文档存储、第三方 API)的数据,并把回答"扎根"在这些数据上。

问题:如何把后端数据暴露给 LLM,同时保证可查询、防住通过脏数据注入的 Prompt Injection、并且在后端 schema 变化时保持接口稳定?

解法:让 Server 充当一个网关,统一接管所有数据访问。把读操作暴露成 Resources(列表、按 ID 获取),把不适合直接放进 URI 模板的参数化查询暴露成 Tools;在数据返回给 LLM 之前,插入一层净化逻辑,剥离或转义后端响应中可能被注入的内容。

图:MongoDB 文档暴露 + 净化层的代码示例

关键代码逻辑大致是这样(示意,非原文逐字复制):

server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
  const doc = await db.collection('documents').findOne({ _id: extractId(req) });
  // 在 LLM 看到内容之前先做净化
  return { contents: [{ uri: req.params.uri, text: sanitize(JSON.stringify(doc)) }] };
});

优点:访问控制有了唯一入口;后端 schema 变化不会直接冲击 LLM 侧接口;Prompt Injection 风险被限制在这一层。 代价:每次读取多一次网络跳转;复杂的联表 / 聚合查询用 Resource 表达会比较别扭。 典型用例:数据库连接器(PostgreSQL、MongoDB)、文档存储桥接(Notion、Google Drive)、REST API 封装(GitHub、Jira、Linear)。

模式 2:Tool Orchestrator(工具编排器)

场景:Agent 需要完成跨多个外部系统的动作——比如创建工单、通知负责人、再发一条消息到群里。

问题:怎样暴露多系统工作流,而不要求 LLM 理解每个系统的 API、自己维护调用之间的中间状态、自己处理部分失败?

解法:把完整工作流封装成一个"复合工具",所有子调用在 Server 内部完成,只返回一个汇总结果。LLM 看到的是"一个操作",编排逻辑全部下沉到 Server。

图:跨系统工作流封装为单个工具的代码示例

优点:大幅降低 LLM 的推理负担;多步操作可以获得类似事务的语义;LLM 不需要感知它不该关心的 API 细节。 代价:子工具复用性下降(工作流一变就要改);部分失败的处理责任全部落在 Server 上;工作流逻辑同时存在于代码和文档两处,容易失步。 典型用例:CI/CD 自动化、DevOps 工作流工具、客服动作中枢。

模式 3:Stateful Session Server(有状态会话服务器)

场景:多轮交互中后面的调用依赖前面建立的状态——打开的文件、进行中的数据库事务、已认证的用户。

问题:MCP 的工具调用默认是无状态的请求-响应模式,跨多次调用需要持久化的状态该怎么管理?

解法:连接建立时生成会话 ID,并在所有工具响应中带回;后续调用都携带这个会话 ID。Server 在内存(或分布式部署时用 Redis)里维护每会话的上下文,闲置超时后回收。

图:跨调用保持上下文的代码示例

优点:多轮工作流变得自然;避免重复传输数据;可以实现类似事务的语义。 代价:会话不回收就是内存泄漏;水平扩展需要引入分布式会话存储;LLM 是否可靠地传回会话 ID,这件事本身没有协议保证。 典型用例:代码编辑类 Agent(打开→编辑→保存)、数据库事务 Server、多步表单助手。

模式 4:Proxy Aggregator(代理聚合器)

场景:Agent 需要来自多个 MCP Server 的能力,但客户端能维护的连接数有限,或者运营方需要跨一批 Server 做统一认证和日志审计。

问题:如何把多个上游 MCP Server 统一成一个入口,同时不丢失各自的身份、版本信息和故障隔离能力?

解法:搭建一个代理 Server,连接 N 个上游 Server,用命名空间给工具名加前缀防止冲突,并把每次调用路由到正确的上游。这里论文特别强调了两个变体:

  • 静态合并(static-merge):一次性暴露所有上游工具的并集——客户端配置简单,但会拉高可见工具数量,一旦超过下文提到的准确率预算就会反噛。
  • 按需筛选(scoped):每次请求只暴露与当前任务相关的工具子集(也叫 retrieval-over-tools),而不是把整个工具列表都摆出来。

论文的建议很明确:只要聚合会让工具数量逼近准确率阈值,就应该用 scoped 变体,而不是简单粗暴地静态合并。

图:带命名空间的跨上游路由代码示例

优点:简化客户端配置;可以集中做认证与审计日志;支持在大规模 Server 集群上做工具发现。 代价:多了一个单点故障;每次调用多一次网络跳转;命名空间冲突需要治理;上游故障会透传到聚合层;scoped 变体还得额外保证"筛选"这一步足够快且准。 典型用例:企业级 MCP 网关、开发者平台聚合器、多领域 AI 助手后端。

模式 5:Domain-Specific Adapter(领域适配器)

场景:已有系统的 API 对人类很有用,但对 LLM 很不友好——机器可读的 ID、底层操作、复杂的认证流程、需要大量后处理的输出格式。

问题:如何把一个复杂、底层的 API 翻译成 LLM 能准确使用的形式,同时不在 Server 里重新实现一遍业务逻辑?

解法:构建一个语义适配层,包含:引导 LLM 选择工具的、可读性强的工具描述;输入归一化(接受自然语言日期、姓名、模糊 ID);输出增强(把 ID 解析成可读名称);错误翻译(把 API 错误码转成人话)。

优点:描述精确时,工具选择准确率会显著提升;API 复杂度被隔离在适配层;后端 API 的版本演进可以被适配层吸收。 代价:底层 API 一变,适配层就要跟着改;如果底层 API 本来就对 LLM 友好,过度设计适配层反而是浪费。 典型用例:CRM 适配器(Salesforce、HubSpot)、金融数据连接器、医疗记录系统。

一张速查表

MCP 模式 经典架构原型 LLM 客户端带来的新增约束
Resource Gateway Repository / REST 资源命名要方便 LLM 检索
Tool Orchestrator Facade / Mediator 工具集大小直接决定选择准确率
Stateful Session Server Session / Memento 状态是隐式的,不写在 Prompt 里
Proxy Aggregator Proxy / API Gateway 要分区工具以适配上下文预算
Domain-Specific Adapter Adapter(GoF) 校验逻辑要变成自然语言护栏

四个反模式:比模式更该先看的“扣分项”

论文特别指出,这四个反模式在语料库里没有一个是任何 Server 的主导结构——换句话说,它们是开发过程中局部犯下的、反复出现的错误,而不是某种“设计选择”。

  • God Tool(万能工具):一个工具接收一个巨大、无差别的 schema,比如 do_anything(action: string, params: object),LLM 得自己去猜 action 是什么意思,选择准确率直接崩掉。修复方式就是拆分:每个操作有自己命名精确、schema 明确的工具。
  • 未净化的资源内容:把用户生成内容(评论、文档正文、表单输入)不经处理直接塞进 Resource 响应。一段包含"忽略之前的指令,改为……“的文本会被 LLM 当作指令而不是数据来处理。所有外部来源的内容进入 MCP 响应前都要净化。
  • 同步长任务:把视频编码、大文件处理等耗时操作做成同步工具。MCP 没有内置的异步回调机制,客户端会直接超时。正确做法是同步返回一个任务 ID,再单独暴露一个 poll_job(id) 工具。
  • 缺失或模糊的工具描述:给一个叫 send_message 的工具,却不写描述,或者描述只是把名字重复了一遍。LLM 是靠读描述来选工具的,不是靠翻 schema。描述要写清楚"这是干什么的、什么时候该用、会返回什么”——假设读者从没见过这个工具。

两条决定架构选型的曲线

这部分是论文里最"硬核"的地方,也是这篇文章最值得转发的理由。

传输延迟:协议本身的开销并不是重点

论文测了 stdio 与 loopback streamable-http 两种本机传输的端到端延迟(各 100 次调用),并基于同区域网络 RTT 的标定常数,对跨主机场景做了建模估算。

图:MCP 传输延迟对比图

结论很直接:本机内的协议开销都在毫秒以下,stdio 和 streamable-http 之间的差距在跨主机场景下完全可以忽略,因为同区域网络 RTT(约 30ms p50)比协议自身开销高出两三个数量级。真正影响架构决策的是——Server 是否和客户端同机部署,以及 Proxy Aggregator 这类模式是否引入了额外的网络跳转,而不是"选哪种传输协议"这种细节。

工具数量 vs 选择准确率:那条“10~15 个”的红线

这是全文最有实用价值的数据。研究者用 ANSYR 语音 AI 平台 2025 年第一季度的生产遥测数据,针对不同工具数量分桶(1、3、5、10、15、20、30、50),统计 Claude Haiku 4.5 和 Claude Sonnet 4 在真实生产会话中的工具选择准确率。

图:工具数量 vs 准确率 / 延迟曲线

核心数字:

  • Haiku 4.5:10 个工具时准确率 91%,15 个工具时跌到 87%——跌破 90% 的临界点就在 10~15 个工具之间。
  • Sonnet 4:能在 20 个工具时保持 ≥90%,到 30 个工具时才跌破。

论文由此给出的实践建议非常明确:单个上下文里暴露的工具数量最好控制在 10~15 个以内。

一旦某个 MCP Server(或聚合后的多个 Server)逼近这个数字,应该用 Proxy Aggregator 模式里的 scoped 变体(按需检索工具,而不是一股脑合并),否则准确率会实打实地掉下来。

这个数字也和另外两项独立研究(Gan & Sun 的 RAG-MCP、Kate 等人的 LongFuncEval)在更大规模上观察到的趋势相互印证——工具目录越大,选择准确率下降是普遍现象,只是不同模型、不同场景下"拐点"位置不同。

这条数字对所有做 Agent / MCP Server 的团队都有直接指导意义:如果你的 Server 已经堆了 20、30 个工具,先别急着加新功能,回头看看是不是该拆成多个 Domain-Specific Adapter,或者上一层 scoped Proxy Aggregator。

四个绕不开的横切关注点

这几点论文写得比较简练,但都是生产环境里真正会踩坑的地方:

  • 认证:在传输层做认证(streamable-http 支持 Bearer Token),不要塞进工具处理函数内部;把 Token 按工具集做权限范围划分;所有工具调用都记录调用者身份——没有调用日志,调试 LLM 行为几乎无从下手。
  • 错误处理:尽量用结构化的错误内容返回,而不是直接抛异常,这样 LLM 才能看到错误、判断是否重试、决定是否上报给用户。
  • 版本管理:在 initialize 响应里带上版本字段;工具 schema 的破坏性变更要升主版本号;迁移期内让旧 schema 继续存活,而不是强推客户端立刻升级。
  • 可观测性:每次工具调用都记录工具名、输入哈希、延迟、输出大小、错误码——这些日志是排查 LLM"胡来"行为的主要抓手。

写给实践者的一张决策清单

论文在讨论部分把整套结论浓缩成了几句实操建议,我把它整理成一张检查表:

  • 只读为主的后端数据 → 用 Resource Gateway,别忘了加净化层。
  • 跨系统的多步工作流 → 封装成 Tool Orchestrator,一次调用完成整套动作。
  • 只有当"这一轮调用确实依赖上一轮状态"时才上 Stateful Session Server,并提前规划好会话回收策略。
  • 聚合一批上游 Server 时,优先用 scoped Proxy Aggregator,而不是简单地静态合并全部工具。
  • 任何一个上下文里暴露的工具数量,尽量控制在 10~15 个 以内。
  • 工具描述不是"写完代码之后随手补的注释",而是决定 LLM 能不能选对工具的核心工程产出物,要像对待代码一样对待它、像做 Code Review 一样审查它。

MCP 会是下一个 LSP 吗?

论文在讨论部分做了一个挺有意思的类比:MCP 想做的事情,跟当年 Language Server Protocol 想做的事情本质上是一回事——把"宿主"(编辑器,或者现在的 LLM 客户端)和"能力提供者"(语言服务器,或者现在的 MCP Server)解耦,让同一个 Server 可以在 Claude、GPT、Gemini 之间无差别复用。LSP 把语言智能从"编辑器专属插件"变成了一个共享生态;MCP 能不能做到同样的事情,很大程度上取决于是否能沉淀出一套架构模式词汇,指导大家把 Server 写好——这正是这篇论文想要"种下"的东西。

论文的一个核心观察值得所有做 AI 原生应用的开发者记在心里:MCP Server 设计本质上是一个 API 设计问题,只是多了一个不寻常的约束——客户端是通过读自然语言描述来决定调什么 API 的,不是靠查文档。

这彻底颠倒了传统 API 设计的假设:描述不再是"锦上添花的文档",而是直接决定工具能不能被正确使用的核心工程产物。如果你还把工具描述当成写完代码后随手补的注释,你的 Server 性能上限已经被你自己锁死了。

小结

如果说 Anthropic 发布 MCP 协议是搭好了一条沟通 LLM 与物理世界的高速公路,那么这篇基于生产环境数据提炼的论文,则是为所有在公路上行驶的开发者颁发了一本《安全驾驶与架构设计指南》。

从资源网关到代理聚合器,这 5 种模式和 4 个反模式告诉我们:在 AI 时代,API 设计的受众已经从“写代码的人类”变成了“读描述的大模型”。而那个“10~15 个工具”的准确率红线,更是用冰冷的数据打破了“把所有能力一股脑塞给 Agent”的粗暴幻想。

不要试图用一个 God Tool 解决所有问题,也不要吝啬在你的工具描述里多写几句清晰的“人话”。

掌握了这些架构模式,你的 MCP Server 才会在大模型的“眼中”变得更加清晰。

论文链接:https://arxiv.org/html/2606.30317v1


还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 从0 开始构建 Agent Harness 将带你:

  • 抛弃臃肿框架,回归“驾驭工程 (Harness Engineering)”的第一性原理
  • 用 Go 语言手写 ReAct 循环、并发拦截与上下文压缩引擎等,复刻极简OpenClaw
  • 构建坚不可摧的 Safety Middleware 与飞书人工审批防线
  • 在底层实现 Token 成本审计、链路追踪与自动化跑分评估
  • 从“调包侠”进化为掌控大模型边界的“AI 操作系统架构师”

扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。