运行在 ARC 上的 blocklet 会在 /mcp 暴露一个 MCP 端点,并在 /.well-known/ 下提供一组发现文档。这些由运行时提供;blocklet 不需要开启它,也不会在缺少它们的情况下被部署。
因此,一个只知道 host URL 的 agent 可以在任何凭证存在之前连上端点、列出可用工具。而它接下来能读到什么,由 blocklet 决定,不由运行时决定。
三条连接方式
| 客户端能做什么 | 端点 |
|---|---|
| 会说 MCP | POST /mcp,streamable HTTP,无状态 |
| 能发 HTTP 但没有工具调用框架 | POST /api/afs/rpc,同一批操作的 JSON-RPC 形式 |
| 只能抓文本 | GET /llms.txt,一个指针,点名另外两条 |
三者服务同一份数据。客户端支持时优先用 /mcp。
先确认基线
匿名 tools/list 在每个 blocklet 上都必须能通:不需要凭证,不需要 initialize,也没有 session。
curl -s -X POST https://<host>/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'它至少会返回八个通用 AFS 工具。如果这一步就不通,问题出在 host 或传输层,不在访问控制。→ 连接客户端
已经失败了?
| 你拿到的 | 意味着什么 | 去哪查 |
|---|---|---|
401 带 WWW-Authenticate | 该方法不是匿名安全的,或你的凭证被拒 | 错误 · 授权客户端 |
200 带 "isError": true 与 AFS_FORBIDDEN | 调用已经触达工具。是 blocklet 没把这条路径向网络客户端开放 | 访问分档 |
| 用 owner 凭证写入依然被拒 | 符合预期。凭证不是写入开关 | 访问分档 |
tools/list 只返回八个 AFS 工具 | 该 blocklet 没有声明任何内容集合 | 工具 |
| 不确定 host 对不对 | GET /.well-known/mcp.json,看它的 url 字段 | 发现面 |
200 不代表成功。 每一次 tools/call 都要检查 result.isError。
什么决定一次调用成不成功
四道彼此独立的闸,由三个不同的方决定:运行时、blocklet、provider。凭证是给运行时的答案,所以它只过一道,另外三道原样不动。
第 3 道 —— blocklet 为该路径声明了什么 —— 是多数 agent 真正撞上的一道,任何凭证都绕不过,包括 owner 身份的凭证。
→ 访问分档,看完整的四道闸以及它们为什么是分开的
公布一个工具,不等于允许调用它
匿名 tools/list 会把写工具和读工具一起公布。不带凭证调用写工具,返回 401 和一个挑战。
这是刻意的。行为规范的 MCP 客户端只调用被公布给它的工具,所以如果隐藏写工具,客户端就永远不会发出那个能产生挑战的请求 —— 而挑战正是标准授权流程的启动信号。公布工具,是让授权变得可发现的前提。
每个 blocklet 签发自己的凭证
一个 host 上的 protected-resource 文档,把同一个 host 指为自己的 authorization server。从一个 blocklet 取得的凭证打不开另一个;凭证携带它被签发时所属的实例,运行时在每次调用时比对该实例。
不存在跨 blocklet 的凭证。
这个 board 的位置
AFS 定义路径、provider 与能力合同。本 board 讲的是从外部触达那份合同:一个 host 上存在哪些协议面、客户端如何向它们认证、以及 blocklet 必须先声明什么,外部调用方才看得见东西。
如果你的问题是「afs_read 保证什么」,去读 AFS。如果是「我的 agent 怎么才能调到它」,就留在这里。