上一篇 AI Edge Gallery 架构解析拆解过客户端怎么把 MCP 集成进端侧 AI 应用;本篇走到另一半——当你决定为团队自己的基础设施(内部 CI、工单系统、发布平台、内部 API)写一个 MCP Server 时,”接上协议”和”敢让全组用”之间隔着一系列设计决策。
这个决策的现实背景是生态体量与质量的巨大落差。官方 MCP Registry 已收录 20,920 台服务器(mcphq.ai 统计,2026-08),月度 SDK 下载量超过 9,700 万(Tech Insider 汇编,2026,转引 AIToolBriefing 统计);但公开扫描研究的结论并不好看:1,899 台开源服务器的学术审计发现 7.2% 含一般漏洞、5.5% 存在 MCP 特有的工具投毒(arXiv:2506.13538,2025-06),攻防评估口径下命令注入比例高达 43%(Equixly,Practical DevSecOps 2026 汇编);行业调研里 24–25% 的服务器完全没有鉴权(Zuplo State of MCP Report,调研期 2025-11 至 2025-12,样本约 100 名开发者)。生态里的多数服务器是 demo,而 demo 的写法搬到团队内网,就是明天的安全事故。
本文的定位是把散落在规范修订、SDK 文档、安全研究和真实事故里的要求收拢成一份设计指南:从协议原语讲到 SDK 选型、工具粒度、鉴权与安全边界,最后落到调试工作流和一份上线前清单。需要说明的是,本文数据来自官方规范、学术论文与公开一手报告(口径与样本量均逐一标注),本文自己的贡献是交叉验证并提炼出可落地的取舍建议。
Key Takeaways
- 生态体量与质量落差巨大:官方 Registry 已有 20,920 台服务器(2026-08),但学术审计显示 7.2% 含一般漏洞、5.5% 有工具投毒(1,899 台样本),24–25% 的服务器完全没有鉴权——"能跑起来"离"敢上线"很远。
- SDK 选型先看两个事实:官方 Python SDK 2.0(2026-06-30 GA)把内置的
FastMCP类重命名为MCPServer,旧 import 写法会直接失效;需要组合、代理、OAuth helper 时用独立 FastMCP 4.x(Prefect 维护),TypeScript 团队用官方 scoped 包。- 工具粒度最常见错误是把 REST 端点 1:1 镜像成工具——REST 是 resource-oriented,MCP 工具应该 intent-oriented;FastMCP 3.1 的 code mode 把 1,000 个工具折叠为 2 个、token 占用最高降 99%。
- 2025-11-25 规范把 token 校验变成资源服务器的强制义务:必须验证 token 的 audience 是自己,PRM 发现改经
WWW-Authenticate头;2026-07-28 大修订还启动了 12 个月的旧版本废弃窗口。- 工具的 description 字段是攻击面而非文档:MCPTox 基准显示主流 agent 对工具投毒的攻击成功率超 60%,Claude 3.7 Sonnet 拒绝率最高也仍有约 34% 中招——描述里只写功能,不写任何指令。
先把协议说清楚:三个原语、两种传输、一层 JSON-RPC
MCP 的协议本体并不复杂:JSON-RPC 2.0 消息流,加上三组语义原语和两种传输方式。写生产级 Server 的第一步是把这三组原语的”谁控制”分清楚,因为它们决定了你的 API 该怎么切。
Tools(工具)是模型控制(model-controlled)的原语:模型读工具的 name、description 和 input schema,自主决定何时调用。Resources(资源)是应用控制(application-controlled):由宿主应用决定把哪些 URI 的内容放进上下文,模型只是被喂数据的一方。Prompts(提示)是用户控制:用户显式选择某个 prompt 模板。这个划分直接回答了”什么该做成 tool、什么该做成 resource”——需要模型自主决策的动作做成 tool;确定性拉取、结构稳定的数据(配置、schema、文档片段)做成 resource,能省下模型每次调用 tool 的回合。
传输方式决定鉴权模型,这是后面安全一节的前置知识:
- stdio:Server 作为宿主的子进程启动,通过标准输入输出收发 JSON-RPC。没有网络暴露面,鉴权等于”宿主进程本身是谁”——个人本地工具的默认选择。
- Streamable HTTP:2025-03-26 规范引入,取代此前的 HTTP+SSE 双端点,单一
/mcp端点同时承载请求与可选的 SSE 流(2025-11-25 规范 changelog);服务端用Mcp-Session-Id头管理会话。远程多用户场景的必选项,也是 OAuth 2.1 鉴权要求生效的传输层。
整体架构用一张图表示:
一个容易忽略的细节:规范要求每个 Server 与恰好一个 Client 连接,多个 Server 就要在 Host 里起多个 Client——这解释了为什么团队内”一个 Server 通吃所有内部系统”的想法在架构上要走代理或组合模式(下文 SDK 选型会回来讲)。
SDK 选型:先接受”官方 SDK 与 FastMCP 已经是两个东西”
2026 年写 Python MCP Server 的第一件事是搞清楚两个同名项目的分野,这直接决定依赖关系和功能边界。
官方 SDK(modelcontextprotocol/python-sdk,MIT)是协议参考实现。它的 2.0 版本于 2026-06-30 GA,把会话中心的内部实现换成了 dispatcher/runner 管线,并且把内置的服务器类从 FastMCP 重命名为 MCPServer(AgenticWire 分析,2026-10-09)。这意味着大量旧教程开头那句 from mcp.server.fastmcp import FastMCP 在全新环境里会直接 ImportError——文档滞后期的坑,选型时先确认教程基于哪个版本。官方 SDK 的定位是最小依赖树、直接控制协议原语,适合协议教学、嵌入式场景或对依赖审查极严的团队。
独立 FastMCP(PrefectHQ/fastmcp,MIT)已由 Prefect 接管维护,3.0 于 2026-02 GA,截至 2026-10 发布到 4.0.11。它把官方 SDK 之上的生产力设施做成了产品:token verifier 与 OAuth proxy(对 GitHub、Google 等 provider 开箱即用)、服务组合(composition)与代理(proxy)、OpenAPIProvider 直接把既有 OpenAPI 规范转成工具集、in-process 测试客户端,以及 3.1 引入的 code mode(工具目录折叠进代码执行环境)。装饰器 API 与官方 SDK 同形,迁移成本低。
TypeScript 路线的格局更简单:官方 TS SDK 已拆分为 scoped 包(@modelcontextprotocol/server、@modelcontextprotocol/client),社区版 FastMCP TS(@prefecthq/fastmcp-ts)由同一团队维护但功能对齐度低于 Python 版。TypeScript 团队优先官方 scoped 包。
| 维度 | 官方 Python SDK 2.x | 独立 FastMCP 4.x | 官方 TS SDK(scoped) |
|---|---|---|---|
| 维护方 | Anthropic / MCP 项目 | Prefect | MCP 项目 |
| 当前版本 | 2.3.0(2026-10) | 4.0.11(2026-10-05) | scoped 包体系 |
| OAuth/鉴权 | 资源服务器侧,需自接授权服务器 | token verifier + OAuth proxy 开箱即用 | 需自接 |
| 组合/代理/OpenAPI 导入 | 无 | 内建 | 无 |
| in-process 测试客户端 | 无 | 内建 | 无 |
| 适合场景 | 协议级控制、最小依赖 | 生产 HTTP Server、快速迭代 | TypeScript 团队 |
(表格信息来源:官方仓库与 MCP.Directory 2026-05 对比、AgenticWire 2026-10-09。)
团队内部的选型经验法则:已经深度使用 FastAPI 的团队,先评估 FastAPI-MCP(把现有 FastAPI 应用一键转成 MCP Server,复用整套中间件与鉴权栈,MCP.Directory);要从零写独立 Server 并打算上远程 HTTP,FastMCP 的鉴权设施能省掉最费时的一块;只有协议教学或依赖审查极严的场景才选官方 SDK 裸写。一个务实提醒:把”协议兼容”当验收标准而不是把某个 SDK 当标准——2026-07-28 规范大修订落地后,SDK 的跟随速度会参差不齐(下文展开)。
工具粒度:把 REST 端点 1:1 镜像成工具是最常见的错误
如果只允许本文保留一个观点,是这一节:工具设计的正确单位是”意图”(intent),不是”端点”(resource)。
行业里的反面证据已经相当一致。Scalekit 在分析多用户 agent 的 MCP 架构时引用了开发者的典型总结:”REST APIs are resource-oriented… MCP should be intent-oriented”——围绕 agent 要完成的事设计工具,而不是围绕你的 API 表面(Scalekit,2026);Apigene 的工程综述同样记录了经验教训:”把 REST 端点 1:1 镜像进 MCP 工具的团队一致地报告问题”(Apigene,2026)。1:1 镜像的三重代价:
上下文成本随端点数线性增长。每个工具的 name、description、input schema 都要进入模型上下文。FastMCP 3.1 的 code mode 把 1,000 个工具的目录折叠为 2 个,token 占用最高降 99%(PrefectHQ/FastMCP 3.1,2026)——这个数字反过来说明:不做任何设计的工具目录,其 token 成本就是线性的。
模型的选择面越大,选错越多。工具数量上去之后,相似描述的工具会让模型的工具选择错误率明显上升——这是把 30 个端点全暴露出去的团队最常反馈的现象。工程上的对策是按意图聚合:一个
deploy_service工具(参数:服务名、环境、版本)内部串联”查构建状态 → 触发部署 → 轮询结果”三个 REST 调用,比三个独立工具加一段”请按顺序调用”的系统提示词可靠得多。聚合后暴露给模型的工具数控制在十几个以内,schema 每个参数都有明确的描述与类型。镜像会漏掉业务语义。REST 端点面向资源,但”给 agent 用”的操作往往横跨多个资源与状态机。照端点写工具,边界条件(幂等性、并发限制、部分失败)就只能靠模型从系统提示词里猜;按意图写工具,这些语义可以直接编码进工具的行为和返回结构里。
一个可操作的收敛路径:先用 code mode 或工具搜索(2025-11-25 规范引入的 progressive disclosure 机制)托底,同时按 agent 的高频任务聚类出 5–15 个意图级工具,再把低频端点收缩为少量通用查询工具。上下文成本和选择错误率会同时下降。
鉴权:2025-11-25 规范把 token 校验变成了你的义务
远程 HTTP Server 的鉴权在 MCP 里不是”可选项的工程加固”,而是规范条款。演进时间线如下:
对写 Server 的人,2025-11-25 修订(官方 changelog)有三处直接改代码的条款。Elicit 工程团队在迁移实录里把它们讲得最透(Elicit,2025-11):
- Token audience binding(强制):Server 必须验证收到的 token 是明确签发给自己的,拒绝只做”签名有效”校验的 token。安全含义是阻断 token 混用——没有 audience 校验时,一个 Server 泄露的 token 可以在所有信任同一授权服务器的 MCP Server 之间重放。FastMCP 在 OAuth proxy 里通过
resource参数实现;自研栈用 JWT 的aud声明校验。 - PRM 发现改经
WWW-Authenticate头:Protected Resource Metadata(RFC 9728)的发现路径从”依赖 401 状态码”改为依赖响应头,且 base URL 的路径部分必须保留(canonical path preservation)。实践上意味着 Server 的 401 响应要带完整的WWW-Authenticate: Bearer resource_metadata="https://..."头——框架默认行为往往不带,需要显式配。 - DCR(动态客户端注册)弱化:规范转向预注册 client ID 或 Client ID Metadata Document,DCR 被标记为 deprecated 路径。内部 Server 建议直接预注册固定 client,省掉一整类滥用面。
配套的现实数据是:24–25% 的已部署 MCP Server 没有任何鉴权(Zuplo,2025-11 至 2025-12 调研),50% 的开发者把安全/访问控制列为 MCP 的第一挑战(同上)。”内网所以不用鉴权”是这批数字背后的常见假设,但它混淆了边界与信任——下文的安全事故会说明这一点。
还有一个工程语义要澄清:按 2026 年规范,MCP Server 是 OAuth 资源服务器(resource server),不是授权服务器。它校验 token、发布 PRM,但不签发 token——签发要么接公司 SSO 的授权服务器,要么用 FastMCP 的 OAuth proxy 把 GitHub/Google 等 provider 当上游(Scalekit)。把这两层职责分开,鉴权架构就清楚了:认证走既有 IdP,Server 只负责”验证这个 token 是给我们的、且声明匹配请求”。
错误处理与安全边界:写给模型的错误信息也是一种 API
生产级 Server 和 demo 在错误处理上的差别,本质是”给谁看”:demo 的错误给人看,生产 Server 的错误有一半给模型看——模型读到错误后要决定重试、改参数还是放弃。这组设计没有规范条款可依,是纯工程判断,但有几个被反复验证的原则。
区分协议错误与工具错误。传输/会话层的故障走 JSON-RPC error(负数错误码,客户端会重连或重试);工具执行的业务失败(参数不合法、资源不存在、权限不足)应以 isError: true 的工具结果返回给模型——这样模型能在同一个会话里看到失败原因并自我修正,而不是收到一个无法恢复的协议异常。错误文案写给模型:说明”哪里错了、改成什么样能成功”,比如 environment 必须是 dev/staging/prod 之一;当前收到 'prod '(含尾部空格)。绝对不要把内部异常堆栈直接回传:一是模型消化不了,二是堆栈里的路径、表名、内部服务地址就是信息泄露。
输入校验全部前置到 schema 与框架层。FastMCP 用 Pydantic 从函数签名自动生成 schema 并校验,非法参数在到达业务代码前就被拒——这一层免费且防住绝大多数注入面。扫描研究里 43% 的命令注入(Equixly)、82% 的路径遍历风险(Endor Labs,2,614 个实现,2025)大多发生在”把工具参数直接拼进 shell 命令或文件路径”的代码里,校验前置加白名单参数化能同时消掉这两类。
工具的 description 字段是攻击面。MCPTox 基准对 20 个主流 agent 做了系统性工具投毒测试:把恶意指令藏进工具描述,攻击成功率(ASR)超 60%(GPT-4o-mini、o1-mini、DeepSeek-R1、Phi-4 等),最高达 72%(arXiv:2508.14925,2025-08);CSA Labs 的复测显示拒绝率最高的 Claude 3.7 Sonnet 仍有约 34% 的用例被执行了投毒指令(CSA Research Note,2026-07-01)。
两条例证说明这不只是学术威胁。其一是供应链污染:周下载 1,500+ 的第三方 Postmark MCP Server 被篡改为把外发邮件静默 BCC 给攻击者(MDPI Electronics,2026);其二是信任绑定缺陷:Cursor 的 MCPoison 漏洞(CVE-2025-54136,2025-08-05 披露)利用”审批绑定服务器名而非内容”的设计,让仓库协作者可以事后替换已批准的 MCP 命令(同上 CSA Research Note)。两者都不需要攻破任何密码学,只需要污染模型读到的元数据。
对自己的 Server 而言,防御写法有三条:description 只写功能语义、不写任何行为指令;不信任其他工具返回的内容再喂给下一个工具(跨服务器级联在受损场景下传染率 72.4%,Practical DevSecOps 汇编);工具集按读写分离——查询类工具与变更类工具分开命名,变更类在宿主侧配置显式审批。
公开扫描研究的风险量级汇总如下(注意:各研究的方法与样本不同,比例不可直接横向比较,仅用于感知风险量级):
调试与集成:Claude Code 下的日常开发工作流
Server 写出来只是开始,日常迭代需要一套趁手的调试循环。以 Claude Code 为宿主的推荐工作流分四层,从快到慢:
- in-process 测试(毫秒级)。FastMCP 提供 in-memory client,测试代码直接在进程内构造 client-server 对,不起子进程、不走网络,适合每次保存后跑的单元级验证。工具的业务逻辑应当与传输层解耦——把”查 CI 状态”的逻辑写成纯函数,工具层只做参数搬运,单测就落在纯函数上。
- MCP Inspector(分钟级)。官方 Inspector(
npx @modelcontextprotocol/inspector)提供交互式界面:连上 Server、列出 tools/resources、手工填参数调用、观察原始 JSON-RPC 报文。排查 schema 是否符合预期、错误码是否符合设计,Inspector 比 IDE 断点更接近真实客户端的行为。 - Claude Code 真机冒烟。
claude mcp add注册本地 Server 后,直接在会话里让 Claude 调用工具。这一层暴露的是”描述写得模型能不能正确理解”的问题——真实模型对工具描述的解读和你的假设经常不一致。写完 description 后让 Claude 复述”你会在什么场景调用这个工具”,是校验描述质量最便宜的方法。 - 日志与协议流隔离。stdio 模式下 stdout 被 JSON-RPC 占用,任何
print()都会污染协议流导致宿主解析失败——这是社区里最常见的”Server 明明能跑但客户端连不上”的原因。日志一律走 stderr(logging 默认配置即可),并保留完整请求日志供事后审计。
与 Claude Code 集成的更多工程实践(skills 组织、CLAUDE.md 约定、审批粒度配置)可以参考此前这篇 CLI 与 skills 实践;把 MCP Server 的工具清单和 API 文档一起维护,能显著降低”描述漂移”——描述与实际行为不一致是工具投毒之外另一类”模型被误导”的来源,虽然动机无辜得多。
结论与上线前清单
把全文收拢成一份可以在 review 时逐条打勾的清单:
- 原语划分:模型自主决策的动作做 tool,稳定数据拉取做 resource,模板做 prompt;不为”多一个入口”把数据塞进 tool。
- 工具粒度:按意图聚合而非 REST 端点镜像;暴露给模型的工具数控制在十几个量级;schema 每个参数有类型和描述。
- SDK 版本:确认 import 基于 2026-06-30 后的官方 SDK 2.x(
MCPServer)或独立 FastMCP 4.x;旧教程的from mcp.server.fastmcp import FastMCP已失效。 - 鉴权:远程 Server 完成 audience binding 校验;401 响应带
WWW-Authenticate与 PRM URL;优先预注册 client 而非 DCR。 - 传输:个人本地工具用 stdio;团队共享/多用户用 Streamable HTTP + OAuth 2.1;会话用
Mcp-Session-Id管理。 - 错误处理:业务失败以
isError: true返回可执行的修正建议;堆栈与内部细节不回传;所有参数校验前置到 schema 层。 - 输入面:工具参数不拼 shell、不拼路径;命令注入与路径遍历类缺陷用白名单参数化消除。
- 描述面:description 只写功能语义,零行为指令;描述与实现同仓同版本维护。
- 输出面:不把一个工具的返回直接喂给另一个工具当作指令解析;跨 Server 组合时保持同样的不信任原则。
- 权限面:读/写工具集分离,变更类工具在宿主侧配置显式审批;上线前用 MCP Inspector 过一遍全部工具的真实行为。
MCP Server 本质上是在给 agent 时代写一套新的内部 API:协议是 JSON-RPC 之上的薄层,难的从来不是协议,而是把工具粒度、鉴权边界和信任模型想清楚。这套取舍在 agent 基础设施选型的更大图景里也只是其中一格——如果对”模型侧能力与 harness 形态如何影响基础设施设计”感兴趣,可以看此前对 Codex 与 DeepSeek 两套 harness 的架构对比;工程化 AI 工具的质量把关,AI 代码评审 skill 的落地是同一思路的另一个切面。
常见问题
内部系统直接让 agent 调 API 不就行了,为什么还要套一层 MCP Server?
两层原因。一是接入标准化:MCP 把”工具发现、参数 schema、结果结构”收敛为统一协议,换宿主(Claude Code、IDE、自研 agent)不用重写集成。二是权限边界:MCP 的鉴权与审批模型(audience 校验、读写分离、宿主审批)给了内部 API 一层专门面向”调用方是模型”的防御,直接暴露 REST API 没有这层语义。58% 的 MCP Server 本质是包装既有 API(Zuplo 调研,2025-11 至 2025-12),说明这层包装是普遍价值而非过度设计。
Python 还是 TypeScript 写 MCP Server?
跟随团队既有栈。两端官方 SDK 都成熟,Python 侧多出 FastMCP 这个生产力层(组合、代理、OAuth proxy、in-process 测试);TypeScript 侧官方 scoped 包是最主流的选择,社区版 FastMCP TS 与 Python 版功能对齐度有限。生态数据上 TypeScript 是新增 Server 的第一大语言(官方 Registry 一周新增 1,074 台中 227 台为 TypeScript,mcphq.ai,2026-08),两条路线都有足够社区支撑。
stdio 和 Streamable HTTP 怎么选?
按使用方选。单机、个人、无并发:stdio,零部署零鉴权面。团队共享、多用户、需要集中权限控制:Streamable HTTP + OAuth 2.1,代价是要维护授权服务器集成与会话管理。拿不准时从 stdio 起步,HTTP 迁移的成本主要在鉴权层——按 2025-11-25 规范把 audience binding 写对,迁移基本只是换个传输配置。
怎么验证我的 MCP Server 足够安全?
分层验证。schema 层:Inspector 里对每个工具提交越界参数(空值、超长、特殊字符)确认被前置拒绝。行为层:对照上文第 6–9 条清单逐项检查。生态层:用 mcp-scan 等工具扫描已发布的服务器(学术审计即用此工具,arXiv:2506.13538);工具描述投毒类问题可参考 MCPTox 的测试用例设计自测宿主的抗性。AI 生成代码的测试有效性本身也值得用变异测试量化,方法见这篇 AI 单元测试有效性验证的姊妹篇思路。
参考
- MCP 规范 2025-11-25 changelog(官方,鉴权修订条款)
- modelcontextprotocol/python-sdk(官方 SDK 仓库)
- PrefectHQ/fastmcp(独立 FastMCP 仓库)
- Elicit: Building MCP servers — auth, the 2025-11-25 spec, and FastMCP(2025-11,迁移实录)
- arXiv:2506.13538 — MCP at First Glance(2025-06,1,899 台服务器审计)
- arXiv:2508.14925 — MCPTox(2025-08,工具投毒基准)
- CSA Labs: MCP Tool Poisoning and IDE Auto-Execution(2026-07-01)
- Practical DevSecOps: MCP Security Statistics 2026(多源汇编)
- Zuplo State of MCP Report(2025-11 至 2025-12 调研)
- Scalekit: Build vs Buy MCP Servers(2026)
- MCP.Directory: FastMCP vs FastAPI-MCP vs Python SDK(2026-05 更新)
- AgenticWire: FastMCP vs MCP Python SDK(2026-10-09)
- Tech Insider: MCP Hits 10,000+ Servers(2026,生态规模汇编与 2026-07-28 规范修订报道;SDK 下载数转引 AIToolBriefing)
- mcphq.ai: 1,074 new MCP servers, week of Aug 3, 2026(Registry 统计)
- MDPI Electronics 15(10):2214 — Beyond Tool Poisoning(2026,Postmark 事件与远程恶意服务器分析)