google-ads-mcp
This server is a read-only MCP gateway to the Google Ads API, letting AI agents discover accounts, run GAQL reports, and access planning/change-history data without ever mutating ads data.
Account discovery: list accessible customer IDs and walk the full MCC hierarchy with
google_ads_list_accessible_customersandgoogle_ads_list_customer_clients.GAQL querying: run read-only Google Ads Query Language queries against any linked customer account with
google_ads_query, including micros-to-units conversion and row limits.Schema exploration: list all GAQL resources and describe selectable/filterable fields, metrics, and segments via
google_ads_list_resourcesandgoogle_ads_describe_resource.Recommendations: read Google's optimization recommendations (keywords, budgets, ads, extensions, etc.) with
google_ads_recommendations.Keyword planning: generate keyword ideas, historical search-volume metrics, and forecast KPIs with
google_ads_keyword_ideas,google_ads_keyword_historical_metrics, andgoogle_ads_keyword_forecast_metrics.Change history: audit who changed what over the last 30 days with
google_ads_change_events, or get lightweight per-resource last-modified info withgoogle_ads_change_status.
Provides read-only access to Google Ads, enabling GAQL queries across accounts, along with tools for retrieving account hierarchy, keyword ideas, historical metrics, forecasts, recommendations, and change history.
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., "@google-ads-mcpShow me my top campaigns by clicks this month"
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.
Google Ads MCP
Read-only MCP server for the Google Ads API. Eleven tools cover discovery, GAQL reporting, resource schema, recommendations, keyword planning and forecasts, and change history for any account reachable under a manager account (MCC). We run this server in production for every ads client. Read-only is enforced at three layers: no mutate or apply service imports, an SDK method allowlist, and a GAQL-starts-with-SELECT guard.
Install
Claude Code:
claude mcp add google-ads \
-e GOOGLE_ADS_DEVELOPER_TOKEN=your-token \
-e GOOGLE_ADS_CLIENT_ID=your-client-id \
-e GOOGLE_ADS_CLIENT_SECRET=your-client-secret \
-e GOOGLE_ADS_REFRESH_TOKEN=your-refresh-token \
-e GOOGLE_ADS_LOGIN_CUSTOMER_ID=1234567890 \
-- uvx scalably-google-ads-mcpCodex:
codex mcp add google-ads \
--env GOOGLE_ADS_DEVELOPER_TOKEN=your-token \
--env GOOGLE_ADS_CLIENT_ID=your-client-id \
--env GOOGLE_ADS_CLIENT_SECRET=your-client-secret \
--env GOOGLE_ADS_REFRESH_TOKEN=your-refresh-token \
--env GOOGLE_ADS_LOGIN_CUSTOMER_ID=1234567890 \
-- uvx scalably-google-ads-mcpClaude Desktop: download google-ads-mcp.mcpb from the latest GitHub release and open it.
Related MCP server: ga-gsc-analytics
Setup
This is the heaviest setup in the gallery: expect up to two days waiting on developer token approval. One set of credentials, rooted at a manager account (MCC), can read any customer account linked under it, so there is no per-client configuration beyond linking an account to the MCC.
Google Ads developer token. Sign in at ads.google.com under your manager account, go to Tools and Settings, API Center, and apply for a developer token. A new token starts on the Explorer access level, which Google grants after a review that can take a few days; discovery, query and recommendation tools work there. Basic access (a separate application) is needed for higher quotas and may be needed for the keyword-planning tools.
Google Cloud OAuth client. In a Google Cloud project, enable the Google Ads API, then create an OAuth client ID of type Desktop app under APIs and Services, Credentials. Note the client ID and client secret, and add the
https://www.googleapis.com/auth/adwordsscope to the OAuth consent screen.Refresh token. Generate a refresh token once, as an admin user of the manager account, using Google's
oauth2ltool or thegenerate_user_credentials.pyexample shipped with thegoogle-adsPython library. Save the refresh token; it does not expire from normal use.Login customer ID. Use the 10-digit customer ID of the manager account itself (no hyphens) as
GOOGLE_ADS_LOGIN_CUSTOMER_ID. Any client account accepts an invite to link under this manager account in its own Google Ads UI, after whichgoogle_ads_list_customer_clientssees it.
Tools (11)
Tool | What it does |
| List every customer_id the OAuth user has direct access to |
| Walk the MCC hierarchy and return every child account |
| Run a GAQL query against a specific customer account |
| Schema (fields, metrics, segments) for a GAQL resource |
| Return the full catalog of GAQL resources |
| Read Google's optimization recommendations for a customer account |
| Generate keyword ideas with search volume, competition and CPC estimates |
| Historical monthly search-volume and competition metrics for specific keywords |
| Forecast KPIs for a proposed keyword plan |
| Audit trail of who changed what, last 30 days |
| Lightweight last-modified change tracker per resource |
Configuration
Variable | Required | Purpose |
| yes | Google Ads API developer token from the Ads API Center |
| yes | OAuth2 client_id for a Desktop-app credential |
| yes | OAuth2 client_secret paired with the client_id |
| yes | Long-lived OAuth2 refresh_token for the adwords scope |
| yes | 10-digit customer ID of the manager account (MCC), no hyphens |
| no | Google Ads API version to target, default v25 |
| no | Use proto-plus message types, default true |
| no | Python log level, default WARNING |
Reply shape
Every tool returns JSON with status (succeeded, partial, no_op), operation, summary, target, result, proof, warnings, recovery. Failures surface as a tool error whose text is google_ads_request_failed: <message> <hint>. proof.apiVersion names the Google Ads API version used. proof.microsConverted is set on google_ads_query. A partial status means the result hit its configured bound (max_rows, page_size or limit); recovery.nextAction says how to continue.
Limits
google_ads_query responses are capped at 64 MB per call by the Google Ads API; split large date ranges across calls. KeywordPlanIdeaService (keyword ideas, historical metrics, forecasts) is rate-limited to 1 query per second and may require Basic Access if you get a permission error on the Explorer tier. google_ads_change_events covers up to 30 days back; google_ads_change_status covers up to 14 days back. metrics.cost_micros and other *_micros fields are 1 unit = $0.000001; google_ads_query emits a matching *_units field alongside when convert_micros is true (the default).
Verify
Each release lists the package version, the .mcpb sha256 and the production commit it was derived from in CHANGELOG.md. CI runs the tests and a clean install of the built wheel on every push.
Privacy Policy
This server runs locally, on your machine, under your own credentials. It collects no personal data, contains no telemetry, stores nothing persistently, and talks only to the vendor API it wraps. No third party, including Scalably, receives your data. Contact: hello@scalably.io. Canonical copy: https://scalably.io/connector-privacy.html
License
MIT. Copyright Scalably.
Available Tools
11 toolsgoogle_ads_change_eventsARead-only
Audit trail: who changed what in the last 30 days.
Max window is 30 days back. Returns: change_date_time, user_email, change_resource_type (CAMPAIGN|AD_GROUP|AD_GROUP_CRITERION|CAMPAIGN_BUDGET| AD|AD_GROUP_BID_MODIFIER|…), old_resource, new_resource, changed_fields, client_type (GOOGLE_ADS_WEB_CLIENT|GOOGLE_ADS_API|…).
Args: customer_id: 10-digit customer_id. days_back: 1–30. resource_types: optional filter to specific change_resource_type enum values. limit: max rows (default 10000, capped 100000).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| days_back | No | ||
| customer_id | Yes | ||
| resource_types | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
google_ads_change_statusARead-only
Lightweight change tracker: last-modified-at timestamps for resources.
Unlike change_event, this is a per-resource "last modified" view rather than a change-diff log. Covers up to 14 days.
Args: customer_id: 10-digit customer_id. days_back: 1–14. resource_types: optional filter by change_status.resource_type enum. limit: max rows.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| days_back | No | ||
| customer_id | Yes | ||
| resource_types | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
google_ads_describe_resourceARead-only
Schema (fields, metrics, segments) for a GAQL resource.
Queries GoogleAdsFieldService for every selectable field on a resource
plus its data type, selectability, filterability, sort-ability, and
selectable_with (which other fields can coexist in a single SELECT).
Args: resource_name: the GAQL resource, e.g. "campaign", "ad_group", "shopping_performance_view", "change_event", "recommendation".
Returns: {resource, fields: [{name, category: ATTRIBUTE|METRIC|SEGMENT, data_type, selectable, filterable, sortable, enum_values, type_url, selectable_with}]}.
Essential before composing GAQL on an unfamiliar resource; prevents FIELD_NOT_COMPATIBLE and FIELD_NOT_FOUND errors.
| Name | Required | Description | Default |
|---|---|---|---|
| resource_name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
google_ads_keyword_forecast_metricsARead-only
Forecast KPIs (impressions, clicks, cost, conversions) for a proposed keyword plan.
Args: customer_id: 10-digit customer_id. campaign_spec: a KeywordPlanCampaign forecast spec. Minimum shape: { "bidding_strategy": "MANUAL_CPC", "daily_budget_micros": 10000000, "keyword_match_type": "BROAD" | "PHRASE" | "EXACT", "language_id": "1000", "geo_target_ids": ["2840"], "keywords": ["running shoes", "trail running shoes"] }
Returns: {campaign_forecast: {impressions, clicks, cost_micros, conversions, average_cpc_micros}, weekly_time_series: [...]}.
Rate limit: 1 QPS. Requires Basic Access.
| Name | Required | Description | Default |
|---|---|---|---|
| customer_id | Yes | ||
| campaign_spec | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
google_ads_keyword_historical_metricsARead-only
Historical monthly search-volume + competition metrics for specific keywords.
Args: customer_id: 10-digit customer_id. keywords: list of keyword strings (max 10,000 per call). language_id / geo_target_ids / keyword_network: same shape as keyword_ideas. year_month_start / year_month_end: optional date range as {year: 2025, month: 1..12}. Defaults to last 12 months.
Returns: {results: [{text, approximate_monthly_searches, monthly_search_volumes: [{year, month, monthly_searches}], competition, high/low_top_of_page_bid_micros}]}.
Rate limit: 1 QPS. May require Basic Access.
| Name | Required | Description | Default |
|---|---|---|---|
| keywords | Yes | ||
| customer_id | Yes | ||
| language_id | No | 1000 | |
| include_adult | No | ||
| geo_target_ids | No | ||
| year_month_end | No | ||
| keyword_network | No | GOOGLE_SEARCH | |
| year_month_start | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
google_ads_keyword_ideasARead-only
Generate keyword ideas with search volume + competition + CPC estimates.
Args: customer_id: customer_id to attribute the request (any Ads account under MCC works). keywords: seed keywords, list of strings. Optional if page_url is given. page_url: seed URL (crawled for keyword extraction). Optional if keywords given. language_id: Google language criterion ID. Default '1000' (English). Common: '1001' Spanish, '1002' French, '1003' German, '1007' Italian. geo_target_ids: list of geo criterion IDs. Default ['2840'] (US). Common: '2826' UK, '2124' Canada, '2036' Australia, '2276' Germany. keyword_network: GOOGLE_SEARCH (default) | GOOGLE_SEARCH_AND_PARTNERS. include_adult: include adult-category keywords (default False). page_size: max ideas to return (default 100, capped at 10000).
Returns: {ideas: [{text, avg_monthly_searches, competition, low_top_of_page_bid_micros, high_top_of_page_bid_micros, concept_group}]}.
Rate limit: 1 QPS for this service. Back off on RESOURCE_EXHAUSTED. Requires Basic Access (Explorer may 403); if you get USER_PERMISSION_DENIED, the dev_token tier is too low.
| Name | Required | Description | Default |
|---|---|---|---|
| keywords | No | ||
| page_url | No | ||
| page_size | No | ||
| customer_id | Yes | ||
| language_id | No | 1000 | |
| include_adult | No | ||
| geo_target_ids | No | ||
| keyword_network | No | GOOGLE_SEARCH |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
google_ads_list_accessible_customersARead-only
List every customer_id the OAuth user has direct access to.
This is a small, cheap list, typically just the MCC itself and any standalone accounts. For the full tree of accounts under the MCC (agency use case), call google_ads_list_customer_clients instead.
Returns: {"resource_names": [...], "customer_ids": [...]}. Each customer_id is 10 digits, no hyphens.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
google_ads_list_customer_clientsARead-only
Walk the MCC (Manager Account) hierarchy and return every child account.
For agency use: this is the canonical "which clients can I query?" call.
Uses GAQL on the customer_client resource. Fast: one streaming call.
Args: mcc_customer_id: MCC customer_id. Defaults to GOOGLE_ADS_LOGIN_CUSTOMER_ID (the configured MCC). Accepts 10-digit or hyphenated. include_managers: include sub-MCCs in the result (default True). include_hidden: include customer_clients marked hidden=True (default False). max_level: max hierarchy depth (default 3, hard cap 10).
Returns per account: customer_id, descriptive_name, currency_code, time_zone, manager (bool), level, status (ENABLED|CANCELED|…), hidden, resource_name.
| Name | Required | Description | Default |
|---|---|---|---|
| max_level | No | ||
| include_hidden | No | ||
| mcc_customer_id | No | ||
| include_managers | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
google_ads_list_resourcesARead-only
Return the full catalog of GAQL resources (FROM-able tables).
Useful when the agent needs to pick the right resource for a question. Each entry: name, category, selectable (whether it can be the FROM target).
Response is cacheable for the session; the catalog is stable across queries.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
google_ads_queryARead-only
Run a GAQL (Google Ads Query Language) query against a specific customer account.
GAQL is SQL-like: SELECT ... FROM <single_resource> WHERE ... ORDER BY ... LIMIT ....
No JOINs; attribute fields from related resources by selecting them directly.
Common resources: campaign, ad_group, keyword_view, search_term_view,
shopping_performance_view, customer, customer_client, conversion_action,
change_event, change_status, recommendation, asset, asset_group.
Use google_ads_describe_resource first if unsure of field names on a new resource; saves a FIELD_NOT_FOUND roundtrip.
Args: customer_id: 10-digit customer_id (no hyphens) for the account to query. gaql: the full GAQL query string (must start with SELECT; no semicolons). max_rows: if set, stop streaming after this many rows. Defaults to unbounded (the 64 MB response cap still applies). convert_micros: if True (default), also emit _units alongside any _micros field (divided by 1,000,000). E.g. cost_micros = 12345678 → cost_units = 12.345678.
Example queries:
SELECT campaign.id, campaign.name, metrics.cost_micros FROM campaign WHERE segments.date DURING LAST_7_DAYS ORDER BY metrics.cost_micros DESC LIMIT 50
SELECT ad_group.name, ad_group_criterion.keyword.text, metrics.impressions, metrics.clicks FROM keyword_view WHERE segments.date DURING LAST_30_DAYS
SELECT segments.product_item_id, metrics.conversions_value FROM shopping_performance_view WHERE segments.date DURING LAST_30_DAYS
Gotchas (surface to user where relevant):
metrics.cost_micros: 1 unit = $0.000001. Divide by 1M for currency.
LAST_30_DAYS = 30 days ending YESTERDAY (today excluded).
Last 72h data is partial; conversions retroactively re-attribute.
Zero-metric rows are excluded when segmenting by date.
Response cap is 64 MB per call; split by date range for huge reports.
GAQL
IN (...)clause is capped at 20,000 items.
| Name | Required | Description | Default |
|---|---|---|---|
| gaql | Yes | ||
| max_rows | No | ||
| customer_id | Yes | ||
| convert_micros | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
google_ads_recommendationsARead-only
Read Google's optimization recommendations for a customer account.
Returns suggestions only; does NOT apply any. Types include: KEYWORD, CAMPAIGN_BUDGET, KEYWORD_MATCH_TYPE, TARGET_CPA_OPT_IN, MAXIMIZE_CLICKS_OPT_IN, OPTIMIZE_AD_ROTATION, RESPONSIVE_SEARCH_AD, ENHANCED_CPC_OPT_IN, SEARCH_PARTNERS_OPT_IN, SITELINK_EXTENSION, CALL_EXTENSION, CALLOUT_EXTENSION, STRUCTURED_SNIPPET_EXTENSION, DISPLAY_EXPANSION_OPT_IN, KEYWORD_MATCH_TYPE, FORECASTING_*, SHOPPING_*, MOVE_UNUSED_BUDGET. (Google adds new types over time.)
Args: customer_id: 10-digit account ID. types: optional list to filter by recommendation_type. Case-sensitive. dismissed: include dismissed recommendations (default False). limit: max rows (default 200).
Each row contains: type, impact (absolute_metrics, base_metrics, potential_metrics), campaign / ad_group ref (if applicable), dismissed flag, recommendation-specific payload (e.g. suggested_keywords, budget_increase).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| types | No | ||
| dismissed | No | ||
| customer_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
11 tool updates
v1.0.0- First observed
google_ads_change_events - First observed
google_ads_change_status - First observed
google_ads_describe_resource - First observed
google_ads_keyword_forecast_metrics - First observed
google_ads_keyword_historical_metrics - First observed
google_ads_keyword_ideas - First observed
google_ads_list_accessible_customers - First observed
google_ads_list_customer_clients - First observed
google_ads_list_resources - First observed
google_ads_query - First observed
google_ads_recommendations
TDQS
Scored across 11 tools
Most tools are clearly separated by domain: account discovery, GAQL querying, schema introspection, keyword planning, recommendations, and change tracking. The two closest pairs (list_accessible_customers vs. list_customer_clients, and change_events vs. change_status) are explicitly differentiated in their descriptions, but their names alone could still cause an agent to hesitate.
All tools share the google_ads_ prefix and snake_case, but the verb pattern is inconsistent: list_accessible_customers, list_resources, list_customer_clients, query, and describe_resource use verbs, while recommendations, keyword_ideas, keyword_historical_metrics, keyword_forecast_metrics, change_events, and change_status are noun phrases. The convention is readable but mixed.
With 11 tools, the server is well-scoped for a Google Ads data-access MCP. Each tool covers a meaningful capability—account hierarchy, GAQL querying, schema discovery, recommendations, keyword research, and change tracking—without unnecessary redundancy or bloat.
The tool surface is strong for read-only Google Ads workflows: account discovery, arbitrary GAQL querying, schema introspection, keyword research, forecasting, recommendations, and change auditing are all covered. The main gaps are the lack of any write/mutation operations and the absence of convenience wrappers for common entities like campaigns, but the generic query tool plus schema metadata lets agents work around those limitations.
Maintenance
Related MCP Connectors
Read-only Search Console analytics, URL inspection, indexing diagnostics, and sitemaps.
Provides read access to your GKE and Kubernetes resources.
Read-only MCP access to your DEXUN AdWhiz account: ad accounts, AI recommendations, savings.
Read-only Google Search Console and Google Analytics for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceProvides read-only access to Google Ads account data including campaigns, ad groups, keywords, and performance reports. Enables querying via GAQL through an MCP interface.MIT
- FlicenseNot gradedqualityCmaintenanceEnables read-only access to Google Analytics 4 and Google Search Console data, allowing users to run reports, query search analytics, and generate combined snapshots for reporting.-
- FlicenseAqualityCmaintenanceEnables AI clients to read Google Ads account data through reporting tools for campaigns, ad groups, keywords, and raw GAQL queries, with no write or mutate capabilities.7-
- AlicenseNot gradedqualityBmaintenanceEnables read-only inspection of Google Ads accounts through MCP, including account inventory, reporting, metadata, change history, and safe GAQL queries.Apache 2.0