SDK Language
Python SDK (composio package)
SDK Version
composio-client==1.41.0, composio==0.17.1 (Also reproduced on composio-client==1.39.0, composio==0.15.0.)
Runtime Environment
Python 3.12.8 on macOS (darwin 24.6.0)
Environment
Local Development
Describe the Bug
Several Google Ads tools exist in the toolkit catalog and are executable via session.execute, but are missing from the tool-router semantic search index (POST /api/v3.1/tool_router/session/{session_id}/search and the COMPOSIO_SEARCH_TOOLS meta tool).
Pattern:
tools.list(toolkit_slug="googleads") returns the full toolkit (22 tools in our project).
tools.retrieve(slug) / composio.tools.get(user_id, tools=[slug]) succeed for affected slugs.
tool_router.session.search never returns them — not in primary_tool_slugs, related_tool_slugs, or tool_schemas.
- When other Google Ads tools are semantically relevant but outside the session allowlist, search lists them under
"Restricted tools (not returned...)". Affected tools are often not even on that restricted list — they appear completely absent from the search corpus.
- The same behavior occurs via
COMPOSIO_SEARCH_TOOLS (session.execute) — not a separate search path.
- With a wildcard session (
toolkits.enable: ["googleads"], no per-tool allowlist), search returns some Google Ads tools but still omits others that are in the catalog.
Example (confirmed): GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA — needed for negative keywords / campaign criteria mutation. Present in catalog, executable when connected, never surfaced by search (even when it is the only tool enabled in the session). We have observed the same class of omission for other Google Ads actions (e.g. ad creation, shared sets, offline conversion upload, keyword idea generation) that appear in catalog/tools.list but not in search results; Pipedream’s Google Ads integration exposes a fuller set for the same workflows.
Expected: Tools in the catalog that match a use case and are allowed by the session should be returned by search, or listed as restricted when semantically relevant but outside the allowlist.
Actual: A subset of Google Ads tools is invisible to search entirely, while sibling tools in the same toolkit are discoverable (or explicitly listed as restricted).
Impact: Agents relying on tool-router discovery cannot find tools users enable in the UI; execution-by-slug still works, so discovery and execution disagree.
Steps to Reproduce
- Initialize
composio_client.Composio with a valid project API key.
- List Google Ads catalog:
client.tools.list(toolkit_slug="googleads", limit=500) — note tools present (e.g. GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA).
- Create a tool-router session scoped to Google Ads — either:
- Single-tool:
tools={"googleads": {"enable": ["GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA"]}}, or
- Wildcard: only
toolkits={"enable": ["googleads"]}.
- Call
session.search with a use case that should match (e.g. "add negative keyword to Google Ads campaign via criteria mutate").
- Observe empty or partial results: affected slugs missing from
primary_tool_slugs / related_tool_slugs / tool_schemas, and often absent from the restricted-tools list too.
- (Optional) Repeat via
session.execute(..., tool_slug="COMPOSIO_SEARCH_TOOLS", ...) — same outcome.
- (Optional)
session.execute with the slug directly (with a connected account) — tool runs (we saw live Google API responses, e.g. 429 RESOURCE_EXHAUSTED, not “tool not found”).
Minimal Reproducible Example
import json
from composio_client import Composio
client = Composio(api_key="YOUR_API_KEY")
TOOLKIT = "googleads"
# Example of a catalog tool missing from search; others in the same toolkit show the same pattern.
EXAMPLE_SLUG = "GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA"
QUERY = "add negative keyword to Google Ads campaign via criteria mutate"
# 1) Catalog includes the tool
catalog = client.tools.list(toolkit_slug=TOOLKIT, limit=500)
catalog_slugs = {t.slug for t in catalog.items}
assert EXAMPLE_SLUG in catalog_slugs
print(f"Catalog: {len(catalog_slugs)} tools, includes {EXAMPLE_SLUG}")
# 2) Search index does not — even when it's the only enabled tool
session = client.tool_router.session.create(
user_id="test_user",
toolkits={"enable": [TOOLKIT]},
tools={TOOLKIT: {"enable": [EXAMPLE_SLUG]}},
manage_connections={"enable": False},
)
resp = client.tool_router.session.search(
session.session_id,
queries=[{"use_case": QUERY}],
)
r = resp.results[0]
print("primary:", r.primary_tool_slugs)
print("related:", r.related_tool_slugs)
print("schemas:", list((resp.tool_schemas or {}).keys()) if isinstance(resp.tool_schemas, dict) else [])
print("guidance:", r.execution_guidance)
# 3) Wildcard session: some googleads tools appear, example slug still missing
wildcard = client.tool_router.session.create(
user_id="test_user",
toolkits={"enable": [TOOLKIT]},
manage_connections={"enable": False},
)
wresp = client.tool_router.session.search(
wildcard.session_id,
queries=[{"use_case": QUERY}],
)
wr = wresp.results[0]
all_returned = set(wr.primary_tool_slugs) | set(wr.related_tool_slugs)
print("wildcard search returned:", sorted(all_returned))
print(f"{EXAMPLE_SLUG} in wildcard results:", EXAMPLE_SLUG in all_returned)
Error Output / Stack Trace
No HTTP error — search returns 200 with incomplete results. Example (single-tool session, criteria-mutate query):
{
"results": [{
"use_case": "add negative keyword to Google Ads campaign via criteria mutate",
"primary_tool_slugs": [],
"related_tool_slugs": [],
"toolkits": [],
"execution_guidance": "IMPORTANT: Some tools are restricted in this environment and have not been returned.\n\nRestricted tools (not returned; you cannot execute these in this environment): GOOGLEADS_MUTATE_CAMPAIGNS, GOOGLEADS_MUTATE_AD_GROUPS, GOOGLEADS_ADD_OR_REMOVE_TO_CUSTOMER_LIST, GOOGLEADS_LIST_ACCESSIBLE_CUSTOMERS, GOOGLEADS_SEARCH_STREAM_GAQL, GOOGLEADS_GET_CAMPAIGN_BY_ID, GOOGLEADS_CREATE_CUSTOMER_LIST\n\nNo matching tools found for \"add negative keyword to Google Ads campaign via criteria mutate\"."
}],
"tool_schemas": {},
"toolkit_connection_statuses": []
}
`GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA` is neither returned nor listed as restricted. Wildcard search for the same query returns other slugs (e.g. `GOOGLEADS_SEARCH_STREAM_GAQL`, `GOOGLEADS_MUTATE_CAMPAIGNS`) but still not the example slug.
Reproducibility
Additional Context or Screenshots
Toolkit
googleads — search index appears to be a strict subset of the catalog.
Tools discoverable via search (examples)
GOOGLEADS_SEARCH_STREAM_GAQL, GOOGLEADS_MUTATE_CAMPAIGNS, GOOGLEADS_MUTATE_AD_GROUPS, GOOGLEADS_GET_CAMPAIGN_BY_ID, GOOGLEADS_LIST_ACCESSIBLE_CUSTOMERS, etc.
Tools in catalog but missing from search (examples)
Includes at least GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA; we’ve seen the same pattern for other Google Ads actions (negative keywords / criteria, ad creation, shared sets, offline conversions, keyword ideas) that show in tools.list but never in session.search.
COMPOSIO_SEARCH_TOOLS
Same empty/partial responses as session.search — not a separate index.
Direct semantic search (tools.get(search=...))
Also weak on natural-language queries for some of these tools; slug-based / tools.list inventory is reliable. Suggests catalog and tool-router search corpora are out of sync, not just ranking.
Related issues
- #2798 — discovery truncation despite active connections
- #3290 — list vs execute mismatch (inverse pattern)
Suggested fix direction
Align tool-router search index with the catalog for googleads (and audit other toolkits for the same gap), or document which tools are intentionally excluded from search and why.
SDK Language
Python SDK (
composiopackage)SDK Version
composio-client==1.41.0, composio==0.17.1 (Also reproduced on composio-client==1.39.0, composio==0.15.0.)
Runtime Environment
Python 3.12.8 on macOS (darwin 24.6.0)
Environment
Local Development
Describe the Bug
Several Google Ads tools exist in the toolkit catalog and are executable via
session.execute, but are missing from the tool-router semantic search index (POST /api/v3.1/tool_router/session/{session_id}/searchand theCOMPOSIO_SEARCH_TOOLSmeta tool).Pattern:
tools.list(toolkit_slug="googleads")returns the full toolkit (22 tools in our project).tools.retrieve(slug)/composio.tools.get(user_id, tools=[slug])succeed for affected slugs.tool_router.session.searchnever returns them — not inprimary_tool_slugs,related_tool_slugs, ortool_schemas."Restricted tools (not returned...)". Affected tools are often not even on that restricted list — they appear completely absent from the search corpus.COMPOSIO_SEARCH_TOOLS(session.execute) — not a separate search path.toolkits.enable: ["googleads"], no per-tool allowlist), search returns some Google Ads tools but still omits others that are in the catalog.Example (confirmed):
GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA— needed for negative keywords / campaign criteria mutation. Present in catalog, executable when connected, never surfaced by search (even when it is the only tool enabled in the session). We have observed the same class of omission for other Google Ads actions (e.g. ad creation, shared sets, offline conversion upload, keyword idea generation) that appear in catalog/tools.listbut not in search results; Pipedream’s Google Ads integration exposes a fuller set for the same workflows.Expected: Tools in the catalog that match a use case and are allowed by the session should be returned by search, or listed as restricted when semantically relevant but outside the allowlist.
Actual: A subset of Google Ads tools is invisible to search entirely, while sibling tools in the same toolkit are discoverable (or explicitly listed as restricted).
Impact: Agents relying on tool-router discovery cannot find tools users enable in the UI; execution-by-slug still works, so discovery and execution disagree.
Steps to Reproduce
composio_client.Composiowith a valid project API key.client.tools.list(toolkit_slug="googleads", limit=500)— note tools present (e.g.GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA).tools={"googleads": {"enable": ["GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA"]}}, ortoolkits={"enable": ["googleads"]}.session.searchwith a use case that should match (e.g."add negative keyword to Google Ads campaign via criteria mutate").primary_tool_slugs/related_tool_slugs/tool_schemas, and often absent from the restricted-tools list too.session.execute(..., tool_slug="COMPOSIO_SEARCH_TOOLS", ...)— same outcome.session.executewith the slug directly (with a connected account) — tool runs (we saw live Google API responses, e.g.429 RESOURCE_EXHAUSTED, not “tool not found”).Minimal Reproducible Example
Error Output / Stack Trace
No HTTP error — search returns 200 with incomplete results. Example (single-tool session, criteria-mutate query): { "results": [{ "use_case": "add negative keyword to Google Ads campaign via criteria mutate", "primary_tool_slugs": [], "related_tool_slugs": [], "toolkits": [], "execution_guidance": "IMPORTANT: Some tools are restricted in this environment and have not been returned.\n\nRestricted tools (not returned; you cannot execute these in this environment): GOOGLEADS_MUTATE_CAMPAIGNS, GOOGLEADS_MUTATE_AD_GROUPS, GOOGLEADS_ADD_OR_REMOVE_TO_CUSTOMER_LIST, GOOGLEADS_LIST_ACCESSIBLE_CUSTOMERS, GOOGLEADS_SEARCH_STREAM_GAQL, GOOGLEADS_GET_CAMPAIGN_BY_ID, GOOGLEADS_CREATE_CUSTOMER_LIST\n\nNo matching tools found for \"add negative keyword to Google Ads campaign via criteria mutate\"." }], "tool_schemas": {}, "toolkit_connection_statuses": [] } `GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA` is neither returned nor listed as restricted. Wildcard search for the same query returns other slugs (e.g. `GOOGLEADS_SEARCH_STREAM_GAQL`, `GOOGLEADS_MUTATE_CAMPAIGNS`) but still not the example slug.Reproducibility
Additional Context or Screenshots
Toolkit
googleads— search index appears to be a strict subset of the catalog.Tools discoverable via search (examples)
GOOGLEADS_SEARCH_STREAM_GAQL,GOOGLEADS_MUTATE_CAMPAIGNS,GOOGLEADS_MUTATE_AD_GROUPS,GOOGLEADS_GET_CAMPAIGN_BY_ID,GOOGLEADS_LIST_ACCESSIBLE_CUSTOMERS, etc.Tools in catalog but missing from search (examples)
Includes at least
GOOGLEADS_MUTATE_CAMPAIGN_CRITERIA; we’ve seen the same pattern for other Google Ads actions (negative keywords / criteria, ad creation, shared sets, offline conversions, keyword ideas) that show intools.listbut never insession.search.COMPOSIO_SEARCH_TOOLSSame empty/partial responses as
session.search— not a separate index.Direct semantic search (
tools.get(search=...))Also weak on natural-language queries for some of these tools; slug-based /
tools.listinventory is reliable. Suggests catalog and tool-router search corpora are out of sync, not just ranking.Related issues
Suggested fix direction
Align tool-router search index with the catalog for
googleads(and audit other toolkits for the same gap), or document which tools are intentionally excluded from search and why.