Skip to content

fiveze/google-ads-mcp

Repository files navigation

Google Ads MCP Server

A local Model Context Protocol server that lets Claude (and other MCP clients) read your Google Ads data and manage campaigns. Built with Python + FastMCP + Google's official google-ads client, running over stdio.

Heads-up before you start: a fresh Google Ads developer token is test-only. To query/modify real accounts you must apply for Basic Access, which typically takes 1–3 business days to approve. Apply early (step 4 below) and develop against a test account meanwhile.


Tools

Read-only (always available)

Tool What it does
list_accessible_customers List customer (account) IDs your credentials can reach.
run_gaql Run any GAQL query — the main reporting tool. Paginated + row-capped.
get_resource_fields List valid fields/metrics/segments for a resource (schema grounding).
get_campaign_performance Quick campaign summary (impressions, clicks, cost, conversions).

Write (guarded — only when GOOGLE_ADS_ALLOW_MUTATIONS is enabled; default on)

Tool What it does
update_campaign_budget Set a campaign budget's daily amount.
update_campaign_status Pause / enable / remove a campaign.
update_ad_group_status Pause / enable / remove an ad group.
set_keyword_bid Adjust a keyword's max CPC bid and/or status.
mutate Advanced escape hatch: arbitrary GoogleAdsService.Mutate operations.

Every write tool defaults to a DRY RUN (Google Ads validate_only): it checks the request and changes nothing unless you pass apply=true. Set GOOGLE_ADS_ALLOW_MUTATIONS=false to hide all write tools entirely.


Prerequisites

  • uv (manages Python + dependencies). It will fetch Python 3.12 automatically (pinned in .python-version).
  • A Google Ads account, ideally with a Manager (MCC) account.

Install

cd /Users/fiveze/Projects/googleadsmcp
uv sync          # creates .venv and installs mcp[cli], google-ads, google-auth-oauthlib

Credentials setup (from scratch)

You need five values, all supplied as environment variables.

1. Google Cloud project + enable the API

2. OAuth consent screen

  • APIs & Services → OAuth consent screen. User type External is fine; you can leave it in Testing.
  • Add your Google account under Test users.
  • Scope used by this server: https://www.googleapis.com/auth/adwords.

3. OAuth client ID → CLIENT_ID + CLIENT_SECRET

  • APIs & Services → Credentials → Create credentials → OAuth client ID.
  • Application type: Desktop app.
  • Copy the Client ID and Client secret (or download the JSON).

4. Developer token → DEVELOPER_TOKEN

  • In your Google Ads Manager (MCC) account: Tools → API Center.
  • Copy the developer token. Apply for Basic Access now — a fresh token only works against test accounts (DEVELOPER_TOKEN_NOT_APPROVED otherwise) and approval takes ~1–3 business days.

5. Refresh token → REFRESH_TOKEN

With CLIENT_ID/CLIENT_SECRET exported (or a client_secret.json downloaded):

export GOOGLE_ADS_CLIENT_ID=...        # or pass the json path as an arg
export GOOGLE_ADS_CLIENT_SECRET=...
uv run scripts/generate_refresh_token.py
# (or) uv run scripts/generate_refresh_token.py /path/to/client_secret.json

A browser opens for consent; the script prints GOOGLE_ADS_REFRESH_TOKEN=....

6. Login customer ID → LOGIN_CUSTOMER_ID

Your Manager (MCC) account ID, digits only (no dashes). Required when the target account is managed by an MCC.

Put it together

cp .env.example .env   # then fill in the five values

.env holds account-wide secrets — it is git-ignored; keep it that way.


Register with Claude Code / Claude Desktop

Claude Code

A project-scoped .mcp.json is already included. It uses ${VAR} expansion, so no secrets are committed — export the values (e.g. source .env) in the shell that launches Claude Code, then approve the server when prompted. Verify with /mcp inside a session, or:

claude mcp list

Prefer the CLI / user scope instead? With your env exported:

claude mcp add google-ads --scope user --transport stdio \
  --env GOOGLE_ADS_DEVELOPER_TOKEN=$GOOGLE_ADS_DEVELOPER_TOKEN \
  --env GOOGLE_ADS_CLIENT_ID=$GOOGLE_ADS_CLIENT_ID \
  --env GOOGLE_ADS_CLIENT_SECRET=$GOOGLE_ADS_CLIENT_SECRET \
  --env GOOGLE_ADS_REFRESH_TOKEN=$GOOGLE_ADS_REFRESH_TOKEN \
  --env GOOGLE_ADS_LOGIN_CUSTOMER_ID=$GOOGLE_ADS_LOGIN_CUSTOMER_ID \
  -- uv run --directory /Users/fiveze/Projects/googleadsmcp server.py

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json and add (literal values — Claude Desktop does not expand ${VAR}):

{
  "mcpServers": {
    "google-ads": {
      "command": "uv",
      "args": ["run", "--directory", "/Users/fiveze/Projects/googleadsmcp", "server.py"],
      "env": {
        "GOOGLE_ADS_DEVELOPER_TOKEN": "...",
        "GOOGLE_ADS_CLIENT_ID": "...",
        "GOOGLE_ADS_CLIENT_SECRET": "...",
        "GOOGLE_ADS_REFRESH_TOKEN": "...",
        "GOOGLE_ADS_LOGIN_CUSTOMER_ID": "1234567890"
      }
    }
  }
}

Then fully restart Claude Desktop. That file now holds real secrets — chmod 600 it and don't sync it.


Test locally (MCP Inspector)

source .env
uv run mcp dev server.py

In the Inspector: confirm the tools list, then call list_accessible_customers (validates auth) and run_gaql with SELECT customer.id, customer.descriptive_name FROM customer.

For writes, call e.g. update_campaign_budget with the default (dry run) first — it should report "Dry run OK" with no change — then apply=true on a low-risk test campaign.


Configuration reference

Env var Required Notes
GOOGLE_ADS_DEVELOPER_TOKEN yes From MCC API Center.
GOOGLE_ADS_CLIENT_ID yes OAuth2 desktop client.
GOOGLE_ADS_CLIENT_SECRET yes OAuth2 desktop client.
GOOGLE_ADS_REFRESH_TOKEN yes From generate_refresh_token.py.
GOOGLE_ADS_LOGIN_CUSTOMER_ID if MCC Manager account ID, digits only.
GOOGLE_ADS_API_VERSION no Pin an API version (e.g. v24); else client default.
GOOGLE_ADS_ALLOW_MUTATIONS no false hides all write tools. Default enabled.

Notes & gotchas

  • Money is micros (÷ 1,000,000). Bids/budgets are set in micros.
  • GAQL field names: use get_resource_fields to avoid invalid-field errors.
  • API version churn: Google sunsets versions periodically — bump GOOGLE_ADS_API_VERSION (or upgrade google-ads) if you hit UNSUPPORTED_VERSION.
  • Safety: write tools are dry-run by default and marked destructive; keep a human in the loop before apply=true.

This server is provided as-is for personal/local use.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages