I Taught an AI to Read My Analytics. Then It Started Doing My Marketing.

“Wait, can you even do that?”

It started, as the best bad ideas do, with a question I didn’t expect a real answer to.

I’d been hearing about MCP — the Model Context Protocol, the thing that lets an AI assistant actually talk to your stuff instead of just hallucinating about it.
And I had a pile of “my stuff”: Google Search Console, GA4, a website with the SEO charisma of a parked domain. So I asked, half-joking: “Could I build a little server that lets Claude read my Search Console directly? Like, is that a thing that’s allowed to exist?”

The answer was “yes.” Which, in hindsight, is exactly what you’d expect an AI to say about giving an AI more access. But here we are.

The first honest version

The rule I set on day one — and never broke — was read-only by default. The whole thing would be a diagnostic console, not a robot with its hands on the controls. You ask “why did traffic drop?”, it pulls the numbers, you (or the AI) reason about them. The server returns raw metrics and plain arithmetic — clicks, impressions, CTR, position, deltas vs the previous period — and zero opinions. No “health scores,” no AI-flavored “insights” baked into the backend. Interpretation is the model’s job; the server just hands over clean facts.

Some self-imposed constraints, because constraints are what stop a weekend project from becoming a Kubernetes cluster you cry about at 2am:

  • One bare Go binary. TLS terminates in-process via autocert. No nginx, no reverse proxy, no sidecars, no “just add Redis.”
  • Stateless, apart from one in-process cache.
  • Narrow tools, small bounded responses. Every tool does one thing and never dumps a novel back at you.

The funnel grows a few more legs

One data source is a chart. Several data sources that line up is a story. So it grew:

  • Search Console — the intent (what people search for).
  • GA4 — the behaviour (what they do once they land).
  • An on-page fetcher — the content (what the page actually says).
  • PageSpeed — the performance (is it slow enough to chase people away).

Suddenly you could ask one question — “this page gets impressions but nobody converts, why?” — and get it answered across all four legs in a single conversation. Intent × content × performance × behaviour.

That’s the moment the toy started feeling like a tool.

The plot twist: I have no acquisition problem to diagnose, because I have no acquisition

Here’s the brutally honest part. I pointed all this beautiful machinery at my own site and the diagnosis came back instantly: the patient has no pulse. Almost all my traffic was existing clients, bookmarks, and invoice links. New organic prospects? A rounding error.

You can’t optimize a funnel that doesn’t have anything entering the top of it. So the conversation pivoted from “diagnose my traffic” to the much scarier “okay, how do I get traffic” — and that’s where Google Ads entered, and where I learned that Google’s developer onboarding is its own boss fight.

Google Ads: a saga in three acts (and one bureaucratic side-quest)

I had a clean plan: (1) read my Ads data, (2) let the AI propose campaigns from real data, (3) a safe write mode — create the campaign, the keywords, the budgets… but leave it paused, so I press Start. Money is the one thing you never autopilot.

What I learned the hard way:

  • You can’t use the Ads API with a humble API key. You need a Manager (MCC) account, a developer token, and Google’s blessing (“Basic access”) via an application form — complete with a design document upload. I genuinely wrote a design doc to ask a company for permission to spend money with them. 2026, everybody.
  • The “just add yourself as a test user” trick that works for OAuth? Doesn’t apply here. A test developer token only talks to test accounts with fake data. For your real account you wait for the approval email like it’s a university acceptance letter.

So while Google’s compliance team deliberates, I built what I could: Phase 1 (read-only reporting: campaigns, keywords, search terms, budgets), Phase 2 (a “propose a campaign” playbook + a keyword-ideas tool that returns real search volumes), and left Phase 3 (the paused-campaign creator) firmly behind a wall, off by default, awaiting both the approval and a deliberate sign-off. The architecture’s whole personality is: the worst-case bug is an inert, paused draft that costs nothing until a human clicks Start.

The part where the AI reviews the AI

Somewhere in here it got delightfully recursive. I’d have Claude build a feature, then spin up a second Claude to do a hostile code review of the first one’s work — and it kept finding real bugs. The best one: a function that was supposed to safely truncate text to a byte limit, but on non-UTF-8 input it quietly collapsed the whole thing to an empty string and ran in O(n²). Caught, fixed, regression-tested. Robots keeping robots honest. I just supplied the suspicious eyebrow.

The “oh, it can just do that” moment

My favourite upgrade came from a complaint. I was porting a site’s header/footer and the assistant kept saying “I only have your analytics data, I can’t see the live markup” — so it was mentally reaching for curl like the rest of us. Except the connector has no shell.

So I added a tool, page_extract: point it at a URL, optionally give it a CSS-ish selector (header, footer, .something), and it returns the raw outerHTML of exactly that region — or, pointed at a stylesheet, the raw CSS. The entire manual ritual of curl the page → grep the CSS links → curl the stylesheet → awk the design tokens → python out the footer collapsed into two native calls. The server quietly became self-sufficient for porting jobs too. (Bounded and size-capped, of course. I’m reckless, not insane.)

Where it landed

What began as “can I let an AI peek at my Search Console?” is now a single, stateless Go binary that:

  • reads Search Console, GA4, on-page content, PageSpeed, and (pending Google’s paperwork) Google Ads;
  • joins them into one funnel narrative;
  • proposes paid campaigns from real demand data;
  • and will eventually draft those campaigns paused, because the day I let software spend my money unsupervised is the day I deserve the invoice.

Read-only by default. One binary. No opinions in the backend — just clean facts handed to something that’s annoyingly good at reasoning about them.

The footnote nobody warns you about

The CI is bright red. Not because the code is broken — every check passes locally — but because I burned through my month’s free GitHub Actions minutes shipping pull requests back-to-back like a man possessed. Somewhere a billing meter is laughing at me.

Totally worth it.