Skip to content

传输与适配器 ​

Surface 协议与传输无关。传输负责携带请求包络、证明发送者身份、返回响应并处理连接失败;它不能复制能力过滤、确认或业务授权。

@plingjs/surface 内没有生产传输。这个包刻意很小:不包含 HTTP 服务、会话数据库、WebSocket 桥、MCP server 或 OAuth 实现。参考案例展示这些部件,但它们是可改造的示例,不是通用服务。

职责划分 ​

层负责不负责
Surface包络校验、暴露交集、限额、防重放、审计元数据Cookie / token 解析、网络路由、业务规则
传输适配器身份验证、来源检查、消息分帧、请求 id、限流与防重放 port工具语义、确认界面、业务状态
网关 / 宿主会话生命周期、撤销、租户策略、审计存储替代页面执行器
外部客户端发现、决策、调用、展示进度批准自己的高风险请求

常见绑定 ​

WebSocket 或 HTTP。 同源 WebSocket 可以把打开页面接到可信桥。桥必须验证页面会话,把一个 socket 绑定到一个用户与租户,并拒绝跨用户消息。普通 HTTP 端点也需要等价的身份与来源检查。

MCP。 MCP 是面向 Agent runtime 的实用客户端绑定。本地 stdio facade 可以把 MCP 工具转换为 describe 与 invoke,但它仍需要页面连接和可信身份路径。不要创建“批准待处理动作”的 MCP 工具;批准属于页面的真人界面。

浏览器扩展或 postMessage。 postMessage 桥必须校验 event.origin、通道 nonce 与目标窗口。生产默认不能使用通配目标来源。桥只应暴露 Surface 方法,不能变成任意脚本执行器。

会话与所有权 ​

传输必须确定请求属于哪个页面会话。交互式页面可以把一个连接绑定到一个打开页面与一个用户会话。服务端网关可以在用户明确开启外部访问后创建页面会话,再与 Agent token 配对。配对码应短期、一次有效,并由服务端交换。

只保存下一次请求真正需要的信息。不要把用户 Cookie、页面管理密钥或 Agent token 放进另一侧上下文。一个能调用所有租户、却不绑定用户会话的网关,已经抹掉了授权与连通性的区别。

失败行为 ​

未认证 socket、未知消息形状、不支持的协议版本、过期配对码、重复领取配对码和页面断连都应 fail-closed。保留结构化错误,让客户端能区分“页面断开”“能力被拒绝”和“业务失败”。

invoke 等待真人审批时,describe 仍应可用。若传输把所有消息串行化,Agent 在长时间确认中就无法重新观察页面;若全部并发,两次审批又可能混淆。参考桥通常串行 invoke,同时允许 describe 继续。

适配器评审 ​

采用一种传输前,验证:

  1. 它在调用 surface.handle 前验证来源与会话。
  2. 它把连接绑定到一个用户、租户和会话。
  3. 它只转发协议消息,并限制消息大小。
  4. 它保留 request.id,重试时不会无脑复用。
  5. 它允许 invoke 等待时继续 describe,但不并发执行变更。
  6. 页面断连或会话撤销时 fail-closed。
  7. 它测试了第二个用户使用第一个用户连接而被拒绝。

协议内核的小 API 是对适配器的约束,不是缺少设计。适配器是网络现实进入系统的位置,因此值得与页面执行器接受同样的评审。

仓库里的进程外 Agent 示例与已鉴权 Todo 示例可以作为参考,但都不是生产身份服务。部署传输必须按自己的威胁模型重新审查。