Quantum ADS MCP
Provides tools for managing Google Ads campaigns, including reading and writing ad data via GAQL queries, campaign management, and performance insights.
Allows interaction with Google Tag Manager for managing tags, triggers, and variables, including server-side tagging and Consent Mode v2.
Enables querying and managing Looker dashboards, looks, and data models, including reading underlying data.
Provides access to YouTube Data API, Analytics, and Reporting for video and channel management, including metrics and content operations.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Quantum ADS MCP Show Google Ads performance for last 7 days"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
quantum-ads-mcp
The most complete open Model Context Protocol control plane for the Google marketing stack — 21 connectors, read + guarded write, Ed25519 signed audit, OAuth 2.1 multi-tenant.
Architecture · The 21 connectors · Install · Configure · Safety · Autonomy · Observability · Roadmap
A sovereign Google marketing-agency control plane over the Model Context Protocol: a shared core (multi-tenant auth, version resilience, a GAQL/query engine, a safety spine with a signed audit ledger) and 21 pluggable per-product connectors spanning the entire Google marketing stack. Built for an AI agent to operate that stack at full granularity, safely.
Status. The full connector surface is built and tested at the logic layer: read + guarded write across 21 products, every tool exercised by mocked tests (no live SDK needed). The per-product live SDK glue is isolated in
sdk.pymodules and smoke-gated (verified against real APIs with your own credentials, not in CI — Google Ads API v26 included; see docs/LIVE_VALIDATION_RESULTS.md). Served over stdio or Streamable HTTP behind OAuth 2.1 (JWT bearer tokens, RFC 9728 metadata, per-tenant credentials and scopes), verified end to end against a real HTTP server. Read-only by default. Every "most X" claim here is meant to be verifiable.
Contents
Why · The 21 connectors · Architecture · Core · Install · Configure · Run · Safety & honest claims · Roadmap
Related MCP server: Google Ads MCP Server
Architecture
flowchart TD
Client["MCP client (AI agent)"] -->|"stdio · or OAuth 2.1 HTTP (multi-tenant)"| Server["FastMCP server"]
Server --> Core["Sovereign core: auth · version resilience · GAQL/query engine · safety spine (read-only default + Ed25519 signed audit) · registry / meta-tool"]
Core --> C1["google_ads · ga4 · gtm · merchant"]
Core --> C2["datamanager · searchconsole · youtube"]
Core --> C3["dv360 · cm360 · sa360"]
Core --> C4["bigquery · adh · looker · meridian"]
Core --> C5["vertex · trends · gbp · language · workspace · recaptcha"]
C1 -. "smoke-gated sdk.py" .-> G["Google APIs (Ads v26, GA4, GTM, Merchant, …)"]
C4 -. "smoke-gated sdk.py" .-> GWhy this exists
Surveying June 2026: Google's official MCP is read-only (3 tools); the best open write-capable servers are pinned to sunsetting API versions, untested, single-product, or have no safety layer; the capable commercial ones are closed and remote-only. No open, self-hostable server is simultaneously complete across the stack, write-capable, safe, tested, version-resilient, and multi-product. Quantum ADS fills that gap.
The 21 connectors
Domain | Connectors |
Paid media | Google Ads (v26), DV360, CM360, SA360 |
Measurement | GA4 (Data + Admin), Data Manager API (Customer Match + conversions), Search Console |
Catalog / tagging | Merchant API, Google Tag Manager (+ server-side, Consent Mode v2) |
Channels | YouTube (Data + Analytics + Reporting), Business Profile, Trends |
Warehouse / BI / MMM | BigQuery (cost-guarded), Ads Data Hub, Looker, Meridian (Bayesian MMM) |
Creative / ops | Vertex AI (Gemini 3.8 / Gemini image / Veo 3.1, pure REST), free text-to-video (Wan 2.2 / LTX-Video on Hugging Face ZeroGPU, no billing), creative studio + campaign insights (anomalies, pacing, search-term mining, GA4 reconciliation; free OpenAI-compatible / SDXL / FLUX fallback when Vertex is unbilled), Cloud Translation + NL, Workspace (Sheets/Drive/Slides), reCAPTCHA Enterprise |
Full tool catalog, backend keys, and required SDK packages: CONNECTORS.md.
Beyond the curated tools, google.api.call runs any write method of 25 marketing Google
APIs (653 write methods, 1,180 in all), checked offline against each API's Discovery contract,
scope-checked, guarded, audited and reversible where the API allows — the way ads.mutate
covers every Google Ads resource.
Core (shared by every connector)
Multi-tenant auth + secret store — credentials load from env / secret manager and never reach the LLM.
Version resilience — pinned Google Ads API v26 from one
DEFAULT_API_VERSION, official sunset table + guard (days-until-sunset), offline GAQL field conformance (every queried field resolved against the SDK protos of the pinned version),ads.api.version_delta(exact resources/services/enums added or removed between two versions), and unknown-enum tolerance for Google's monthly releases.Query engine — GAQL build / validate (single-FROM, no-
OR, segment rules, 37-month cap) / stream / flatten, with quota token-buckets + exponential backoff. SA360 uses the same query shape.Safety spine — read-only by default; every mutation is guarded:
validate_onlypreview → two-step confirm token → Ed25519-signed, hash-chained audit ledger, persisted across restarts and verifiable withaudit.status. Consent-aware (Data Manager / Consent Mode v2) and cost-aware (BigQuery dry-run, $6.25/TiB).Connector registry + meta-tool discovery (
list_capabilities,describe_tool) and env-based connector selection (QUANTUM_ADS_CONNECTORS) so the tool list stays focused.
Install
git clone https://github.com/Casius999/quantum-ads-mcp.git
cd quantum-ads-mcp
uv sync --extra dev
uv run pytest -m "not live" # 600+ tests incl. Hypothesis property fuzzing, no credentialsOther ways in (each release ships them, with signed provenance):
One-click bundle — download
quantum-ads-mcp.mcpbfrom the latest release and open it in Claude Desktop; it asks for the developer token and OAuth values and keeps the secrets in the OS keychain.Container —
ghcr.io/casius999/quantum-ads-mcpserves Streamable HTTP on:8080(gh attestation verify oci://ghcr.io/casius999/quantum-ads-mcp:<version> -R Casius999/quantum-ads-mcp). Deployment on Cloud Run, and "Sign in with Google" for a team: docs/DEPLOY.md.PyPI / MCP Registry —
uvx quantum-ads-mcpand the registry entryio.github.casius999/quantum-ads-mcp(server.json) publish from the release workflow once PyPI trusted publishing is enabled for the repository.
Per-connector live SDKs (e.g. google-analytics-data, google-api-python-client,
google-cloud-bigquery) are installed only when you wire a connector's live backend — see
CONNECTORS.md. The core + mocked test suite need none of them.
Configure
Credentials come from process environment variables (set them in your MCP client's env block;
no secrets on disk). Every connector whose credentials resolve is wired at startup — lazily, so a
bad credential only affects its own connector; the rest answer BACKEND_NOT_CONFIGURED.
GOOGLE_ADS_USE_PROTO_PLUS=True
GOOGLE_ADS_API_VERSION=v26
GOOGLE_ADS_DEVELOPER_TOKEN=...
GOOGLE_ADS_CLIENT_ID=....apps.googleusercontent.com
GOOGLE_ADS_CLIENT_SECRET=...
GOOGLE_ADS_REFRESH_TOKEN=... # also serves GA4/GTM/Merchant/YouTube/... if scoped
GOOGLE_OAUTH_CLIENT_ID=... # optional dedicated non-Ads credential (+ _SECRET, _REFRESH_TOKEN)
GOOGLE_CLOUD_PROJECT=my-project # BigQuery, Vertex, Language, reCAPTCHA + quota routing
GOOGLE_VERTEX_LOCATION=global # optional
LOOKERSDK_BASE_URL=... # Looker (+ LOOKERSDK_CLIENT_ID / _CLIENT_SECRET)
QUANTUM_ADS_READ_ONLY=true # writes refused until set to false
QUANTUM_ADS_CONNECTORS=google_ads,ga4,gtm # optional: mount a subset (default: all)
QUANTUM_ADS_AUDIT_DIR=~/.quantum-ads/audit # signed audit ledger (default shown; empty = in memory)Full credential matrix: auth & guardrails · template: .env.example.
Never commit
.env,google-ads.yaml, orclient_secret*.json— all gitignored, andgitleaksruns in CI. See SECURITY.md.
Run
quantum-ads-mcp # stdio MCP server (what MCP clients launch)
quantum-ads-mcp serve --transport http # remote: Streamable HTTP behind OAuth 2.1Wire the stdio form into your MCP client (Claude Desktop / VS Code). The HTTP form is an OAuth 2.1
resource server: every request needs Authorization: Bearer <JWT> (signature, iss, aud
bound to the resource URL, expiry and the ads:read scope are checked; ads:write is required
for guarded writes), and it refuses to start without token verification configured.
# With your identity provider (Entra ID, Okta, Auth0, Keycloak, Google, ...):
QUANTUM_ADS_OAUTH_JWKS_URI=https://idp.example/.well-known/jwks.json
QUANTUM_ADS_OAUTH_ISSUER=https://idp.example
QUANTUM_ADS_PUBLIC_URL=https://ads.agency.example # audience = <public url>/mcp
# ...or self-hosted, with the built-in Ed25519 issuer:
quantum-ads-mcp keygen # prints QUANTUM_ADS_OAUTH_PUBLIC_KEY_FILE=...
quantum-ads-mcp token --tenant acme --scope "ads:read ads:write" --ttl 3600
# Multi-tenant: one credential set per tenant, selected by the token's `tenant` claim.
QUANTUM_ADS_TENANTS_SECRET=quantum-ads-tenants # Google Secret Manager (recommended), or
QUANTUM_ADS_TENANTS_FILE=tenants.json # {"tenants": {"acme": {"GOOGLE_ADS_...": "..."}}}With an external identity provider the server publishes Protected Resource Metadata (RFC 9728)
at /.well-known/oauth-protected-resource/mcp, so MCP clients discover where to sign in. Each
tool call runs as the token's tenant: its own backends, Google Ads client, write permission and
audit identity — never another tenant's or the operator's. Per-tenant rate limiting applies.
Safety & honest claims
Read-only by default; tokens never reach the model; zero secrets in the repo. CI runs lint, strict type-check, the full test suite (≥90% coverage gate), CodeQL, OpenSSF Scorecard, and gitleaks.
The defensible "most powerful" claim is coverage breadth + engineering rigor + safety + version resilience, each verifiable — not "record ad performance" (that depends on budget, creative, and Google's auction, not the server). Documentation states only what the test suite proves; the per-product live SDK calls are smoke-gated and labelled as such.
Google Ads: create and change anything
ads.mutate sends official MutateOperation JSON for any of the API's 65 mutable resource
kinds in one GoogleAdsService.Mutate request (temporary negative ids link new objects; atomic
unless partial_failure), validated offline against the pinned version's protos first.
ads.campaign.create_search, ads.campaign.create_pmax and ads.campaign.create_demand_gen
build complete Search, Performance Max and Demand Gen campaigns in one call; A/B experiments
(ads.experiment.create / schedule / promote / end), asynchronous BatchJobs for large
changes (ads.batch.submit / status), Reach Planner forecasts (allowlisted tokens), Keyword Planner
ideas, recommendations (list / apply / dismiss) and ads.mutate.schema complete the plane.
Every applied ads.mutate records its inverse in the signed audit trail — updated fields are
read back first, created objects are removed on undo — and ads.rollback replays it.
Agent autonomy and MCP-native features
The agent is the decision-maker: it holds the data. With QUANTUM_ADS_WRITE_MODE=auto a write
is validated by the API (validate_only) and applied in the same call — a failed validation
never applies; confirm (default) keeps a two-call preview/commit. Guardrails are opt-in: a
QUANTUM_ADS_POLICY_FILE (default + per-tenant sections) can forbid or allow operations by
glob, cap any *amount_micros, bound operations per call, restrict UTC hours and limit writes
per tenant per day — no file, no limits.
Tool annotations on every tool (
read_only_hint,destructive_hint,idempotent_hint,open_world_hint, title) so clients auto-run reads and treat destructive writes accordingly.Resources:
quantum-ads://capabilities,quantum-ads://google-ads/versions,quantum-ads://google-ads/field-deltas,quantum-ads://session(tenant, scopes, write mode, effective policy).Prompts (playbooks chaining the tools end to end): weekly account audit, Search campaign launch, PMax diagnosis, search-terms mining, budget reallocation, Merchant feed optimisation, GA4↔Ads reconciliation, demand research, creative studio.
Background tasks (
QUANTUM_ADS_TASKS=true,uv sync --extra tasks): video, Veo, Gemini, BigQuery runs, Meridian fits and ADH queries run as MCP tasks (SEP-2663) on modern-protocol (2026-07-28) clients — a task handle to poll instead of a held call; every long-running tool also carries a timeout.Tool search (
QUANTUM_ADS_TOOL_SEARCH=true): the catalog collapses tosearch_tools+call_tool(BM25) plus the meta tools, so an agent loads only the tools a task needs.
Observability
Every tool call writes one JSON line to stderr — tool, tenant, outcome, error code, duration,
trace id; never arguments or results — and health reports call counters. FastMCP's
OpenTelemetry spans carry quantum_ads.tenant / outcome / error_code and are exported over
OTLP when the standard variables are set (uv sync --extra observability):
OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318 # or OTEL_TRACES_EXPORTER=console (stderr)
OTEL_SERVICE_NAME=quantum-ads-mcp # default
QUANTUM_ADS_LOG_CALLS=false # silence the per-call JSON linesAudit anchoring
The audit ledger is signed and hash-chained; audit.anchor additionally publishes its head to
Bitcoin through public OpenTimestamps calendars (only a SHA-256 leaves the machine) and saves a
standard .ots proof under <audit dir>/anchors/, verifiable by anyone with ots verify.
audit.anchor_status upgrades pending proofs once Bitcoin confirms them and checks each one
against the block's merkle root from a public explorer rather than trusting the calendar
(bitcoin_verified; uv sync --extra anchoring).
Roadmap
Waves 1–6 of docs/ROADMAP_V1.md are in: MCP-native foundation, Google Ads complete, insights and creative studio, the generic Google API plane, Sign in with Google and distribution, agent evals and mutation testing. Still open:
typed output schemas per tool, record/replay cassettes for credential-free CI, async I/O;
live checks that need accounts the project cannot create (ADH, CM360, Business Profile, DV360), a real Google sign-in on a public URL, and PyPI trusted publishing (one setting on pypi.org);
paid Veo generation stays opt-in (
VERTEX_LIVE_VEO=1).
License
MIT — see LICENSE.
— Julien Compain · NovaQuantiX
Available Tools
163 toolsadh.customers.listAdh customers listARead-onlyIdempotent
List Ads Data Hub customers (accounts) the authenticated user can access.
Inputs: no named parameters. Returns: object
adh.jobs.getAdh jobs getARead-onlyIdempotent
Poll a started ADH analysis-query run by operation name (status + result reference).
Inputs: operation_name (required). Returns: object
adh.queries.listAdh queries listBRead-onlyIdempotent
List the stored analysis queries owned by an ADH customer.
Inputs: customer_id (required). Returns: object
adh.query.createAdh query createB
Create a stored ADH analysis query (guarded: validate_only preview + confirm token). Creates only; does not run the query.
Inputs: title (required), query_text (required), customer_id (required), confirm. Returns: object
adh.query.startAdh query startARead-onlyIdempotent
Start a stored ADH analysis query over a date range; returns an operation/job ref (async, privacy-checked run — poll adh.jobs.get for the result).
Inputs: end_date (required), query_id (required), start_date (required), customer_id (required). Returns: object
ads.api.version_deltaAds api version deltaARead-onlyIdempotent
Exact resources/services/enums added or removed between two API versions (computed from the installed SDK; plan an upgrade without a token).
Inputs: to_version, from_version. Returns: object
ads.batch.statusAds batch statusBRead-onlyIdempotent
Status of a BatchJob and, once done, its per-operation results.
Inputs: batch_job (required), customer_id (required), limit. Returns: object
ads.batch.submitAds batch submitA
Submit a large mutation (thousands of MutateOperations) as an asynchronous BatchJob; track it with ads.batch.status.
Inputs: operations (required), customer_id (required), confirm. Returns: object
ads.budget.updateAds budget updateCDestructiveIdempotent
Update a campaign budget amount in micros (guarded).
Inputs: budget_id (required), customer_id (required), amount_micros (required), confirm. Returns: object
ads.campaign.create_demand_genAds campaign create demand genB
Create a complete Demand Gen campaign in one atomic call: budget, campaign, ad group targeting, image/logo assets and a multi-asset ad.
Inputs: name (required), final_url (required), headlines (required), customer_id (required), +11 more. Returns: object
ads.campaign.create_pmaxAds campaign create pmaxA
Create a complete Performance Max campaign in one atomic call: budget, bidding, targeting, text + image assets (base64, e.g. from vertex.imagen.generate), asset group, and brand assets (business name, logo) under brand guidelines.
Inputs: name (required), images (required), final_url (required), headlines (required), +13 more. Returns: object
ads.campaign.create_searchAds campaign create searchA
Create a complete Search campaign in one atomic call: budget, bidding, geo/language targeting, negatives, ad group, keywords and a responsive search ad.
Inputs: name (required), keywords (required), final_url (required), headlines (required), +11 more. Returns: object
ads.campaign.set_statusAds campaign set statusBDestructiveIdempotent
Pause/enable a campaign (guarded: validate_only preview + confirm token).
Inputs: status (required), campaign_id (required), customer_id (required), confirm. Returns: object
ads.change_historyAds change historyDRead-onlyIdempotent
Change history (audit=change_event, delta=change_status).
Inputs: customer_id (required), mode, limit, date_range. Returns: object
ads.experiment.createAds experiment createB
Create an A/B experiment on a campaign: control + treatment arms with a traffic split. Edit the treatment draft (arm in_design_campaigns) with ads.mutate, then schedule.
Inputs: name (required), customer_id (required), base_campaign_id (required), suffix, +3 more. Returns: object
ads.experiment.endAds experiment endCDestructive
End a running experiment.
Inputs: experiment (required), customer_id (required), confirm. Returns: object
ads.experiment.promoteAds experiment promoteCDestructive
Promote an experiment's treatment changes to the base campaign.
Inputs: experiment (required), customer_id (required), confirm. Returns: object
ads.experiment.scheduleAds experiment scheduleCDestructive
Start (schedule) an experiment.
Inputs: experiment (required), customer_id (required), confirm. Returns: object
ads.fields.deltasAds fields deltasBRead-onlyIdempotent
Curated 2026 field/view/resource deltas (v22 to v26).
Inputs: no named parameters. Returns: object
ads.fields.new_viewsAds fields new viewsCRead-onlyIdempotent
New 2026 reporting views.
Inputs: no named parameters. Returns: object
ads.gaql.queryAds gaql queryCRead-onlyIdempotent
Run an arbitrary read-only GAQL query.
Inputs: query (required), customer_id (required). Returns: object
ads.keyword_ideasAds keyword ideasBRead-onlyIdempotent
Keyword Planner ideas from seed keywords and/or a URL: monthly searches, competition, top-of-page bid range.
Inputs: customer_id (required), url, limit, keywords, +2 more. Returns: object
ads.mutateAds mutateBDestructive
Create/update/remove ANY Google Ads resource: MutateOperation JSON list (e.g. {'campaign_operation': {'create': {...}}}), temporary ids (-1) link new objects, atomic unless partial_failure. See ads.mutate.schema.
Inputs: operations (required), customer_id (required), confirm, partial_failure. Returns: object
ads.mutate.schemaAds mutate schemaARead-onlyIdempotent
List the mutate operation kinds, or the fields of one kind, for the pinned version.
Inputs: operation_kind. Returns: object
ads.reach.forecastAds reach forecastBRead-onlyIdempotent
Reach Planner forecast (reach curve, on-target impressions) for a media plan: products [{code, budget_micros}], location, currency, duration.
Inputs: products (required), customer_id (required), location_id (required), currency_code (required), +1 more. Returns: object
ads.reach.locationsAds reach locationsBRead-onlyIdempotent
Reach Planner: plannable locations (ids for ads.reach.products / forecast).
Inputs: no named parameters. Returns: object
ads.reach.productsAds reach productsCRead-onlyIdempotent
Reach Planner: plannable video/display products for a location.
Inputs: location_id (required). Returns: object
ads.recommendations.applyAds recommendations applyCDestructive
Apply Google Ads recommendations by resource name (from ads.recommendations.list).
Inputs: customer_id (required), resource_names (required), confirm. Returns: object
ads.recommendations.dismissAds recommendations dismissCDestructive
Dismiss Google Ads recommendations by resource name.
Inputs: customer_id (required), resource_names (required), confirm. Returns: object
ads.recommendations.listAds recommendations listCRead-onlyIdempotent
Active Google Ads recommendations with their estimated conversion/cost impact.
Inputs: customer_id (required), limit, types. Returns: object
ads.report.ai_maxAds report ai maxCRead-onlyIdempotent
AI Max matched-location-interest report.
Inputs: customer_id (required), date_range. Returns: object
ads.report.campaignAds report campaignDRead-onlyIdempotent
Campaign performance report.
Inputs: customer_id (required), date_range. Returns: object
ads.report.conversionsAds report conversionsDRead-onlyIdempotent
Conversions by conversion date.
Inputs: customer_id (required), date_range. Returns: object
ads.report.pmax_asset_groupsAds report pmax asset groupsCRead-onlyIdempotent
Performance Max asset-group report.
Inputs: customer_id (required), date_range. Returns: object
ads.report.search_termsAds report search termsCRead-onlyIdempotent
Search-terms report (incl. AI Max source).
Inputs: customer_id (required), date_range. Returns: object
ads.rollbackAds rollbackADestructive
Undo a Google Ads change from the signed audit trail (latest reversible change of this tenant, or audit_index): restores updated fields, removes created objects.
Inputs: confirm, audit_index. Returns: object
audit.anchorAudit anchorA
Anchor the audit chain head in Bitcoin via OpenTimestamps (only its SHA-256 leaves).
Inputs: no named parameters. Returns: object
audit.anchor_statusAudit anchor statusCRead-onlyIdempotent
Upgrade pending OpenTimestamps proofs; report pending vs Bitcoin-confirmed anchors.
Inputs: no named parameters. Returns: object
audit.statusAudit statusCRead-onlyIdempotent
Signed audit ledger: persistence, path, chain verification, public key.
Inputs: no named parameters. Returns: object
bigquery.dataset.createBigquery dataset createB
Create a dataset under a project (guarded: validate_only preview + confirm token).
Inputs: dataset_id (required), project_id (required), confirm. Returns: object
bigquery.datasets.listBigquery datasets listBRead-onlyIdempotent
List datasets in a BigQuery project.
Inputs: project_id (required). Returns: object
bigquery.query.dry_runBigquery query dry runARead-onlyIdempotent
Dry-run a query: estimate scanned bytes + USD cost ($6.25/TiB), billing nothing.
Inputs: sql (required), project_id (required). Returns: object
bigquery.query.runBigquery query runBRead-onlyIdempotent
Run a query only if it scans under max_bytes_billed (default 1e9 bytes).
Inputs: sql (required), project_id (required), max_bytes_billed. Returns: object
bigquery.table.createBigquery table createC
Create a table with a schema under a dataset (guarded).
Inputs: schema (required), table_id (required), dataset_id (required), project_id (required), +1 more. Returns: object
bigquery.tables.listBigquery tables listCRead-onlyIdempotent
List tables in a BigQuery dataset.
Inputs: dataset_id (required), project_id (required). Returns: object
cm360.campaigns.listCm360 campaigns listBRead-onlyIdempotent
List campaigns visible to a CM360 user profile.
Inputs: profile_id (required). Returns: object
cm360.floodlight_activities.listCm360 floodlight activities listBRead-onlyIdempotent
List Floodlight activities (conversion tags) visible to a CM360 user profile.
Inputs: profile_id (required). Returns: object
cm360.placements.listCm360 placements listBRead-onlyIdempotent
List placements (ad-serving slots) visible to a CM360 user profile.
Inputs: profile_id (required). Returns: object
cm360.placement.updateCm360 placement updateBDestructiveIdempotent
Update a placement by id with a partial field set (guarded: preview + confirm token).
Inputs: fields (required), profile_id (required), placement_id (required), confirm. Returns: object
cm360.report.insertCm360 report insertA
Create a report definition from a report body (guarded: preview + confirm token).
Inputs: report (required), profile_id (required), confirm. Returns: object
cm360.report.runCm360 report runBRead-onlyIdempotent
Run a report definition by id under a CM360 user profile (returns the report file).
Inputs: report_id (required), profile_id (required). Returns: object
cm360.reports.listCm360 reports listBRead-onlyIdempotent
List report definitions visible to a CM360 user profile.
Inputs: profile_id (required). Returns: object
cm360.user_profiles.listCm360 user profiles listARead-onlyIdempotent
List the CM360 user profiles the authenticated user can access.
Inputs: no named parameters. Returns: object
creative.pmax_packCreative pmax packBRead-onlyIdempotent
Generate a Performance Max pack: validated headlines, long headlines, descriptions, and images fitted to 1200x628 / 1200x1200.
Inputs: product (required), audience (required), scenes, language, +1 more. Returns: object
creative.search_adsCreative search adsBRead-onlyIdempotent
Generate validated responsive-search-ad copy (15 headlines <=30, 4 descriptions <=90) with Gemini.
Inputs: product (required), audience (required), language, final_url. Returns: object
datamanager.audience.remove_membersDatamanager audience remove membersCDestructiveIdempotent
Remove Customer Match audience members by hashed identifier (guarded).
Inputs: members (required), audience_id (required), destination_id (required), confirm. Returns: object
datamanager.audience.upload_membersDatamanager audience upload membersB
Upload Customer Match audience members (guarded). Identifiers must be SHA-256 hashed/normalized; consent (ad_user_data/ad_personalization) required for EEA.
Inputs: consent (required), members (required), audience_id (required), destination_id (required), +1 more. Returns: object
datamanager.conversions.uploadDatamanager conversions uploadB
Upload offline + enhanced conversions (guarded). Enhanced-conversion identifiers must be SHA-256 hashed/normalized; consent required for EEA.
Inputs: consent (required), conversions (required), destination_id (required), confirm. Returns: object
datamanager.request_statusDatamanager request statusCRead-onlyIdempotent
Retrieve a Data Manager ingestion request's status (optional read backend).
Inputs: request_id (required). Returns: object
datamanager.statusDatamanager statusBRead-onlyIdempotent
Report the Data Manager upload plane identity + operator contract (hashing/consent).
Inputs: no named parameters. Returns: object
describe_toolDescribe toolCRead-onlyIdempotent
Describe a registered tool by name.
Inputs: name (required). Returns: object
dv360.advertisers.listDv360 advertisers listCRead-onlyIdempotent
List advertisers under a DV360 partner.
Inputs: partner_id (required). Returns: object
dv360.campaigns.listDv360 campaigns listCRead-onlyIdempotent
List campaigns under a DV360 advertiser.
Inputs: advertiser_id (required). Returns: object
dv360.insertion_orders.listDv360 insertion orders listCRead-onlyIdempotent
List insertion orders under a DV360 advertiser.
Inputs: advertiser_id (required). Returns: object
dv360.line_item.set_statusDv360 line item set statusCDestructiveIdempotent
Set a line item's entityStatus (activate/pause/archive) (guarded).
Inputs: line_item_id (required), advertiser_id (required), entity_status (required), confirm. Returns: object
dv360.line_items.listDv360 line items listCRead-onlyIdempotent
List line items under a DV360 advertiser.
Inputs: advertiser_id (required). Returns: object
dv360.line_item.updateDv360 line item updateBDestructiveIdempotent
Update a line item by id with a partial field set (guarded: preview + confirm token).
Inputs: fields (required), line_item_id (required), advertiser_id (required), confirm. Returns: object
ga4.admin.create_audienceGa4 admin create audienceC
Create an audience with filter clauses on a property (guarded).
Inputs: property_id (required), display_name (required), filter_clauses (required), confirm. Returns: object
ga4.admin.create_key_eventGa4 admin create key eventB
Create a key event (conversion) on a property (guarded: preview + confirm token).
Inputs: event_name (required), property_id (required), confirm. Returns: object
ga4.admin.list_data_streamsGa4 admin list data streamsCRead-onlyIdempotent
List data streams under a GA4 property.
Inputs: property_id (required). Returns: object
ga4.admin.list_key_eventsGa4 admin list key eventsCRead-onlyIdempotent
List key events (conversions) under a GA4 property.
Inputs: property_id (required). Returns: object
ga4.admin.list_propertiesGa4 admin list propertiesCRead-onlyIdempotent
List GA4 properties under an Admin account.
Inputs: account_id (required). Returns: object
ga4.realtimeGa4 realtimeCRead-onlyIdempotent
GA4 Data API realtime report (runRealtimeReport).
Inputs: metrics (required), dimensions (required), property_id (required). Returns: object
ga4.reportGa4 reportCRead-onlyIdempotent
GA4 Data API report (runReport over a date range).
Inputs: metrics (required), end_date (required), dimensions (required), start_date (required), +1 more. Returns: object
gbp.accounts.listGbp accounts listARead-onlyIdempotent
List Google Business Profile accounts the authenticated user can access.
Inputs: no named parameters. Returns: object
gbp.location.getGbp location getBRead-onlyIdempotent
Fetch a single GBP location's details by resource name.
Inputs: location_name (required). Returns: object
gbp.locations.listGbp locations listBRead-onlyIdempotent
List locations under a Google Business Profile account.
Inputs: account_id (required). Returns: object
gbp.location.updateGbp location updateBDestructiveIdempotent
Update a location's fields by resource name (guarded: preview + confirm token).
Inputs: fields (required), location_name (required), confirm. Returns: object
gbp.performance.fetchGbp performance fetchCRead-onlyIdempotent
Fetch daily performance metrics (calls/directions/clicks/impressions) for a location.
Inputs: end_date (required), start_date (required), location_name (required). Returns: object
gbp.review.replyGbp review replyCDestructive
Reply to a review by resource name (guarded: preview + confirm token).
Inputs: comment (required), review_name (required), confirm. Returns: object
gbp.reviews.listGbp reviews listARead-onlyIdempotent
List reviews for a location (legacy v4 host — requires Google allowlist approval).
Inputs: location_name (required). Returns: object
google.api.callGoogle api callADestructive
Run a write method of any listed Google API (GA4 Admin, GTM, Merchant, YouTube, DV360, CM360, Business Profile, Search Console, Sheets/Drive/Slides...). api is the short name from google.api.list (e.g. analyticsadmin), method the id from google.api.methods (e.g. properties.customDimensions.create), params only the URL path/query parameters (e.g. parent), body the request object. Contract-checked, guarded, audited, reversible where the API allows; deletes need allow_delete.
Inputs: api (required), method (required), body, params, +3 more. Returns: object
google.api.describeGoogle api describeCRead-onlyIdempotent
One method's parameters (location, required, pattern, enum) and request body fields.
Inputs: api (required), method (required), version. Returns: object
google.api.listGoogle api listBRead-onlyIdempotent
Google APIs reachable through the generic plane, with default versions.
Inputs: no named parameters. Returns: object
google.api.methodsGoogle api methodsCRead-onlyIdempotent
Methods of a Google API from its Discovery contract (filter by resource, writes only).
Inputs: api (required), version, resource, writes_only. Returns: object
google.api.readGoogle api readCRead-onlyIdempotent
Run a read-only method of any listed Google API, validated against its Discovery contract.
Inputs: api (required), method (required), params, version. Returns: object
google.api.rollbackGoogle api rollbackBDestructive
Undo the latest reversible google.api.call of this tenant (or audit_index) from the audit.
Inputs: confirm, audit_index. Returns: object
gtm.create_tagGtm create tagB
Create a tag in a workspace (guarded: validate_only preview + confirm token).
Inputs: tag_name (required), tag_type (required), workspace_path (required), confirm, +1 more. Returns: object
gtm.create_versionGtm create versionC
Freeze a workspace into a new container version (guarded).
Inputs: name (required), workspace_path (required), confirm. Returns: object
gtm.list_accountsGtm list accountsBRead-onlyIdempotent
List accessible GTM accounts.
Inputs: no named parameters. Returns: object
gtm.list_containersGtm list containersCRead-onlyIdempotent
List containers under an account path.
Inputs: account_path (required). Returns: object
gtm.list_tagsGtm list tagsCRead-onlyIdempotent
List tags under a workspace path.
Inputs: workspace_path (required). Returns: object
gtm.list_triggersGtm list triggersCRead-onlyIdempotent
List triggers under a workspace path.
Inputs: workspace_path (required). Returns: object
gtm.list_variablesGtm list variablesBRead-onlyIdempotent
List user-defined variables under a workspace path.
Inputs: workspace_path (required). Returns: object
gtm.list_versionsGtm list versionsBRead-onlyIdempotent
List container version headers under a container path.
Inputs: container_path (required). Returns: object
gtm.list_workspacesGtm list workspacesCRead-onlyIdempotent
List workspaces under a container path.
Inputs: container_path (required). Returns: object
gtm.publish_versionGtm publish versionCDestructiveIdempotent
Publish a container version (guarded).
Inputs: version_path (required), confirm. Returns: object
gtm.update_tagGtm update tagCDestructiveIdempotent
Update an existing tag by path (guarded).
Inputs: fields (required), tag_path (required), confirm. Returns: object
healthHealthBRead-onlyIdempotent
Server + Google Ads API version health.
Inputs: no named parameters. Returns: object
insights.anomaliesInsights anomaliesARead-onlyIdempotent
Campaign anomalies: latest day vs each campaign's own history (robust z on cost, conversions, clicks).
Inputs: customer_id (required), days, threshold. Returns: object
insights.apply_negativesInsights apply negativesADestructive
Find wasted search terms (cost, no conversion) and add them as exact negative keywords in one guarded, audited write (undo with ads.rollback).
Inputs: customer_id (required), days, confirm, min_waste_cost_micros. Returns: object
insights.ga4_reconcileInsights ga4 reconcileBRead-onlyIdempotent
Daily Google Ads conversions vs GA4 key events from google / cpc, with flagged gaps.
Inputs: customer_id (required), property_id (required), days. Returns: object
insights.pacingInsights pacingBRead-onlyIdempotent
Month-to-date spend vs daily budgets, projected to month end; over/under-pacing campaigns.
Inputs: customer_id (required). Returns: object
insights.search_termsInsights search termsBRead-onlyIdempotent
Search-term mining: wasted terms -> negative keywords, converting untargeted terms -> new keywords, each with a ready ads.mutate operation.
Inputs: customer_id (required), days, min_conversions, min_waste_cost_micros. Returns: object
language.analyze_entitiesLanguage analyze entitiesARead-onlyIdempotent
Extract salient entities from ad content. Incurs Cloud Natural Language API cost.
Inputs: text (required). Returns: object
language.analyze_sentimentLanguage analyze sentimentARead-onlyIdempotent
Analyze sentiment (score + magnitude) of ad content. Incurs Cloud Natural Language API cost.
Inputs: text (required). Returns: object
language.batch_translateLanguage batch translateARead-onlyIdempotent
Translate many texts into a target language in one call for multi-market reach. Incurs Cloud Translation API cost per text.
Inputs: texts (required), target_language (required), source_language. Returns: object
language.detect_languageLanguage detect languageBRead-onlyIdempotent
Detect the dominant language of a text. Incurs Cloud Translation API cost.
Inputs: text (required). Returns: object
language.translateLanguage translateARead-onlyIdempotent
Translate text into a target language (auto-detects source if omitted). Incurs Cloud Translation API cost.
Inputs: text (required), target_language (required), source_language. Returns: object
list_capabilitiesList capabilitiesCRead-onlyIdempotent
List connector capabilities and their tools.
Inputs: no named parameters. Returns: result
looker.dashboard.createLooker dashboard createB
Create a dashboard under a model (guarded: validate_only preview + confirm token).
Inputs: model (required), title (required), confirm. Returns: object
looker.dashboards.listLooker dashboards listBRead-onlyIdempotent
List dashboards on the Looker instance.
Inputs: no named parameters. Returns: object
looker.look.runLooker look runBRead-onlyIdempotent
Run a saved look by id (result_format defaults to json).
Inputs: look_id (required), result_format. Returns: object
looker.looks.listLooker looks listBRead-onlyIdempotent
List saved looks on the Looker instance.
Inputs: no named parameters. Returns: object
looker.query.runLooker query runCRead-onlyIdempotent
Run an inline model/view query with fields + filters.
Inputs: view (required), model (required), fields (required), filters (required). Returns: object
merchant.accounts.getMerchant accounts getCRead-onlyIdempotent
Get a Merchant Center account.
Inputs: merchant_id (required). Returns: object
merchant.product.deleteMerchant product deleteCDestructiveIdempotent
Delete a product by resource name (guarded).
Inputs: product_name (required), confirm. Returns: object
merchant.product.getMerchant product getCRead-onlyIdempotent
Get a single product by its resource name.
Inputs: product_name (required). Returns: object
merchant.product.insertMerchant product insertB
Insert a product via productInput (guarded: validate_only preview + confirm token).
Inputs: merchant_id (required), product_input (required), confirm. Returns: object
merchant.products.listMerchant products listBRead-onlyIdempotent
List products under a Merchant Center account.
Inputs: merchant_id (required). Returns: object
merchant.product_statuses.listMerchant product statuses listBRead-onlyIdempotent
List item-level product statuses/issues for an account.
Inputs: merchant_id (required). Returns: object
merchant.product.updateMerchant product updateBDestructiveIdempotent
Update a product by resource name with a partial field set (guarded).
Inputs: fields (required), product_name (required), confirm. Returns: object
meridian.budget.optimizeMeridian budget optimizeARead-onlyIdempotent
Optimal per-channel allocation for total_budget under a fitted MMM. Read-only (recommends only); may run posterior simulations.
Inputs: model_id (required), total_budget. Returns: object
meridian.fitMeridian fitARead-onlyIdempotent
Fit a Bayesian MMM on dataset_ref with config; returns a model/job handle. Read-only (no account mutation) but COMPUTE-HEAVY: MCMC sampling, minutes-to-hours.
Inputs: config (required), dataset_ref (required). Returns: object
meridian.model.summaryMeridian model summaryBRead-onlyIdempotent
Fit-summary rows for an already-fitted MMM (by model_id). Read-only; cheap.
Inputs: model_id (required). Returns: object
meridian.roi.by_channelMeridian roi by channelBRead-onlyIdempotent
Per-channel ROI / contribution rows for a fitted MMM (by model_id). Read-only.
Inputs: model_id (required). Returns: object
recaptcha.assessment.annotateRecaptcha assessment annotateC
Annotate an assessment LEGITIMATE/FRAUDULENT to improve the model (guarded).
Inputs: annotation (required), project_id (required), assessment_id (required), confirm. Returns: object
recaptcha.assessment.createRecaptcha assessment createBRead-onlyIdempotent
Score a reCAPTCHA token: risk score 0.0-1.0 + reasons (the lead-quality signal).
Inputs: token (required), site_key (required), project_id (required), expected_action (required). Returns: object
recaptcha.keys.listRecaptcha keys listBRead-onlyIdempotent
List the reCAPTCHA site keys configured under a project.
Inputs: project_id (required). Returns: object
sa360.conversion.uploadSa360 conversion uploadB
Upload SA360 conversions (guarded: preview + confirm token).
Inputs: conversions (required), customer_id (required), confirm. Returns: object
sa360.customers.list_accessibleSa360 customers list accessibleARead-onlyIdempotent
List SA360 customers (accounts) the authenticated user can access.
Inputs: no named parameters. Returns: object
sa360.report.ad_groupSa360 report ad groupCRead-onlyIdempotent
Ad-group performance report (SA360).
Inputs: customer_id (required), date_range. Returns: object
sa360.report.campaignSa360 report campaignCRead-onlyIdempotent
Campaign performance report (SA360).
Inputs: customer_id (required), date_range. Returns: object
sa360.searchSa360 searchBRead-onlyIdempotent
Run an arbitrary read-only SA360 query (SA360 query language: SELECT ... FROM ...).
Inputs: query (required), customer_id (required). Returns: object
searchconsole.search_analyticsSearchconsole search analyticsCRead-onlyIdempotent
Query Search Analytics (organic clicks/impressions/ctr/position) for a property.
Inputs: end_date (required), site_url (required), dimensions (required), start_date (required), +1 more. Returns: object
searchconsole.sitemaps.deleteSearchconsole sitemaps deleteCDestructiveIdempotent
Delete a sitemap feed path for a property (guarded).
Inputs: feedpath (required), site_url (required), confirm. Returns: object
searchconsole.sitemaps.listSearchconsole sitemaps listBRead-onlyIdempotent
List sitemaps submitted for a property.
Inputs: site_url (required). Returns: object
searchconsole.sitemaps.submitSearchconsole sitemaps submitA
Submit a sitemap feed path for a property (guarded: preview + confirm token).
Inputs: feedpath (required), site_url (required), confirm. Returns: object
searchconsole.sites.listSearchconsole sites listARead-onlyIdempotent
List Search Console properties the authenticated user can access.
Inputs: no named parameters. Returns: object
searchconsole.url_inspectSearchconsole url inspectCRead-onlyIdempotent
Inspect a URL's index status for a property (URL Inspection API).
Inputs: site_url (required), inspection_url (required). Returns: object
trends.interest_by_regionTrends interest by regionCRead-onlyIdempotent
Geographic breakdown of interest in a keyword (geo-targeting).
Inputs: keyword (required), resolution. Returns: object
trends.interest_over_timeTrends interest over timeBRead-onlyIdempotent
Relative search interest over time for a comparison set (demand / seasonality).
Inputs: keywords (required), geo, timeframe. Returns: object
trends.trending_nowTrends trending nowBRead-onlyIdempotent
Currently trending searches for a country (breakout demand).
Inputs: geo. Returns: object
vertex.gemini.generateVertex gemini generateBRead-onlyIdempotent
Generate text with Gemini (creative copy/long-form). Incurs Vertex generation cost.
Inputs: prompt (required), model, max_tokens. Returns: object
vertex.gemini.generate_ad_copyVertex gemini generate ad copyCRead-onlyIdempotent
Build a structured brief and ask Gemini for n ad-copy variants. Incurs Vertex cost.
Inputs: product (required), audience (required), n. Returns: object
vertex.imagen.generateVertex imagen generateARead-onlyIdempotent
Generate n images, returned as base64 (default model gemini-3.1-flash-image; pass model to override). Incurs Vertex cost per image.
Inputs: prompt (required), n, model, aspect_ratio. Returns: object
vertex.veo.generateVertex veo generateBRead-onlyIdempotent
Generate a video clip with Veo 3.1 (returns an operation to poll with vertex.veo.status). Incurs Vertex cost.
Inputs: prompt (required), model, duration_seconds. Returns: object
vertex.veo.statusVertex veo statusBRead-onlyIdempotent
Poll a Veo operation; when done, returns the generated video URIs/bytes. No cost.
Inputs: operation_name (required). Returns: object
video.generateVideo generateBRead-onlyIdempotent
Generate a short video from a text prompt for free (Wan 2.2 -> LTX-Video on Hugging Face ZeroGPU; no billing). Returns the mp4 path (+ base64 on request). Daily GPU quota applies.
Inputs: prompt (required), seed, provider, aspect_ratio, +2 more. Returns: object
workspace.drive.list_filesWorkspace drive list filesBRead-onlyIdempotent
List Drive files the authenticated user can access (optional files.list query).
Inputs: query. Returns: object
workspace.sheets.createWorkspace sheets createC
Create a new spreadsheet with a title (guarded).
Inputs: title (required), confirm. Returns: object
workspace.sheets.get_metadataWorkspace sheets get metadataBRead-onlyIdempotent
Fetch spreadsheet metadata (title, sheet tabs, grid sizes).
Inputs: spreadsheet_id (required). Returns: object
workspace.sheets.read_rangeWorkspace sheets read rangeBRead-onlyIdempotent
Read a cell range (A1 notation) from a spreadsheet.
Inputs: range_a1 (required), spreadsheet_id (required). Returns: object
workspace.sheets.write_rangeWorkspace sheets write rangeBDestructive
Write values into an A1 range of a spreadsheet (guarded: preview + confirm token).
Inputs: values (required), range_a1 (required), spreadsheet_id (required), confirm. Returns: object
workspace.slides.create_deckWorkspace slides create deckC
Create a new Slides deck with a title (guarded).
Inputs: title (required), confirm. Returns: object
youtube.analytics.queryYoutube analytics queryCRead-onlyIdempotent
Query organic video performance (views/watch time/etc.) from YouTube Analytics.
Inputs: ids (required), metrics (required), end_date (required), dimensions (required), +1 more. Returns: object
youtube.channel.getYoutube channel getBRead-onlyIdempotent
Get a channel's snippet/statistics + uploads-playlist id (Data API v3).
Inputs: channel_id (required). Returns: object
youtube.playlist.add_itemYoutube playlist add itemC
Add a video to a playlist (playlistItems.insert) — guarded.
Inputs: video_id (required), playlist_id (required), confirm. Returns: object
youtube.playlist_items.listYoutube playlist items listBRead-onlyIdempotent
Enumerate playlist items (use the uploads playlist; avoid quota-scarce search.list).
Inputs: playlist_id (required). Returns: object
youtube.reporting.ensure_jobsYoutube reporting ensure jobsCRead-onlyIdempotent
Ensure Reporting API bulk-report jobs exist (reports retained 30/60d — persist early).
Inputs: report_type_ids (required). Returns: object
youtube.videos.listYoutube videos listBRead-onlyIdempotent
List full video resources for a batch of video ids (Data API v3).
Inputs: video_ids (required). Returns: object
youtube.video.updateYoutube video updateBDestructiveIdempotent
Update video metadata (title/description/tags) — guarded; no media upload.
Inputs: fields (required), video_id (required), confirm. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 163 tools
Several tools have overlapping boundaries: google.api.read/call can duplicate platform-specific list/write tools, ads.mutate overlaps with ads.campaign.create_* and ads.budget.update/set_status, and multiple ad-copy/video generators serve similar goals. Descriptions help, but the generic planes create real misselection risk across a 163-tool surface.
Most tools use lowercase dot-separated namespaces such as merchant.product.insert or ga4.admin.list_properties, but the pattern varies: gtm.list_accounts, youtube.channel.get, looker.dashboards.list, and unprefixed tools like health/list_capabilities/describe_tool. The naming is still readable, but it is not one predictable convention.
At 163 tools, this is far beyond a well-scoped tool set and is extremely difficult for an agent to navigate reliably. Even if each tool serves a broad multi-platform ads suite, the count represents extreme over-provisioning.
The surface covers core read, write, reporting, analytics, and audit workflows across Google Ads, DV360, CM360, SA360, GA4, GTM, Merchant, Search Console, YouTube, BigQuery, and more, often with a generic Google API fallback. Some platform-specific CRUD or lifecycle operations are thin, such as DV360/CM360 create paths, but agents can generally work around them.
Maintenance
Related MCP Connectors
Google Ads MCP with 20,000+ account peer context and staged approve-then-execute writes.
Hosted MCP server for marketing agencies: connect Google Ads, GA4, Search Console, Meta, LinkedIn and more to Claude or ChatGPT. Pull reports and make changes via OAuth login, no setup.
Context and control for any AI. Agent identity, scoped access, and proof across tools.
AI marketing agent for Google Ads, Meta, GA4, TikTok, LinkedIn, Shopify, HubSpot and more.
Related MCP Servers
- AlicenseAqualityAmaintenanceGoogle Ads, Reddit Ads, GA4, Tag Manager, Search Console and Merchant Center in your AI client. Read reports and make changes with a preview, a dry run validated by Google, and budget and bid caps before anything goes live. Self-host (MIT, pip install adloop) or connect AdLoop Cloud at https://mcp.getadloop.com/mcp.1532,317 PyPI297MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage, report, and analyze Google Ads campaigns securely with encrypted multi-client support, real-time API integrations, and audit trail logging.69 npmMIT
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol server providing full read and write control over Google Ads, enabling AI assistants to build campaigns, fix targeting, rewrite ads, and manage bidding strategies without opening a browser.1MIT
- AlicenseNot gradedqualityBmaintenanceEnables self-hosted Google Ads and Meta Ads management through MCP, with human approval, hard spending limits, and audited writes; agents like Claude Code or Codex can connect to ad accounts while the server controls all credential access and platform writes.Apache 2.0