# Tool Filtering

Tool filtering controls which MCP tools are available to each persona. Rules use wildcard patterns to allow or deny tools by name.

!!! note "Two levels of tool filtering"
    **Persona tool filtering** (this page) is a **security boundary**. It controls which tools a user can call via `tools/call` based on their persona. Unauthorized calls are rejected.

    **Global tool visibility** (configured via the top-level `tools:` block) is a **token optimization**. It controls which tools appear in `tools/list` responses to reduce LLM context usage. It does not block `tools/call`. See [Tool Visibility Configuration](../server/configuration.md#tool-visibility-configuration) for details.

## Rule Structure

Each persona has `allow` and `deny` lists:

```yaml
tools:
  allow:
    - "trino_*"           # Allow all trino tools
    - "datahub_search"    # Allow specific tool
  deny:
    - "*_delete_*"        # Deny any tool with delete in name
```

## Evaluation Order

1. **Deny rules are checked first** - If a tool matches any deny pattern, it's blocked
2. **Allow rules are checked second** - Tool must match at least one allow pattern
3. **No match = denied** - Tools not matching any allow pattern are blocked

```mermaid
graph TD
    A[Tool Request] --> B{Matches Deny?}
    B -->|Yes| C[Blocked]
    B -->|No| D{Matches Allow?}
    D -->|Yes| E[Allowed]
    D -->|No| C
```

## Wildcard Patterns

| Pattern | Matches |
|---------|---------|
| `*` | Everything |
| `trino_*` | trino_query, trino_execute, trino_explain, trino_browse, trino_export, etc. |
| `*_list_*` | s3_list_buckets, s3_list_objects, trino_list_connections, etc. (does **not** match `trino_browse` or `datahub_browse`) |
| `datahub_get_*` | datahub_get_entity, datahub_get_schema, etc. |
| `s3_*` | All S3 tools |
| `trino_query` | Exact match only |

Wildcards match zero or more characters.

## Common Patterns

### Full Access

```yaml
tools:
  allow: ["*"]
  deny: []
```

### Read-Only Access

```yaml
tools:
  allow:
    - "trino_query"
    - "trino_explain"
    - "trino_browse"
    - "trino_describe_*"
    - "trino_list_connections"
    - "datahub_*"
    - "s3_list_*"
    - "s3_get_*"
  deny:
    - "trino_execute"
    - "s3_put_*"
    - "s3_delete_*"
    - "s3_copy_*"
```

### Metadata Only (No Queries)

```yaml
tools:
  allow:
    - "datahub_*"
    - "trino_browse"
    - "trino_describe_*"
    - "trino_list_connections"
  deny:
    - "trino_query"
    - "trino_execute"
    - "trino_explain"
```

### Data Exploration

```yaml
tools:
  allow:
    - "trino_*"
    - "datahub_search"
    - "datahub_get_*"
  deny:
    - "*_delete_*"
```

### S3 Read-Only

```yaml
tools:
  allow:
    - "s3_list_*"
    - "s3_get_object"
    - "s3_get_object_metadata"
    - "s3_presign_url"
  deny:
    - "s3_put_*"
    - "s3_delete_*"
    - "s3_copy_*"
```

## Tool Names Reference

Use these exact names in your patterns:

**Trino Tools:**
- `trino_query` (read-only)
- `trino_execute` (read-write)
- `trino_explain`
- `trino_browse`
- `trino_describe_table`
- `trino_export` (requires portal; exports query results to asset)
- `trino_list_connections`

**DataHub Tools:**
- `datahub_search`
- `datahub_get_entity`
- `datahub_get_schema`
- `datahub_get_lineage`
- `datahub_get_queries`
- `datahub_get_glossary_term`
- `datahub_browse`
- `datahub_get_data_product`
- `datahub_create` (if not read-only)
- `datahub_update` (if not read-only)
- `datahub_delete` (if not read-only)
- `datahub_list_connections`

**S3 Tools:**
- `s3_list_buckets`
- `s3_list_objects`
- `s3_get_object`
- `s3_get_object_metadata`
- `s3_presign_url`
- `s3_list_connections`
- `s3_put_object` (if not read-only)
- `s3_delete_object` (if not read-only)
- `s3_copy_object` (if not read-only)

## Examples

### Analyst Persona

Analysts can query and explore, but not modify:

```yaml
analyst:
  tools:
    allow:
      - "trino_*"
      - "datahub_*"
      - "s3_list_*"
      - "s3_get_*"
    deny:
      - "s3_put_*"
      - "s3_delete_*"
      - "s3_copy_*"
```

### Data Steward Persona

Data stewards can view metadata but not execute queries:

```yaml
data_steward:
  tools:
    allow:
      - "datahub_*"
      - "trino_browse"
      - "trino_describe_*"
      - "trino_list_connections"
    deny:
      - "trino_query"
      - "trino_execute"
      - "trino_explain"
```

### ETL Service Persona

ETL services need full access:

```yaml
etl_service:
  tools:
    allow: ["*"]
    deny: []
```

### Viewer Persona

Viewers can only search and browse:

```yaml
viewer:
  tools:
    allow:
      - "datahub_search"
      - "datahub_get_entity"
      - "datahub_browse"
      - "trino_browse"
    deny:
      - "trino_query"
      - "trino_execute"
      - "trino_explain"
      - "trino_describe_*"
      - "s3_*"
```

## Gateway Tools

Tools proxied through the gateway toolkit appear in `tools/list` under a connection-namespaced name: `<connection_name>__<remote_tool_name>`. Persona rules match these names with the same wildcard syntax as native tools, so a single persona can grant or deny access to a third-party MCP at any level of granularity:

```yaml
personas:
  marketer:
    roles: ["marketing_team"]
    tools:
      allow:
        - "trino_query"           # Native: read warehouse data
        - "datahub_get_*"         # Native: look up metadata
        - "vendor__list_*"        # Gateway: read vendor objects
        - "vendor__send_*"        # Gateway: trigger vendor sends
      deny:
        - "vendor__delete_*"      # Block destructive vendor calls
```

The double-underscore separator (`__`) is a deliberate marker — it makes "gateway tool" visually obvious in audit logs, persona configs, and tool-list responses, and it never collides with the single-underscore separators used by native toolkits (`trino_query`, `datahub_search`, `s3_get_object`).

### Composite personas

A composite persona combines native and gateway access for a single role. The example above gives the `marketer` role read access to the warehouse plus action access to a third-party MCP wired through the gateway. The same audit log captures every tool call, regardless of whether it landed on Trino, DataHub, S3, or a proxied vendor.

## Deny Takes Precedence

Deny rules always win over allow rules:

```yaml
tools:
  allow:
    - "s3_*"           # Allow all S3 tools
  deny:
    - "s3_delete_*"    # But deny delete operations
```

Result: `s3_list_buckets` ✓, `s3_delete_object` ✗

## Testing Rules

To verify your rules work as expected, check which tools are available for each persona:

1. Authenticate as a user with the persona's roles
2. Ask Claude to list available tools
3. Verify the expected tools are present/absent

Or test programmatically by checking the tool filter logic:

```go
filter := persona.NewToolFilter(persona.ToolRules{
    Allow: []string{"trino_*"},
    Deny:  []string{"trino_query"},
})

filter.Allows("trino_browse")         // true
filter.Allows("trino_describe_table") // true
filter.Allows("trino_query")         // false
filter.Allows("datahub_search")      // false
```

## Next Steps

- [Role Mapping](role-mapping.md) - Map roles to personas
- [Authentication](../auth/overview.md) - Configure user authentication
