Typed tool catalog (with narrow read-only escape hatches)
When the agent acts on an ad account, it selects a tool from a fixed registry. Each tool has a strict input schema, a named handler, and a single responsibility — pull performance, list campaigns, pause a campaign, generate a creative, etc.
The catalog is backed by ~100+ vetted Python scripts in apps/ppc-backend/client-tools/ plus a smaller set of TypeScript handlers in the web app. For write actions (create, update, pause, budget changes, creative uploads), the agent never writes SQL, GraphQL, or shell — it picks a named handler like pause_campaign or update_campaign_budget and passes structured arguments.
For reads, a few platforms expose constrained, read-only query languages — Google Ads (GAQL), LinkedIn (GraphQL), Meta (Insights API). The agent can pass those queries through tools like run_gaql_query, but the queries are scoped to the caller's connected account and cannot mutate data. See the GAQL escape hatch below.
You can browse the catalog at /docs/mcp/tools and the source ships in the jshorwitz/synter-media repo.