Advanced Tool Use & Agent Engineering

MCP Tool Filtering: Allowlists, Denylists, and Mixed Patterns

Connecting an MCP server means trusting every tool it exposes — unless you filter. The mcp_toolset's two config layers give you allowlists, denylists, and everything in between, with one simple precedence rule.

Claude 3P 101 · Updated July 2026 · Unofficial guide

A remote Model Context Protocol (MCP) server decides for itself which tools it exposes — and that list can change without warning, because MCP tool availability is dynamic. If you connect a third-party server through the MCP connector, you probably do not want Claude calling every tool the server happens to offer today. A CRM server might expose both search_contacts and delete_contact; an enterprise almost certainly wants the first without the second.

The mcp_toolset entry — the required companion of every mcp_servers definition — is where you draw that line. It carries two configuration layers, and understanding how they stack is the whole trick.

The two layers and the precedence rule

Each toolset supports a default_config object, which sets defaults for all tools on that server, and a configs map, which sets per-tool overrides keyed by tool name. Each tool config supports two settings: enabled (default true) and defer_loading (default false — covered in its own article).

Precedence, highest first: tool-specific configs → set-level default_config → system defaults. A per-tool entry always beats the toolset default, which always beats the built-in defaults (enabled: true, defer_loading: false).

That one rule generates all three filtering patterns.

Pattern 1: allowlist (deny by default)

Disable everything at the default layer, then explicitly enable the tools you trust:

{
  "type": "mcp_toolset",
  "mcp_server_name": "crm",
  "default_config": {"enabled": false},
  "configs": {
    "search_contacts": {"enabled": true},
    "get_contact": {"enabled": true}
  }
}

This is the right default posture for third-party servers: if the server adds a new tool tomorrow, it arrives disabled, because the new tool has no per-tool entry and falls through to your default_config. Nothing changes in Claude's behavior until you deliberately allow it.

Pattern 2: denylist (allow by default)

Leave the default alone (or set enabled: true explicitly) and disable the specific tools you never want called:

{
  "type": "mcp_toolset",
  "mcp_server_name": "crm",
  "configs": {
    "delete_contact": {"enabled": false},
    "merge_contacts": {"enabled": false}
  }
}

Convenient for servers you operate yourself, but note the mirror-image risk: a tool the server adds tomorrow is allowed automatically. For anything security-sensitive, prefer the allowlist.

Pattern 3: mixed

Because per-tool entries can set both enabled and defer_loading independently, you can combine postures — for example, disable most tools, enable a handful eagerly, and enable a longer tail with deferred loading so their definitions stay out of the context window until Claude searches for them. The precedence rule resolves any apparent conflict: whatever the per-tool entry says, wins.

The quiet failure mode: unknown tool names

There is one validation behavior worth engraving in your review checklist. If a name in configs does not match any tool the server currently exposes, the API does not return an error — it logs a backend warning and carries on. This is deliberate (MCP servers have dynamic tool availability, so a strict check would break legitimate setups), but it means a typo in a denylist fails silently: misspell delete_contact as delete_contacts and the real tool stays enabled. Two defenses:

Filtering is not authorization

Keep the layers straight: toolset filtering controls what Claude may call, but the server's own credentials define what the connection can do. The authorization_token you pass for OAuth-protected servers should itself be scoped to least privilege — filtering on top of a broad token narrows Claude's behavior, not the blast radius of a leaked token. Treat the two as complementary controls.

Where to go next

See defer_loading and the tool search tool for the context-cost half of tool configs, and the platform split for where the connector is available at all.

Sources