Observed since 20 Oct, 19:37 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Dynamic tool search for Google ADK — load tools on demand instead of all at once
ADK-native deferred tool discovery for large function and MCP catalogs.
SearchableToolset exposes four lightweight management tools initially. The model searches the
catalog, activates an exact result, and ADK exposes the selected tool on the next model step.
Selected tools execute through ADK's normal tool pipeline, preserving authentication,
confirmation, callbacks, plugins, tracing, and lifecycle behavior.
Large tool catalogs increase prompt size and make tool selection less reliable. Tool search keeps full schemas out of the initial model request while retaining a searchable local catalog.
Initial request: search_tools, load_tool, unload_tool, clear_loaded_tools
↓
search_tools("weather by city")
↓
[{"name": "get_weather", "description": "...", "score": 4.2}]
↓
load_tool("get_weather")
↓
Next model step: management tools + get_weather
pip install adk-tool-search
from google.adk.agents import LlmAgent
from adk_tool_search import SearchableToolset
def get_weather(location: str) -> dict:
"""Get current weather for a location.
Args:
location: City or coordinates.
"""
return {"location": location, "temperature": 22}
toolset = SearchableToolset(
namespace="assistant",
tools=[get_weather],
max_loaded_tools=20,
)
agent = LlmAgent(
name="assistant",
model="gemini-2.5-flash",
instruction=(
"Use search_tools to discover capabilities, load_tool to activate an exact result, "
"then call the activated tool."
),
tools=[toolset],
)
Loaded names are persisted in session state under:
adk_tool_search.loaded_tools.<namespace>
Wrap the McpToolset instead of detaching its tools at startup:
from google.adk.agents import LlmAgent
from google.adk.tools.mcp_tool import McpToolset, StdioConnectionParams
from mcp import StdioServerParameters
from adk_tool_search import SearchableToolset
mcp = McpToolset(
connection_params=StdioConnectionParams(
server_params=StdioServerParameters(
command="npx",
args=["-y", "@modelcontextprotocol/server-github"],
)
)
)
github_tools = SearchableToolset(
namespace="github",
source=mcp,
tool_name_prefix="github",
)
agent = LlmAgent(
name="github_assistant",
model="gemini-2.5-flash",
tools=[github_tools],
)
The wrapper delegates source authentication and close(), so ADK retains ownership of MCP
connections and cleanup. Use one prefixed SearchableToolset per authenticated MCP server because
ADK supports one authentication configuration per toolset.
SearchableToolsetSearchableToolset(
*,
namespace: str,
tools: Iterable[BaseTool | Callable] = (),
source: BaseToolset | None = None,
always_available: Iterable[BaseTool | Callable] = (),
index_factory: Callable[[], BM25ToolIndex] | None = None,
top_k: int = 5,
max_loaded_tools: int = 20,
tool_name_prefix: str | None = None,
)
tools: static deferred tools. Mutually exclusive with source.source: one dynamic ADK toolset, including McpToolset.always_available: tools exposed on every model request but excluded from search.index_factory: creates an exclusively owned index for each context-specific source snapshot.top_k: maximum search results.max_loaded_tools: active deferred-tool budget.tool_name_prefix: ADK-compatible prefix for management and active tools.The toolset exposes:
search_tools(query)load_tool(tool_name)unload_tool(tool_name)clear_loaded_tools()load_tool does not execute another tool internally. The selected tool is executed normally by ADK
on a subsequent model step.
ToolCatalogNormalizes callables to stable FunctionTool instances, validates names, rejects duplicates, and
extracts descriptions and parameter metadata.
BM25ToolIndexIndexes tool names, descriptions, argument names, and argument descriptions. It supports custom stopwords and minimum token lengths.
ToolSearchResultStructured retrieval result containing name, description, and score.
Use one searchable toolset per source and prefix each surface:
agent = LlmAgent(
name="assistant",
model="gemini-2.5-flash",
tools=[
SearchableToolset(namespace="github", source=github_mcp, tool_name_prefix="github"),
SearchableToolset(namespace="slack", source=slack_mcp, tool_name_prefix="slack"),
],
)
This preserves independent authentication, lifecycle, catalog refresh, and loaded-tool state.
uv sync --all-extras
uv run ruff format --check .
uv run ruff check .
uv run pytest
Live model tests require .env credentials:
uv run pytest -m llm
The default test suite also starts a local stdio MCP subprocess and exercises real MCP listing,
calling, and cleanup without network access. Live LLM tests use the ADK_TOOL_SEARCH_LLM_MODEL,
ADK_TOOL_SEARCH_LLM_API_BASE, and ADK_TOOL_SEARCH_LLM_API_KEY values from .env.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.3.0 | 12 Jul 2026 | 10 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 19:37 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:f5ce17d9cc19087b3d7eef3fed6721ecc3b9635285f8e0bc55afb2c15986b0e2