SaaS Toolkit Routing Registry
SaaS Toolkit Routing Registry
Canonical lookup for every SaaS toolkit the platform touches → which MCP server handles it for each tenant. Any session (Claude Code, Cursor, Windsurf, VS Code, Codex CLI) reads this file when deciding how to satisfy a multi-toolkit request such as “pull Kahuna GTM + Analytics + HubSpot”.
This file also doubles as the ADR-058 Path 2 audit trail for toolkits Composio doesn’t cover (those land with vendor = PIPEDREAM or CF_WORKER).
One grep away from the answer.
grep -i googletagmanager docs/composio/toolkit-registry.mdreturns the row that tells you which MCP to call and with which tenant identifier.
Registry
| toolkit_slug | vendor | mcp_server (ascend) | mcp_server (kahuna) | tool_prefix | status | notes |
|---|---|---|---|---|---|---|
hubspot | COMPOSIO | composio-ascend | composio-kahuna | HUBSPOT_* | LIVE | Tenant routing via user_id={slug}. Lifecycle dates: use hs_v2_date_entered_{stage_id} only. |
salesforce | COMPOSIO | composio-ascend | composio-kahuna | SALESFORCE_* | LIVE | SOQL via SALESFORCE_EXECUTE_SOQL_QUERY. Kahuna prod v66.0. |
googleads | COMPOSIO | composio-ascend | composio-kahuna | GOOGLEADS_* | LIVE | v24. MCC routing: login-customer-id header = MCC, path = sub-account CID. |
googleanalytics | COMPOSIO | composio-ascend | composio-kahuna | GOOGLEANALYTICS_* | LIVE | GA4 Data API v1beta only. Kahuna 273714189, Ascend 503817619. |
googlesuper | COMPOSIO | composio-ascend | composio-kahuna | GOOGLESUPER_* | LIVE | Unified Google Workspace (Drive, Sheets, Docs). |
gmail | COMPOSIO | composio-ascend | composio-kahuna | GMAIL_* | LIVE | Search threads, send, label. |
googlecalendar | COMPOSIO | composio-ascend | composio-kahuna | GOOGLECALENDAR_* | LIVE | Events, free/busy, suggest time. |
googletagmanager | PIPEDREAM | pipedream-gtm-ascend | pipedream-gtm-kahuna | PIPEDREAM_GTM_* | LIVE | Path D per ADR-061. Composio does not cover GTM. Ascend connect verified 2026-05-20 (apn_JjhBPDA); Kahuna connect verified 2026-05-20 (apn_AVhav9D). Project proj_ELsVB0b. Both tenants share one Google login (mishaal@ascendgtm.net) and one GTM account (4703167523 — named “Kahuna” but hosts both containers); tenant routing keys off container_id — ascend→GTM-KXTJZ8QD (ascendgtm.net), kahuna→GTM-NFPWVVL (kahunaworkforce.com). Authorized scopes: tagmanager.readonly, tagmanager.edit.containers, tagmanager.publish (covers ~all version operations via workspaces). tagmanager.edit.containerversions not exposed by Pipedream’s stock GTM OAuth app — defer to custom-OAuth-client ADR if versions.live / versions.undelete strictly needed. Container mapping authoritative in this file until tenant_config:{tenant}.gtm KV is wired. Discovery recipe: manual-googletagmanager.md. Capability index: docs/tools/pipedream-googletagmanager/capability_registry.yaml. |
slack | COMPOSIO | composio-ascend | — | SLACK_* | LIVE | All scopes granted. Ascend-only (no Kahuna Slack connection). |
gong | COMPOSIO | — | composio-kahuna | GONG_* | LIVE | Basic Auth, us-58396.api.gong.io. Kahuna-only. |
apollo | COMPOSIO | composio-ascend | — | APOLLO_* | LIVE | Mixed people / company search, bulk enrich. |
semrush | COMPOSIO | composio-ascend | composio-kahuna | SEMRUSH_* | LIVE | Domain analytics + keyword research. |
linkedin | COMPOSIO | composio-ascend | composio-kahuna | LINKEDIN_* | LIVE | Organic posts + profile. |
linkedin_ads | COMPOSIO | — | composio-kahuna | LINKEDIN_ADS_* | LIVE | Kahuna-only (paid LinkedIn). |
gamma | COMPOSIO | composio-ascend | composio-kahuna | GAMMA_* | LIVE | 2 tools only: GAMMA_GENERATE_GAMMA, GAMMA_GET_GAMMA_FILE_URLS. No list/search — cannot enumerate existing decks. |
quickbooks | COMPOSIO | composio-ascend | — | QUICKBOOKS_* | LIVE | Realm 9341455490822583. Always pass account explicitly (not “default”). |
vercel | COMPOSIO | composio-ascend | — | VERCEL_* | LIVE | Deployments + project management. |
perplexityai | COMPOSIO | composio-ascend | — | PERPLEXITYAI_* | LIVE | Web-augmented LLM. |
aws (Bedrock / SES / Textract) | V5_CALL_API | ascend-gateway | ascend-gateway | aws_* | LIVE | Frozen fallback worker. Tools: llm_invoke, aws_bedrock_invoke, aws_ses_send, aws_textract. |
anthropic | V5_CALL_API | ascend-gateway | ascend-gateway | claude / llm_invoke | LIVE | Through AI Gateway (invariant 12). Frontier judges + user-facing only — background calls default to DeepSeek. |
web_fetch | V5_CALL_API | ascend-side-channel | ascend-side-channel | web_fetch / perplexity_search | LIVE | SSRF-safe HTTP fetch, Jina markdown mode. |
arbitrary_http | V5_CALL_API | ascend-gateway | ascend-gateway | call_api | LIVE | Generic HTTP escape hatch. Use ONLY for one-off authenticated calls with no registry row. Undocumented SaaS does NOT belong here — file under ADR-058 Path 2 → Pipedream. |
Status values
| status | meaning |
|---|---|
LIVE | Connected and verified end-to-end. Safe to call. |
PENDING | Connection ID exists or vendor onboarding incomplete (e.g. consent pending). |
WONT-FIX | Provider assessed and deprioritized. Will not integrate. |
Vendor values
| vendor | meaning | when to choose |
|---|---|---|
COMPOSIO | Native Composio toolkit, OAuth managed end-to-end | First-choice for any OAuth SaaS provider Composio covers. |
PIPEDREAM | Pipedream Connect (sanctioned gap-fill per ADR-061) | OAuth SaaS Composio does NOT cover. Default fallback before reaching for V5_CALL_API. |
V5_CALL_API | V5 Worker call_api / direct platform tools | AWS, LLM (Anthropic / DeepSeek / Gemini / xAI / OpenRouter), arbitrary HTTP with no other route, web_fetch. |
CF_WORKER | Persistent CF Worker built for one provider | Only when Pipedream also lacks the toolkit AND traffic justifies a custom worker. Requires an ADR. |
NATIVE_MCP | Dedicated MCP server (e.g. github, mem0, cloudflare-api) | When the provider ships an official MCP we trust. |
Adding a row
- Find the toolkit’s row OR add a new one with the recipe from
docs/composio/missing-toolkit-runbook.md. - Pick vendor based on the table above.
- Fill
mcp_server (ascend)/mcp_server (kahuna)from the corresponding row in.mcp.json——if the tenant is not connected. - Set
tool_prefixto the literal prefix of the MCP tool names ({TOOLKIT}_{ACTION}for Composio,PIPEDREAM_{TOOLKIT}_*for Pipedream). - Run
npm run check:pre-commit— check 25 enforces this row exists for every MCP server in.mcp.json.
git add docs/composio/toolkit-registry.mdgit commit -m "docs(routing): record {toolkit} routing (vendor={vendor})"Multi-toolkit queries
When a single user ask spans multiple toolkits (e.g. “pull GTM + Analytics + HubSpot for kahuna”):
- Decompose the ask per toolkit.
- Look up each toolkit in the registry above → identify
vendorandmcp_server ({tenant}). - Fan out in parallel — one assistant message with N MCP tool calls. See
.claude/rules/parallelization.md. - Pass the tenant identifier on every call:
- Composio →
user_id={slug}(ascendorkahuna). - Pipedream →
external_user_id={slug}.
- Composio →
- Aggregate in the session, never in any vendor — none of the MCPs federate.
Worked example — “pull Kahuna GTM + Analytics + HubSpot”
| Toolkit | Registry row says | Call shape |
|---|---|---|
googletagmanager | PIPEDREAM, pipedream-gtm-kahuna | mcp__pipedream-gtm-kahuna__* — GTM v2 endpoint via Pipedream proxy, external_user_id=kahuna |
googleanalytics | COMPOSIO, composio-kahuna | mcp__composio-kahuna__GOOGLEANALYTICS_RUN_REPORT({ user_id: "kahuna", property_id: "273714189", ... }) |
hubspot | COMPOSIO, composio-kahuna | mcp__composio-kahuna__HUBSPOT_HUBSPOT_LIST_CONTACTS({ user_id: "kahuna", ... }) |
All three issued in one parallel batch. The session aggregates the three responses.
Discoverability
Run discover_apis({query: "list GTM tags"}) (V5 Worker) — it returns gtm_list_tags from docs/tools/pipedream-googletagmanager/capability_registry.yaml alongside Composio’s HubSpot/GA4 rows. Semantic discovery is the unified entrypoint across vendors.
Drift CI
scripts/checks/25-toolkit-registry-routing.ts enforces:
- Every MCP server in
.mcp.jsonwith namecomposio-*orpipedream-*has at least one row referencing it. - Every row with
vendor != WONT-FIXlists anmcp_serverthat exists in.mcp.json. - Every
docs/tools/*/capability_registry.yamlmatches a row whosetoolkit_slugfield is present.
Drift fails npm run check:pre-commit.