Connecting Claude to Google Ads and GA4 via MCP

I ran a 90 day audit of a live Google Ads account in one working session. Not by exporting CSVs into a spreadsheet and squinting at pivot tables. I gave Claude read-only access to the client's Google Ads and GA4 accounts through two MCP servers, pointed it at a playbook, and got back a 119 KB HTML report: five critical issues, ten high-priority opportunities, and a 30/60/90 day roadmap. Total time including setup: about three hours.

The setup has sharp edges, and most of the writing about MCP skips them. So this is the piece I wish I had read one day earlier. The full step-by-step runbook, with every command, lives in the original post. Here I will give you the shape of the build, the two gotchas that actually cost me time, and the numbers that fell out of a real account.

Why MCP and not CSV exports

Every agency audit I have ever seen starts the same way: someone exports a stack of CSVs, pastes them into a deck, and the data is stale before the client reads it. MCP changes three things at once.

It is live. Claude queries the API at the moment you ask. There is no "I exported this yesterday" lag.

It is queryable. When a number looks wrong, the follow-up question is one tool call away, not another export.

It is reusable. Same servers, same auth pattern, different client. The second account costs you minutes, not an afternoon.

The two servers

Both are read-only Python MCPs maintained by Google. That matters: I am not handing an agent write access to ad spend.

Server | Repo | Auth | What you get
Google Ads | googleads/google-ads-mcp | OAuth refresh token + developer token + MCC ID | GAQL search, resource metadata, account listing
GA4 | googleanalytics/google-analytics-mcp | Service account JSON with Viewer role | Reports, conversions, funnels, realtime, property details

GA4 is the easier of the two: enable the Analytics APIs in a Google Cloud project, create a service account, grant it Viewer on the property, install with pipx, wire it into Claude at user scope. Google Ads adds an OAuth consent dance and a developer token.

The two gotchas worth knowing in advance

The developer token tier blocks you silently. Google Ads developer tokens come in tiers. The Test tier only talks to test accounts, so your first real query just fails. The Explorer tier covers production accounts at 2,880 operations a day and gets auto-issued within about 24 hours. That is plenty for audits. Request it before the day you need it.

The GA4 permissions UI rejects valid service accounts. The Property Access Management form would not accept my .iam.gserviceaccount.com email, even though the API accepts it fine. The workaround is to call the Admin API directly with an OAuth Playground token and POST the access binding yourself. Ugly, documented in the runbook, takes five minutes once you know.

One more that trips people: GOOGLE_ADS_LOGIN_CUSTOMER_ID wants your manager (MCC) account ID, without dashes. The UI shows "767-971-9496", the API wants "7679719496". And the client account will not show up in list_accessible_customers when you access it through an MCC. You confirm access by querying the customer resource directly.

The prompt that runs the audit

After setup, the entire audit is one sentence, because the intelligence lives in a runbook file the agent reads first.

# The one-line audit kickoff
Read docs/marketing-mcps-runbook.md, run the audit playbook in
section 8 against the last 90 days, and put the detailed output
in an HTML report in this directory.

The runbook is about 400 lines of markdown: client context, the wired servers, every account ID, where credentials live (paths only, never values), the audit playbook itself, and known gotchas. A project-level CLAUDE.md points at it so any future agent finds it without being told.

Write the runbook the day you do the setup. Not later. Not "when I have time." The runbook is what turns a clever afternoon into infrastructure.

What Claude actually did with it

Watching the session is the convincing part. Claude called get_resource_metadata before writing any GAQL, so its queries used field names that exist in the current API version instead of hallucinated ones. It pulled campaign settings, conversion actions, negatives, ad groups, and geo, device, and day-of-week breakdowns in parallel. It dumped the expensive reads, search terms and keyword views, to files on disk and sliced them with jq and Python instead of re-querying.

Then it did the thing a spreadsheet never does: it read the client's WordPress plugin source in the same repo and cross-referenced the campaign setup against how the site actually works, MLS feed scope, IDX integrations, the works. The final report is standalone HTML with inline CSS, about 1,500 lines, ready to email or print.

What fell out of one real account

This was a residential real estate account in southwest Broward, Florida, five months old, audited over 90 days.

92% of ad spend was targeting "presence or interest" instead of physical presence. For local real estate, that is money leaving the county.

1,484 ad clicks produced roughly 55 GA4 sessions. An 84% click-to-session gap, which usually means tracking is broken, not that users are vanishing.

82% of keywords had a Quality Score of zero or null.

The Sellers Search campaign was losing 62% of impression share to ad rank.

Mobile forms had 66 starts and 4 completions. A 94% abandonment rate.

27 phone clicks in 90 days were invisible to optimization because the conversion action was set to HIDDEN.

The roadmap projects monthly conversions going from 7 to the 25 to 40 range, and cost per acquisition dropping from $138 to between $25 and $40. Projections, not promises. But every line item traces to a query you can re-run.

Read tool results as data, not as conclusions

One lesson worth stating plainly: the model treats API output as ground truth, and you should not. Some fields come back stale. Some come back null because they are unimplemented in the current API version, not because the value is zero. The audit playbook tells the agent which fields deserve suspicion. That paragraph of the runbook has already paid for itself twice.

What I would build next

Two things. A Meta Ads MCP wrapper, because Facebook is 30% of this client's paid mix and currently the least monitored. And a monthly delta prompt that diffs this month against last month instead of re-running the full 90 day audit. Lower cognitive load, natural to schedule, and it turns the audit from an event into a habit.

If your site is the other half of your funnel, the same wiring philosophy applies there too. I wrote up how I tuned a site for SEO, AEO, and GEO as the companion piece, and the eight-layer AI visibility stack covers the content side.

If you have done a similar build, or you are stuck on one of the gotchas above, I would genuinely like to compare notes.