Tool registry and sandbox pattern for AI agents

GuideLast reviewed Oct 16, 2026By Himanshu Ramchandani
Short answer

Keep a registry of every tool an agent can call, with its schema, description, owner, permission level (read, reversible write, irreversible write), rate limit and credentials. Agents can only call registered tools, the orchestrator enforces the permission level (irreversible actions need approval), and tools that run code or touch systems run in an isolated sandbox with the narrowest credentials possible. The registry is your inventory and your policy in one place: if a tool isn't in it, the agent can't use it.

What can go wrong

An agent with a generic "run Python" tool and production credentials can do anything, including things nobody intended. Prompt injection makes this worse: text in a web page or an email can tell the agent to use its tools against you.

Registry

Each entry describes one tool:

Field Example
Name and version refund_order v2
Description What it does and when to use it, written for the model
Schema Arguments and types
Permission level read, reversible write, irreversible write
Approval None, or required above a threshold
Rate limit 10 calls per run
Owner Payments team
Credentials A scoped key for this tool only

The orchestrator reads the registry, offers only the tools the current agent is allowed to use, and checks every call before running it.

from dataclasses import dataclass


@dataclass(frozen=True)
class Tool:
    name: str
    level: str
    max_calls: int
    needs_approval: bool = False


REGISTRY = {
    t.name: t
    for t in [
        Tool("get_order", "read", max_calls=20),
        Tool("create_ticket", "reversible_write", max_calls=3),
        Tool("refund_order", "irreversible_write", max_calls=1, needs_approval=True),
    ]
}


def authorise(name: str, calls_so_far: dict[str, int], approved: bool = False) -> str:
    tool = REGISTRY.get(name)
    if tool is None:
        return "deny: not registered"
    if calls_so_far.get(name, 0) >= tool.max_calls:
        return "deny: call limit reached"
    if tool.needs_approval and not approved:
        return "pause: waiting for human approval"
    return "allow"


calls = {"get_order": 2}
for name in ["get_order", "run_python", "refund_order"]:
    print(f"{name:<14}{authorise(name, calls)}")

Sandbox

Tools that execute code, browse the web or touch files run in isolation:

  • A container or a micro-VM per run, destroyed afterwards.
  • No network access unless the tool needs it, and then only to allowed hosts.
  • Time, memory and CPU limits.
  • A read-only filesystem except for a scratch directory.
  • No secrets inside the sandbox other than the tool's own scoped credentials.

Credentials

  • One credential per tool, per environment.
  • Short-lived tokens where possible.
  • Read-only database users for read tools.
  • Never the developer's or the admin's credentials.

Audit

Log every call: the agent, the run, the tool, the arguments, the result, the approver if any, and the time. That log is how you answer "what did the agent do?" after an incident. See audit logs.

MCP and the registry

With the Model Context Protocol, tools come from MCP servers. The registry still applies: decide which servers and which of their tools each agent may use, and don't let an agent connect to arbitrary servers.

Measuring it

  • Calls to unregistered or denied tools (should be zero, and every attempt worth reading).
  • Approval requests and rejection rate.
  • Sandbox escapes in red-team tests.

From the floor

In the production pipeline I teach, the agent zone has a secure tool registry, any kind of tool an agent can call, a calculator, an external API, a Python function, a calendar or a spreadsheet, and the tools execute in an isolated sandbox environment, so they don't interfere with the agent's own execution.

In DevFix, the generated code ran inside Docker, and a safety guard blocked code with calls to remove files or execute arbitrary commands before it reached the sandbox at all.

Next step

Read the exact values pattern.

Sources