← Back

AI Agent Tool Permissions: Design the Smallest Scope

Design AI agent tool permissions around actions, resources, and trusted identity. Learn how scoped tools, server checks, and audit records limit accidental access.

AI agent tool permissions should describe what the application allows, not what the model promises to avoid. A tool description saying “only access the current customer's records” is useful guidance. A server-side check that rejects every other customer's record is the permission boundary.

Start with the actual task. An assistant that explains an order's delivery status needs a narrow read operation. It does not need a general SQL console, a refund endpoint, or credentials that work across every tenant.

Define permissions along three axes

For each tool, specify the action, resource scope, and conditions. “Read orders” is incomplete. “Read delivery status for orders owned by the authenticated account, excluding payment details” is much closer to an enforceable contract.

Conditions may include an approved workspace, a maximum number of records, or a valid user session. Keep them grounded in trusted application state. Letting the model supply is_admin: true would turn a condition into a suggestion.

OWASP's authorization guidance recommends least privilege, denial by default, and permission checks on every request. Agent tools are another application interface where these principles apply.

Write denied cases before implementing the tool. Can one user request another user's order? Can a stale session still run a queued action? Can a bulk endpoint bypass per-record checks? These questions expose gaps that a happy-path demonstration will not reveal.

Prefer operations with bounded meaning

A tool named update_customer often accepts a broad patch object. That makes it difficult to distinguish harmless profile changes from changing an email address, billing owner, or security setting. Split operations when they require materially different authority.

An illustrative tool set might include:

get_delivery_status(order_id)
propose_address_change(order_id, address)
apply_approved_address_change(proposal_id)

These names are a design example, not an SDK. The application derives the account identity from the authenticated request and stores proposals server-side. The model cannot choose a different principal through an argument.

Narrow tools also make error messages more useful. “This order belongs to another account” may itself reveal too much; a generic inaccessible-resource response can be more appropriate. Decide what denials disclose as part of the interface.

Distinguish discovery from authorization

Hiding a tool from a model reduces accidental use, but it does not replace server enforcement. A stale client, another integration, or a direct request might still invoke the endpoint. Enforce the same policy at the operation boundary.

Conversely, a tool can be discoverable without every resource being accessible. This is common in shared APIs. Your execution layer should validate the requested resource against the current principal each time, including when resuming a previously paused workflow.

The MCP authorization specification requires servers to validate that access tokens were issued for the intended audience. That protects an important protocol boundary. It does not replace your domain policy about which customer records a token holder may access.

Keep token validation and application authorization as separate checks with separate failure reporting. Avoid passing a broadly privileged upstream token to a tool merely because doing so is convenient.

Scope data as carefully as actions

Read-only access can still be sensitive. An assistant might reveal private data through its answer, a generated file, or another tool. Reducing write access while returning complete database rows is an incomplete design.

Return only fields needed for the task. For delivery questions, a status and expected delivery window may be enough. Avoid returning payment tokens, internal fraud notes, or unrelated account details that the assistant never needs to answer.

Define pagination and volume limits. One allowed record lookup should not silently become permission to enumerate every record by repeatedly guessing identifiers. Rate controls, query constraints, and monitoring can help detect this pattern, depending on the product.

OWASP's AI agent guidance calls for per-tool permission scoping and minimal capabilities. Apply those controls to returned data as well as to tool names.

Make authority expire predictably

A queued task can outlive the session that created it. Decide whether execution requires current authorization, a separately issued task capability, or a fresh approval. Document the choice rather than inheriting whatever a background worker can access.

For sensitive changes, bind approval to a specific proposal and its relevant inputs. If the destination address changes after approval, the old approval should not authorize the new destination. Treat retries as the same operation, using a stable operation identifier and appropriate idempotency handling.

Revocation also matters. If a user loses access while a task waits, decide which pending operations must stop. A stored “authorized earlier” flag should not bypass a policy that requires current access at execution time.

Test enforcement without the model

Call tool endpoints directly in tests with unauthorized resource IDs, missing scopes, expired credentials, and malformed inputs. The expected denial should not depend on a model's behavior.

Then test the agent workflow separately: does it choose an appropriate tool, explain denials without inventing success, and avoid repeated attempts to exceed its permissions? These are distinct quality questions.

Record principal, operation, scoped resource, policy version, and outcome in audit events. Avoid logging credentials or unnecessary payload bodies. A denial trail should help an operator explain what happened without creating another source of sensitive data exposure.

The prompt injection guide explains why tool authority must survive a compromised model decision. The OIDC trust-policy guide provides a complementary example of binding identity to a narrow execution context. The model should never be the sole enforcer of its own permissions.