Skip to main content
Glama
v-p3truk

Google Ads MCP

by v-p3truk
README.md
# Google Ads MCP — with write operations

An MCP server that lets Claude (or any MCP client) **read _and_ change** a Google Ads account.

This is a rebuilt fork of [cohnen/mcp-google-ads](https://github.com/cohnen/mcp-google-ads).
The original is query-only — it exposes 12 read tools and cannot modify anything. Google's own
[googleads/google-ads-mcp](https://github.com/googleads/google-ads-mcp) is read-only too: it wraps GAQL
search and resource metadata, with no mutate operations at all.

So if you want an agent that actually *manages* campaigns — pauses ads, updates budgets, pushes negative
keywords — neither of those will do it. This fork adds that layer.

**What's different from upstream:**

- **16 write tools** built on a shared `_mutate()` helper (upstream had none)
- **Google Ads API v19 → v24** (v19 and v20 are deprecated)
- Credentials are read from `.env` everywhere — no hardcoded secrets, and `.gitignore` actually
  covers them (upstream's last entry was glued together by a missing newline, so it matched nothing)
- Helper scripts: OAuth re-authorization, a standalone GAQL runner for debugging

## Tools

**Read** — `run_gaql`, `execute_gaql_query` (arbitrary GAQL), `get_campaign_performance`,
`get_ad_performance`, `get_ad_creatives`, `get_image_assets`, `download_image_asset`, `get_asset_usage`,
`analyze_image_assets`, `get_account_currency`, `list_accounts`, `list_resources`

**Write** — `create_campaign`, `create_ad_group`, `create_rsa_ad`, `add_keywords`, `update_keyword_status`,
`add_negative_keywords`, `remove_negative_keywords`, `create_shared_negative_set`, `add_to_shared_negative_set`,
`attach_shared_set_to_campaign`, `update_campaign_status`, `update_ad_status`, `update_campaign_budget`,
`update_campaign_geo_targeting`, `add_sitelink_extensions`, `add_callout_extensions`

**Not covered** — keyword/ad-group level bids, bidding strategies, Performance Max assets, audiences,
ad scheduling. Do those in the UI, or extend `_mutate()`.

## What you need

1. **Google Ads developer token** — MCC account → Tools → API Center. A fresh token starts at *Test*
   level, which only sees test accounts; request Basic access to work against live accounts.
2. **OAuth client ID + secret** — Google Cloud Console → create a project → enable the Google Ads API →
   APIs & Services → Credentials → Create OAuth client ID → type **Desktop app**.
3. **Refresh token** — you don't get this by hand; `reauth.py` generates it (step 3 below).

## Setup

```bash
python3 -m venv .venv && ./.venv/bin/pip install -r requirements.txt

cp .env.example .env          # fill in the developer token and OAuth pair from above

./.venv/bin/python reauth.py  # opens a browser for consent, writes client_secret.json
```

Then point your MCP client at it:

```json
{
  "mcpServers": {
    "google-ads": {
      "type": "stdio",
      "command": "/absolute/path/to/.venv/bin/python",
      "args": ["/absolute/path/to/google_ads_server.py"],
      "env": { "GOOGLE_ADS_AUTH_TYPE": "oauth" }
    }
  }
}
```

Everything else is picked up from `.env` — the server loads it via `python-dotenv`.

## Helper scripts

| File | Purpose |
|------|---------|
| `reauth.py` | get or refresh the OAuth refresh token when it expires |
| `gaql_rest.py` | run a GAQL query straight over REST, bypassing MCP — handy for debugging |
| `pause_ads.py` | example: bulk-pause ads by ID |
| `gaql-google-ads-query-language.mdc` | GAQL syntax cheatsheet |

## Secrets

They live in `.env` and `client_secret.json` only. Both are gitignored — don't commit them.
If you add your own scripts, pull values with `os.getenv()`; never inline them.

## License

MIT, inherited from [cohnen/mcp-google-ads](https://github.com/cohnen/mcp-google-ads)
(Copyright © 2025 Ernesto Cohnen — ixigo). See [LICENSE](LICENSE). Modifications © 2026 Vlad Petruk.