Google Analytics MCP server
--demo needs no accountanacraft serves a Google Analytics 4 property over the Model Context Protocol, so Claude, ChatGPT or any MCP client answers how is the site doing without a human reading a dashboard.
Twelve tools. One URL to paste, or one command in a terminal. Eleven of them only read, and one of them —
audit_site — tells the assistant whether the other eleven
are worth quoting.
01Wire it up
Nothing to install, and no terminal. Add one URL to your AI tool:
https://app.anacraft.dev/mcp
- In Claude, open Settings → Connectors → Add custom connector and paste the URL. In ChatGPT it is Settings → Connectors → Create; in Cursor, add it as a remote MCP server.
- Your tool opens a sign-in page. Sign in with the Google account that has your Analytics, pick your site, and press Allow.
- Ask it how your site is doing.
It reads the site you picked. Pick Every property instead and it can read all of them, asking which one you mean. The connect page names the app it is sending you back to — if that is not the tool you started from, do not allow it. To disconnect every tool at once, open mcp on any row at app.anacraft.dev and turn your connector off.
Or paste a link for one property
For a tool that has no sign-in step, or to give an assistant only one site: sign in at app.anacraft.dev, press mcp on that site's row, and paste the link it gives you in place of the URL above. The link has its token built in and reads only that property. It is the same link next week and on every device, so treat it like a password; the same switch turns every link off at once.
For developers: from the terminal
Optional — skip this if the link above works for you. It keeps everything on your own machine, and it is how Cursor, Windsurf and other local clients connect.
Claude Desktop is one command. It merges into the config and leaves any other servers alone.
# sign in, pick a property, then install $ craft login $ craft use 397412345 $ craft mcp --install # or try it first — synthetic data, no account $ craft mcp --install --demo # and take it back out again $ craft mcp --uninstall
Restart the client and ask it how the site is doing. For Claude Code the command is
claude mcp add anacraft -- craft mcp; any other client takes the same command and
argument. Writing a config by hand, use an absolute path — a desktop app is not launched from a
shell and does not inherit the PATH where craft works.
which craft gives the value to paste.
{
"mcpServers": {
"anacraft": {
"command": "/usr/local/bin/craft",
"args": ["mcp"]
}
}
}
When the client cannot spawn it
A sandboxed client may not be able to run craft at all. A strictly confined
snap cannot read a hidden directory at the top of your home, which is both where the binary
usually sits and where ~/.anacraft/ keeps the credentials; a Mac App Store build
is walled into its container; a container may have no home directory worth the name. All of
them can open a loopback socket. So leave the process outside the sandbox and give the client a URL
instead of a command:
$ craft serve --idle 0 --no-open
The server prints one string with the token already in it:
http://127.0.0.1:7777/v1/mcp?token=<token>
That is the whole configuration for a client whose only field is a URL. For Claude Code
the server prints the command too — claude mcp add --transport http anacraft
'http://127.0.0.1:7777/v1/mcp?token=<token>' — and a client with somewhere to put a
header can send the token as Authorization: Bearer <token> against the bare
/v1/mcp instead. All three are on the server's own page, behind one mcp link
per property in the list, and on c in craft, which puts the link on the
clipboard. Your Google credentials stay in ~/.anacraft/ and never enter the sandbox;
the client only ever holds a token to a port on your own machine. It is the same twelve tools,
answering the same way.
A token in a query string is usually a thing to avoid, because query strings turn up in access
logs and Referer headers. This one goes to a server on loopback that writes no log
and is never a web page's origin, and it was going to sit in the client's config file either way —
so treat the link like a password and nothing more.
It is the same line tomorrow. The port is the one the server took last time, and the
token is an HMAC of your Google account id and the property id under a secret minted once and kept
at 0600 in ~/.anacraft/mcp-http.json — so a client configured today is
still configured next week, where a freshly minted token would have quietly stopped working
overnight. There is one token per property and it names the property it was cut for, so a
connector goes on reading the site it was wired to no matter which property the dashboard is
showing. --token still overrides the lot, for a caller that has to know the token in
advance.
02The twelve tools
| Tool | Answers |
|---|---|
| site_status | How the site is doing — every headline metric against the period before it, the daily user series, and the milestones the numbers crossed |
| audit_site | Whether those numbers can be trusted — twelve graded checks on how the property is measuring. What it checks → |
| live_visitors | Who is on the site right now, by country. Realtime, so it ignores the window |
| list_pages | Most-visited pages, by views |
| list_events | Events by count, with the per-day total against the previous period |
| list_referrers | The URLs sending traffic, by sessions |
| list_traffic_sources | GA4 source / medium pairs, by sessions |
| list_countries | Traffic by country |
| list_properties | Every property this account can read, and which is the default |
| search_pages | Pages whose path contains a substring |
| search_events | Events whose name contains a substring |
| configure_site | The one write — creates the property and web stream for a domain and returns the tag to paste |
Every report tool takes an optional property and falls back to the saved default, so an
assistant that knows nothing about your config still gets answers. Each carries its own
days default rather than sharing one, because the window a question needs is part of the
question: seven days is the right answer to how are we doing and the wrong one to is anything
broken, so audit_site advertises twenty-eight.
03What comes back
Labelled JSON, not rendered panels. Every answer carries the property id and the exact window it covers, so an assistant can attribute the numbers it quotes rather than reporting a figure with no period attached to it.
The window is reported as the first and last day the API actually returned, rather than computed
locally: last 7 days resolves in the property's reporting time zone, which is not
necessarily the machine's. Identical reports are cached for a minute — and say so in the answer, so an
assistant watching a number that will not move knows why rather than concluding the site went quiet.
04One writer, and it is obvious which
configure_site takes a domain, creates the Google Analytics property and
web stream for it, and hands back the tag with its real measurement id. It is annotated in the schema
as the one tool that is not read-only, which is what makes a client show it differently and think
before calling it.
Nothing here signs in, writes credentials to disk, or moves your default property.
login and use stay human-only commands, and configure_site never
changes what the dashboard opens on. If no credentials are stored, the tools say to run
craft login rather than opening a browser inside your client's subprocess.
05What it will not do
It serves one property at a time and it serves Google Analytics. There is no Search Console, no Google Ads and no Meta here, so an assistant asked to explain a drop can say which channel carried it and not which campaign paid for it.
And it will not pretend a broken property is a quiet one. That is what
audit_site is for: a site with nothing marked as a key event
reports zero conversions perfectly truthfully, and saying nothing here is marked as a conversion
is a different answer from conversions fell.
06Try it without an account
# synthetic data over the same twelve tools $ craft mcp --demo
No Google account, no subscription. The wiring can be tested and the answers looked at first.
The live server is part of the Anacrafter Elite ($9.99) plan. Without a login or a subscription it still starts, and its tools say which one is missing — so the client never reports it as disconnected, and the answer arrives where you asked the question.
Building with Lovable? anacraft × Lovable adds GA4 to your app, then reads the numbers back from Claude or any MCP client.
09Questions
What is an MCP server for Google Analytics?
The Model Context Protocol is a standard way for an AI assistant to call tools. An MCP server for Google Analytics exposes the reporting API as tools the assistant can call, so it can read a property's real numbers instead of being pasted a screenshot. craft mcp is one: a single command that speaks the protocol on stdin and stdout, which the client spawns as a child process. A client that cannot spawn one — a confined snap, a Mac App Store build, a container — reaches the same tools over HTTP instead, at craft serve's /v1/mcp.
How do I connect Claude to Google Analytics?
Add https://app.anacraft.dev/mcp as a custom connector in Claude (Settings, Connectors, Add custom connector), sign in with the Google account that has your Analytics, and press Allow. From a terminal instead: craft login, craft use to pick a property, then craft mcp --install to write the server into Claude Desktop's config. For Claude Code the command is claude mcp add anacraft -- craft mcp.
Can the assistant change anything in my Analytics account?
Eleven of the twelve tools only read. The exception is configure_site, which creates a property and web data stream for a domain the account does not measure yet and returns the tag to paste. Nothing signs in, writes credentials to disk, or changes which property the dashboard opens on — login and use stay human-only commands.
Does it work without a Google account?
craft mcp --demo serves synthetic data over the same twelve tools, so the wiring can be tested and the answers looked at before any account is connected. It needs no login and no subscription.
What does the assistant get back?
Labelled JSON carrying the property id and the exact date window the numbers cover, so an assistant can attribute what it quotes rather than reporting a figure with no period attached. Identical reports are cached for a minute, so a chatty agent does not burn the API quota the dashboard needs.