---
title: "Use case: Control which tools an AI agent may call"
canonical_url: "https://tokenobserve.com/use-cases/govern-mcp-tool-access"
published: 2026-09-02
last_updated: 2026-10-21
---

# Use case: Control which tools an AI agent may call

Put one Token Observe endpoint in front of every upstream Model Context Protocol server and authorise the call rather than the list, because filtering a list is a usability feature and a client can send a name it was never shown. Grants are deny-by-default and action-level, and a descriptor rewritten upstream is quarantined until a human approves it again.

## The stated limit

What is not governed here: A tool the agent calls from its own process, never routed through it

## A filtered tool list reads as access control and is not.

Tool access starts as a list of servers in a client configuration file, granting whole servers rather than actions, so an agent that needs one read against the order database gets the refund endpoint beside it. A gateway that filters the list is the next attempt, and a client can call a tool name it was never shown. Almost nobody governs the descriptor, which is text the model reads and obeys.

## The steps, in this order

1. Register each server behind one endpoint. A server row carries a name, a destination and the name of an environment variable holding its Authorization header, never the credential itself.
2. Grant actions, not systems. Write the specific tools each agent's declared purpose requires. Everything else is denied by default.
3. Point the client at one URL. Replace every upstream server with the gateway endpoint and the agent's own bearer token. Tools arrive namespaced and filtered to its grants.
4. Pin the descriptors you reviewed. Approving a tool hashes its name, description and input schema. A later change quarantines it and raises a high-severity finding.

### Permissions decide the tool; policy decides the argument.

An action is allowed only when a permission on one of the agent's roles explicitly allows it and none denies it, and the deny path returns first, so a guardrail role wins wherever it is listed. Delegation intersects rather than unions: the failure mode of an intersection is under-privilege, which surfaces as a ticket, while the failure mode of a union is an escalation that looks legitimate.

- Wildcards do not leak: tool:orderdb/* matches every tool on that server and nothing on any other. Every other metacharacter is escaped.
- Roles are flat: A name, a description and a list of permissions, with no inheritance. More typing, and less to reason about.
- Permissions do not read arguments: Refunds over £200 need approval is a policy. A permission has to be readable by a reviewer in one line.
- Roles cannot be deleted while referenced: The check runs in the same transaction as the deletion. Deleting a role under a running agent is a silent permission change.

### The tool descriptor is part of the prompt, so it is pinned.

Every catalogue refresh recomputes the hash and compares. Unpinned is deliberately not a block (a gateway that refused every unreviewed tool would not be adopted), so an unpinned tool stays usable and is described to the model as unverified, while drift quarantines immediately. Only the hash is kept, so a quarantine screen cannot show a diff and says so rather than letting an operator approve on a false premise.

## What this still does not solve

- A tool call that never reaches Token Observe is not refused by anything here. Evaluating proposed calls is defence in depth rather than a guarantee.
- There are no time-bound or just-in-time grants. A permission stands until somebody edits the role, and credentials are long-lived bearer tokens rotated by hand.
- An unpinned tool is not blocked, and a quarantine screen cannot show you a diff, because only the hash of the approved descriptor is stored.
- The bearer token is the agent. Any process holding that string is that agent, with no binding to a workload unless an operator wired one up.

## Questions and answers

Q: Why does the gateway check permissions twice?
A: Because filtering a tool list is a usability feature, not access control: a client can call a tool name it was never shown, so the call path re-evaluates from scratch. A tool the agent cannot see returns the protocol error for an unknown tool, because confirming existence is an inventory disclosure.

Q: What happens when an upstream tool's description changes?
A: It is quarantined on the next catalogue refresh and refused until a human approves it again. A mismatch against the pinned hash hides the tool, records the drift with both hashes, publishes an event and raises a high-severity discovery finding.

Q: Can a low-privileged agent get access by asking a higher-privileged agent?
A: No. The effective permission set is the intersection of every agent in the chain, so the request is refused at the first link that does not hold the grant. The chain is asserted rather than proven, but because it can only add links and every link must allow, forging it buys strictly less than sending none.
