Article Information
Category: Development
Published: April 24, 2026
Author: Chris de Gruijter
Reading Time: 12 min
Tags

Managing Google Ads with Claude Using AdLoop MCP
Published: April 24, 2026
I manage Google Ads for multiple clients at Webfluentia, and for a long time that meant constant context-switching: Ads dashboard for campaign data, GA4 for conversion attribution, the code editor for everything else. This week I wired up AdLoop as an MCP server so Claude can read and manage campaigns directly from my terminal. No more tab switching. No more manual data pulling. I just ask Claude what's happening across accounts and tell it what to change — with a safety model that prevents anything destructive from happening without explicit confirmation. Here's exactly how I set it up and why it fits well in an agency context.
What This Actually Does
AdLoop is an open-source MCP (Model Context Protocol) server that gives Claude direct access to the Google Ads API and GA4. Once installed, Claude gets 43 tools covering everything from reading campaign performance and search terms to creating ad groups, adjusting bids, adding negative keywords, and cross-referencing Ads clicks against GA4 sessions.
MCP (Model Context Protocol) is the standard that lets AI assistants like Claude connect to external tools and data sources. If you've used MCP servers before — Supabase, GitHub, filesystem — this follows the exact same pattern. You register AdLoop as an MCP server, restart Claude Code, and the tools appear in context.
In practice, this means I can open a Claude Code session and say: "Show me the campaigns for KindChiro over the last 30 days, flag anything with CTR below 1.5%, and give me a recommendation on which keywords to add as negatives." Claude runs the queries, combines the data, and gives me an actionable answer — without me opening a single browser tab.
Why This Matters for an Agency
Running Google Ads for multiple clients amplifies every inefficiency. Switching between MCC sub-accounts, pulling comparison data, building reports — it all compounds. The real value of AI-assisted Ads management in an agency context isn't just convenience, it's consistency and speed at scale.
- Multi-account context — AdLoop supports MCC (Manager Account) setup, so I can query across all client accounts from a single session and switch context per conversation.
- Cross-referencing Ads + GA4 — AdLoop maps Google Ads clicks to GA4 sessions, which is critical for attribution. It's GDPR-aware too, so it doesn't misread normal EU cookie rejection as a tracking failure.
- Audit trail — every operation (including dry runs) is logged to
~/.adloop/audit.log. For agency work this matters — you have a record of every change made. - Safety by default — all write operations default to dry-run mode. Budget caps per campaign, maximum bid increase limits, and a two-step draft → confirm workflow mean nothing goes live by accident.
- Analysis speed — what used to take 20 minutes of tab-switching (open Ads, filter by date, export, open GA4, compare) takes 30 seconds as a natural language query.
The Existing Dashboard vs This Tool
Before going further: I also have a client-facing dashboard at Webfluentia where clients can log in and see their Google Ads stats — campaigns, spend, conversions, ROAS. That's a separate system with its own sync pipeline (Google Ads API → Supabase → Next.js). AdLoop is not that. AdLoop is an internal agency tool — it's for me and Claude to work with, not for clients to view.
The two are complementary: AdLoop gives me the analysis and management layer, the dashboard gives clients the read-only transparency layer. They share the same underlying Google Ads data but serve completely different audiences.
Full Setup Guide
Here's exactly how I set this up on Ubuntu. The setup takes about 30–60 minutes of actual work, with a potential 1–3 day wait if your Google Ads developer token needs production approval (Explorer access is instant).
Prerequisites
- Claude Code installed (claude.ai/code)
uv— Python package manager by Astral (install below)- A Google Ads account — either a direct account or an MCC (Manager Account)
- A Google Cloud project (free tier is fine)
Step 1 — Install uv and clone AdLoop
# Install uv (Astral's fast Python package manager)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone AdLoop to your 3rd-party repos directory
git clone https://github.com/kLOsk/adloop /home/YOUR_USER/Projects/3rd-party-repos/adloop
# Install dependencies
cd /home/YOUR_USER/Projects/3rd-party-repos/adloop && uv syncThe uv sync step installs all 89 dependencies including the Google Ads Python client, GA4 client, and FastMCP. Takes under 30 seconds.
Step 2 — Get a Google Ads Developer Token
In your Google Ads account (or MCC): Tools & Settings → API Center → Apply for access. There are two tiers:
- Explorer access — approved instantly, 2,880 API operations/day. Enough for analysis and light management.
- Basic access — 15,000 operations/day, requires a short application. Apply for this in parallel so it's approved by the time you need it.
Copy your 22-character developer token. You'll need it in the config below.
Step 3 — Set Up GCP OAuth Credentials
AdLoop ships with bundled OAuth credentials, but for agency use I strongly recommend using your own GCP project. It gives you full control, no shared credential limits, and keeps your auth isolated.
- Go to console.cloud.google.com and select or create a project
- Search for Google Ads API → Enable it
- Go to APIs & Services → OAuth consent screen → External → fill in app name + your email → add yourself as a Test User
- Go to APIs & Services → Credentials → + Create Credentials → OAuth client ID
- Application type: Desktop app → name it → Download JSON
- Save the JSON to
~/.config/adloop/oauth_client.jsonandchmod 600it
Note: Leave the app in Testing mode initially. Once everything works, go back to the consent screen and click Publish app — this removes the 7-day token expiry for Testing mode apps.
Step 4 — Create the AdLoop Config
mkdir -p ~/.adloop && chmod 700 ~/.adloop
mkdir -p ~/.config/adloop && chmod 700 ~/.config/adloopCreate ~/.adloop/config.yaml:
google:
credentials_path: "~/.config/adloop/oauth_client.json"
token_path: "~/.adloop/token.json"
ga4:
property_id: "" # auto-discovered after OAuth
ads:
developer_token: "YOUR_22_CHAR_TOKEN"
customer_id: "XXX-XXX-XXXX" # client account ID
login_customer_id: "XXX-XXX-XXXX" # your MCC ID
safety:
max_daily_budget: 50.00 # reject any campaign creation above this
max_bid_increase_pct: 100
require_dry_run: true # all writes are dry-run until you flip this
log_file: "~/.adloop/audit.log"
blocked_operations: []chmod 600 ~/.adloop/config.yamlStep 5 — Authorize with Google
Run this once to trigger the OAuth browser flow. It requests all scopes (Ads + GA4) in a single token:
cd /home/YOUR_USER/Projects/3rd-party-repos/adloop && uv run python3 -c "
import sys; sys.path.insert(0, 'src')
from adloop.config import load_config
from adloop.auth import _oauth_flow
config = load_config()
creds = _oauth_flow(config)
print('OAuth complete — token saved.')
"A browser window opens. Sign in with the Google account that has access to your MCC. Grant all permissions. Your browser will redirect to localhost — that page won't load, that's expected. The token is saved to ~/.adloop/token.json and refreshes automatically going forward.
If no browser opens (headless/SSH), AdLoop falls back to a manual flow: it prints a URL, you open it in any browser, authorize, copy the full redirect URL from the address bar, and paste it back in the terminal.
Step 6 — Enable GA4 APIs in GCP
The Google Ads API gets enabled in Step 3, but GA4 needs two additional APIs enabled in the same GCP project. Without these, the Ads connection works fine but GA4 cross-referencing will return a 403 error.
In GCP Console, search for and enable both of these:
- Google Analytics Admin API — required for account/property discovery
- Google Analytics Data API — required for running reports and session data
Wait 2–3 minutes after enabling before testing. You can verify with the AdLoop health check tool once the MCP is running — it separately reports ads: ok and ga4: ok so you'll know exactly which connection is failing if something isn't right.
Step 7 — Create the MCP Wrapper Script
Claude Code uses a wrapper script pattern for MCP servers that need credentials. Create ~/.claude/mcp-adloop.sh:
#!/bin/bash
# AdLoop MCP wrapper — credentials live in ~/.adloop/config.yaml
exec /home/YOUR_USER/.local/bin/uv run \
--directory /home/YOUR_USER/Projects/3rd-party-repos/adloop \
adloopchmod 700 ~/.claude/mcp-adloop.shStep 8 — Register in Claude Code
Add the MCP entry to your ~/.claude.json. Open the file and add to the mcpServers object:
"adloop": {
"command": "/home/YOUR_USER/.claude/mcp-adloop.sh",
"type": "stdio"
}Restart Claude Code. The adloop MCP server will appear in your tools list.
Step 9 — Verify the Connection
After restarting, ask Claude to run a health check:
# Verify credentials before Claude Code restart
cd /home/YOUR_USER/Projects/3rd-party-repos/adloop && uv run python3 -c "
import sys, asyncio
sys.path.insert(0, 'src')
from adloop.config import load_config
from adloop.auth import get_ads_credentials, get_ga4_credentials
async def main():
config = load_config()
ads = get_ads_credentials(config)
ga4 = get_ga4_credentials(config)
print('Ads credentials valid:', ads.valid)
print('GA4 credentials valid:', ga4.valid)
asyncio.run(main())
"Security Model
This is the part people ask about first when I mention AI managing ad spend. AdLoop's safety model is genuinely well-thought-out:
- All writes default to dry-run —
require_dry_run: truein config means nothing is applied until you explicitly flip the flag. Claude shows you exactly what it would do. - Two-step confirmation — every mutation goes through a draft →
confirm_and_applyworkflow. No single tool call applies a change. - Budget cap —
max_daily_budget: 50.00hard-rejects any campaign creation or budget change above that amount. - New entities start paused — campaigns and ads created by AdLoop cannot go live without a separate manual activation.
- Broad Match + Manual CPC blocked — AdLoop automatically blocks this high-risk combination.
- Audit log — every operation including dry runs is written to
~/.adloop/audit.log.
For credentials: the developer token, OAuth client JSON, and access token all live in ~/.adloop/ and ~/.config/adloop/ — outside any git-tracked directory, with chmod 600. The wrapper script contains no secrets. Nothing in your project repos or Claude config files holds a live credential.
What You Can Do With It
Once the MCP is running, here are some things I've actually used it for in the first session:
- "Show me all campaigns for customer 457-693-0925 over the last 30 days, sorted by spend. Flag anything with ROAS below 2."
- "Find search terms with more than 50 impressions and 0 conversions — recommend which ones to add as negatives."
- "What's the average CTR across all campaigns? How does it compare to the industry benchmark for local services?"
- "Draft a new ad group for the keyword cluster 'chiropractor amsterdam' — keep it paused, dry-run first."
- "Cross-reference last week's Ads clicks with GA4 sessions — are there any campaigns where the click-to-session ratio is suspiciously low?"
The GA4 cross-reference capability is particularly useful for diagnosing landing page issues. If Google Ads reports 200 clicks but GA4 only records 80 sessions from the same campaign, something is wrong — broken tracking, slow page, redirect chain, or consent rejection eating the sessions. AdLoop surfaces this automatically.
Caveats and Limitations
- Explorer token limit — 2,880 operations/day sounds like a lot but a single campaign performance query across 90 days can use dozens of operations. Apply for Basic access (15,000/day) as soon as you have the Explorer token.
- Testing mode token expiry — if you leave the GCP consent screen in Testing mode, OAuth tokens expire after 7 days. Publish the app to Production to remove this limit.
- customer_id is a default, not a lock — the config
customer_idis just the default account. You can query any account under your MCC by specifying it per request. - No direct campaign UI — AdLoop works best as a complement to the Ads UI, not a replacement. For bulk structural changes, the Ads Editor is still faster. For analysis, decision support, and targeted mutations, AdLoop wins.
Where This Fits in the Agency Stack
At Webfluentia I now have three layers for Google Ads:
- AdLoop + Claude Code — internal management and analysis tool. For me. Deep queries, anomaly detection, campaign decisions, negative keyword research.
- Client dashboard (dashboard.webfluentia.agency) — client-facing read-only view. Syncs data from Google Ads API into Supabase via a daily cron. Clients see their own campaigns, spend, conversions, and ROAS without ever touching the Google Ads UI.
- Google Ads UI / Google Ads Editor — for bulk structural changes, creative review, policy compliance, anything that's easier with a point-and-click interface.
The client dashboard and AdLoop are completely independent — they both read Google Ads data but through different pipelines for different purposes. Neither replaces the other.
Keeping It Updated
AdLoop is actively developed (currently v0.6.4). Since it's a cloned repo, updating is just a git pull followed by uv sync:
cd /home/YOUR_USER/Projects/3rd-party-repos/adloop
git pull
uv syncNo reinstallation, no MCP config changes needed. The wrapper script and config stay as-is.
Frequently Asked Questions
Do I need a Google Cloud service account for AdLoop?
No. AdLoop uses OAuth 2.0 Desktop App credentials, not a service account. Service accounts are for server-to-server auth without user interaction. For AdLoop running locally on your machine with your own Google account, OAuth Desktop App is the correct approach.
Can AdLoop make changes to my Google Ads account without confirmation?
Not with the default config. All write operations require dry-run mode to be disabled in config.yaml, and every mutation goes through a draft → confirm_and_apply two-step workflow. New campaigns and ads also start paused by default, so nothing can go live accidentally.
What is the Google Ads developer token and where do I get it?
A developer token is a 22-character string that authorizes API access to Google Ads. You get it from your Google Ads account under Tools & Settings → API Center. Explorer access (2,880 operations/day) is approved instantly. Basic access (15,000/day) requires a short application review.
Does AdLoop work with a Google Ads Manager (MCC) account?
Yes. Set login_customer_id to your MCC account ID and customer_id to the sub-account you want to manage by default. You can query any account under your MCC per request — the customer_id in config is just the default.
Is this the same as the official Google Ads MCP server?
No. Google's official MCP server (developers.google.com) is read-only — it can only query data, not make changes. AdLoop is a third-party MCP server that supports both reads and writes, with a safety model for write operations. For analysis-only use cases, the official server is simpler to set up.
Will my OAuth token expire?
Only if your GCP consent screen is in Testing mode — in that case tokens expire after 7 days. Go to APIs & Services → OAuth consent screen → Publish app to move it to Production, which removes the expiry. Your app stays private — publishing just removes the testing restriction.
Can I use this for multiple client accounts?
Yes. With an MCC account as your login_customer_id, you can query and manage any sub-account. Change customer_id per session for the client you are working on. AdLoop's list_accounts tool shows all accounts accessible under your MCC.