# How to Use Tool Allow/Deny Lists with AllowToolsPolicy in aisuite

> Learn how to use tool allow deny lists with AllowToolsPolicy in aisuite. Block unauthorized tool invocations efficiently and control access with this runtime whitelist.

- Repository: [Andrew Ng/aisuite](https://github.com/andrewyng/aisuite)
- Tags: how-to-guide
- Published: 2026-07-28

---

**The `AllowToolsPolicy` class in aisuite implements a runtime whitelist that permits only specified tool names while rejecting all others, returning a `ToolPolicyDecision` that blocks unauthorized invocations before they execute.**

aisuite provides a structured policy framework for controlling large language model (LLM) agent behavior at the tool level. By implementing tool allow/deny lists with AllowToolsPolicy in aisuite, you can enforce strict security boundaries, ensuring agents invoke only explicitly authorized Python functions while maintaining audit trails through decision metadata.

## How AllowToolsPolicy Implements Whitelisting

The `AllowToolsPolicy` class, defined in [`aisuite/agents/policies.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/policies.py) (lines 30-40), operates as a gatekeeper between the LLM and your registered functions. When an agent attempts a tool call, the framework passes a `ToolPolicyContext` object—defined in [`aisuite/agents/types.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/types.py)—containing the agent name, tool name, and arguments to the policy's `evaluate` method.

The constructor signature requires a list of permitted tool names:

```python
def __init__(self, allowed_tools: list[str], reason: Optional[str] = None):
    self.allowed_tools = set(allowed_tools)  # Converted to set for O(1) lookup

    self.reason = reason

```

The `evaluate` method returns a `ToolPolicyDecision` containing an `allowed` boolean and optional `reason` string:

```python
def evaluate(self, context: ToolPolicyContext) -> ToolPolicyDecision:
    allowed = context.tool_name in self.allowed_tools
    return ToolPolicyDecision(
        allowed=allowed,
        reason=None if allowed else self.reason or "tool not in allowlist",
    )

```

This design ensures that unauthorized tool calls return immediately with a denial reason, preventing the underlying Python function from ever executing. The test suite in [`tests/agents/test_tool_metadata_policy.py`](https://github.com/andrewyng/aisuite/blob/main/tests/agents/test_tool_metadata_policy.py) validates these behaviors against concrete scenarios.

## Configuring Tool Allow Lists

To restrict an agent to specific capabilities, instantiate `AllowToolsPolicy` with an explicit list of permitted tool names. The framework matches these names against the `tool_name` attribute in the `ToolPolicyContext`, which corresponds to the function name or metadata override specified via the `@tool` decorator.

```python
from aisuite.agents.policies import AllowToolsPolicy

# Permit only file reading operations

policy = AllowToolsPolicy(
    allowed_tools=["read_file"],
    reason="Security policy restricts file system access"
)

```

If you omit the `reason` parameter, the policy defaults to the message "tool not in allowlist" when denying requests.

## Implementing Deny Lists and Alternative Policies

While `AllowToolsPolicy` provides whitelist functionality, aisuite supports complementary restriction strategies through the same `tool_policy` interface:

**DenyAllToolPolicy**: Located in [`aisuite/agents/policies.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/policies.py), this class rejects every tool invocation unconditionally, useful for creating read-only agents or testing modes.

**Custom ToolPolicy**: Implement the `ToolPolicy` protocol by defining an `evaluate` method that accepts `ToolPolicyContext` and returns `ToolPolicyDecision`. This approach enables complex logic such as time-based restrictions, argument validation, or category-based filtering using metadata attached via the `@tool` decorator in [`aisuite/utils/tools.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/utils/tools.py).

```python
from aisuite.agents.types import ToolPolicyContext, ToolPolicyDecision

class CustomDenyPolicy:
    def evaluate(self, context: ToolPolicyContext) -> ToolPolicyDecision:
        # Block tools with "delete" in the name

        allowed = "delete" not in context.tool_name.lower()
        return ToolPolicyDecision(
            allowed=allowed,
            reason=None if allowed else "Delete operations prohibited"
        )

```

## Attaching Policies to Agents

Associate your policy with an agent using the `tool_policy` parameter in the `Agent` constructor. You may also pass policies directly to `Client.run` calls for temporary overrides.

```python
from aisuite import Agent
from aisuite.client import Client
from aisuite.utils.tools import tool
from aisuite.agents.policies import AllowToolsPolicy

@tool
def read_file(path: str) -> str:
    """Read a text file and return its contents."""
    with open(path, "r", encoding="utf-8") as f:
        return f.read()

@tool
def delete_file(path: str) -> str:
    """Delete the specified file."""
    import os
    os.remove(path)
    return f"Deleted {path}"

# Configure agent with whitelist

agent = Agent(
    name="SecureFileAgent",
    model="gpt-4o-mini",
    tools=[read_file, delete_file],
    tool_policy=AllowToolsPolicy(["read_file"])  # delete_file implicitly blocked

)

client = Client()

```

## Complete Working Example

The following implementation demonstrates the full lifecycle: tool registration, policy application, and differentiated execution outcomes based on the allow list.

```python
from aisuite import Agent
from aisuite.client import Client
from aisuite.utils.tools import tool
from aisuite.agents.policies import AllowToolsPolicy

# Step 1: Define tools with optional metadata

@tool(metadata={"risk_level": "low"})
def read_file(path: str) -> str:
    """Read a text file and return its contents."""
    with open(path, "r", encoding="utf-8") as f:
        return f.read()

@tool
def list_files(directory: str) -> list[str]:
    """Return a list of file names in the directory."""
    import os
    return os.listdir(directory)

# Step 2: Create agent with explicit allow list

agent = Agent(
    name="FileReaderOnly",
    model="gpt-4o-mini",
    tools=[read_file, list_files],
    tool_policy=AllowToolsPolicy(["read_file"])  # Only read_file permitted

)

client = Client()

# Step 3: Execute allowed tool

result = client.run(
    agent,
    "Please read the content of the file example.txt"
)
print(result.final_output)  # Returns file contents

# Step 4: Attempt denied tool

result = client.run(
    agent,
    "List all files in the current directory"
)
print(result.final_output)  # Returns: "Tool call denied: tool not in allowlist"

```

In this workflow, the `read_file` invocation succeeds because it appears in the `allowed_tools` set, while `list_files` triggers the denial path defined in [`aisuite/agents/policies.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/policies.py).

## Summary

- **`AllowToolsPolicy`** maintains an internal `set` of permitted tool names initialized via the `allowed_tools` parameter, enabling O(1) membership checks during runtime.
- The policy evaluates each invocation against [`aisuite/agents/policies.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/policies.py) logic, returning a `ToolPolicyDecision` with `allowed=True` only for whitelisted functions defined in the agent's tool registry.
- Attach controls via the `tool_policy` argument when constructing an `Agent` or running `Client.run`, with denied calls returning structured reasons before function execution.
- Complementary strategies include **`DenyAllToolPolicy`** for complete restriction or custom implementations of the `ToolPolicy` protocol defined in [`aisuite/agents/types.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/types.py).

## Frequently Asked Questions

### What parameters does the AllowToolsPolicy constructor accept?

The `__init__` method in [`aisuite/agents/policies.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/policies.py) accepts two parameters: `allowed_tools` (a `list[str]` of permitted tool names) and an optional `reason` (`Optional[str]`). The constructor converts the list to a Python `set` for efficient lookup during evaluation.

### How does AllowToolsPolicy determine whether to allow a tool call?

During execution, the policy's `evaluate` method receives a `ToolPolicyContext` object containing metadata about the requested invocation, including `tool_name`. It checks whether `context.tool_name` exists within `self.allowed_tools` (the internal set), returning a `ToolPolicyDecision` with `allowed=True` only upon match.

### Can AllowToolsPolicy function as a deny list instead of an allow list?

No, `AllowToolsPolicy` specifically implements whitelist functionality. To create a deny list, you must either implement a custom policy class satisfying the `ToolPolicy` protocol or use `DenyAllToolPolicy` (which blocks everything) combined with selective overrides. The protocol requires only an `evaluate` method accepting `ToolPolicyContext` and returning `ToolPolicyDecision`.

### Where are the ToolPolicyContext and ToolPolicyDecision types defined?

These data structures are defined in [`aisuite/agents/types.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/types.py). `ToolPolicyContext` encapsulates runtime information including the agent name, tool name, and arguments, while `ToolPolicyDecision` contains the boolean `allowed` flag and optional `reason` string consumed by the framework's execution engine.