讨论 AI Agent 工具的兴起如何冲击 MCP 架构的地位,以及如何让 MCP 在新的工具生态中保持价值。
MCP 是否已因为 Agent Skills 而消亡?
有时候感觉 AI 不仅在颠覆旧世界(如 SaaS),也在吞噬新世界中自己的孩子。不到一年前,Model Context Protocol(MCP)还是业界的"宠儿",各个厂商和平台都争相集成它。但仅仅 6 个月后,焦点又转移了——这次轮到了 Agent Skills,这个小兄弟似乎从 MCP 那里抢走了大量关注。
突然间,社交媒体到处都是"MCP 已死"的说法,就像之前的"SaaS 已死"一样。但这是社交媒体的典型特性——用极端措辞来激发情绪和制造传播效应。让我们先听听 MCP 和 Agent Skills 的父母 Anthropic 怎么说。当 Anthropic 在 2025 年末把 MCP 捐赠给 Linux 基金会并发布 Agent Skills 开放标准时,他们说道:
我们也看到了 skills 和 MCP 服务器是如何互补的。MCP 提供与外部软件和数据的安全连接,而 skills 提供有效使用这些工具的过程性知识。在 MCP 整合上有强劲投入的合作伙伴自然是一个很好的起点。—— Mahesh Murag,Anthropic 产品经理
以下是真实的行业经验,说明了这实际上是如何运作的:
如果你想深入了解 MCP 的利弊,这是一篇在 HackerNews 引发热议的好文章:
MCP is Dead; Long Live MCP!
我赞同作者的观点,即远程 HTTP MCP 服务器才是真正的游戏改变者,将成为组织和企业采用的关键支点,推动从"氛围编码"向"Agent 工程"的转变。
因此,内置 OAuth 支持是曾经加入的一个很好的特性,如果不是最好的话。这绝对是组织和企业适配最重要的事情之一,可以由上述文章中的以下例子很好地说明:
工程师离开了你的团队?撤销他们的 OAuth 令牌和对 MCP 服务器的访问权限;他们从一开始就从未拥有其他密钥和机密的访问权限。
这就是为什么我也写了一篇文章,演示了如何从零开始创建一个带有 OAuth 支持的 HTTP MCP 服务器,以便安全地启用 AI 对数据库的访问:
Turning Your Database Into an MCP Server With Auth
我的博文在 ZenStack 社区中获得了相当多的关注。鉴于 ZenStack 解决方案多么简洁,我预期会看到许多集成了 Auth 的 MCP 服务器被发布。
不幸的是,这从未发生过。直到以下 GitHub issue 被用户创建时,我才意识到原因所在:
[Feature Request] Optimized Schema Generation for MCP Servers
简而言之,即使用户试图加载 MCP 服务器提供的单个工具,上下文窗口也会膨胀到 400K,使其根本无法使用。这个"上下文膨胀"问题是 MCP 最受批评的问题之一,也是为什么人们转向 Skill 的原因。例如,这是官方 Playwright GitHub 对 Playwright CLI vs Playwright MCP 的看法:
现代编码 Agent 越来越倾向于将 CLI 工作流作为 SKILL 公开,而不是 MCP,因为 CLI 调用在令牌方面更高效:它们避免了将大型工具模式和冗长的无障碍树加载到模型上下文中,允许 Agent 通过简明的、专用的命令进行操作。
ZenStack 的方法实际上将这个问题放大到了最大程度。原因是 ZenStack MCP 服务器公开的工具是 ORM 的查询 API,这是 Prisma ORM 查询 API 的超集。它的优势之一是允许嵌套关系查询。这意味着你可以从单个函数调用中遍历整个数据库中的所有模型,就像这样:
const users = await db.user.findMany({ select: { id: true, name: true, posts: { // relation-level filter where: { tags: { some: { name: "typescript" } }, }, select: { id: true, title: true, tags: { // deep filter where: { name: "typescript" }, select: { name: true }, }, comments: { where: { body: { contains: "great" }, }, // switch to include here — we want all Comment columns include: { author: { select: { id: true, name: true }, }, }, }, }, }, },});
水能载舟,亦能覆舟。即使对于单个 MCP 服务器工具生成的 JSON 模式也会变得臃肿,包含了整个应用程序的模式。
一个简单的修复方法是限制嵌套关系遍历的深度以简化 JSON 模式。但我认为这更多是一个变通方案,而不是真正的解决方案:
它既不实用也不可扩展,因为它只能选择模型的有限部分,对大型项目来说不可行。
它失去了查询 API 的优势。原本可以通过单个查询完成的工作现在需要多个请求/响应周期,影响性能并导致更高的令牌使用。
软件开发世界的一个好处是,无论你遇到什么问题,大多数情况下你都不是第一个面对它的人。更好的是,人们可能会分享他们的问题和解决方案。Cloudflare 就带来了一个:
Code Mode: give agents an entire API in 1,000 tokens
仅从标题就能看出,这正是我需要的。😄 他们采用的解决方案是,与其将每个操作描述为单独的工具,不如让 LLM 直接编写代码,他们将其命名为 Code Mode。具体来说,整个 Cloudflare API 的 MCP 服务器只公开两个工具:search 和 execute。结果是,无论存在多少个 API 端点,足迹都保持固定。因此,他们成功地将使用的输入令牌数量减少了 99.9%,降低到大约 1k 个令牌。
让我们看看如何使用这个方法来解决我们的问题!
我们本可以使用与 Cloudflare 相同的方法来公开 search 和 execute 工具。但我们可以做得更好,因为 ZenStack 的情况有两个内在特征:
一个模型在技术上连接到整个数据库中的所有其他模型。如上所述,这是上下文膨胀问题的罪魁祸首。
LLM 已经相当熟悉如何编写查询 API,因为由于 Prisma,它在训练数据中遇到了无数的例子,来自 GitHub 和博客文章。
因此,它提供 3 个工具:
与其提供 search 工具,我们会提供一个 schema 工具,将整个模式发送给 LLM,让它对应用程序有一个完整的认识,以及一些简单的例子。虽然这个方法意味着工具的足迹不再是固定的,但整个模式文本文件的大小对大多数 LLM 来说是可以管理的。
execute 仅此而已。实际上,它甚至更简单,因为它只会运行固定数量的函数调用对应查询 API,如 findMany、createMany、updateMany 等,而不是任意代码。
这个工具用于 LLM 检查它组合的函数调用参数在 execute 之前是否有效。这有点像锦上添花,因为我相信 LLM 仍然可以从 execute 返回的错误信息中找出正确的参数。实际上,在 Claude 中使用 MCP 服务器并获得几次成功响应后,我才意识到它其实从未真正调用过 check。这是我问他为什么没有按提示调用 check 时得到的回应:
你说得对,这是一个合理的指正。gym:check 工具描述明确说:"首先使用 'check' 工具验证调用,然后执行它。"我完全跳过了它——这意味着我在运行查询时没有对其进行类型检查。我很幸运查询碰巧有效,但这不是正确的方法。check 步骤存在是为了在无效字段名、错误的参数形式或不支持的操作到达数据库之前捕获它们。
我不得不在 execute 的提示中添加一个 MUST 以确保它被调用。
You MUST use the "check" tool first to validate the query before calling this tool
添加这个 check 的原因是遵守软件工程原则"高内聚低耦合",这对人和 AI 都有好处。例如,execute 只运行有效的函数调用,所以它返回的任何错误都是用户肯定需要意识到的运行时问题。
我用超过 50 个模型和 AI 生成的模拟数据模拟了一个复杂的健身房应用,并使用 Claude 桌面版和 Sonnet 4.6 进行了测试。老实说,结果看起来相当不错。
它可以生成包含超过 10 个模型的非常复杂的嵌套查询,并且渲染结果相当好:
如果无法在一个操作中完成任务,它知道要使用多个操作来完成。
更令人印象深刻的是,在我的整个实验中,只有一次 LLM 创建的初始函数调用是不正确的,这被 'check' 工具捕获了。而且它只是采取了另一条路线来完成工作。
这里是一个你可以在本地运行的简单项目:
ZenStack Code Mode MCP Server with Authorization
你可以通过改变 schema.zmodel 以适应你的应用程序,简单地为你自己的应用程序测试。我学到的经验让我相当确信你可能会遇到一些问题。如果你能让我知道,我将非常感谢,这样我们可以迭代它以使其更有用。