Skip to main content

What a Zanzibar-Style Relationship Graph Buys a Deploy MCP Server Over a Scoped API Key

8 min readDora NodaDora Noda
Share
On this page

An agent holds a valid API key scoped to tenant:acme, scope:write. That key can call rollback on every app acme owns — including the one currently mid-incident, where an on-call engineer just told the agent, in the same chat thread, "don't touch checkout-api, we're diagnosing a data corruption bug." The key doesn't know that. It was minted before the incident started, and it's just as valid after. Nothing about "scope:write" changes when the context around the call does.

That's the gap AuthZed is now pitching SpiceDB — its open-source, Zanzibar-inspired permissions database — to close for AI agents specifically. The pitch: relationship-based access control (ReBAC), where "can this agent call rollback on this app" is answered by graph reachability across live relationship data, not by a scope string baked into a token at issuance. Here's what that actually buys a deploy/rollback MCP server, with the schema to back it up — and the honest cost of adding another stateful service to get it.


What ReBAC actually checks

A scoped API key encodes a decision made once, at mint time: this key, these scopes, until it expires or gets rotated. Everything the key can and can't do has to be squeezed into that scope string up front. Google's 2019 Zanzibar paper — the design SpiceDB implements — takes a different premise: model permissions as a graph of relationships between subjects and resources, and answer each request by walking that graph at request time, against whatever the relationship data says right now.

The vocabulary is deliberately small. A relation links a subject to a resource (agent:codex-1 is a member of team:ops). A permission is a computed set built from relations — union, intersection, or exclusion of other relations and permissions. A check asks whether a specific subject has a specific permission on a specific resource, and the answer comes from traversing the graph of relationship tuples stored in the database, not from decoding a token.

The practical difference: revoking access means deleting one relationship tuple (agent:codex-1 is no longer a member of team:ops), and it takes effect on the very next check — no key rotation, no token blacklist, no waiting for an expiry window to lapse.

A schema for a deploy/rollback MCP server

Here's what that looks like modeled for a platform that exposes deploy and rollback as MCP tools — the shape of an AI-agent-operated PaaS:

text
definition user {}
 
definition team {
  relation member: user
}
 
definition tenant {
  relation owner: team
}
 
definition agent {
  relation operator_of: tenant
  relation scoped_to: app
}
 
caveat not_frozen(freeze_active bool) {
  freeze_active == false
}
 
definition app {
  relation tenant: tenant
  relation deploy_freeze: tenant#owner with not_frozen
 
  permission deploy = tenant->owner->member + agent->scoped_to
  permission rollback = (tenant->owner->member + agent->scoped_to) & deploy_freeze
}

Two things carry the whole design. First, deploy and rollback are computed, not stored — they're the union of "member of the tenant's owning team" and "an agent explicitly scoped to this app," evaluated fresh on every check. Second, rollback intersects that set with deploy_freeze, a relation carrying a caveat: a CEL expression (freeze_active == false) attached to the relationship itself. When an incident starts, one write flips freeze_active to true on that single app's tuple. Every agent that had rollback access a second ago loses it instantly — without anyone rotating a key, editing a role, or touching the agent's own permissions at all.

The call a scoped key structurally can't make

Now the actual check, the one the cold open described. The agent calls the MCP server's rollback tool against app:checkout-api. The server issues:

text
CheckPermission(
  resource: app:checkout-api#rollback,
  subject: agent:codex-1
)

SpiceDB walks the graph: is agent:codex-1 in tenant->owner->member (no — it's not a human team member) or agent->scoped_to (yes — it was granted scoped access to this specific app)? That branch resolves to true. Then it evaluates the intersection: is deploy_freeze present and does its caveat evaluate true? The freeze tuple for checkout-api has freeze_active: true — the caveat evaluates false — so the intersection collapses to empty. Denied, specifically on this app, specifically right now, with every other app the agent is scoped to unaffected.

A flat scoped key has no way to express that outcome. tenant:acme, scope:write is a single claim evaluated once at token-verify time — it can't intersect against a second, independently-updated fact (this one app is frozen) without either minting an entirely new, narrower key mid-incident (who does that, at 2 a.m., under pressure?) or building a second out-of-band check that duplicates the same logic the key was supposed to encode. The scoped key isn't missing a feature here; it's the wrong shape of primitive for a decision that depends on two independently-changing facts intersecting at check time.

What "machine frequency" actually means

The MCP ecosystem already has an answer for can this agent connect to this server at all — Enterprise-Managed Authorization (EMA), the extension that went stable in June 2026, hands that decision to the identity provider via a token issued once at session start. What EMA explicitly doesn't do — by its own spec's design, not by oversight — is re-evaluate anything after that token is minted. A valid EMA-issued scope is a ceiling set once; it says nothing about the state of checkout-api five minutes into a live incident.

That's the distinction AuthZed is selling ReBAC on for agents: a check per tool call, not a decision per session. Every deploy, every rollback, every destructive action an agent takes generates a fresh CheckPermission call against current relationship state, not a cached scope decision from whenever the token was issued. AuthZed's own materials cite SpiceDB scaling to millions of authorization checks per second and trillions of stored relationships — numbers aimed squarely at "check on every call" being viable at agent-driven volumes, where a single agent session might invoke a dozen tools in a minute, each one a candidate for its own authorization decision.

The other capability this unlocks: transitive delegation that's revocable in one write. agent->scoped_to in the schema above means an agent's access to checkout-api can be granted (or pulled) independent of its team membership, its tenant-level role, or any other key it holds — because the relationship graph tracks this specific edge, not a bundle of scopes serialized into one token. A scoped key bundles everything the key's owner can do into one artifact; a relationship graph lets you cut exactly one edge.

The honest cost: is it worth another stateful service?

None of this is free. SpiceDB is a service you run and operate — it needs a backing datastore (PostgreSQL, CockroachDB, or Spanner), it has its own consistency model to reason about (checks can run against a "zed token" for read-after-write guarantees, which is a concept your team now has to understand and get right), and it's one more thing that pages someone at 3 a.m. if it falls over. For a deploy/rollback MCP server, the authorization check sits directly on the hot path of every tool call — that's a new network hop and a new failure mode in a place where "the platform is unreachable" used to just mean "the API server is unreachable."

It's also not the only option. OpenFGA — Auth0/Okta's open-source Zanzibar implementation — models the same relationship-graph shape but leans more opinionated and approachable, at the cost of being less strictly Zanzibar-faithful than SpiceDB. Cedar, AWS's policy language behind Amazon Verified Permissions, takes a genuinely different shape: declarative policy-as-code rather than a relationship graph, and independent benchmarks put it 28-35x faster at policy evaluation than OpenFGA — a real advantage if your authorization logic is closer to "evaluate a policy against attributes" than "traverse a graph of who's connected to what." Cedar just doesn't answer the multi-hop delegation question the way a graph does; expressing "agent inherits access through three levels of team membership" in a policy language is possible but not what the tool is shaped for.

And the plain alternative most agent-operated platforms — bex included, today — actually ship is coarser: scoped API keys plus an audit log. That combination is legitimately sufficient when the whole fleet is small enough that "who can deploy what" fits in a handful of roles, when there's no cross-tenant delegation chain to model, and when a human reviewing the audit log after the fact is an acceptable substitute for blocking the bad call before it happens. Running SpiceDB to solve a permission model with three roles and one tenant per deployment is real operational weight bought for a problem that doesn't exist yet.

Where it earns its keep is the opposite shape: multiple tenants, multiple agents with different scopes, delegation chains that change during an incident, and destructive actions (rollback, destroy) where "checked once, valid until rotation" is a worse failure mode than "checked every time, one relationship edge away from being cut." A platform that lets an AI agent hold standing rollback access across a fleet of tenants — which is exactly the shape of an agent-operated PaaS's roadmap, not a hypothetical — is the case ReBAC was actually built for.


A scoped API key answers one question, asked once: is this token still valid? A relationship graph answers a sharper one, asked on every call: given everything true about this agent, this app, and this moment, should this specific action happen right now? For a deploy/rollback MCP server, that second question is the one that actually matters — the first one just happens to be easier to build.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with deploy/rollback exposed as MCP tools an agent can call directly. Per-call authorization that can gate on live state — not just a token's scope at mint time — is the kind of infrastructure decision that belongs to the platform, not a policy someone hopes an agent respects. Star the repo on GitHub or deploy your first app today.

Related articles

Give your agents a chain backend

Autonomous agents hit RPC endpoints very differently than people do. See what bex router handles on their behalf.

Read the agents guide