Skip to main content
Glama
ambo-sk

Google Ads MCP Worker

by ambo-sk

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_id points at. create_campaign, create_ad_group and create_responsive_search_ad default to PAUSED, 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

  1. Google Cloud Console → pick/create a project → enable the Google Ads API.

  2. APIs & Services → Credentials → Create credentials → OAuth client ID → Desktop app.

  3. 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 YYYYMMDD dates; reporting uses YYYY-MM-DD. Tools take YYYY-MM-DD everywhere and convert.

  • updateMask uses snake_case field names — relevant if you hand-write operations for mutate.

  • Access tokens are cached per Worker isolate; refresh tokens do not expire unless revoked or unused for 6 months.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ambo-sk/mcp-google-ads'

If you have feedback or need assistance with the MCP directory API, please join our Discord server