The headline pitch of #490 — bot-to-bot federation falls out of MCP+WAC+DID — is currently only true in principle. Today, an agent talking to two pods has to register both as separate MCP servers in its client. That works but isn't federation; it's just client-side aggregation.
A real federation primitive lets a bot on pod A invoke an MCP tool on pod B, with WAC enforced on both ends. No new wire format, no new identity model — just the existing primitives composed.
What
A new MCP tool:
```
call_remote_pod — Invoke an MCP tool on another pod by URL.
arguments:
pod_url: string — the remote pod's origin
tool: string — tool name to call on the remote
arguments: object — arguments to the remote tool
auth: object (optional) — credentials for the remote
type: "bearer" | "nip98" | "dpop"
... type-specific fields
```
The MCP server:
Validates the caller has `acl:Write` on a designated `/private/federation/` resource (the WAC gate on outbound federation — owner decides which agents are allowed to initiate)
Constructs an MCP request to the remote pod with the provided credentials
Forwards the response back as the local tool result
Logs the exchange (for audit)
Scope
New tool handler in `src/mcp/tools.js`
Local WAC gate on `/private/federation/` (or configurable)
HTTP client for remote MCP calls (with timeout, error handling)
Audit log entry per call
Test: spin up two test servers, have one call the other's `read_resource`
Doc with bot-to-bot worked example
Estimated ~200-350 lines including tests.
Open design questions
Where does the federation gate live in the ACL tree? Proposed: `/private/federation/` with default `acl:Write` = owner only. Agents the owner trusts get explicit `acl:agent` entries.
Credential storage: do bots store remote-pod credentials in their pod, or get them per-call from the user? Pod-resident credentials are convenient but a security surface.
Cycle detection: should we set a max federation depth to prevent A → B → A loops? Probably yes; a header like `MCP-Federation-Depth` capped at 3.
Acceptance
`call_remote_pod` invokes an MCP tool on another pod
Activity
feat(mcp): subscribe, read_acl/write_acl, call_remote_pod (closes #494 …