toolcue Join the waitlist

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-slim 2.65.0, with 6 end-to-end tests. Toolcue is in early access: join the waitlist.

Install#

bash
pip install "toolcue[pydantic-ai]"         # toolcue + pydantic-ai-slim>=2
export TOOLCUE_URL=...  TOOLCUE_TOKEN=...  TOOLCUE_ADMIN_TOKEN=...

Use it#

python
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 hookWhenWhat it does
before_runOnce per runSends the prompt and the message history to Toolcue
prepare_toolsEvery stepOffers only the selected tools; tools outside your Toolcue catalog always pass
get_toolsetAgent setupAdds a find_tools tool: what it finds is offered for the rest of the run
wrap_tool_executeEvery tool callRefuses 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.