跳转至

v0.2 协议升级指南

协议版本:0.1.x → 0.2.0 目标读者:python-sdk / rust-sdk 实现工程师 发布节奏:破坏性升级,需同步发布三方(Agent / Computer / MCP Server helper)

Greenfield 阅读提示

本指南默认 SDK 已实现 v0.1 完整功能并据此描述"迁移路径"。如果你所维护的 SDK 从未实现某个子系统(典型如 DPE / Window URI 解析器),那么相关章节应按 Greenfield 实现规范阅读:

  • 关于"旧形式"的描述可作为反面参考(避免按 v0.1 模式实现)
  • 关于"新形式"和"行为约束"是 SDK 必须实现的目标
  • "迁移步骤"中提到的"修改 X 文件"对未实现的 SDK 来说是"新建 X 文件"

1. 摘要

v0.2 是一次破坏性协议升级,包含四组变更:

  1. URI 纯标识符化window://dpe:// 都变成纯标识符,不再携带元数据 query;元数据下沉到 MCP Resource.annotations + Resource._meta
  2. DPE 协议从 Finder 中独立:v0.1 把"DPE 抽象"和"文档目录浏览器(Finder)"耦合在一起;v0.2 把 Finder 从协议范围整体移除,只保留 DPE 文档抽象作为底层原语
  3. DPE 内容投递重构:DPE 内容不再走 Socket.IO——Computer 端业务层注册 DPE Resolver hook,把 DPE Resource 转成 Agent 可访问的 URI(对象存储 / 本地文件 / 任意 scheme),Agent 用应用层协议(HTTP / file / ...)自取
  4. 协议版本握手:引入 Socket.IO connect 阶段的版本校验机制(详见 versioning.md
  5. MCP 上游授权错误码:新增 4006 / 4007 / 4008 / 4011 / 4012 / 4013

核心改动一句话版

  1. Window/DPE URI 变成纯标识符(不再携带元数据 query)
  2. 元数据下沉到 MCP Resource.annotations(标准字段:priority / audience / lastModified)+ Resource._meta(A2C 扩展:fullscreen / keywords / file_type / page_count / file_uri
  3. Finder 整体从协议移除——client:list_finder / server:update_finder / notify:update_finder / ListFinderReq / DPEDocumentSummary / organize_finder 全部删除;文档发现/检索/聚合视图未来作为内置 MCP Server 重做,与协议核心解耦
  4. 新增 client:get_dpe:Agent 把 DPE URI 提交给 Computer,Computer 调本地业务 Resolver hook 转成访问 URI 返回;Resolver 实现完全交给业务方(上传 OSS / 落本地缓存 / 任意 scheme),协议不规定生命周期/可用性 4'. 新增 client:get_resources:透明转发 MCP 标准 resources/list 给 Agent(含 cursor 翻页);mcp_server 必填,Computer 不做协议级过滤;与 client:get_config 组合实现 Agent 端的 dpe / window / 业务自定义资源发现,替代 v0.1 Finder 聚合视图
  5. 新增 Socket.IO 连接必带 URL query ?a2c_version=0.2.0;Server 在 HTTP 中间件层校验,不兼容时返回 HTTP 400 + 4008
  6. 元数据字段分工原则:MCP 标准 annotationspriority / audience / lastModifiedMUST 放入 annotations;A2C 自定义字段(fullscreen / DPE 业务字段)放入 _meta。Window audience=["assistant"]、DPE audience=["user"]

2. 受影响范围

2.1 代码影响矩阵

Python SDK 路径基于 python-sdk 仓库实际现状;Rust SDK 列仅作示意——rust-sdk 实际目录结构由 rust-sdk 实现方维护,本文档不锚定具体路径,仅描述需要修改/新建的职能模块

职能模块 Python SDK 路径 Rust SDK 说明
WindowURI 解析器 a2c_smcp/computer/utils/window_uri.py rust-sdk 决定 移除 priority / fullscreen query 解析
DPE URI 解析器 a2c_smcp/computer/utils/dpe_uri.py rust-sdk 决定(v0.2 待新建) URI 纯标识符化(不解析 query);拒绝 dpe://host 形式(无 doc-ref)
organize_desktop a2c_smcp/computer/desktop/organize.py rust-sdk 决定 Resource.annotations.priority 读优先级(float [0,1]);Resource._meta.fullscreen 读全屏标记
DPE Resolver Hook(新增) a2c_smcp/computer/dpe/resolver.py rust-sdk 决定(v0.2 待新建) Computer 业务层注册接口;把 DPE URI + ResourceContents 转成访问 URI
MCP Manager a2c_smcp/computer/mcp_clients/manager.py rust-sdk 决定 维护 MCP Server 名称索引(client:get_resources 路由)+ host → MCP Server 反查索引(client:get_dpe 路由);host 注册时检测冲突 + 记 WARN;运行时按 first-registered-wins
Socket.IO Client(Agent 侧) a2c_smcp/agent/socketio/client.py rust-sdk 决定 新增 get_dpe / get_resources 方法;移除 list_finder
Socket.IO Client(Computer 侧) a2c_smcp/computer/socketio/client.py rust-sdk 决定 新增 on_get_dpe / on_get_resources 处理器;移除 on_list_finder / update_finder
数据类型 a2c_smcp/smcp.py rust-sdk 决定 新增 GetDPEReq / GetDPERet / GetResourcesReq / GetResourcesRet;删除 ListFinderReq / ListFinderRet / DPEDocumentSummary / DPEPageSummary / DPEElementDetail
错误码枚举 a2c_smcp/smcp.py::ErrorCode rust-sdk 决定 新增 4006 / 4007 / 4008 / 4011 / 4012 / 4013
协议版本常量 a2c_smcp/__init__.py::PROTOCOL_VERSION rust-sdk 决定 新增导出;SDK 包版本 MAJOR.MINOR MUST 锁定协议 MAJOR.MINOR(见 versioning.md SDK 仓库
Agent/Computer 连接逻辑 a2c_smcp/agent/socketio/client.pya2c_smcp/computer/socketio/client.py rust-sdk 决定 连接时 URL 拼 ?a2c_version=...auth 默认仅传 role(业务字段由用户回调注入,详见 data-structures.md ConnectAuth);解析 HTTP 400 body 识别 4008 → 主动 disconnect() → 抛 ProtocolVersionError
Server 连接处理 a2c_smcp/server/ 的 HTTP 中间件 + connect handler rust-sdk 决定(socketioxide 默认 HTTP 路径 /socket.io/ 在 Socket.IO handler 之前于 HTTP 层校验 a2c_versionconnect handler 处理 auth.roleserver:list_room 返回含版本
测试 tests/unit_tests/computer/tests/integration_tests/ rust-sdk 决定 所有涉及 URI query 解析、Finder 事件、keywords 参数的测试要重写或删除;新增 get_dpe / Resolver / 版本握手矩阵测试

2.2 非代码影响

  • MCP Server 示例仓库(若存在)需要更新
  • 文档站点docs/specification/docs/guides/docs/appendix/faq.md 已更新
  • 示例 / quickstart:需要按新模式改写

2.3 不变的部分(明确告知,避免过度改动)

  • 事件名(Desktop)client:get_desktop / server:update_desktop / notify:update_desktop 保持不变
  • Window URI 与 Desktop 行为:URI 形态、组织算法不变;仅元数据声明位置从 URI query 迁移到 Resource.annotations / _meta
  • Room 模型 / Server 路由:完全不变
  • 安全模型(零凭证传播、房间隔离):完全不变

3. 破坏性变更详表

# 变更点 旧形式 新形式 兼容策略
B1 Window URI query 移除 window://host/path?priority=80&fullscreen=true window://host/path 硬切换;旧 URI 解析时丢弃 query 并记录 WARN
B2 Window 元数据位置 URI query Resource.annotations.priority(float [0,1])+ Resource._meta.fullscreen + Resource.annotations.audience=["assistant"] 硬切换;priority 语义由 int [0,100] 迁移到 MCP 标准 float [0,1],audience 固定 ["assistant"]
B3 DPE URI 收缩到 Document 层 dpe://host/doc?format=mddpe://host/doc/pages/Ndpe://host/doc/elements/ID dpe://host/doc-ref(doc-ref 可单段或分段路径) 硬切换;DPE URI 纯文档标识符化——sub-path(pages/N、elements/ID)与所有 content-control query(format / depth / offset / limit / categories)全部移除;Page / Element 由 DPE 内容 JSON 在 Document 内部表达
B4 DPE 文档元数据位置 Level 0/1 response body 中的扁平字段 Resource._meta.{keywords, file_type, page_count, file_uri} + Resource.annotations.lastModified + Resource.annotations.audience=["user"] 硬切换;audience 固定 ["user"](DPE 文档是用户数据资产)
B5 Finder 整体从协议移除 client:list_finder / server:update_finder / notify:update_finder / ListFinderReq / ListFinderRet / DPEDocumentSummary / DPEPageSummary / DPEElementDetail / organize_finder 不再存在 硬删除;文档发现/检索未来作为内置 MCP Server 重做,与协议核心解耦
B6 新增 client:get_dpe 无(v0.1 通过 list_finder + MCP resources/read 直接返回内容) client:get_dpe(uri) → GetDPERet(uri=访问URI);DPE 内容不走 Socket.IO,由业务 Resolver hook 转成访问 URI(HTTP/file/任意 scheme),Agent 应用层自取 新增;SDK 必须实现该事件;Computer 必须暴露 Resolver 注册 API
B6' 新增 client:get_resources client:get_resources(mcp_server, cursor?) → {resources, next_cursor};透明转发 MCP 标准 resources/list,含 cursor 翻页;不做协议级过滤;为 Agent 提供资源发现入口(替代 v0.1 Finder 聚合视图) 新增;Computer 必须实现透明转发;mcp_server 必填,不存在返回 404
B7 host 唯一性 MUST(v0.1 后期加,跨 Server 强制唯一) SHOULD 跨 MCP Server 唯一(非 MUST);Computer 注册时检测重复 + 记 WARN(不阻塞注册);运行时 client:get_dpe 路由按 first-registered-wins 从硬约束放宽为软约束;旧实现不受影响
B8 Socket.IO 连接握手 无版本校验,任意客户端可连接 必须在 URL query 携带 ?a2c_version=...;Server HTTP 中间件层校验,不兼容返回 HTTP 400 + 4008 硬切换;旧客户端未带 a2c_version 被拒(HTTP 400)
N1 MCP 上游授权错误码 泛化为 4003 4006 / 4007(独立码) 新增;旧 Computer 返回 4003 在 Agent 侧仍可工作但体验降级
N2 DPE 资源访问错误码 4011 DPE Resolver Not Configured / 4012 Invalid DPE URI / 4013 DPE Resolution Failed 新增;为 client:get_dpe 路径提供专属错误语义
N3 SessionInfo 字段扩展 {sid, name, role, office_id} 新增 a2c_version 新增字段,对老客户端向后兼容(可忽略不识别字段)

4. 详细变更规范

4.1 Window URI 重构

URI 语法

// 旧
window://host/path1/path2?priority=P&fullscreen=F

// 新
window://host/path1/path2

校验规则

  • 解析时若 URI 含 query 部分,MUST 丢弃并记录 WARNING 级日志
  • path 段继续支持 URL 编码(c%2Fd 保持为单段)
  • host 跨 MCP Server SHOULD 唯一(非 MUST);Computer 注册重复时记 WARN,不阻塞注册

元数据声明(由 MCP Server 在 resources/list 响应中设置)

字段 类型 必需 默认 说明
Resource.annotations.priority float [0, 1] 0.0 MCP 标准;布局排序依据,值越大越优先,仅同一 Server 内比较
Resource.annotations.audience ["assistant"] 推荐 MCP 标准;Window 面向 Agent 渲染,MCP Server 应显式声明 ["assistant"]
Resource.annotations.lastModified ISO 8601 MCP 标准;v0.2 Computer 透传不排序
Resource._meta.fullscreen bool false A2C 扩展;全屏渲染标记

organize_desktop 行为变更

  • 输入:windows: list[tuple[SERVER_NAME, Resource, ReadResourceResult]](Resource 对象必须完整携带 annotations_meta
  • 排序键改为 Resource.annotations.priority(float),fullscreen 标记改读 Resource._meta.fullscreen
  • 不再解析 URI query

4.2 DPE URI 重构

URI 语法

// 旧(多层 URI + content-control query)
dpe://host/doc-ref?format=markdown&offset=0&limit=20
dpe://host/doc-ref/pages/N?categories=table
dpe://host/doc-ref/elements/ID

// 新(纯文档标识符,只到 Document 一层;doc-ref 可分段路径)
dpe://host/doc-ref
dpe://host/reports/2026/annual                # 分段路径示例
dpe://host/src/main/java/Foo.java             # 含扩展名示例

解析器行为

  • 拒绝 dpe://host 形式(无 doc-ref);返回解析失败 / 4012
  • doc-ref 可分段:从 host 之后第一个 / 起到 URI 结尾的整段 path,整体作为文档唯一标识;不再有 sub-path(pages/N、elements/ID)概念——Page / Element 在 DPE 内容 JSON 内部表达
  • 拒绝 query / fragment:解析时检测到则记录 WARN 并丢弃;Agent SDK 构造 URI 时不应附加 query 或 fragment
  • host 跨 MCP Server SHOULD 唯一(非 MUST)——client:get_dpe 通过 URI 中 host 反查 Server,重复时记 WARN + 先注册优先

文档元数据声明(替代旧的 URI query / Level 0 body)

每个文档作为一个 Resource 出现在 resources/list 响应中:

Resource(
    uri="dpe://com.example.docs/rpt-2026",
    name="2026 年度报告",                              # = title
    description="2026 年度财务与运营报告",              # = summary
    mimeType="application/json",
    annotations=Annotations(
        audience=["user"],                            # DPE 文档是用户数据资产,固定 ["user"]
        lastModified="2026-01-15T08:30:00Z",
    ),
    _meta={
        "keywords": ["财务", "年报"],
        "file_type": "xlsx",
        "page_count": 12,                             # 推荐:Agent 据此规划翻页
        "file_uri": "file:///data/reports/2026-annual.xlsx",
    },
)

不再有 v0.1 的 Level 0/聚合端点

dpe://host 形式(v0.1 用作 catalog 端点)整体移除。文档发现走 MCP 标准 resources/list 或未来的 Finder MCP Server。

详见 DPE 文档协议


4.3 client:get_dpe 与 DPE Resolver Hook(新增)

设计动机

v0.1 的 DPE 内容通过 MCP resources/read 直接经 Socket.IO 返回给 Agent。对大体量文档(Excel / PDF / PPT 数十 MB)这是不可行的——Socket.IO 默认 maxHttpBufferSize 1MB;即便调大,单消息阻塞通道、Server 全量缓冲等问题都会暴露。

v0.2 把 DPE 内容投递与 A2C 传输层解耦:

Agent → client:get_dpe(uri) → Computer → DPE Resolver Hook → 访问 URI
                                     业务存储(OSS / 本地 / etc)
        Agent ← 应用层协议(HTTP / file / ...)拉取 ←

A2C 协议本身承载 DPE 内容;URI 的生命周期、可用性、签名机制全部交给业务方。

新增事件

事件常量 事件名称 数据结构
GET_DPE_EVENT client:get_dpe GetDPEReqGetDPERet
class GetDPEReq(AgentCallData, total=True):
    agent: str
    req_id: str
    computer: str
    uri: str                  # dpe://host/doc-ref(doc-ref 可单段或分段路径)
    timeout: NotRequired[int]


class GetDPERet(TypedDict, total=False):
    uri: str                  # 业务 Resolver 输出的访问 URI
    mime_type: NotRequired[str]
    size: NotRequired[int]
    req_id: str

Computer 必须实现 DPE Resolver 注册 API

class DPEResolver(Protocol):
    async def resolve(
        self,
        dpe_uri: str,
        contents: list[ResourceContents],   # Computer 已从 MCP Server 读到的内容
        hint: ResolverHint,                  # mcp_server_name / mime_type 等上下文
    ) -> ResolvedResource: ...


# Computer SDK 启动时业务方注册
computer.register_dpe_resolver(MyOSSResolver())

未注册时收到 client:get_dpe 必须返回 4011 DPE Resolver Not Configured——禁止降级到 inline 透传 ResourceContents。

Computer 处理流程

  1. 接收 client:get_dpe(uri=dpe://...)
  2. 校验 URI(dpe scheme + 非空 host + 非空 doc-ref + 无 query/fragment);非法返回 4012
  3. 检查 Resolver 是否注册;未注册返回 4011
  4. 解析 host → 定位对应 MCP Server
  5. 调 MCP Server 的 resources/read(uri) 拿 ResourceContents
  6. 调 Resolver resolve(uri, contents, hint) 拿访问 URI
  7. 返回 GetDPERet(uri=访问URI, ...)
  8. 任一步失败 → 返回 4013 DPE Resolution Failed(含 reason)

详见 DPE 文档协议


4.4 MCP Server host 唯一性(从 MUST 放宽为 SHOULD + Computer WARN)

v0.2 起 host 跨 MCP Server SHOULD 唯一(非 MUST)——保留 host 作为路由依据的同时引入软约束 + 显性警告。

路径与路由依据

协议路径 路由依据 host 角色
client:get_dpe(uri=dpe://host/...) URI 中的 host 反查 MCP Server 索引 路由关键字——保持 URI 自包含寻址能力
client:get_resources(mcp_server=name) mcp_server 字段直接定位 不参与路由
client:get_desktop organize_desktop 按 MCP Server 名称分组 仅参与单 Server 内的窗口排序

Computer 端实现要求(v0.2 新规约)

阶段 行为
MCP Server 注册时 Computer MUST 检测新 Server 的 host 是否与已有 Server 冲突;冲突时记 WARN 日志(含两个 Server 名称 + 共用 host);仍允许注册成功(不阻塞业务)
client:get_dpe 路由时 (a) host 唯一匹配 → 路由到该 Server;(b) host 多个匹配 → first-registered-wins + WARN;(c) host 无匹配 → 返回 4013 DPE Resolution Failed

设计取向

  • 保留 URI 自包含寻址:Agent 持有任意 dpe URI 即可调 get_dpe,不需要外部元信息
  • 软约束 + 显性 WARN:host 重复是 MCP Server 命名 bug;Computer 不阻塞注册(避免硬故障),但通过 WARN 让冲突可见
  • first-registered-wins:路由确定性——后注册的同 host 资源在 get_dpe 路径上被错误路由到先注册者,这是 visible 信号,促使业务方修复

实践建议

  • MCP Server 采用反向域名风格(com.example.<service>)天然回避冲突
  • 同一 Computer 部署多个 MCP Server 时统一规划 host 命名空间
  • 监控 Computer WARN 日志中的 host 冲突告警

详见 DPE host 路由策略 / Window URI 校验规则


4.5 错误码新增

MCP 上游授权(4006 / 4007)

代码 名称 含义
4006 Tool Authorization Required 工具需要 MCP 上游授权(如 OAuth),Computer 当前无有效凭证
4007 Tool Authorization Failed 上游授权流程失败、Token 失效、刷新失败、权限不足

详见 error-handling.md 4006/4007 判定决策表

DPE 资源访问(4011 / 4012 / 4013)

代码 名称 含义
4011 DPE Resolver Not Configured Computer 未注册 DPE Resolver hook
4012 Invalid DPE URI URI 不符合 dpe:// scheme 规范
4013 DPE Resolution Failed Resolver 执行失败(业务异常 / 上游 MCP Server 不可用 / 等)

详见 error-handling.md DPE 资源访问错误


4.6 协议版本握手(新增)

客户端

# python-sdk 内部实现
from a2c_smcp import PROTOCOL_VERSION

await sio.connect(
    f"wss://server.example.com?a2c_version={PROTOCOL_VERSION}",
    socketio_path="/smcp",
    auth={"role": "agent"},
)

Server

HTTP 中间件层校验 a2c_version,不兼容返回 HTTP 400 + 4008。详细规范、Python/Rust 实现示例、跨语言通用约束见 versioning.md

Client SDK 收到 4008 后必须主动 disconnect

防止底层库自动重连导致死循环。详见 versioning.md § 4. Client SDK MUST 主动断开连接


5. 迁移步骤

5.1 MCP Server 实现者(最小改动)

  1. Window:把 URI query 中的 priority / fullscreen 改成 Resource 元数据

    # 旧
    Resource(uri="window://host/path?priority=80&fullscreen=true", ...)
    
    # 新
    Resource(
        uri="window://host/path",
        annotations=Annotations(priority=0.8, audience=["assistant"]),
        _meta={"fullscreen": True},
    )
    

  2. DPE:把所有 query 参数移除;把文档元数据迁到 Resource 上

    Resource(
        uri="dpe://host/doc-ref",
        name="...", description="...", mimeType="application/json",
        annotations=Annotations(audience=["user"], lastModified="..."),
        _meta={"keywords": [...], "file_type": "xlsx", "page_count": 12, "file_uri": "..."},
    )
    

  3. DPE 内容形态自决:A2C 协议不规定 resources/read 响应 JSON schema;与 Agent / Resolver 之间约定即可

5.2 Computer SDK 工程师

  1. WindowURI 解析器:移除 query 解析;解析时若有 query,丢弃并记录 WARN
  2. DPE URI 解析器:拒绝 dpe://host 形式(无 doc-ref);拒绝 query 参数
  3. organize_desktop:从 Resource.annotations.priority 读优先级;从 Resource._meta.fullscreen 读全屏标记
  4. 删除 organize_finder / Finder 事件处理:v0.2 协议无 Finder
  5. 新增 DPE Resolver 注册 API:暴露 register_dpe_resolver(resolver) 接口
  6. 新增 client:get_dpe 处理器:按 §4.3 处理流程 实现
  7. MCP Manager:维护两套索引——(a) MCP Server 名称索引(用于 client:get_resources 直接定位);(b) host → MCP Server 反查索引(用于 client:get_dpe 按 URI 中 host 路由);注册时检测 host 重复 + 记 WARN(不阻塞);多匹配时 first-registered-wins
  8. 错误码枚举:新增 4006 / 4007 / 4008 / 4011 / 4012 / 4013

5.3 Agent SDK 工程师

  1. 删除 list_finder 方法
  2. 新增 get_dpe(uri) 方法:返回 GetDPERet;Agent 业务代码拿到访问 URI 后用应用层协议自取实际内容
  3. 新增 get_resources(mcp_server, cursor=None) 方法:透明转发 MCP resources/list;返回 {resources, next_cursor}mcp_server 必填
  4. HTTP / file URI 内置拉取:建议 SDK 内置 http(s):// 与 file:// 的拉取能力;其他 scheme 由用户业务代码处理
  5. 不缓存 URI 跨 session:拿到 URI 仅在本次会话使用;过期时重新调用 get_dpe
  6. 协议版本握手:连接 URL query 拼 ?a2c_version=...;解析 HTTP 400 body 识别 4008 → 主动 disconnect() → 抛 ProtocolVersionError
  7. DPE 发现链路:典型路径是 get_config(computer) → 对每个 server name 翻页 get_resources → 按 scheme/元数据自决过滤 → get_dpe

6. 测试矩阵

6.1 URI 解析器

用例 Window DPE 预期
纯标识符 URI window://host/path dpe://host/doc-ref ✅ 解析成功
带 query window://host/path?priority=0.8 dpe://host/doc-ref?format=md ✅ 丢弃 query + WARN
多段路径 window://host/a/b/c dpe://host/reports/2026/annual ✅ 解析成功(doc-ref="reports/2026/annual")
URL 编码 window://host/a%2Fb ✅ 单段,解码 a/b
缺 host window:///path dpe:///doc-ref ❌ 解析失败
DPE 缺 doc-ref dpe://host ❌ 解析失败 / 4012
DPE 含 query dpe://host/doc?format=md ❌ WARN + 丢弃 query;解析后 doc-ref="doc"

6.2 organize_desktop(与 v0.1 保持算法一致,仅元数据来源变化)

  • 优先级排序:从 annotations.priority(float)降序
  • 全屏处理:从 _meta.fullscreen,per-Server 处理
  • 缺失值同义:annotations is Noneannotations.priority is None 等价处理为 0.0

6.3 client:get_dpe + Resolver

用例 预期
注册 Resolver + 合法 dpe URI ✅ 返回 GetDPERet(uri=...)
未注册 Resolver 4011 DPE Resolver Not Configured
非法 URI(缺 doc-ref / 非 dpe scheme / 含 fragment 等) 4012 Invalid DPE URI
Resolver 抛异常 4013 DPE Resolution Failed(含 reason)
上游 MCP Server resources/read 失败 4013 DPE Resolution Failed
Resolver 返回 https URL ✅ Agent 应用层 GET 拿到内容
Resolver 返回 file URL(同机部署) ✅ Agent 应用层读本地文件

6.3.1 client:get_resources(资源发现)

用例 预期
已注册的 mcp_server + cursor=None ✅ 返回 {resources, next_cursor?}(透明转发 MCP resources/list
已注册的 mcp_server + 翻页 cursor ✅ 拿下一页;末页 next_cursor 缺省
未注册的 mcp_server 404 Not Found(错误信息含 server 名称)
Computer 不做协议级过滤 ✅ 响应中含任意 scheme 的 Resource(dpe / window / 业务自定义),由 Agent 自决过滤
完整发现流程 ✅ Agent 用 get_config + 多次 get_resources 翻页 + 自决过滤 → 拿到 dpe URI 列表 → get_dpe 拿访问 URI

6.4 host 路由 / 唯一性

用例 预期
两个 MCP Server 声明不同 host ✅ 注册成功;get_dpe 按 host 反查正确路由
两个 MCP Server 声明相同 host(同一 Computer) ⚠️ 注册成功但记 WARN(含两个 Server 名 + 共用 host)
host 重复时 get_dpe(uri=dpe://repeated-host/...) ⚠️ 路由到先注册的 Server + 记 WARN;后注册者的同 URI 资源无法被命中
get_dpe(uri=dpe://unknown-host/...)(host 不在任何 Server 索引中) 4013 DPE Resolution Failed
单 MCP Server 内 URI 重复(MCP 标准已禁) ❌ 由 MCP resources/list 自身校验拒绝

6.5 协议版本握手

场景 Client Server 预期
完全匹配 0.2.0 0.2.0
PATCH 差异 0.2.1 0.2.0
MINOR 差异(v0.x) 0.2.0 0.3.0 ❌ HTTP 400 + 4008
MAJOR 差异 1.0.0 0.2.0 ❌ HTTP 400 + 4008
缺失 a2c_version 0.2.0 ❌ HTTP 400
非法版本号 "abc" 0.2.0 ❌ HTTP 400
中间件前置性 connect handler 抛异常 0.2.0 校验仍正常工作

6.6 集成测试

  • 完整 get_dpe 流程:Mock MCP Server 返回 dpe:// Resource → Agent client:get_resources 发现 → Agent client:get_dpe 解析 → Computer 调 Resolver → Agent 用应用层拉取
  • 4008 死循环防御:底层 socketio 自动重连开启时,收到 4008 SDK 必须主动 disconnect

6.7 回归测试重点

  • Desktop 全链路:list → notify:update_desktop → 重新 list(Window 行为完全不变,仅元数据来源变化)
  • 工具调用全链路:未受 v0.2 影响,确保不破坏

7. 兼容性策略

7.1 协议层:硬切换

v0.1.x 与 v0.2.0 在 URI 形态、Finder 移除、get_dpe 新增等多处无法互通。Server 端通过 HTTP 中间件 a2c_version 校验,不兼容直接拒绝(HTTP 400 + 4008)。

不内建 v0.1 MCP Server fallback

v0.2 SDK MUST NOT 内建针对 v0.1 MCP Server 的 URI query fallback 解析。当 v0.2 Computer 遇到只在 URI query 中携带 ?priority= / ?fullscreen= 的 v0.1 MCP Server 时:

  • 按 v0.2 校验规则丢弃 URI query 部分(仅 WARN)
  • 不读取 _meta / annotations 之外的元数据来源
  • Desktop 中该窗口降级显示为 priority=0.0, fullscreen=false

理由:保持协议纯粹;用户感知到降级会主动升级 MCP Server,比静默兼容更早暴露问题。

7.2 数据层:Agent 视角

  • Window 端 Agent 看到的 Desktop 字符串列表形态不变
  • DPE 端 Agent 拿到的是访问 URI(v0.1 没有这个语义,是新增);具体内容由应用层拉取

7.3 MCP Server 生态

  • 旧 MCP Server(只输出 URI query 形态)在 v0.2 Computer 下 Desktop MUST 降级priority=0.0, fullscreen=false 并 WARN
  • 旧 MCP Server(实现 v0.1 DPE Level 0)在 v0.2 Computer 下,Level 0 响应被忽略(Computer 不再调用)

结论:v0.2 Computer 对旧 MCP Server 宽容(降级运行),但 v0.1 Computer 无法消费 v0.2 MCP Server。升级顺序:Computer 先于 MCP Server。

7.4 建议的升级顺序

阶段 1:发布 v0.2 Computer SDK(含 DPE Resolver API + get_dpe + get_resources)
阶段 2:用户升级 Computer 到 v0.2,业务方注册 Resolver
阶段 3:发布 v0.2 MCP Server Helper(Window 用 annotations,DPE 用 _meta)
阶段 4:MCP Server 增量升级(Window/DPE 元数据迁移)
阶段 5:发布 v0.2 Agent SDK(含 get_dpe / get_resources 客户端 + 应用层拉取)
阶段 6:Agent 升级;旧 v0.1 客户端无法连接 v0.2 Server,由 4008 提示用户升级

8. 版本号与发布

8.1 语义化版本

versioning.md PATCH 自由 / MINOR 严格 / v0.x 规则:v0.1 → v0.2 是 MINOR bump(v0.x 阶段 MINOR 也是破坏性)。

8.2 发布清单

  • 协议规范文档(docs/specification/docs/migrations/)已更新
  • python-sdk 实现完成 + 测试通过
  • rust-sdk 实现完成 + 测试通过
  • python-sdk 包版本 0.2.0 发布
  • rust-sdk crate 版本 0.2.0 发布
  • CHANGELOG / 升级公告已发出

8.3 文档变更

  • docs/specification/dpe.md新建(替代旧 finder.md)
  • docs/specification/finder.md已删除(Finder 移出协议范围)
  • docs/guides/finder-sdk-guide.md已删除
  • docs/specification/desktop.md:已更新(priority float / audience / _meta.fullscreen
  • docs/specification/data-structures.md:删除 ListFinderReq / ListFinderRet / DPEDocumentSummary / DPEPageSummary / DPEElementDetail;新增 GetDPEReq / GetDPERet
  • docs/specification/events.md:删除 client:list_finder / server:update_finder / notify:update_finder;新增 client:get_dpe
  • docs/specification/error-handling.md:新增 4006/4007/4008/4011/4012/4013
  • docs/specification/architecture.md:DPE 章节重写(去掉 Finder Organizer,加入 Resolver Hook)
  • docs/specification/versioning.md:协议依赖 / SDK 版本锁定 / 4008 disconnect / 等
  • docs/appendix/faq.md:DPE Q&A 重写

9. 联系与反馈