Pydantic AI: one capability for per-turn tool selection
Add one capability to your Pydantic AI agent and every run (one user turn) gets only the tools it needs, selected once at the start of the run by Toolcue in about 35 ms.
Verified on 2026-11-02 with
pydantic-ai-slim2.65.0, with 6 end-to-end tests. Toolcue is in early access: join the waitlist.
Install#
pip install "toolcue[pydantic-ai]" # toolcue + pydantic-ai-slim>=2
export TOOLCUE_URL=... TOOLCUE_TOKEN=... TOOLCUE_ADMIN_TOKEN=...Use it#
from dataclasses import dataclass
from pydantic_ai import Agent
from toolcue.pydantic_ai import Toolcue
@dataclass
class Session:
roles: list[str]
agent = Agent("anthropic:claude-opus-5-5", tools=TOOLS, deps_type=Session,
capabilities=[Toolcue("acme-billing", user=lambda deps: {"roles": deps.roles})])
result = agent.run_sync("Refund the last invoice for Globex", deps=Session(roles=["agent"]))Pass message_history= as usual for follow-ups: Toolcue reads it, including tool calls and their results.
How the capability works#
| Capability hook | When | What it does |
|---|---|---|
before_run | Once per run | Sends the prompt and the message history to Toolcue |
prepare_tools | Every step | Offers only the selected tools; tools outside your Toolcue catalog always pass |
get_toolset | Agent setup | Adds a find_tools tool: what it finds is offered for the rest of the run |
wrap_tool_execute | Every tool call | Refuses a catalog tool that wasn't offered, even if the model names it |
for_run gives each run its own selection, so concurrent runs never share one. If Toolcue fails, the run gets every tool.
Compared with ToolSearch#
Pydantic AI's ToolSearch capability lets the model search tools you mark defer_loading=True when it realises one is missing. Toolcue selects before the model starts, from the whole conversation, and adds the lookups the selected tools depend on. Use Toolcue for the turn's tools; keep find_tools for the rare miss.