Google Ads MCP Worker
Enables 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.
README
Google Ads MCP Worker
Google Ads MCP server on a Cloudflare Worker. Same shape as mcp-gsc: TypeScript, REST via fetch, no Google client library.
- Reimplementation of FGRibreau/mcp-google-ads (Rust, API v23) on API v25
- Auth: OAuth2 refresh token. The Google Ads API does not accept service accounts, so the GSC JWT approach does not apply here
- Transports: Streamable HTTP (
/mcp) and legacy SSE (/sse)
Writes are unguarded. No dry-run, no budget ceiling, no bid-increase cap, no two-step confirmation, no audit log. Every mutation tool applies immediately to whichever account
customer_idpoints at.create_campaign,create_ad_groupandcreate_responsive_search_addefault toPAUSED, but that is a default you can override, not a lock. Point this at a test account until you trust the setup.
Setup
1. Google Ads developer token
Manager (MCC) account → Tools & Settings → API Center → apply for a developer token. Until Basic Access is approved the token only works against test accounts.
2. OAuth client
- Google Cloud Console → pick/create a project → enable the Google Ads API.
- APIs & Services → Credentials → Create credentials → OAuth client ID → Desktop app.
- Note the client ID and client secret.
3. Refresh token
npm install --legacy-peer-deps
npm run token -- <CLIENT_ID> <CLIENT_SECRET>
Opens a browser, asks for the adwords scope, prints GOOGLE_ADS_REFRESH_TOKEN.
Sign in as a Google account that has access to the Ads account you want to manage.
4. Deploy
npx wrangler secret put GOOGLE_ADS_DEVELOPER_TOKEN
npx wrangler secret put GOOGLE_ADS_CLIENT_ID
npx wrangler secret put GOOGLE_ADS_CLIENT_SECRET
npx wrangler secret put GOOGLE_ADS_REFRESH_TOKEN
npx wrangler secret put MCP_AUTH_TOKEN # any long random string: openssl rand -hex 32
npm run deploy
Set the non-secret defaults in wrangler.jsonc:
| Var | Meaning |
|---|---|
GOOGLE_ADS_CUSTOMER_ID |
Default account, digits only. Tools take customer_id to override per call. |
GOOGLE_ADS_LOGIN_CUSTOMER_ID |
Your MCC id, sent as login-customer-id. Leave empty if not under a manager. |
GOOGLE_ADS_API_VERSION |
Defaults to v25. Bump here when Google ships a new version. |
Local dev: copy .dev.vars.example to .dev.vars, then npm run dev.
5. Connect a client
claude mcp add --transport http gads https://gads-mcp.<your-subdomain>.workers.dev/mcp \
--header "Authorization: Bearer <MCP_AUTH_TOKEN>"
Claude Desktop / stdio-only clients:
{
"mcpServers": {
"gads": {
"command": "npx",
"args": [
"mcp-remote",
"https://gads-mcp.<your-subdomain>.workers.dev/mcp",
"--header",
"Authorization: Bearer <MCP_AUTH_TOKEN>"
]
}
}
}
Then call health_check — it reports OAuth status, developer token presence, and the accounts reachable.
Tools
46 tools. Every customer-scoped tool takes an optional customer_id.
Read (21)
| Tool | What |
|---|---|
health_check |
Auth status, API version, configured accounts |
list_accounts |
Accessible accounts (with names when an MCC is configured) |
get_account_info |
Currency, time zone, auto-tagging, test-account flag |
run_gaql |
Any GAQL query; searchStream by default, paged when page_size/page_token given |
get_campaign_performance |
Campaign metrics by cost |
get_ad_group_performance |
Ad group metrics |
get_ad_performance |
Ad metrics with RSA headlines/descriptions and approval status |
get_keyword_performance |
Keyword metrics with match type, quality score, bid |
get_search_terms |
Actual queries — the negative keyword source |
get_negative_keywords |
Campaign / ad group / shared-set negatives |
get_geo_performance |
Metrics by location |
get_device_performance |
Metrics by device |
get_change_history |
Change events (API retains 30 days) |
list_assets |
Assets and their attachment level |
get_policy_issues |
Disapproved and limited ads with policy topics |
get_conversion_actions |
Conversion actions with category, counting, lookback |
list_recommendations |
Google's recommendations plus impact estimates |
search_geo_targets |
Place name → geo target constant id |
discover_keywords |
Keyword ideas from seeds and/or a URL |
get_keyword_historical_metrics |
Volume/competition for a fixed keyword list |
get_keyword_forecasts |
Forecast for a hypothetical campaign |
Write (25)
| Tool | What |
|---|---|
create_campaign_budget |
Daily budget, shared or not |
create_campaign |
Campaign + optional budget in one call |
update_campaign |
Name, status, budget, dates, bidding strategy |
create_ad_group / update_ad_group |
Ad groups and default CPC |
add_keywords / update_keyword |
Positive keywords, bids, final URLs |
add_negative_keywords |
Campaign or ad group negatives |
create_responsive_search_ad |
RSA with pinning; length limits checked before sending |
set_entity_status |
Pause / enable / remove anything by resource name |
add_geo_target |
Target or exclude locations, with bid modifiers |
set_campaign_geo_target_type |
Presence vs presence-or-interest |
set_ad_schedule |
Dayparting windows and bid modifiers |
add_audience_targeting / create_custom_audience |
Audiences |
create_asset / attach_assets / remove_asset_link |
Sitelinks, callouts, snippets, text, images |
create_conversion_action / update_conversion_action |
Conversion setup, primary/secondary |
create_bidding_strategy |
Portfolio strategies |
apply_recommendation / dismiss_recommendation |
Act on Google's suggestions |
mutate |
Raw mutate on any resource collection — covers everything above |
mutate_batch |
Atomic googleAds:mutate with temp ids across resources |
mutate and mutate_batch are the escape hatches: anything Google adds, or any resource with no named tool
(shared sets, user lists, asset groups, experiments, labels), goes through them without a code change.
Both accept validate_only if you want a manual dry run.
Checks
npm run typecheck # tsc --noEmit
npm test # pure-logic selfcheck: micros, dates, resource names, bidding payloads
Notes
- Money is passed in currency units (
25.5) and converted to micros internally. - Mutate payloads use
YYYYMMDDdates; reporting usesYYYY-MM-DD. Tools takeYYYY-MM-DDeverywhere and convert. updateMaskuses snake_case field names — relevant if you hand-write operations formutate.- Access tokens are cached per Worker isolate; refresh tokens do not expire unless revoked or unused for 6 months.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.