Skip to content
Merged
29 changes: 29 additions & 0 deletions docs/design/mcp-management-runtime-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,32 @@ Server provenance remains distinct: user settings, workspace settings,
project `.mcp.json`, and extensions. Disabling project or workspace servers
writes the exclusion to workspace-local settings without modifying the shared
project file.

## Daemon API ownership

Durable MCP configuration uses `/workspace/config/mcp/*` for user scope and
`/workspaces/:workspace/config/mcp/*` for workspace scope. Runtime observation
and control use the matching `/runtime/mcp/*` routes. Qualified routes always
resolve the selected workspace and never fall back to the primary runtime.
Runtime operations and workspace-scoped configuration mutations require trust;
daemon-local configuration reads and user-scoped mutations do not.

Each workspace coordinator serializes MCP preparation, reload, restart, and
authentication against its physical ACP runtime. Its capability status exposes
an operation `revision` and the observed `runtimeEpoch`; consumers may render
them but do not send them back. The revision rejects stale results from an
older MCP operation, while the epoch rejects results from a replaced ACP child.
A result is ready only when discovery is complete and came from the current
live epoch. Configuration written while the runtime is cold is durable and
reconciles on the next ensure. Configuration written during a drain is replayed
if the drain rolls back.

OAuth remains owned by each workspace's ACP child, while daemon-global
admission serializes authentication because every child uses the same callback
port. The owning Bridge retains admission until authentication is observed as
settled or its runtime exits.

The Web Shell MCP manager uses configuration routes for add, edit, remove,
enable, and disable, and runtime routes for status, discovery, tools,
resources, restart, approval, and OAuth. Existing legacy MCP routes remain as
a compatibility surface for older clients.
81 changes: 42 additions & 39 deletions docs/design/workspace-runtime-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
Workspace-runtime-centric 的目标设计与堆叠交付契约。该设计由四个可独立合并的
PR 渐进落地;本文描述最终形态,不表示 foundation PR 已实现所有 capability。

> **当前落地进度(foundation)**:已实现 Bridge 权威的五态 lifecycle snapshot、
> **当前落地进度(Foundation + MCP)**:已实现 Bridge 权威的五态 lifecycle snapshot、
> workspace 级单调 epoch、完整物理 work lease、绝对启动 deadline、无参数
> `ensure/status`、10 分钟可续期保活、drain/removal/shutdown admission,以及
> SDK 的 primary/qualified runtime 方法。第 10~13 节描述的 capability
> generation/revision、Catalog 投影和 operation 状态机仍属于后续阶段;当前
> `ensure` 只保证 ACP runtime 已初始化并可复用,不宣称各领域 Catalog 已 ready。
> SDK 的 primary/qualified runtime 方法,以及 MCP 的 revision、Catalog 和
> runtime management。当前 `ensure` 会在同一观察预算内准备 MCP;Extensions、
> Skills、Tools 的 generation/revision、Catalog 投影和 operation 状态机仍属于后续阶段。

### 1.1 当前实现与目标设计

Expand All @@ -21,14 +21,14 @@ PR 渐进落地;本文描述最终形态,不表示 foundation PR 已实现
- **Target(未实现)**:后续 PR 的目标契约,当前调用方不得依赖;
- **Legacy(兼容)**:迁移期间保留的旧入口,新调用方不应采用。

| 领域 | Foundation(已实现) | Target(后续阶段) |
| ----------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| Runtime lifecycle | Bridge 权威五态、workspace 单调 epoch、物理 work lease、启动 deadline、drain/removal admission | capability 健康状态参与统一对外投影 |
| `ensure` | 无参数;仅确保 ACP Channel 完成 initialize;成功后续期 10 分钟 | 准备 Extensions、MCP、Skills、Tools,并通过 capability status 表达收敛 |
| `status` | lifecycle、`runtimeLive`、`runtimeEpoch` 快照 | capability、generation、revision、error 和 operation 投影 |
| SDK | primary/qualified `ensure` 与 `status` 的 REST 方法 | config/runtime Catalog、operation 和统一 deadline 的完整 owner-aware API |
| 领域 | Foundation(已实现) | Target(后续阶段) |
| ----------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| Runtime lifecycle | Bridge 权威五态、workspace 单调 epoch、物理 work lease、启动 deadline、drain/removal admission | capability 健康状态参与统一对外投影 |
| `ensure` | 无参数;确保 ACP Channel 完成 initialize 并准备 MCP;成功后续期 10 分钟 | 准备 Extensions、Skills、Tools,并通过 capability status 表达收敛 |
| `status` | lifecycle、`runtimeLive`、`runtimeEpoch` 与 MCP capability 快照 | 其他 capability、generation、revision、error 和 operation 投影 |
| SDK | primary/qualified runtime 与 MCP config/runtime 方法 | 其他 Catalog、operation 和统一 deadline 的完整 owner-aware API |

除明确标为 Foundation 的段落外,第 9~14 节中 capability、Catalog、generation、
除明确标为当前实现的 MCP 契约外,第 9~14 节中其他 capability、Catalog、generation、
revision 和 operation 的详细状态机均是 Target 契约。

核心目标只有一个:
Expand Down Expand Up @@ -386,9 +386,9 @@ startup preheat 是迁移期策略,不是目标架构的启动入口。完成

### 8.4 Draining 与移除

Foundation 的 workspace removal activity 已包含 Session 之外的 Bridge 物理 work 和
在途 ensure。非 `force` 移除遇到这些活动项返回 `workspace_busy`。进入 `draining`
后,Registry 阻止新的路由解析,
当前组合实现的 workspace removal activity 已包含 Session 之外的 Bridge 物理 work、
在途 ensure 和已接纳的 workspace-scoped management operation。非 `force` 移除遇到
这些活动项返回 `workspace_busy`。进入 `draining` 后,Registry 阻止新的路由解析,
Coordinator 关闭新的 ensure admission;已经解析但尚未开始物理工作的请求以
`workspace_draining` 失败。移除回滚时一并恢复 admission,提交后的强制清理才终止
现有 work。
Expand Down Expand Up @@ -510,27 +510,28 @@ POST /workspaces/:workspace/runtime/ensure
primary workspace 使用等价的 `POST /workspace/runtime/ensure`。两个入口都拒绝非空
body;调用方不选择 capability,也不传 timeout、keepalive 或初始化顺序。

#### Foundation(已实现)
#### 当前实现(Foundation + MCP capability)

当前 Coordinator 的职责刻意很薄:
当前 Coordinator:

1. 校验 workspace 已准确解析、受信任且未 draining;
2. 调用 Bridge 的物理 preheat/initialize,等待 ACP Channel handshake 完成;
3. 将本次成功转换为 workspace 级 10 分钟 keepalive;并发调用保留最长窗口;
4. 从 Bridge 读取 lifecycle snapshot 并返回。
4. 在同一请求观察预算内准备 MCP,并返回 lifecycle 与 `capabilities.mcp`。

`ensure` 成功只证明 ACP Channel 已完成 initialize 且可由后续 Session、MCP、Skills
等请求复用;它不证明 MCP discovery、Extension refresh 或任一 Catalog 已 ready。
若同一物理启动正在进行,并发 `ensure` 复用 Bridge 的启动 Promise;每个成功调用都
从自己的成功时刻续期 keepalive。若启动卡住,Bridge 的绝对启动 deadline 会中止并
清理该次启动,后续显式 `ensure` 可以发起新的尝试。
`ensure` 成功证明 ACP Channel 已完成 initialize,并启动或继续当前 MCP revision 的
准备。只有 `capabilities.mcp.state === 'ready'`、epoch 与 lifecycle 一致且 MCP status
来自 live runtime 时,调用方才可读取 MCP Catalog。若同一物理启动正在进行,并发
`ensure` 复用 Bridge 的启动 Promise;每个成功调用都从自己的成功时刻续期
keepalive。若启动卡住,Bridge 的绝对启动 deadline 会中止并清理该次启动,后续显式
`ensure` 可以发起新的尝试。

服务端观察预算为 60 秒。预算耗尽时请求以可重试的
`runtime_still_starting` 错误结束;底层物理启动仍由独立的绝对启动
deadline 约束。当前没有 capability 后台收敛 operation,也不会返回 capability
`starting`。`GET /runtime/status` 只观察 lifecycle,不启动或重试 runtime。
服务端观察预算为 60 秒。ACP Channel 尚未就绪时,预算耗尽以可重试的
`runtime_still_starting` 错误结束;Channel 已就绪但 MCP 尚未完成时,返回 capability
`starting`,后台继续有界收敛。`GET /runtime/status` 只观察 lifecycle 和 capability,
不启动或重试 runtime。

#### Target(未实现)
#### Target(部分实现)

后续 Coordinator 将在同一次 workspace runtime command 中固定准备标准能力
`extensions -> (mcp, skills, tools)`:
Expand All @@ -541,10 +542,11 @@ deadline 约束。当前没有 capability 后台收敛 operation,也不会返
4. 初始化标准 capability 集合并更新可轮询状态;
5. 命令完成、失败或安全排空后释放 lease。

MCP 已按 revision + epoch 实现上述收敛;Extensions、Skills 与 Tools 尚未迁移。
Target 中 Coordinator 先 prepare Extensions,再并行处理其派生能力;同一 capability
的并发工作合并。HTTP 观察预算耗尽可以先返回 capability `starting`,后台收敛受另一
个固定 deadline 约束,客户端通过 `/runtime/status` 观察终态。此语义在 capability
Coordinator 落地前不得由 SDK/UI 假设。
Coordinator 落地前不得由 SDK/UI 假设;当前只适用于已接入的 MCP。

按 capability 的 prepare 只是 Coordinator 的内部实现,不暴露 HTTP 或 SDK 接口。
新增 capability 时只修改 Coordinator 的标准能力集合和初始化逻辑。
Expand Down Expand Up @@ -593,8 +595,9 @@ deadline;前者到达可先返回 `starting`,后者不随 poll 重置。MCP

HTTP/SDK 请求超时与 operation deadline 是不同概念:

- Foundation ensure 的 HTTP 预算结束时返回可重试错误;Target capability ensure
才返回 `starting`;命令型 operation 返回 `operationId`;
- ACP 物理启动在 HTTP 预算结束时返回可重试错误;已实现的 MCP capability prepare
可以返回 `starting`,其他 Target capability 后续采用相同语义;命令型 operation
返回 `operationId`;
- 请求断开不自动宣告 operation 失败;
- operation 是否继续、取消或超时由其 deadline 和取消策略决定;
- UI 通过 operation/status 查询观察终态。
Expand Down Expand Up @@ -946,17 +949,16 @@ Catalog GET 始终保持只读,不以“页面加载”为理由启动 ACP。

- 让 WorkspaceRuntime 聚合成为唯一运行时边界;
- Bridge 收口 channel、epoch、物理 lease 和 idle 回收;
- Coordinator 只投影 runtime lifecycle,并提供无 capability 参数的 ensure/status;
- Foundation Coordinator 投影 runtime lifecycle,并提供无 capability 参数的 ensure/status;
- 将 Coordinator 纳入 workspace drain、removal 和 daemon shutdown;
- 保持现有领域 mutation 路由不变,不在 foundation 中引入 MCP、Extension 或 Skills
专属状态。

### 阶段二:收口状态与 operation(未开始)
### 阶段二:收口状态与 operation(部分完成)

- Coordinator 增加 capability、Extension generation、MCP/Skills revision 和
operation 投影;
- 所有 capability 状态绑定 epoch;
- 清除跨 epoch ready 合并;
- 已完成:Coordinator 增加 MCP capability 与 revision 投影并绑定 epoch,清除 MCP
跨 epoch ready 合并;
- 待完成:Extension generation、Skills revision 和 operation 投影;
- 将 Extension desired/applied generation 更新改为同一 runtime 回执,MCP/Skills 使用
revision + epoch 丢弃迟到结果;
- 使用绝对 deadline;幂等收敛由 status、命令型长任务由 operation 暴露终态;
Expand All @@ -966,10 +968,11 @@ Catalog GET 始终保持只读,不以“页面加载”为理由启动 ACP。
### 阶段三:迁移模块和 SDK(部分完成)

- 已完成:Workspace SDK 的 foundation ensure/status 对 runtime 路由显式使用 REST;
- 待完成:SDK config/runtime Catalog、operation 和 capability status 契约;
- 已完成:SDK MCP config/runtime Catalog 与 capability status 契约;
- 待完成:其他模块的 config/runtime Catalog 与 operation 契约;
- 待完成:Skills snapshot 增加 live source、runtime epoch 和 revision freshness;
- 待完成:Web Shell 接入 primary/qualified ensure;
- Extensions、MCP、Skills 页面迁移到统一 config/runtime/operation 模型;
- 已完成:Web Shell MCP 页面接入 primary/qualified ensure 和统一 config/runtime 模型;
- 待完成:Extensions、Skills 页面迁移到统一 config/runtime/operation 模型;
- 管理区域以无参数 runtime ensure 启动完整标准能力,各页面不再传 capability;
- Extensions 页面从 runtime Catalog 取得实际状态,不从 config refresh 调 Bridge;
- User scope 状态失效覆盖所有受影响工作区;可选事件也要 fan out;
Expand Down
Loading
Loading