Computer 运行时契约(Runtime Contract)¶
本文定义业务 client 可以跨 SDK 依赖的单个 Computer runtime 公共语义。它不是 wire protocol,也不规定 Python、Rust、TypeScript 或其它 SDK 的代码形态。
Runtime contract 的目标是:同一份声明式 ComputerConfig 和 RuntimeOptions 在不同 SDK 中产生等价 runtime intent,并通过一致的生命周期、错误分类、marketplace/plugin 挂载、sync_config final state 和 shutdown 语义交付给业务 client。
1. 边界¶
Runtime contract 负责:
- 从声明式 config 创建一个 runtime Computer。
- 启动、停止、连接、断开、同步配置、关闭一个 runtime Computer。
- 默认值解析、生命周期状态、错误分类和 retryability。
- marketplace / plugin / user / MCP source 能力挂载语义。
- 单个 runtime 与 Agent-facing protocol projection 的一致性。
- 共享 JSON fixture 与生命周期 conformance tests。
Runtime contract 不负责:
- 多 Computer 编排、UI 状态、账号选择、Server 选择、office 策略和审计流。
- Python dataclass、Rust builder、TypeScript constructor、trait 名、class 名或 method 名。
- 内部缓存、锁、watcher、目录布局、进程模型、async runtime、CLI UX。
2. 核心对象¶
2.1 ComputerConfig¶
SDK SHOULD 接受一个声明式 config 对象,并具备以下语义内容:
| 字段族 | 稳定语义预期 |
|---|---|
| identity | Computer protocol name 和可选本地展示元数据 |
| mcp_servers | MCP Server configs、disabled flags、forbidden tools、tool metadata 和 transport parameters |
| inputs | 用于本地渲染 MCP Server configs 的 input definitions |
| skills | User DropIn roots 或等价本地 SKILL source declarations |
| marketplaces | Known marketplace source declarations 和 trust/update policy |
| plugin_installation | installedPlugins:全局安装意图(已安装 <plugin>@<marketplace> 集合);install 写此集且不激活,见 §2.3 / §2.4 |
| plugin_enablement | enabledPlugins:per-scope 启用意图(<plugin>@<marketplace> → bool);仅 true 激活,absent/false=本 scope 不活跃;与 installation 正交,见 §2.4 |
| settings_policy | Scope merge result 或等价治理策略 |
| connection | 可选默认 Server URL、namespace、office 和 auth payload policy |
不同 SDK 的 config shape 可以不同,但共享 conformance fixtures MUST 能表达为 JSON,并映射为等价 runtime intent。
Installation 与 enablement 是两个独立状态、独立生命周期。 Installation 是全局一次的安装事实(
installedPlugins);enablement 是 per-scope 的启用意图(enabledPlugins)。SDK MUST NOT 用单一开关同时表达二者——否则一个 scope 的启用会泄漏到其它 scope。尤其:installMUST NOT 激活(不写enabledPlugins、不进投影),enable才激活;完整状态机见 §2.4。
2.2 RuntimeOptions¶
SDK SHOULD 接受 runtime options,用于表达环境相关行为:
| 选项族 | 稳定语义预期 |
|---|---|
| home | 可选本地 Computer home 或 storage root |
| secret providers | 本地 input/secret resolver hooks |
| auth payload provider | 用于添加非 A2C 业务 auth fields 的 callback 或 value |
| network options | Socket.IO path、namespace、transport、timeout 和 reconnect options |
| blob thresholds | inline、too-large 和 chunk-size budgets |
| policy hooks | 本地 source trust、plugin approval 和 management authorization hooks |
| diagnostics hooks | logging、metrics 和 health observers |
RuntimeOptions MAY 使用 SDK-specific 名称和默认值。最终外部可见行为 MUST 符合本 contract。
2.3 状态权威与资产分档¶
权威方向 MUST 为 意图 → 派生态,不可逆。 声明式意图是唯一权威写入入口,含:installedPlugins(全局安装意图)、enabledPlugins(per-scope 启用意图)、marketplace declarations,以及 ComputerConfig 其余声明字段。任何命令式管理操作 MUST 先写对应声明式意图(config-first):install 写 installedPlugins、enable/disable 写 enabledPlugins、add-marketplace 写 marketplaces;锁 / 物化账本 / 克隆缓存 / 活跃集均为其下游派生物。派生态 MUST 仅由 reconcile 从意图重建,MUST NOT 被直接编辑、也 MUST NOT 作为独立输入参与决策;因此运行时无需为“中间层突变”编写应对逻辑。
反模式(rust-sdk#96 根因):把能力归属 / 活跃集只持在运行期内存、无法从持久化意图重建,重启即丢。根治是 boot 从持久化意图 reconcile(§4.8),而非让
install去写enabledPlugins——install本就不表达启用意图(见 §2.4)。SDK MUST NOT 让任何 boot 依赖的状态只存在于内存。
分层深度 MUST 按资产是否有远端 fetch 步骤而定:
| 资产类别 | 分层 |
|---|---|
| Fetch 资产(marketplace / plugin) | 意图 → 物化账本(派生缓存,记 resolved 版本/位置)→ 克隆缓存 → 活跃集 |
| 纯声明资产(MCP Server 定义、本地 DropIn SKILL) | 意图 → 活跃集 |
SDK MUST NOT 为纯声明资产引入锁或物化目录。物化账本(若实现保留,如 installed_plugins.json)MUST 是可从 installedPlugins 意图重建的派生缓存,MUST NOT 手编、MUST NOT 提升为权威。
命令式 runtime MCP Server CRUD 的持久化语义(deliberately unspecified):上文“声明式意图 MUST 持久化、boot 从持久化意图 reconcile”的权威对象是 plugin / marketplace 声明意图(
installedPlugins/enabledPlugins/ marketplaces)——因为 boot reconcile 的正确性依赖它(§4.8,rust-sdk#96)。它不延伸到对非-bundled MCP Server 的运行期命令式 add / update / remove:该操作是 Computer 管理面(CLI / 桌面客户端)与内核之间的本地约定,其结果是落盘为 durable 声明意图(重启存活)还是仅内存生效(持久化留给 host 编辑声明文件),协议刻意不作规范(落在 §3「本地 API / 文件布局 / 进程模型」与 sdk-api-guidance §9 非目标之内)。两种选择都与 config-first 自洽:boot 只从已持久化的声明意图 reconcile,未被 durable 声明的运行期临时增量在重启后消失,本就是 config-first 的应有之义,而非上文反模式(后者约束的是 boot 依赖的能力归属 / 活跃集只存内存)。SDK MAY 提供「transient / mount」与「declare-durable」两条显式路径;选择与默认交由 SDK,durable 变体 MUST 写入调用方拥有的位置(协议不规定文件名 / 布局)。物化账本(materialization ledger,如
installed_plugins.json):reconcile 从installedPlugins意图派生出的、机器本地的物化记录,登记 resolved 身份(version / commitSha)、落地位置(installPath)与能力归属(bundled server 属于哪个 plugin)。它只记“已物化成什么”、不记“应该装什么”(后者由installedPlugins承载)——因此是可弃、可重建的描述性索引,不是权威、不是复现锁。判据:删除它无损——boot 可从installedPlugins重新 clone / 解析重建;缺失只是下次 boot 重新物化。安装集本身不丢,因为它在installedPlugins,不在账本。
2.4 Plugin 生命周期(install ⊥ enable)¶
Plugin 有两个正交、独立生命周期的状态维度:是否安装(全局,installedPlugins)与本 scope 是否启用(per-scope,enabledPlugins)。二者组合出三个可分别停留的静止态:
| 状态 | installedPlugins |
enabledPlugins(本 scope 合并后) |
投影(skills / bundled MCP server) |
|---|---|---|---|
available |
不含 | —— | 不出现 |
installed_disabled |
含 | absent 或 false |
不出现(已安装但未启用,惰性静止) |
installed_enabled |
含 | true |
出现(skills 与 bundled server 一并活跃) |
enabledPlugins[<plugin>@<marketplace>] 三态(用于 scope 合并 user < project < local):absent = 本 scope 无意见、继承上层(无任何 scope 置 true 即不激活);true = 本 scope 启用(激活);false = 本 scope 显式禁用(覆盖上层 true)。
默认不激活。 仅被
install的 plugin,在任何 scope 未显式true前处于installed_disabled——skills 不进client:get_skills、bundled MCP server 不挂。这是相对 v0.2.x「装即活跃」的破坏性行为变更,迁移见 v0.3.0 迁移指南。
状态迁移 MUST 遵循下表;每个命令式操作 MUST 先写声明式意图(config-first,见 §2.3):
| 操作 | 意图写入 | 物化 / 投影副作用 | 结果态 |
|---|---|---|---|
install |
installedPlugins 增 |
物化(clone / 账本)、校验 manifest、依赖预检(plugin 声明依赖的 MCP Server 按 bundle_id 与运行期权威配置集比对:已存在 = 依赖已满足 → 提示并正常安装,交 reconcile 收敛,MUST NOT 以此拒绝安装;见 §2.5);MUST NOT 激活、MUST NOT 写 enabledPlugins |
installed_disabled |
enable |
enabledPlugins[scope] = true |
把 skills 与 bundled MCP server 原子并入投影(见下);失败 MUST 回滚到 installed_disabled |
installed_enabled |
disable |
enabledPlugins[scope] = false |
从投影移除其贡献;保留 installedPlugins 与物化 |
installed_disabled |
uninstall |
installedPlugins 删、清其 enabledPlugins 条目 |
teardown 物化;其声明依赖的 MCP Server 按 §4.9.1 回收判据处理(无人再依赖 ∧ 非用户声明才回收) | available |
enable 原子性(消除“半态”)。
enableMUST 把该 plugin 的 skills 与 bundled MCP server 条目作为整体一并纳入投影。被禁止的“半态”锚定在投影面不一致——skill 已在client:get_skills、而 bundled server 条目缺席于 config/tool 投影(此即 rust-sdk#102)。在 client-owns-MCP-config 下,把 bundled server 记为 enabled-可查询条目即已满足原子性——其进程拉起是客户端职责(见 §4.8 边界,不算半态),skills 照常一并投影、无需等待其就绪。仅当 server 连投影条目都无法建立(manifest / 物化失败)时,才整体保持installed_disabled并给出公开诊断。
2.5 Plugin 与 MCP Server:依赖关系与来源优先序¶
plugin 与 MCP Server 均为一级资源,二者是依赖关系而非所有关系:plugin 通过 bundle_id 声明依赖某 MCP Server(身份正交性)。由此:
- 依赖已满足不是冲突。install/enable 时若声明的
bundle_id已存在于本地任一来源(如用户 mcp.json 声明),SDK MUST NOT 拒绝——MUST 视为「依赖已满足」,SHOULD 提示(复用既有实例、按来源优先序 reconcile、卸载本 plugin 不移除它),随后正常安装。 - 仍为硬错误的情形:同一 mcp.json 文件内两个 key 归一到同一
bundle_id(声明面写法错误)——注册边界 MUST fail-fast 并提示改名或显式指定bundleId。 -
来源优先序(配置与 enable/disable 开关的合并序,双端 MUST 一致),由低到高:
- plugin 声明是最低基线层:其携带的 server 配置仅在更高来源缺失该
bundle_id时生效,被任何用户侧 scope 覆盖(用户主权);origin=plugin的可信性由 install ∧ enable 门保证,不走 settings 信任面(见 §5 item 10 与 审批门对齐指南)。 - settings 与 mcp.json 两套来源 MUST 使用同一优先序;
flag统一为次高(CLI 显式传入的受信覆盖,仅低于 policy)。历史实现把 mcp.json 的 flag 层排为最低(--config老接口遗留),该形态废止。 - flag scope 的文件对为
--mcp-config(flag 层 mcp.json,含servers/inputs;由旧--config更名)与--settings(flag 层 settings.json),与其余 scope 的双文件形态对称。 embed为宿主构造挂载层(embedded-constructor,如Computer(mcp_servers=...)构造入参):代码级显式意图,与flag同属「调用方显式受信层」——宿主自身 flag 仍可覆盖代码默认,policy 最高不变。它是非-plugin origin,参与 §4.9.1-2 回收判据「非用户声明」的判定(宿主自有 server 不因 plugin 卸载连坐)。- 运行期权威集约束:依赖预检、
client:get_config等 一切 wire 投影与预检决策 MUST 读取运行期权威配置集(含动态挂载 / 重挂项),MUST NOT 读取构造期快照——快照对运行期变更不可见,会把「依赖已满足」误判为「未满足」并腐蚀账本记录。 - 运行期权威配置集 MUST 携带
origin(Discussion #32 裁决):该集合定义为 resolve 后带origin的集合,每条挂载路径 MUST 在其中留下携带正确 origin 的条目——durable scopes(user/project/local/policy)、flag(--mcp-config)、embedded-constructor(embed);唯 plugin-enable 路径产生origin == plugin。origin 的取得机制不钉——scope 纯推导(查询时从声明面推导)与挂载时标记(注册接缝携归属入参)行为等价即合规——但 MUST 可从当次 boot 的声明式输入(文件、flag、构造入参、plugin 意图)重建,MUST NOT 落盘为快照(§4.9.1-1 禁账本 provenance 不变)。本条只做 scope 级 plugin/非-plugin 二分,不引入租户级归属(嵌入式多实例 ownership 混源轴维持共识外)。
- plugin 声明是最低基线层:其携带的 server 配置仅在更高来源缺失该
3. 生命周期状态¶
SDK SHOULD 暴露生命周期状态或等价公开诊断,并具备以下语义:
| 状态 | 含义 |
|---|---|
created |
Runtime object 已存在,但尚未初始化本地资源 |
starting |
Runtime 正在加载 config、解析本地状态或启动 MCP 资源 |
started |
本地 runtime 已初始化;可能已连接或未连接 SMCP Server |
connecting |
Runtime 正在建立 Socket.IO 连接并执行协议握手 |
connected |
Socket.IO 连接已建立,但 Office join 可能尚未完成 |
joined_office |
Computer 已加入 Office,可以接收路由来的 client:* events |
syncing |
Runtime 正在应用新 config 或 reconcile desired state |
degraded |
Runtime 部分可用,并带有公开诊断 |
disconnecting |
Runtime 正在离开或关闭 Socket.IO 连接 |
stopping |
Runtime 正在停止本地 MCP/service activity |
stopped |
Runtime 已停止 service activity |
shutdown |
Runtime 已释放资源,不应再发出 stale events |
error |
Runtime 在没有外部动作或新 config 的情况下无法继续推进 |
如果 SDK 文档化了等价映射,不需要使用这些精确字符串。
4. 必需能力¶
4.1 从 Config 创建¶
SDK SHOULD 提供一个稳定语义入口,等价于 from_config(config, runtime_options)。
该操作 MUST NOT 仅因解析 config 就连接远端 Server 或执行 MCP tools。它 MAY 校验 shape、解析默认值并构建本地 runtime intent。
无效 config MUST 返回公开 validation error,并在可行时包含 field/path 信息。错误中 MUST NOT 泄露 secret values。
4.2 Start¶
start 或等价操作初始化服务前所需的本地 runtime 资源:
- 加载并校验 desired state。
- 初始化 MCP Server manager intent。
- 初始化 SKILL registry、blob resolver 和 Desktop/resource tracking。
- Reconcile 本地可用的 marketplace/plugin/user/MCP source capability。
- 构建 Agent-facing projection。
start MAY 立即或惰性启动 MCP Server processes,但连接后的最终 client:get_* 行为 MUST 匹配已加载的 desired state。
4.3 Stop¶
stop 或等价操作停止 service activity,但不一定删除 durable desired state:
- 按 SDK policy 停止或 detach 本地 MCP Server activity。
- 停止 watchers 和 update emitters。
- 在 stop 完成后阻止新的 Agent-facing work 被接受。
- 保留 durable desired state,除非调用方明确要求删除。
4.4 Connect And Join Office¶
connect 或等价操作建立协议连接:
- 除非另有配置,使用
/smcpnamespace。 - 发送 URL query
a2c_version。 - 连接握手
auth仅承载调用方提供的非敏感业务 auth fields(不含role)。 - 当提供 office config 或调用方要求时,使用
server:join_office(role = "computer",角色即在此声明)加入 Office。
连接失败 MUST 被分类,使调用方能区分 protocol version mismatch、auth failure、network failure 和 join failure。
4.5 Disconnect¶
disconnect 或等价操作结束 Socket.IO 连接,但不销毁 durable local config。断开后:
- Runtime MUST NOT 向之前的 Office 发送
server:update_*。 - Runtime MAY 继续本地管理操作。
- 后续 reconnect MUST 投影当前 desired state,而不是上一次连接留下的 stale state。
4.6 Sync Config¶
sync_config(new_config) 或等价操作把新的 desired state 应用到既有 runtime。
实现 MAY 使用 incremental update、rebuild、restart、lazy apply 或 full reconcile。contract 只要求:
- 最终 public runtime state 匹配
new_config。 - 已移除或禁用的 capabilities 不再保持可见或可调用。
- 新启用的 capabilities 在成功 reconcile 后变为可见。
- 如果已加入 Office,Agent-facing projection 变化会发送对应
server:update_*。 - Partial failure 进入
degraded或返回公开 partial-failure result;它 MUST NOT 暴露歧义能力或被 policy-rejected 的能力。 - Secret values MUST NOT 出现在 errors、发送给 Agent 的 diagnostics 或 public protocol projection 中。
4.7 Shutdown¶
shutdown 或等价操作释放 runtime 资源:
- 如果已连接,则断开 SMCP Server。
- 停止 runtime 拥有的 MCP Server activity。
- 停止 watchers、timers、background tasks 和 update emitters。
- 释放 runtime 拥有的 blob/spool resources。
- 在 shutdown 完成后阻止 stale callbacks、
server:update_*emissions 或迟到的 tool-call ack attempts。
删除 durable config 不属于 shutdown,除非由独立管理操作明确请求。
4.8 Boot 治理恢复(Governance Recovery)¶
从既有 home 重建 runtime(进程重启或以相同 home 重新构造)时:
- Boot MUST 以持久化声明式意图为权威重建派生态与活跃集:安装集取自
installedPlugins,活跃集 = 已安装 ∧ 本 scope 启用(enabledPlugins合并后为true);installed_disabled(已装未启用)MUST 恢复为惰性、不进投影。start的 reconcile(§4.2 第 4 步)MUST 覆盖此恢复。 - 重建后的 Agent-facing projection MUST 完整包含 enabled plugin 贡献的 bundled MCP Server、bundled SKILL 及由其派生的 MCP-source SKILL,且 MUST NOT 依赖任何调用方持有的内存归属表(in-memory ownership map)。
- 能力归属元数据(source / marketplace / plugin id 等)MUST 为 boot 的纯函数输出(意图 + resolved location + manifest 重新推导),每次 boot 可复现。
- Boot reconcile MUST 幂等且 additive-only;删除 MUST 走独立显式路径(prune / gc),MUST NOT 作为 reconcile 的副作用。
- settings / plugin-marketplace / MCP 三条 reconcile pipeline MAY 各自独立执行;本 contract 不要求把它们合并为单一 reconcile。
归属恢复 vs 进程拉起(client-owns-MCP-config 边界):上文“完整包含 bundled MCP Server”约束的是归属与身份——重建后它 MUST 可作为纯函数从意图 + 账本推导(§4.8.2 / §4.8.3),使调用方无需内存 ownership map。但 bundled MCP server 的进程拉起 / 物化MAY 需要调用方提供物化 hooks:当 SDK 约定 MCP server 物化归客户端所有(client owns MCP config)时,SDK MUST 使 enabled bundled server 可查询(供客户端据此物化,或经治理恢复接口显式拉起),但 MAY 不在 boot 内直接启动其进程。此边界 MUST NOT 退化为“调用方凭内存 map 猜归属”。
4.9 物化账本地位与运行期稳定性¶
本 contract 不要求存在 lock 或物化账本文件。复现性 MUST 来自持久化的声明式意图 + reconcile 重解析(latest-compatible):相同意图在同一或不同机器上重建,MUST 产出等价活跃集(marketplace 按声明 ref 解析当前条目,允许上游漂移)。
- 若实现保留物化账本,它 MUST 只由 reconcile 从
installedPlugins意图写入,MUST NOT 被直接编辑,MUST NOT 作为权威来源;它是可弃、可 GC、可从installedPlugins重建的派生缓存。 - committed pin-lock(记录
commitSha/integrity并令 boot 优先按锁复现)是可选、非必需的更强复现扩展;实现 MAY 提供,但 MUST NOT 以派生缓存冒充可复现 lock。 - 运行期稳定:会话内派生态快照 SHOULD 冻结;后台或磁盘侧变更 MUST NOT 在运行中打乱已投影的 Agent-facing 状态,而是作为 pending 差异留到下次 boot 吸收。此保证“改配置后再启动”确定、“反复重启”结果一致。
4.9.1 账本的 MCP 依赖记录与回收判据¶
账本中每条 plugin 记录以 mcpServers: ["<bundle_id>", ...] 纯数组登记其声明依赖的 MCP Server(§2.5 依赖关系):
- 只记
bundle_id。MUST NOT 记 displayname(会随显式bundleId改名而失真;展示用名可从 install_path 实时解析);MUST NOT 记「安装时本地是否已有」一类时点快照事实(如 provenance/introduced 标记)——它会随其他 plugin 的卸载而失真,任何回收/门控/归属判定 MUST NOT 依赖此类字段。 - 回收判据(纯函数,零落盘状态):disable / uninstall plugin P 时,对其声明的每个
bundle_idX——回收 X ⟺ 无其他 plugin 声明依赖 X ∧ X 非用户声明(运行期权威配置集中不存在origin != plugin的 X 条目)。用户自有 server 永不连坐由「非用户声明」保证;多 plugin 共享依赖由第一条保证。「X 非用户声明」MUST 评估在 §2.5 第 5 条定义的带origin的运行期权威配置集之上——MUST NOT 以裸 manager 活跃集(无 origin)判定(transient flag 挂载与 embedded-constructor 挂载在其中与 plugin 挂载可观测同形,会连坐用户 / 宿主自有 server);MUST NOT 以「活跃集 ∖ 全 plugin 声明集」差集判定(回收候选必然落在 plugin 声明集内,该差集对其恒空,判定退化为死代码——已实测证伪)。 - uninstall 停摘自足:停摘名单 MUST 在账本记录移除之前取得,且 MUST 仅依赖账本自身字段——MUST NOT 依赖
installPath指向的树(uninstall 流程中该树在停摘前已被删除,「从 install_path 重解析」在此路径恒不成立)。 - 旧格式迁移:检测到旧账本格式(如 name 数组)MUST 整条丢弃、经 reconcile 从
installedPlugins意图重建(§4.9 判据「删除它无损」),MUST NOT 编写 name→bundle_id 映射迁移逻辑。
5. Marketplace And Plugin Contract¶
暴露 marketplace/plugin management 的 SDK SHOULD 对齐以下语义:
- Marketplace reconcile 默认 additive:声明的 sources 会被 installed/updated/refreshed;未声明但已物化的 sources 不会被删除,直到 explicit prune/gc。
- Marketplace sync failure 是 degraded:其它 sources 可以继续;如果 failed source 物化失败,其能力不会作为 active 暴露。
- 为跨 SDK fixture 目的,Plugin id 使用语义形式
<plugin>@<marketplace>。SDK MAY 把它包装为 typed IDs。 - Enabling plugin 会把它的 SKILL、MCP Server、input 和 tool metadata contributions reconcile 到既有 projection surfaces(skills 与 bundled server 原子一并,见 §2.4)。Installing 只物化并写
installedPlugins,MUST NOT 进入 projection。 - Disabling/removing plugin 会让它贡献的 capabilities 变为不可见或不可调用。
- plugin 声明依赖的 MCP Server 以
bundle_id与运行期权威配置集比对(§2.5):已存在 = 依赖已满足,MUST NOT 拒绝,SHOULD 提示并交 reconcile 按来源优先序收敛;display name 相同、bundle_id不同是协议允许的合法共存,MUST NOT 视为冲突。唯一硬错误是同一声明文件内多 key 归一同bundle_id(fail-fast,§2.5 第 2 条)。 - Plugin-scoped inputs MUST 避免同一 bare input id 在不同 plugin 间泄露值。
- 安装路径 MUST NOT 作为权威状态。MUST 存在纯函数
(marketplace, plugin, version) → path;持久化路径仅为提示,boot MUST 重新校验,失效即重算(worktree / seed 场景 MUST NOT 信任存储的 install location)。 - 声明(可提交)与凭据(机器本地)MUST 使用不同持久化契约:secret / OAuth token MUST 存于 keychain 或等价机器本地存储,MUST NOT 落入任何可提交的声明文件。
-
MCP Server 启停有两套正交开关,MUST 分清并分别应用:project-scope 声明 server 的信任门(
enabledMcpjsonServers/disabledMcpjsonServers/enableAllProjectMcpServers)与通用禁用开关(按bundle_id键,仅作用于声明的 server)。审批门拆为两层,MUST 分别判定(详见 审批门对齐指南 §2): - 安全层(Gate 1-3:
deniedMcpServers/allowedMcpServers/disabledMcpjsonServers)——所有 server(含 plugin baseline)必经,方向为 DENY / 白名单收窄 / 用户侧禁用,即 fail-safe 全局底线 - 信任层(Gate 4-7:trusted_origin/enabledMcpjsonServers/enableAllProjectMcpServers/PENDING)——仅声明 server 与 project-enable bundled server 进入,方向为 ENABLE,需受信 scope 供给判据plugin 声明依赖的 server,当其 enable 判据(
enabledPlugins)来自受信 scope(user/local/flag/policy)时,MUST NOT 进入信任层迭代(Gate 4-7),但 MUST 仍经过安全层(Gate 1-3)——安全层按bundle_id全局拒绝不产生 §2.4 所禁半态(过滤发生在 skill+server 原子投影之前);其启停由 plugin enable/disable 整体控制,单独打掉某个 bundled server 仍属半态禁令;管理员经 policyenabledPlugins: false可强停整个 plugin。当 enable 判据仅由projectscope 供给时(project settings.json 入 git、随仓库分发),该 bundled server MUST 进入门迭代并落PENDING——project scope 不得为 bundled server 是否受信提供判据(同 审批门对齐指南 §2.1 通则;与档⑤enabledMcpjsonServers/ 档⑥enableAllProjectMcpServers拒 project scope 同构)。此处PENDING只决定该 bundled server 是否「免批准挂载」,不破坏 enable 原子性(整插件启停仍由 enable/disable 控制)。审批/信任门的实现 MUST NOT 依赖物化账本的名集(见 审批门对齐指南)。 11. Plugin input 解析序。渲染绑定 pluginP@M(P = plugin、M = marketplace,语义形式见第 3 条)的 MCP server config 时,裸引用${input:<id>}的解析序 MUST 为:① 先尝试 plugin-scoped id<P>@<M>/<id>;② 若未命中、且存在同 kind(value / secret 一致)的全局 input<id>→ 回退全局;③ 若仍不可解析 → SDK MUST 产出结构化缺失错误(§6missing_input),其id= 完整 scoped id<P>@<M>/<id>(补救方式由 embedding client 决定,协议不规定)。补充:显式完整引用${input:<P>@<M>/<id>}直接命中 scoped、不回退全局;未绑定 plugin 的 server(用户自定义)裸引用仅解析全局<id>、无 scoped 步(行为不变);跨 kind 不回退——scoped secret 缺失时 MUST NOT 回退全局 value(反之亦然),直接产出 scoped 缺失错误;scoped 缺失错误 MUST NOT 透露 global 侧是否命中。本条 resolver-agnostic:规定"SDK 用哪个 id 去问 resolver"、不规定 resolver 实现(交互式 prompt 与运行期 client 注入两条路径套用同一序)。本条与第 7 条对偶——第 7 条禁止串值、本条规定取值序。 12. PickString 取值与失效语义。本条适用于所有 MCP server 的 input 解析(含未绑定 plugin 的用户自定义 server),不限于 plugin 绑定的 server。pickStringinput 的候选值匹配任一option.value即合法(schema 约束见 MCPServerPickStringInput)。已存值(resolver / 用户实际值)不匹配任一option.value→ SDK MUST 产出结构化invalid_selection错误(§6),该错误 MUST 至少携带id字段(= input id),MUST NOT 回退default或首项——失效即报错,静默改值会掩盖用户改选意图。真正无用户值(resolver 从未供给过值)时沿解析链:先尝试default;仍无值时 SDK MAY 选择首项(不反向持久化——不写回任何存储,下次解析仍从解析链开始;该回退行为双 SDK 既有实现一致,自 0.3.2 起明确入典)。本条与第 11 条同精神:resolver-agnostic,规定"什么值合法、失效给什么错误",不规定 resolver 实现。 13. Input 重解析时机。本条适用于所有 MCP server(含未绑定 plugin 的用户自定义 server)。SDK MUST 分别保留含${input:<id>}占位的 raw config 与当前进程实际使用的 rendered config(raw/rendered 术语与 connection-identity 摘要条款同源,见 data-structures 摘要输入条款)。每次把 MCP server 从stopped状态实际启动(含 stop→start、restart 语义、批量启动操作中每个实际启动的 server),SDK MUST 从 raw config 重新解析 Input 再创建 client——已存的 rendered 品 MAY 作为缓存,但 MUST NOT 作为实际启动时的解析结果来源。运行中进程不热更新:resolver 返回值或 input 定义在运行中变化,MUST NOT 打断已运行实例,留待下一次实际启动吸收(与 §4.9 第 3 条"改配置后再启动确定"一致)。对已运行 server 的幂等 start MAY no-op(不重复解析)。实际启动时的重解析失败 MUST 产出结构化错误,并尽量保留仍在运行的旧进程(restart 场景)。不新增单独的 rematerialize API。
6. 错误类别¶
SDK SHOULD 暴露等价的公开错误类别:
| 类别 | 典型触发 | 可重试性 |
|---|---|---|
validation |
config shape 非法、plugin id 非法、marketplace name 非法、scope 非法 | 修复 config 后重试 |
missing_input |
plugin input 解析序(§5.11)耗尽仍不可解析 | embedding client 注入值后重试 |
invalid_selection |
已存 PickString 值不匹配任一 option.value(§5.12) |
用户改选合法值后重试 |
policy |
Source blocked、permission denied、policy-only field in user scope | policy 变更后重试 |
conflict |
同一声明文件内多 key 归一同 bundle_id(§2.5 fail-fast)、concurrent writer conflict |
解决冲突后重试 |
auth |
SMCP auth failure、source auth failure、MCP upstream authorization failure | credentials/auth flow 完成后重试 |
network |
Server unreachable、marketplace fetch failed、transient transport failure | 通常可重试 |
protocol_version |
HTTP handshake 4008 |
不改版本则不可重试 |
startup |
MCP Server startup failure、dependency missing | 取决于 diagnostic |
partial_failure |
Some sources applied, some failed | 重试 failed subset 或 sync |
shutdown |
Cleanup failure | 重试 cleanup 或 force stop |
错误 MUST NOT 包含 secret values。管理面错误不会变成 Agent-facing ErrorPayload,除非它们发生在既有 client:* handler 内;此时适用既有协议错误 shape。
7. Client 责任¶
业务 client 仍负责:
- 管理多个 Computer runtimes。
- 持久化 user/workspace account selection。
- 选择 Server、office 和 user-facing reconnect policy。
- 拥有 product UI state 和 operation audit logs。
- 按产品策略存储 secrets。
- 协调多个 runtimes 的更新。
单个 Computer runtime 仍负责:
- 管理一个 Computer 的 MCP lifecycle。
- 解析本地 inputs 和 secrets。
- 将 tools/resources/Desktop/SKILL/Blob 投影到 Agent-facing protocol。
- 在 shutdown 时释放拥有的 resources。
8. 兼容性¶
兼容性标签:Runtime-contract。
SDK 可能需要新增 public API wrappers 或 conformance fixtures,但不需要改变 Agent-facing wire schema。