tool_search tool that loads them on demand.
The 16 built-in autonomous-loop tools alone are roughly 2,600 tokens per request, and a single MCP server can add 40 more tools on top. Selection accuracy also falls as the list grows — a model choosing among 80 tools chooses worse than one choosing among 8.
How It Works
Tools are deferred: registered, searchable, and executable, but not advertised. Onlytool_search is always present alongside your control tools. The model searches the catalog by keyword, the matching schemas are loaded, and they become callable on the next turn.
Enabling It
dynamic_tools is a constructor parameter on Agent and is True by default.
bool
default:"True"
Defer tool schemas behind
tool_search instead of sending them all on every request. Set to False to restore classic eager registration, where every tool schema ships with every call.When Deferral Actually Activates
Settingdynamic_tools=True on its own does nothing. Deferral needs something to defer, so it activates only when at least one of these is true:
If none apply,
agent.tool_loader stays None and no catalog is built.
When deferral activates, a system-prompt notice headed
## MOST TOOLS ARE NOT LOADED is appended once at construction. It tells the model that its visible tool list describes what exists, not what it can call right now, and that it must search before concluding a task is impossible.Inspecting the Catalog
agent.tool_loader is a DynamicToolLoader. It reports what is deferred and what has been loaded so far.
Searching the Catalog
The model callstool_search with a query. Matching is deliberately simple, dependency-free, and deterministic, so it can be tested.
Keyword search
Keyword search
The query is lowercased and split into tokens, with underscores treated as spaces so
get_weather matches both get and weather. Each catalog entry scores 3 points for a name match and 1 point for a description or parameter-name match, summed over the query’s terms. Entries scoring zero are dropped, and results are sorted by score then name.Exact selection with select:
Exact selection with select:
Prefix the query with Unknown names are silently ignored. If none of the names match, the loader falls back to a keyword search over the guessed names rather than returning nothing.
select: to load tools by exact name, bypassing ranking, limit, and min_score_ratio entirely.Stopword filtering
Stopword filtering
Common words (
a, the, and, of, to, can, please, …) and single characters are dropped before matching. Without this, a query like "weather in a city" would match every tool whose description contains "a" and load the entire catalog, defeating the point.Misses are actionable
Misses are actionable
A search that matches nothing returns the available tool names rather than an empty string, so the model can retry with
select:. The listing is capped at 30 names with a (+N more) suffix so a large catalog cannot flood the conversation.Dynamic Tools in the Autonomous Loop
Withmax_loops="auto", the loop’s own tools are deferred too — but the control tools that let the agent make progress are never deferred, since an agent that has to search for its own complete_task cannot finish.
Always loaded: create_plan, think, subtask_done, complete_task, respond_to_user.
Deferred into the catalog: create_file, update_file, read_file, list_directory, delete_file, run_bash, grep, create_sub_agent, assign_task, check_sub_agent_status, cancel_sub_agent_tasks, plus every tool you passed in tools.
Plan-Based Pre-Warming
Searching one subtask at a time wastes turns. When the agent callscreate_plan, the loop takes the task description plus every step description as a single query and pre-loads the tools that plan implies — at no extra turn cost, since it runs inside the create_plan handler that just succeeded.
The
create_plan result then tells the model what it already has:
selected_tools filters the loop’s tool list before deferral, so a tool you exclude is not merely hidden — it never enters the catalog and cannot be found by tool_search at all.MCP Servers
MCP tools are the strongest case for deferral: a single server can contribute dozens of schemas that would otherwise ship on every request. Withdynamic_tools=True they join the catalog instead.
tool_search simply has nothing to find.
Prompt Caching
Every load changes the tool array, which invalidates the provider’s cached prompt prefix. Two mitigations are built in:schemas()returns tools in a stable order —always_loadedfirst, thentool_search, then loaded tools sorted by name — so two runs that load the same tools produce an identical prefix.- The
tool_searchdescription explicitly instructs the model to load everything it expects to need in a single call rather than one tool at a time.
Turning It Off
Setdynamic_tools=False for classic eager registration — every schema ships with every request, and agent.tool_loader is None.
Gotchas
Deferred is not disabled
Deferred is not disabled
tool_struct is built from self.tools before deferral, so a model that guesses a correct tool name can still execute it. Only the schema is withheld. Dynamic tool loading is a token-and-accuracy optimization, not an access control mechanism.The name tool_search is reserved
The name tool_search is reserved
A tool of your own named
tool_search is dropped from the catalog with a warning, and becomes permanently uncallable — both it and the search tool would appear in the list and the model could not tell them apart. Rename yours.tools_list_dictionary is owned by the loader
tools_list_dictionary is owned by the loader
Once deferral is active,
tools_list_dictionary becomes an output of the loader — it is overwritten every time a search loads something. Schemas you append to it after construction are clobbered. Register them with agent.defer_tool_schemas([...]) instead.setup_dynamic_tools rebuilds from scratch
setup_dynamic_tools rebuilds from scratch
Calling
setup_dynamic_tools() discards the existing loader, including which tools were already marked loaded. Autonomous agents call it twice by design. MCP schemas survive via an internal cache; anything you registered manually must be re-added with defer_tool_schemas().Handoffs are never deferred
Handoffs are never deferred
The
handoff_task tool registered by the handoffs parameter is preserved across setup and stays always-loaded, so delegation works on turn one without a search.Next Steps
Dynamic Tool Examples
Runnable end-to-end examples for local tools, MCP, and the autonomous loop
DynamicToolLoader API
Full class reference for the loader, its search algorithm, and its methods
Agent Tools
How tools are defined, converted to schemas, and executed
MCP Integration
Connect MCP servers and defer their tool catalogs
Reference
- Loader:
swarms/tools/dynamic_tool_loader.py - Agent parameter and activation:
swarms/structs/agent.py(dynamic_tools,setup_dynamic_tools,defer_tool_schemas,defer_mcp_tools) - Autonomous-loop control tools and pre-warming:
swarms/agents/autonomous_loop.py