02 能力声明(buildCapabilities)契约 本节摘要:服务端有一件很重要的事——告诉客户端「我能做什么」。这不是让客户端瞎猜,而是通过一份「能力声明」契约,明确列出服务端支持哪些能力(技能/插件/MCP/命令的读写、审批模式、沙箱后端、令牌作用域等)。本节讲清这份契约:它声明什么、客户端怎么用它、为什么这种「自述能力」对多客户端协作至关重要。 一、为什么服务端要「自述能力」 考虑没有能力声明的场景:客户端(桌面、CLI、企业云)想用服务端的某个功能,但它不知道服务端支不支持、怎么调。结果: 客户端要么「假设支持」硬调,不支持就报错。 要么「瞎试」,效率低。 不同服务端版本能力不同,客户端没法适配。 能力声明解决这个——服务端主动告诉客户端「我支持什么」,客户端据此决定行为。
本节摘要:服务端有一件很重要的事——告诉客户端「我能做什么」。这不是让客户端瞎猜,而是通过一份「能力声明」契约,明确列出服务端支持哪些能力(技能/插件/MCP/命令的读写、审批模式、沙箱后端、令牌作用域等)。本节讲清这份契约:它声明什么、客户端怎么用它、为什么这种「自述能力」对多客户端协作至关重要。
考虑没有能力声明的场景:客户端(桌面、CLI、企业云)想用服务端的某个功能,但它不知道服务端支不支持、怎么调。结果:
能力声明解决这个——服务端主动告诉客户端「我支持什么」,客户端据此决定行为。这就像餐厅的菜单:你不用问「有没有 X」,看菜单就知道。
服务端的能力声明大致含这些:
| 声明项 | 内容 |
|---|---|
| 版本 | 服务端版本、底层引擎版本(让客户端知道运行环境) |
| 能力资源读写 | 技能/插件/MCP/命令/配置 各自是否可读、可写 |
| 审批模式 | 是否支持审批、超时多久 |
| 沙箱后端 | 支持哪种沙箱 |
| UI | UI 相关能力 |
| 令牌作用域 | 是否启用作用域、有哪些 scope(owner/collaborator/viewer) |
| 代理 | 是否代理引擎 |
| 工具提供者 | 浏览器、文件收发(inbox/outbox)等 |
能力声明(示例结构): { schemaVersion: 1, serverVersion: "...", opencodeVersion: "...", skills: { read: true, write: true }, // 技能可读写 plugins: { read: true, write: true }, mcp: { read: true, write: true }, commands: { read: true, write: true }, config: { read: true, write: true }, approvals: { mode: "manual", timeoutMs: ... }, tokens: { scoped: true, scopes: ["owner","collaborator","viewer"] }, proxy: { opencode: true }, toolProviders: { browser: ..., files: { inbox, outbox, ... } } }
注意「读写」的区分——有些服务端实例是只读模式(如 demo、受限环境),这时所有 write 都是 false。客户端看到只读,就不提供「编辑」按钮,避免用户尝试后失败。
客户端拿到能力声明后,用它来决定 UI 和行为:
skills.write = true → 提供「编辑技能」入口。skills.write = false(只读)→ 隐藏编辑入口,只允许看。tokens.scoped = true → 知道有权限作用域,按 scope 处理。approvals.mode → 按模式决定要不要等审批。客户端启动 │ ▼ 拉取服务端能力声明 │ ▼ 据此配置 UI(显示/隐藏功能)和行为(只读/可写) │ ▼ 用户操作时,只调服务端声明支持的能力
这让客户端「自适应」不同服务端——同一个客户端,连全功能服务端时啥都能干,连只读服务端时自动变成只读浏览器。
这套机制的重要性在多客户端协作里特别明显:
💡 类比 OpenAPI:它和 OpenCode 的 OpenAPI(OpenCode 教程第 3 章)思想类似——都是「服务端主动描述自己」。区别是 OpenAPI 描述「接口形状」,能力声明描述「运行时能力」(可读可写、模式等)。
这套机制和第 2 章「服务端消费优先」哲学呼应——客户端是服务端的客户端,所以客户端的「能干什么」由服务端决定。能力声明就是这个「决定」的载体:
服务端(声明能力)──► 客户端(按声明行为)
如果客户端「自作主张」做声明里没有的事(比如只读服务端里硬编辑),就违反了「服务端消费优先」——它会失败,因为服务端不支持。
能力声明带一个 schemaVersion(当前是 1)。这个版本号让契约能演进——未来如果声明结构大改(加新字段、改语义),升 schemaVersion,客户端按版本解析。这是契约演进的标配做法。
能力声明讲清了,下一节讲服务端如何「代理」底层引擎——透明反代。