# Give your AI sub-agent a budget, not your keys

> Source: <https://dev.to/grantor/give-your-ai-sub-agent-a-budget-not-your-keys-2e7h>
> Published: 2026-08-21 19:06:18+00:00

Spawn a sub-agent in CrewAI, LangGraph, AutoGen, or a Claude sub-agent

setup and check what it actually holds: your credentials. The parent's

keys, at full scope, forever. The throwaway agent you created to summarize

three PDFs can call every tool your orchestrator can, and the only

"revocation" is rotating keys everywhere at once.

We accept this because handing a child *less* than everything has been

genuinely hard: OAuth scopes need an authorization server someone runs;

role systems need an admin; API keys don't subdivide. So the ecosystem

quietly standardized on "copy the parent's environment" and moved on.

Here's a different shape, as an MCP server you run locally:

```
npx -y @grantor/mcp serve
# or wire it into Claude Code:
claude mcp add grantor-mcp -- npx -y @grantor/mcp serve
```

That gives any MCP-speaking framework five tools. The whole model fits in

one transcript:

```
grant    {tools: ["search","fetch"], max_uses: 20, ttl_secs: 3600}
         → {child_id: "…", sub: "…"}          # a bounded child identity

check    {child_id, tool: "search"}
         → {allow: true, remaining_uses: 19}   # gate EVERY action on this

check    {child_id, tool: "write"}
         → {allow: false, code: "CapabilityDenied"}   # not granted → denied

delegate {parent: child_id, tools: ["search"], max_uses: 5}
         → {child_id: "…"}                     # a narrower grand-child

revoke   {child_id}
         → revoked                             # authority withdrawn
```

The interesting properties are in what you *can't* do:

`delegate`

for a tool the
parent doesn't hold is refused before anything is signed. Asking for
more uses or a longer expiry silently clamps to the parent's bound.
This isn't a policy file the framework consults — the delegation chain
is cryptographically signed link by link, and verification re-checks the
narrowing math on every `check`

.`max_uses: 20`

means the 21st `check`

is
denied with `UsesExhausted`

, not logged-and-allowed.`revoke`

bumps a revocation
epoch on a public smart contract; every capability in that cohort fails
its next `check`

no matter which process holds it.And the part that makes this different from every "policy engine" you've

seen: **there is no server.** No authorization service, no policy backend,

no vendor API in the hot path. Authority anchors to a public registry

contract on Base; verification is a local computation plus one `eth_call`

that any RPC provider can serve. The broker runs on your machine, next to

the framework it guards, and holds the child keys so your agents never see

key material at all.

The zero-setup run above works because the package ships pointed at a

live shared sandbox tenant on the production registry — real chain, real

verification, publish-on-purpose demo key that controls nothing outside

the sandbox. Honest limits: it's an unaudited developer preview, the

sandbox broker self-issues its anti-replay challenge (it's holder and

verifier in one process), and use-metering is local to the broker.

Production is one contract call away (USDC on Base, no signup — your

agent can even read the machine-readable onboarding manifest and do it

itself). Docs: [https://chaingrantor.com/docs/guide/mcp-broker](https://chaingrantor.com/docs/guide/mcp-broker)

**MCP standardized what agents can
call. A2A standardized how they talk. Nobody standardized what they're
allowed to do — that's the layer this fills.**
