跳到主要内容

ARC 开发者文档

访问分档

一次调用要过四道彼此独立的闸:方法白名单、凭证、路径策略、provider 能力。凭证只过其中一道,不是四道。

一次调用能否成功,由四道闸按顺序决定。它们彼此独立:过了一道,不说明下一道也能过。

最常见的误解是以为有凭证就够了。凭证只过第 2 道。第 3、4 道依然生效 —— 在一个没有声明任何网络规则的 blocklet 上,即使是 owner 身份的调用方,写入照样被拒。

#由谁决定失败长什么样
1方法白名单这个 JSON-RPC 方法是否匿名安全401 + WWW-Authenticate
2凭证你发的 bearer token 或 session cookie401 + WWW-Authenticate
3路径策略blocklet 为该路径声明了什么200,带 isErrorAFS_FORBIDDEN
4provider 能力该路径背后的 provider 实现了什么200,带 isError 与「不支持」错误

第 1、2 道在传输层:直接以 HTTP 状态码答复,没有 JSON-RPC 结果。第 3、4 道发生在一次成功的 MCP 调用内部 —— 调用本身通了,操作没通。见错误

为什么是四道

因为它们由三个不同的方决定,谁也不能替谁回答。

由谁决定它真正在问什么
1、2运行时这个方法在没有调用方时也安全吗?这个调用方是他自称的那个人吗?
3blocklet我把这条路径向网络开放了吗?
4provider这个操作我到底实现了没有?

这就是凭证不够用的原因,也是「换一个更高权限的凭证」同样没用的原因:凭证是给运行时的答案,而运行时并不拥有第 3、4 道闸。没有任何 token 能代替 blocklet 发言,也没有任何 token 能凭空补上 provider 从未实现的操作。

失败形态也由此而来。第 1、2 道在触达工具之前就判完了,所以只能用 HTTP 答复;第 3、4 道是已经跑起来的代码判的,所以答在一个 200 里面。

第 1 道 —— 方法白名单

不带凭证时,只有这些被允许:

匿名允许匿名不允许
initializenotifications/initializedtools/callafs_writeafs_deleteafs_exec
tools/listresources/listprompts/list其他任何方法,包括未知方法
tools/callafs_readafs_listafs_searchafs_statafs_explainsearch_contentlist_contentget_content

规则是 fail-closed:不在清单上的一律拒绝;批量请求中每一条都必须被允许,否则整批拒绝。

第 2 道 —— 凭证

三种过法:

凭证从哪来
匿名
认证Authorization: Bearer blocklet-… 或 DID-Connect session cookie授权客户端device grant
loopback operator经校验的同机 socket peer,仅 Node 运行时无需获取。不通过网络提供;Cloudflare 运行时从不授予

Role

人在批准一个客户端时,同意界面会要求选一个访问级别。提供四种:

Role
owner同意界面上的默认值
admin
member
guest

凭证携带这个人所选的 role,作用域限于该 blocklet 实例。它不是全局 role:同一个人可以在一个 blocklet 上是 owner,在另一个上毫无权限。

role 是上界,不是授予。 它打不开第 3 道闸关掉的路径。

第 3 道 —— 路径策略

这是大多数调用方真正撞上的一道,也是任何凭证都绕不过的一道。

blocklet 逐路径决定网络客户端可以做什么。没有被声明的路径对网络关闭 —— 对 owner 也一样。拒绝信息会直接给出修法:

json
{
  "result": {
    "content": [{
      "type": "text",
      "text": "AFS_FORBIDDEN: Forbidden at /instance/notes.txt: network clients cannot write base paths; use a resolver overlay or internal code"
    }],
    "isError": true
  },
  "jsonrpc": "2.0",
  "id": 3
}

读和列出是同一种形状,文案换成 cannot read base paths / cannot list base pathsdeclare a networkRead rule or use an overlay

声明带来的差别,用两个 blocklet 对照:

调用什么都没声明的 blocklet声明了集合且 readRole: guest 的 blocklet
匿名 afs_list /拒绝200
匿名 afs_list /packages拒绝200
匿名 afs_list /.knowledge拒绝拒绝,因为这条路径同样没被声明
匿名调已声明集合的 list_content工具未注册200
owner 凭证 afs_write 任一 base path拒绝拒绝

最后一行是要记住的那条。从网络写入不是凭证能打开的东西,它需要一个 resolver overlay 或运行在 blocklet 内部的代码。如果你要做的 agent 必须写入,那是 blocklet 拥有者的决定 —— 见声明 agent 能看到什么

第 4 道 —— provider 能力

每条路径由一个 provider 提供服务,而它只实现其中一部分操作。afs_stat 会同时报告 provider 能做什么、以及你被允许做什么:

json
{
  "capabilities": ["list", "read", "stat", "search", "write", "delete", "exec", "explain"],
  "accessMode": "readonly"
}

capabilities 是 provider 的实现。accessMode 是你过完第 3 道之后的有效访问。一条路径可以在 capabilities 里列着 write,而对你仍然是 readonly

把某个操作写进集成之前先查 capabilities。这些操作所属的合同见 AFS

实际含义

  • 读取已发布内容不需要任何凭证 —— 前提是 blocklet 声明了它。这是大多数 agent 的预期路径,也是内容工具存在的意义。
  • 取凭证值得做 的场景是:你需要某个特定的人所看到的数据,或者该 blocklet 已经向网络开放了写入路径。
  • 凭证不是写入开关。 如果认证之后写入仍被拒,原因是第 3 道闸,而只有 blocklet 拥有者能改。