🎉 Limited lifetime deal only for $29.

Tool-Level Access Control for Agents

@mem0ai
mem0@mem0ai
24 views Sep 18, 2026 ~9 min read
Advertisement

To let an agent draft a page in Notion, you give it a Notion token. That same token can delete every page and export the whole workspace. You wanted to grant one action, and the smallest thing you could hand over was all of them.

Media image

That is the problem in a single move. An agent works by making one tool call at a time, linear__get_issue, stripe__create_refund, send_discord_message, so the tool is the smallest thing it does and the obvious place to decide what it may do. But permission is still decided a level up, at the credential, and a credential is the whole integration. The grant is coarser than the call.

Media image

This is not a small mismatch, and it is not rare. Machine identities already outnumber humans by more than 80 to 1 (CyberArk, 2025), 42% of them hold privileged access, and agents are the fastest-growing class of them. The over-privileged service account was already the standing joke of enterprise security; the 2024 Snowflake intrusions spread through customer accounts that leaned on broad standing credentials with no MFA. An agent is that account with a promptable brain wired to it. This piece walks the mechanism: why the grant is too big, why the protocol agents use does not fix it, the exact check that does, where the labs have got to, and how Mem0 built it.


The grant is coarser than the call

Most access resolves to an OAuth scope, and a scope names a category of API surface, not an action. Line up what you can grant against what the agent needs and the mismatch is exact:

Media image

Google's drive scope is the entire Drive. GitHub's repo scope is full read and write with no read-only variant, so an agent that only needs to list private repos gets write too.

The standards to narrow a token exist, token exchange (RFC 8693) downscopes and resource indicators (RFC 8707) audience-bind, but using them means minting a reduced token before every call, which almost no one wires up. So the token stays broad, and the agent holds all of it for the whole session.

This is least privilege (Saltzer and Schroeder, 1975) failing at the grain: you cannot grant little, because the smallest thing on offer is already large.


The tool is atomic, but MCP authorizes the server

The interface agents use already made the tool the unit. In the Model Context Protocol (Anthropic, Nov 2024; adopted by OpenAI, Google, and Microsoft through 2025) a server advertises tools with tools/list and the model invokes one with tools/call. Each tool is a named operation with its own schema. The agent's world is a flat list of callable tools.

Authorization, though, binds a level up. MCP's auth spec is a solid OAuth 2.1 design: it makes the MCP server an OAuth resource server and requires (via RFC 8707) that the client name the server's canonical URI as the token's audience, so a token minted for one server cannot be replayed against another.

POST /token
grant_type=authorization_code
resource=https://mcp.acme.com/mcp     # audience = the SERVER, not a tool
Media image

That one token then rides tools/call for anything the server exposes. There is no per-tool grant in the protocol. The spec's own security guidance concedes the cost under "scope minimization": a broad token means an "expanded blast radius" and lets high-risk tools run "without further elevation." Its fix is advice, "SHOULD implement a progressive, least-privilege scope model," not a mechanism. The interface got fine-grained. The permission stayed at the server.

This is an old failure with a name. A confused deputy (Hardy, 1988) is a program that holds standing authority and is steered by an untrusted instruction into misusing it. An agent is that deputy with a bigger surface: it carries its tokens and it takes instructions from content it did not write, a web page it summarizes, a ticket it processes.

Prompt injection is the steering, and OWASP files the result as LLM06 Excessive Agency, with "excessive permissions" as a named cause. You cannot stop the model from being tricked. You can bound what a tricked agent is holding.

A 2026 audit, Capability Gates Are Not Authorization, found that agent frameworks ship capability gating but no fail-closed check on each call, so the unauthorized call runs by default. The fix the field is converging on (MiniScope, Dec 2025) is a mechanical check at the call, run by the layer, not the model.


The check a call has to clear

Here is the whole idea in one place. A tool-level layer keeps two facts about each agent, the ceiling of what its connector can do and the grant of what this agent was given, and it runs an ordered, deny-by-default check on every call:

Media image

The last check is the one that matters here. The connector sets the ceiling of what is possible; the per-agent grant narrows it to what this agent may do; a call has to fit inside both. Everything below is which lab has built which part of this check.


Where the labs are

Every frontier lab ships part of this, each inside its own runtime. The grain is the tell.

Media image

Anthropic's Claude Code has the sharpest per-tool control in production, rules that match a tool, a command, even an argument, enforced by the harness rather than the model:

// .claude/settings.json
"permissions": {
  "allow": ["Bash(npm run test:*)", "mcp__github__get_*"],
  "deny":  ["Read(./.env)", "mcp__github__delete_*"]
}

Its docs mention: "Permission rules are enforced by Claude Code, not by the model." But it lives in one harness, and the caller identity is still your login. Google reaches individual tool names, and read versus write, in its enterprise Agent Gateway, and is moving agents onto per-agent identities to "eliminate over-permissioned agents," all inside Google's stack.

Microsoft's Entra Agent ID gives every agent its own directory identity but gates token issuance, not the call, and its tool control bottoms out at the connector.

AWS AgentCore has the strongest identity story ("zero token sharing") and an AgentCore Gateway that turns APIs into MCP tools, but per-tool control is interceptor code you write, and the default grain is the gateway's shared role.

The pattern: per-agent identity is being solved (Microsoft, AWS, Google), per-tool control is being solved (Anthropic, Google), each inside one vendor's runtime, over that vendor's agents.

Two of these products are even named "gateway" and both are locked to their own cloud. Nobody governs the tools your agents reach across providers, and nobody governs the surface with no lock at all: your own internal APIs, which every OpenAPI-to-tool generator turns into one callable tool per endpoint, including the endpoints that only ever expected a trusted caller on the office network.


Introducing Mem0 Gateway

Mem0 Gateway is a control plane for what your agents are allowed to do. You give each agent one key that permits exactly the actions you choose and nothing else, you watch every call it makes on one live screen, and you stop it with a single click. It is built for teams already running agents against real tools, and it runs on Mem0's own production agents.

Mechanically, it is the check from the diagram above, run as one plane in front of everything an agent calls. SaaS tools arrive over MCP, your own services arrive over OpenAPI, and both land in one catalog under the same per-agent, per-tool grant, so a Notion tool and an internal refunds endpoint are governed the same way. The rest of this section is the path a request takes through it.

Media image

Connect, once. An admin connects a service by OAuth, or uploads an OpenAPI spec to bring an internal API into the catalog. Gateway stores the upstream credential encrypted and uses it server-side; the agent never sees it. Connecting imports capability. It grants nothing.

Media image

Grant, per agent. Create an agent, grant it the exact tools its job needs, and Gateway issues one scoped key (mg_...) with an expiry, a rate limit, and a spend cap. Point the agent's MCP client at Gateway and it inherits that grant and nothing else:

claude mcp add --transport http mem0-gateway \
  <https://gateway-mcp.mem0.ai/mcp> \
  --header "Authorization: Bearer mg_live_..."

Enforce, on every call. This is the check from the diagram above, run in order and deny-by-default. A research agent granted linear__list_issues and linear__get_issue that reaches for a delete is stopped before the call leaves Gateway:

> linear__delete_comment(id=…)
mem0 gateway denied this call (out_of_scope).

Let the agent ask. A short grant only works if the agent can get more when the job needs it. We pointed Claude Code at Gateway and asked it to file a Linear ticket it had no grant for. It did not fail silently and it did not guess. It found the tool and asked for it, with a reason:

find_tools("create a linear ticket", type="requestable")
  -> linear__create_issue, linear__update_issue
request_access(["linear__create_issue"], reason="file the bug the user reported")

The request and its reason show up in the console. An admin approved one tool and denied another. The agent used what it got, said what it could not do, and never held a wider key. No new key, no re-paste, no redeploy.

Watch, and kill. Every call, allowed or denied, is written against the agent that made it (agent, connector, tool, argument hash, outcome, reason) in a log a database trigger will not let anyone edit. One kill switch refuses an agent's next call everywhere at once, instead of rotating credentials across five vendors at 2am.

And it keeps the catalog off the prompt. Because an agent holds only its granted tools and reaches the rest through discover / find_tools / invoke, connecting 500 tools does not load 500 definitions. Gateway reports tool-definition overhead falling from about 50k tokens to under 1k. That is a real benefit and a secondary one, since Claude Code and Codex already trim the same bloat on their side.

An agent acts one tool at a time, so permission belongs at the tool. Connect is not grant.

Try Gateway here- https://mem0.ai/gateway


In Context

This piece is part of In Context, a @mem0ai series on AI agent memory and context engineering.

Mem0 is an open-source memory layer for LLMs and AI agents, built for long-term, personalized, context-aware interactions across sessions.

  • Get a free API key: app.mem0.ai
  • Self-host from the open-source repository

  • References

    Mem0 Gateway

  • Mem0 Gateway · pricing
  • Scale of the problem (2024-2025)

  • CyberArk, machine identities outnumber humans 80 to 1 (2025)
  • CSA, unpacking the 2024 Snowflake breach
  • CSA, Securing NHIs in the Age of AI Agents (2025)
  • MCP and its authorization model

  • Anthropic, Introducing MCP (2024)
  • MCP spec, Tools
  • MCP spec, Authorization
  • MCP spec, Security Best Practices
  • Frontier-lab tool controls (2025)

  • Anthropic, Claude Code permissions
  • Anthropic, Tool Search Tool
  • OpenAI, Agents SDK guardrails and approvals
  • Google, Gemini Enterprise Agent Gateway
  • Google, Vertex AI agent identity
  • Microsoft, Entra Agent ID
  • AWS, Bedrock AgentCore Identity
  • AWS, Bedrock AgentCore Gateway
  • Agent security taxonomy and research (2025-2026)

  • OWASP, LLM06:2025 Excessive Agency
  • OWASP, Agentic Security Top 10 (2026)
  • MITRE ATLAS, AML.T0051 Prompt Injection
  • Capability Gates Are Not Authorization (arXiv:2606.28679)
  • MiniScope: Least Privilege for Tool-Calling Agents (arXiv:2512.11147)
  • Foundations

  • Saltzer & Schroeder, least privilege (1975)
  • Hardy, The Confused Deputy (1988)
  • OAuth Token Exchange (RFC 8693) · Resource Indicators (RFC 8707)
  • Actions
    What You Can Do
    • Export as PDF or Markdown
    • Batch Export to Notion
    • Bookmark & Highlight
    • LinkedIn & Instagram Carousel Maker
    Create Free Account

    Includes 7-day Premium trial

    Advertisement