Article Information

Category: Development

Published: April 24, 2026

Author: Chris de Gruijter

Reading Time: 12 min

Tags

Google AdsClaudeMCPAI AutomationAgency
Business presentation on ad spend with charts and graphs in a modern office setting

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 sync

The 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.

  1. Go to console.cloud.google.com and select or create a project
  2. Search for Google Ads API → Enable it
  3. Go to APIs & Services → OAuth consent screen → External → fill in app name + your email → add yourself as a Test User
  4. Go to APIs & Services → Credentials → + Create Credentials → OAuth client ID
  5. Application type: Desktop app → name it → Download JSON
  6. Save the JSON to ~/.config/adloop/oauth_client.json and chmod 600 it

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/adloop

Create ~/.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.yaml

Step 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 \
  adloop
chmod 700 ~/.claude/mcp-adloop.sh

Step 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-runrequire_dry_run: true in 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_apply workflow. No single tool call applies a change.
  • Budget capmax_daily_budget: 50.00 hard-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_id is 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:

  1. AdLoop + Claude Code — internal management and analysis tool. For me. Deep queries, anomaly detection, campaign decisions, negative keyword research.
  2. 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.
  3. 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 sync

No 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.