Purview 是什么
Purview 实现了 MCP GUI Bridge Protocol v0.1.0。它位于你真实的 GUI 与 MCP 客户端之间,对外提供应用的一份投影:一组窗口,每个窗口携带若干语义化内容块(字段、表格、列表、通知、媒体……)以及动作。
你无需自己拼装任何协议消息。你只负责描述窗口并让它保持最新,剩下的交给库。
为什么叫 Purview
英文里的 purview 指一个人被允许看到、被允许决定的范围——常见搭配是 within the purview of(在……的职权范围之内)。这恰好就是投影的含义:投影就是 agent 对你的应用所拥有的 purview。你放进投影的内容,agent 才读得到;你暴露出来的动作,agent 才调用得到。其余的一切并不是被一道权限检查挡在门外——它根本不会出现在协议消息里。
这个词里还藏着 view,这是故事的另一半:agent 拿到的始终是你 GUI 的一份视图,而不是 GUI 本身。它无法点击你的按钮,也无法越过投影去触碰你的控件;它只能通过你定义的动作,请求某件事发生。
三个核心理念
核心不绑定 GUI 框架。 purview crate 不链接任何 GUI 工具包。它只通过你在启动时注册的一个闭包抵达主线程。
语义化,而非像素。 Agent 读到的是结构化内容块——带标签的字段、有类型的行——而不是一张需要它自行辨认的截图。
协议由库负责。 动态 tools/list、模态链、乐观并发、脱敏、通知:全部由你维护的那份投影推导得出。
该用哪个 crate?
| Crate | 适用场景 |
|---|---|
purview | 总是需要。它是核心:投影、协议、服务端。 |
purview-gpui | 你的 UI 基于 gpui。它省掉了线程调度的样板代码——参见 使用 purview-gpui。 |
心智模型
一共两条数据流,把它们分清楚是最重要的一个习惯:
读侧(GUI → 库)。 你的 UI 在变更事件中,通过此前保留的类型化句柄把新值写入投影。这是内容块唯一发生变化的地方。
写侧(Agent → GUI)。 每个动作都会成为一个 MCP 工具。它的处理器触发真实的业务逻辑或 GUI 操作;它不直接修改投影——变更会经由读侧回流。
为什么这很重要
如果处理器直接写投影,那么 Agent 触发的变更与人触发的变更就走了两条不同的路径,迟早会出现分歧。把所有变更收拢到同一个方法里——本文档的例子都统一用一个 sync() 或 bump()——投影就不可能失真。
你需要持有的三样东西
| 句柄 | 来自 | 用途 |
|---|---|---|
AppHandle<Cx> | build() | 打开窗口;读取快照 |
Window<Cx> | app.open(title) | 摘要、内容块、动作、模态、关闭 |
| 内容块句柄 | win.blocks().fields(..) 等 | 之后更新对应的内容块 |
它们全都可以廉价克隆,满足 Send + Sync,并且只持有共享核心的弱引用——所以你可以把它们存进 GUI 组件,并从任意线程调用。一旦核心被释放,它们的操作会安全地退化为空操作。