2026-09-23·by Sijie Wang#standmeet#architecture#design

owner-facade-from-registry

Owner MCP facade = 在两个容器上做通用的发现与调用

上级:backend-domain-modules · 相关:facade-parity · facade-directions

决定(2026-07-27,owner)

owner 的 agent(owner 自己的 MCP 客户端 / Claude Code)必须以和访客 agent 完全相同的通用方式 去触达各种能力:从容器里发现,按名字调用。不允许为每个能力单独写 host 代码。

给 owner agent 在 MCP 上开两扇通用的"发现+调用"门——每个容器一扇:

容器discover(发现)invoke(调用)
capabilitycapreg列出已注册的能力名字调用某个能力的工具,在owner 上下文
connectorHub列出已连接的 connectorconnector.invoke(category, verb, args)(不透明的门——已经存在)

"这样就通用了"——用两扇通用的门,取代 N 个显式的 owner 能力。owner 订房 = 发现 booker 能力 → 调用它;owner 设置策略 = 同样的路径;owner 使用日历 = 发现 calendar connector → 调用。 owner 这一侧是零显式能力代码

这个决定替换 / 删掉了什么

  • 整个 internal/plugins/ownercore 里显式的 cap_* 表面(约 29 个手写的 owner 能力: cap_calendar / cap_booking / cap_chat / cap_corpus_* / ……)。它们会变成从 registry 里发现出来的,而不是手写的。cap_calendar/cap_booking 尤其是 owner 点名批评过的反模式: 一个本该被externalized(外部化)的能力(booker sandbox)却被重新实现成了显式的 host 代码。 见 external-means-fully-external
  • 这是 facade-from-registryfacade-parity)的终局:每一个 facade 都由同一个能力 registry 生成、并与之校验。

唯一要建的真实机制(关键点)

capreg 当时已经有 List()(发现这一块已经做完了)。缺的那一块是在 owner 上下文里调用一个 能力——尤其是 sandbox 能力。 那时 sandbox 能力只能在访客会话里被拨通 (Capability.VisitorBinding(ctx, AssembleInput) → 按 ConversationIDdialAndListextMCPCapability/mcpAppCapability 都是 ShapeVisitorOnlyOwnerMCPBindings() 返回 [])。没有 owner 上下文的拨号路径:owner 没有访客会话,只有一个 owner_id

已建成(7f02bccc1,2026-07-29):manifest 把 owner 工具声明成数据(mcpplugin.Manifest.OwnerToolsinternal/capabilities/mcpplugin/manifest.go),routes/capload/capreg_mcp_app_owner.go 把每一条声明变成 一个 OwnerMCPBindings() 条目,其 handler 只在被调用时才拨号 sandbox,带 owner 上下文 (owner_id,没有 visitor/code/conversation),转发那次 tools/call。工具表在装配时就枚举出来, 于是 facade-parity 不用在启动时拨任何东西就能对账。sandbox 工具跑自己的逻辑时,走的还是它已经在用的 那条通用回连路径(connector.invoke + capstore + owner.meta);booker 在 mcp-servers/booker/main.go 里声明了自己面向 owner 的工具(owner 版 list_slotscalendar_cancel_booking、policy get/set、bookings-list),host 侧那份重复的 policy/slots 求值器在同一 提交里删掉。同一个洞后来在设置上又开了一次 —— 能力能声明 owner 工具却不能声明 owner 可调的字段, 于是 booker 的预约策略又被手写回 host —— 用同样的办法堵上:Manifest.Config / capconfig (cc5c1db47,2026-07-31)。

internal/ 的影响

"plugins 清空"这个目标卡在这个 build 上,而它已经走通:internal/plugins 并入 owner/ (fea7ae93f,2026-07-29),各领域自己声明 op、dispatcher 只做聚合(53733b661,2026-08-01), ownercore 本身也没了(f35e82c04,2026-08-02)。截至 2026-09-07,internal/ 下是 11 个目录 —— 8 个核心领域 + capabilities + routes + infra —— 正好就是 check-internal-dirs.sh 强制的那份白名单。

范围 / 验证

这是基础性的改动,替换掉 ownercore,必须靠真实的 owner + visitor 订房端到端测试来验证 (gcal + sandbox 重建;make test-only SPEC=booking)。编译+lint 通过不算数

状态

已上线。 owner 上下文调用 2026-07-29(7f02bccc1),plugins 拆解 2026-07-29(fea7ae93f), ownercore 删除 2026-08-02(f35e82c04)。证据文件:internal/routes/capload/capreg_mcp_app_owner.gointernal/capabilities/mcpplugin/manifest.gointernal/plugins/internal/owner/ownercore/main 上已不存在。

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →

owner-facade-from-registry