Catalog PyPI
PACKAGE EXPLORERView in registry

adk-tool-search

PyPI

Dynamic tool search for Google ADK — load tools on demand instead of all at once

adkagentaigeminillmmcptool-searchtools
Versions collected1
Direct dependencies10From release 0.3.0
Last observed20 Oct, 19:37 UTC

README

Version 0.3.0 documentation

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.

Why

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

Install

pip install adk-tool-search

Function Tools

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>

MCP Tools

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.

Public API

SearchableToolset

SearchableToolset(
    *,
    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.

ToolCatalog

Normalizes callables to stable FunctionTool instances, validates names, rejects duplicates, and extracts descriptions and parameter metadata.

BM25ToolIndex

Indexes tool names, descriptions, argument names, and argument descriptions. It supports custom stopwords and minimum token lengths.

ToolSearchResult

Structured retrieval result containing name, description, and score.

Multiple Sources

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.

Development

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.

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.3.012 Jul 202610

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
manojlds/adk-tool-search

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 19:37 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:f5ce17d9cc19087b3d7eef3fed6721ecc3b9635285f8e0bc55afb2c15986b0e2