能力

能力设计

MCP-first 系统中每项业务能力应如何结构化、命名和暴露——从七个构建块到 Action 层优先原则。

能力(Capability) 是系统最小的可描述单元:类型化、 权限验证、可审计,对人类和智能体同样可用。 MCP-first 不从界面开始,而从这些能力出发。只有在能力集完整之后, Web 应用、移动应用、CLI 和智能体接口才作为客户端构建在其之上。

七个构建块

MCP-first 用七个结构元素建模每项能力。

Resources

可被读取的数据与上下文。Resources 为智能体提供经过处理的上下文—— 不是原始数据库表,而是对系统状态经过过滤的、目的明确的视图。

Tools

系统可执行的操作。每个 Tool 都有类型化的输入 Schema、 输出 Schema、错误 Schema 和审计 Schema。Tool 是 Web 应用中 按钮所代表的真实操作。

Prompts / Workflows

引导智能体完成复杂多步骤流程的预定义工作流。 Workflows 定义应按何种顺序、以何种上下文调用哪些工具—— 以及在哪里需要人工输入。

Policies

规则、权限、保护级别和审批流程。Policies 决定谁可以查看、 调用和自主执行某项能力。它们不是事后添加的层—— 而是能力定义的一部分。

Audit Events

每个操作都会生成一条审计记录:谁、做了什么、何时、 经过何种审批、结果如何。审计事件不是可选的运营扩展, 而是每项能力的必备组成部分。

Human Confirmation Gates

在执行操作前智能体必须主动征求用户确认的机制。 确认节点以声明方式存储在能力中——而非在 UI 中临时实现。

Risk Metadata

每项能力都标注一个风险等级:lowmediumhighcriticalforbidden_for_ai。这些元数据控制发现过滤、确认要求 和升级身份验证——并以机器可读形式在工具合约中可用。

每个实体应提供什么

无论业务领域如何,每个实体都需要一套一致的基础能力集。

每个实体的基础能力
  • entity.list 返回经过过滤的列表
  • entity.search 带范围限制的全文搜索
  • entity.get 获取单个实体及上下文
  • entity.create 创建新实体
  • entity.update 修改字段,幂等操作
  • entity.archive 停用而非删除
  • entity.audit 获取变更历史
  • entity.permissions 查询有效权限
  • entity.related 加载关联实体
  • entity.recommended_next_actions 智能体可用的行动建议

Action 层优先

每个功能首先在中央 Action 层作为 Action 实现。 随后才创建各个接口适配器。

Action: create_project

使用者:
  Web 应用
  移动应用
  MCP Tool
  Worker
  CLI

这样就不存在重复实现:当 Web 应用按钮调用 create_project 而智能体做同样的事情时,两者使用相同的代码、 相同的验证逻辑、相同的审计事件。

Build capabilities once. Expose them everywhere.

核心主张

MCP 服务器是适配器

MCP 服务器不包含业务逻辑。它是智能体客户端与 Action 层之间的 轻量适配器。

其职责:

  • 发现(Discovery) — 在此上下文中有哪些工具和 Resources?
  • Schema 暴露 — 输入、输出和错误的类型化描述
  • Auth 上下文映射 — 将客户端 Token 映射到用户和租户上下文
  • Policy 检查 — 该智能体在此上下文中是否可以调用此工具?
  • 审计日志 — 为每次工具执行写入执行事件

类型化的输入和输出

每个 Tool 定义四个 Schema:

Schema用途
Input SchemaTool 期望哪些参数、哪些类型、哪些必填字段?
Output SchemaTool 成功时返回什么?
错误 Schema可能有哪些错误码——permission_deniedconfirmation_requiredpolicy_violation
审计 Schema审计事件中写入什么内容?

不使用松散的 JSON 结构。智能体——以及编译器和测试—— 都依赖这些 Schema。无类型的输出会在客户端产生猜测逻辑。

幂等性(Idempotenz)

许多 Tool 应该是幂等的:对相同请求返回相同结果, 不产生不必要的重复。

create_download_link(fileId, expiresAt)

如果 fileId 对应的有效链接已存在且 expiresAt 相同, 则返回现有链接——不创建第二个。这减少了智能体重试时的错误, 使 Workflow 对网络中断更具鲁棒性。