google-ads-mcp
This server lets any MCP client report on and manage Google Ads accounts through the Google Ads REST API.
Discover accounts and fields —
list_accessible_customersfinds reachable accounts and the MCC client tree;account_overviewgives account details plus account-wide totals;gaql_fieldslooks up GAQL field metadata (types, enums, selectability).Read structure —
list_campaigns,list_ad_groups,list_adsreturn status, budgets, bids, RSA headlines/descriptions and policy status.Report on performance —
campaign_performanceandad_group_performance(optionally segmented by date/week/month/device/network),keyword_performance(quality score, match type, bid),search_terms_report(real queries, the negative-keyword goldmine), andgeo_performanceby user location.Run arbitrary queries —
gaql_searchexecutes any GAQL query with pagination and micros→money conversion.Pause/enable things —
set_campaign_status,set_ad_group_status,set_ad_status.Manage budgets and bids —
set_campaign_budget(currency units, refuses shared budgets unless allowed),update_keyword(status and/or max CPC).Add and remove keywords —
add_keywords,add_negative_keywords(campaign- or ad-group-level, withvalidate_onlydry runs),remove_resourcefor keywords, ads, ad groups and campaigns.Escape hatch —
mutatepasses rawGoogleAdsService.mutateoperations for anything else, atomically or with partial failure.Operational niceties — micros converted to currency, automatic pagination, readable flattened
GoogleAdsFailureerrors, MCC-aware targeting viacustomer_id, hourly refresh-token caching, stdio or stateless HTTP mode (bearer-token auth) and Docker support.
Allows reporting on and managing Google Ads accounts, including GAQL queries, campaign/ad group/keyword performance, search terms, budgets, pausing, and negative keywords.
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-mcp @google-ads-mcp what were my top campaigns by clicks last week?"
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-api-mcp
An MCP (Model Context Protocol) server for the Google Ads API. Lets any MCP client — Claude, Cursor, obot, etc. — report on and manage Google Ads accounts: GAQL queries, campaign/ad group/keyword performance, search terms, budgets, pausing, negatives.
Zero Google client-library dependency: it talks to the REST endpoint directly with fetch, so it starts fast under npx and tracks new API versions with one environment variable.
Tools
Discover
Tool | Description |
| Accounts the credentials can reach, plus the full MCC client tree |
| Account details + account-wide totals for a date range |
| Field metadata: data types, enum values, what selects with what |
Read
Tool | Description |
| Structure with status, budgets, bids, RSA headlines/descriptions, policy status |
| Metrics by date range, optionally segmented by date/week/month/device/network |
| Keywords with quality score, match type, bid, metrics |
| Real search queries with matched keyword — the negative-keyword goldmine |
| Metrics by user location |
| Any GAQL query, paginated, with micros converted |
Write
Tool | Description |
| Enable or pause |
| Daily budget in currency units; refuses shared budgets unless told otherwise |
| Status and/or max CPC bid |
| Bulk add, campaign- or ad-group-level negatives, |
| Remove a keyword, ad, ad group, campaign by resource name |
| Raw |
Niceties handled for you:
Micros → money —
cost_micros: 3300000comes back ascost: 3.3; budgets and bids are given and returned in currency units.Pagination —
gaql_searchfollows page tokens until yourlimit.Readable errors —
GoogleAdsFailuredetails are flattened toERROR_CODE — message (field: …)plus the request id.MCC aware — set
GOOGLE_ADS_LOGIN_CUSTOMER_IDto a manager account and every tool can target any client under it viacustomer_id.Token caching — the refresh token is exchanged once per hour, not per call.
Related MCP server: google-ads-manager-mcp
Setup
You need four things from Google, all one-time:
Developer token — Google Ads → a manager account → Tools → API Center. A test-account token works for test accounts only; apply for Basic access for production.
OAuth client — Google Cloud Console → APIs & Services → Credentials → OAuth client ID (Desktop app). Enable the Google Ads API on the project.
Refresh token — run any OAuth flow for scope
https://www.googleapis.com/auth/adwordswith that client. The official guide has scripts; any generic "get refresh token" helper works.Customer IDs — the account to report on, and (if you go through an MCC) the manager account ID.
Then configure your MCP client:
{
"mcpServers": {
"google-ads": {
"command": "npx",
"args": ["-y", "google-ads-api-mcp"],
"env": {
"GOOGLE_ADS_DEVELOPER_TOKEN": "...",
"GOOGLE_ADS_OAUTH_CLIENT_ID": "....apps.googleusercontent.com",
"GOOGLE_ADS_OAUTH_CLIENT_SECRET": "...",
"GOOGLE_ADS_REFRESH_TOKEN": "1//...",
"GOOGLE_ADS_LOGIN_CUSTOMER_ID": "1234567890",
"GOOGLE_ADS_CUSTOMER_ID": "0987654321"
}
}
}
}Environment variables
Variable | Required | Description |
| yes | From API Center in a manager account |
| stdio only | OAuth 2.0 client ID |
| stdio only | OAuth 2.0 client secret |
| stdio only | Refresh token with the |
| no | Manager (MCC) account to authenticate through; needed when the account is accessed via a manager |
| no | Default client account when a tool call omits |
| no | Default |
| no |
|
| no | HTTP mode listen settings. Defaults |
HTTP mode (behind an auth proxy such as Nango)
With MCP_TRANSPORT=http the server speaks stateless Streamable HTTP and holds no user credentials. Every request must carry Authorization: Bearer <Google access token> with the https://www.googleapis.com/auth/adwords scope, and that token is used for that request only. The proxy keeps the Google login and refreshes it. Only the account-level settings stay in env: GOOGLE_ADS_DEVELOPER_TOKEN, and optionally GOOGLE_ADS_LOGIN_CUSTOMER_ID / GOOGLE_ADS_CUSTOMER_ID.
MCP_TRANSPORT=http PORT=8000 GOOGLE_ADS_DEVELOPER_TOKEN=... GOOGLE_ADS_LOGIN_CUSTOMER_ID=... node dist/index.jsGET /health returns {"ok":true}. Only POST /mcp is served (GET and DELETE return 405), and a request without a bearer token gets 401. Keep it on a private network behind the proxy.
Docker
docker build -t google-ads-api-mcp .
docker run -e GOOGLE_ADS_DEVELOPER_TOKEN=... -e GOOGLE_ADS_OAUTH_CLIENT_ID=... -e GOOGLE_ADS_OAUTH_CLIENT_SECRET=... -e GOOGLE_ADS_REFRESH_TOKEN=... google-ads-api-mcpThe container speaks MCP over stdio by default. For HTTP mode:
docker run -p 8000:8000 -e MCP_TRANSPORT=http -e GOOGLE_ADS_DEVELOPER_TOKEN=... -e GOOGLE_ADS_LOGIN_CUSTOMER_ID=... google-ads-api-mcpGAQL cheatsheet
Ask the model to use gaql_fields when unsure, but the shape is always:
SELECT campaign.name, metrics.clicks, metrics.cost_micros
FROM campaign
WHERE segments.date DURING LAST_30_DAYS AND campaign.status = 'ENABLED'
ORDER BY metrics.cost_micros DESC
LIMIT 50Useful FROM resources: campaign, ad_group, ad_group_ad, keyword_view, search_term_view, geographic_view, conversion_action, campaign_budget, asset, change_event, recommendation, customer_client.
Development
npm install
npm run build
GOOGLE_ADS_DEVELOPER_TOKEN=... GOOGLE_ADS_OAUTH_CLIENT_ID=... GOOGLE_ADS_OAUTH_CLIENT_SECRET=... GOOGLE_ADS_REFRESH_TOKEN=... GOOGLE_ADS_CUSTOMER_ID=... node dist/index.js
npm run smoke # spawns the server over stdio and exercises the read tools against your accountLicense
MIT
Available Tools
21 toolsaccount_overviewAccount overviewARead-only
Account details (name, currency, time zone, auto-tagging, status) plus account-wide totals for the date range: impressions, clicks, cost, conversions.
Inputs: end_date, date_range, start_date, customer_id.
add_keywordsAdd keywordsAIdempotent
Add keywords to an ad group. Each keyword has text, match type and an optional max CPC bid (currency units). Set validate_only to check for policy/duplicate errors without saving.
Inputs: keywords (required), ad_group_id (required), status, customer_id, +1 more.
add_negative_keywordsAdd negative keywordsAIdempotent
Add negative keywords at campaign level (default) or ad group level. Typical follow-up to search_terms_report. Negatives at campaign level block the term for every ad group in the campaign.
Inputs: keywords (required), ad_group_id, campaign_id, customer_id, +1 more.
ad_group_performanceAd group performanceARead-only
Per-ad-group metrics for a date range, optionally filtered to a campaign and segmented.
Inputs: limit, segment, end_date, date_range, +4 more.
campaign_performanceCampaign performanceARead-only
Per-campaign metrics for a date range: impressions, clicks, CTR, avg CPC, cost, conversions, conversion value, cost/conv, plus search impression share. Optionally segment by date/week/month/device/network. Money is in account currency units.
Inputs: limit, segment, end_date, date_range, +4 more.
gaql_fieldsGAQL field metadataARead-only
Look up GAQL fields, resources, segments and metrics: data type, whether selectable/filterable/sortable, enum values, and which resources they can be selected with. Use name_like with SQL wildcards (e.g. 'campaign.%' for every campaign field, 'metrics.%conversion%').
Inputs: name_like (required), limit, category, selectable_only.
gaql_searchRun GAQL queryARead-only
Run any Google Ads Query Language (GAQL) query against a customer. Use for anything the specific report tools do not cover (assets, conversion actions, change history, bidding strategies, audiences, geo targets, budgets, recommendations…). Pagination is handled; rows are capped by limit. Money fields are converted from micros unless convert_micros is false. Use gaql_fields to discover selectable fields.
Inputs: query (required), limit, customer_id, convert_micros.
geo_performanceGeographic performanceARead-only
Metrics by user location for a date range (country/region/city geo target constants). Resolve the constant names with gaql_search on geo_target_constant if needed.
Inputs: limit, end_date, date_range, start_date, +2 more.
keyword_performanceKeyword performanceARead-only
Per-keyword metrics for a date range with match type, status, quality score and effective CPC bid. Filter by campaign or ad group. Sorted by cost.
Inputs: limit, end_date, date_range, start_date, +4 more.
list_accessible_customersList accessible customersARead-only
List the Google Ads accounts reachable with the configured credentials: the accounts the OAuth user can access directly, plus the full client tree under GOOGLE_ADS_LOGIN_CUSTOMER_ID when it is a manager (MCC). Use this to find a customer_id.
Inputs: no named parameters.
list_ad_groupsList ad groupsARead-only
List ad groups (id, name, status, type, default CPC bid) with their campaign. Optionally filter to one campaign.
Inputs: limit, campaign_id, customer_id, include_removed.
list_adsList adsARead-only
List ads with type, status, policy approval, ad strength, final URLs and — for responsive search ads — all headlines and descriptions with pinning. Filter by campaign or ad group.
Inputs: limit, ad_group_id, campaign_id, customer_id, +1 more.
list_campaignsList campaignsARead-only
List campaigns with status, channel type, bidding strategy, daily budget (currency units), schedule and serving status. No metrics; use campaign_performance for those.
Inputs: limit, status, customer_id, include_removed.
mutateRaw mutateADestructive
Advanced: send raw GoogleAdsService.mutate operations using REST field names (camelCase), e.g. [{ campaignOperation: { update: { resourceName, status }, updateMask: 'status' } }]. Supports every resource the API can create/update/remove (campaigns, ads, assets, conversion actions, extensions…). Use validate_only: true first to dry-run. Operations are atomic unless partial_failure is true.
Inputs: operations (required), customer_id, validate_only, partial_failure.
remove_resourceRemove resourceADestructiveIdempotent
Remove (soft-delete) a keyword, negative keyword, ad, ad group or campaign by its resource name (e.g. customers/123/adGroupCriteria/456~789). Removal is permanent in Google Ads; removed entities stay visible in reports with status REMOVED.
Inputs: resource_name (required), customer_id.
search_terms_reportSearch terms reportARead-only
Actual search queries that triggered your ads, with the matching keyword, status (ADDED/EXCLUDED/NONE) and metrics. The main source for finding negative keywords to add. Sorted by impressions.
Inputs: limit, end_date, date_range, start_date, +4 more.
set_ad_group_statusEnable or pause ad groupAIdempotent
Set an ad group to ENABLED or PAUSED.
Inputs: status (required), ad_group_id (required), customer_id.
set_ad_statusEnable or pause adAIdempotent
Set an ad (within its ad group) to ENABLED or PAUSED.
Inputs: ad_id (required), status (required), ad_group_id (required), customer_id.
set_campaign_budgetSet campaign daily budgetAIdempotent
Change a campaign's daily budget, given in account currency units (e.g. 5.50). Looks up the campaign's budget resource first. Refuses to change a shared budget unless allow_shared is true, since that affects every campaign using it.
Inputs: campaign_id (required), daily_amount (required), customer_id, allow_shared.
set_campaign_statusEnable or pause campaignAIdempotent
Set a campaign to ENABLED or PAUSED.
Inputs: status (required), campaign_id (required), customer_id.
update_keywordUpdate keywordAIdempotent
Change a keyword's status (ENABLED/PAUSED) and/or its max CPC bid (currency units). Identify the keyword by ad_group_id and criterion_id from keyword_performance.
Inputs: ad_group_id (required), criterion_id (required), status, cpc_bid, +1 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 21 tools
Multiple tools have overlapping purposes, e.g., set_ad_group_status, set_campaign_status, set_ad_status, update_keyword, and mutate all modify statuses or bids. The generic mutate duplicates nearly all specific tools, creating significant ambiguity in choosing the right tool.
Naming conventions are inconsistent. Some tools follow verb_noun (set_ad_group_status), others use noun_verb (gaql_search), and some are generic (mutate). The mix of snake_case and camelCase in tool names (e.g., gaql_search vs. update_keyword) further reduces predictability.
With 21 tools, the count is within the 16-25 range, but many tools are redundant (e.g., multiple status setters, update_keyword vs. mutate). The surface area could be trimmed to ~10 distinct tools without losing functionality, making the set feel heavy.
The tool set covers most Google Ads entities (campaigns, ad groups, ads, keywords, search terms, geo) and provides a generic GAQL query and mutate for advanced operations. However, it lacks specific create/read operations for some entities and relies on generic tools, leaving minor gaps in direct coverage.
Maintenance
Related MCP Connectors
Google Ads MCP server — manage campaigns, keywords, and metrics.
Google Ads MCP: reports, search terms, negatives, budgets, campaigns. Approval on every write.
Hosted Google Ads MCP with OAuth, bounded reads, and prepare/confirm writes.
Hosted MCP for Google Ads, Search Console, GA4 and Merchant Center: ask, build, approve changes.
Related MCP Servers
- AlicenseBqualityBmaintenanceUnofficial Google Ads MCP for campaigns, keywords, budgets, reports and gated mutations.3071 npm4MIT
- AlicenseAqualityCmaintenanceMCP server to read and manage Google Ads accounts via GAQL queries, campaign/ad group/keyword operations, and safe write support with draft-confirm flow.1641 npmMIT
- FlicenseNot gradedqualityCmaintenanceEnables management of Google Ads accounts via MCP, providing read and write tools for campaigns, ad groups, keywords, assets, and more, with support for reporting and mutations.-
- AlicenseAqualityCmaintenanceEnables MCP clients to retrieve Google Ads performance data, run GAQL queries and keyword planner research, and create or manage search and P-MAX campaigns, budgets, keywords, and ad status. Includes safety defaults such as paused creation and read-only mode.16MIT