BuildWithMatija
  1. Home
  2. Blog
  3. Tools
  4. Google Analytics MCP: Setup for Cursor, Claude, Codex

Google Analytics MCP: Setup for Cursor, Claude, Codex

Configure analytics-mcp for Cursor, Claude Code & Codex to query GA4—pipx, service account and OAuth setup with tested…

22nd June 2026·Updated on:24th June 2026··
Tools
Google Analytics MCP: Setup for Cursor, Claude, Codex

📚 Get Practical Development Guides

Join developers getting comprehensive guides, code examples, optimization tips, and time-saving prompts to accelerate their development workflow.

No spam. Unsubscribe anytime.

📄View markdown version
0

Frequently Asked Questions

About the author

Matija Žiberna

Matija Žiberna

Full-stack developer, co-founder

AboutResume

Self-taught full-stack developer sharing lessons from building software and startups.

I'm Matija Žiberna, a self-taught full-stack developer and co-founder passionate about building products, writing clean code, and figuring out how to turn ideas into businesses. I write about web development with Next.js, lessons from entrepreneurship, and the journey of learning by doing. My goal is to provide value through code—whether it's through tools, content, or real-world software.

Contents

  • What the server gives you
  • Two things you need before you start
  • Step 1: Enable the APIs
  • Step 2: Set up credentials
  • Option A: Service account JSON (headless setups)
  • Option B: OAuth user credentials (local development)
  • Step 3: Smoke-test the server
  • Step 4: Wire it into each client
  • Cursor
  • Claude Code
  • Codex
  • A shortcut, if you're working in the buildwithmatija repo
  • Step 5: Confirm GA4 access for real
  • Verifying the setup
  • Troubleshooting
  • Security notes
  • What this setup doesn't cover
  • FAQ
  • Wrapping up
On this page:
  • What the server gives you
  • Two things you need before you start
  • Step 1: Enable the APIs
  • Step 2: Set up credentials
  • Step 3: Smoke-test the server
Build with Matija logo

Build with Matija

Modern websites, content systems, and AI workflows built for long-term growth.

Services

  • Headless CMS Websites
  • Next.js & Headless CMS Advisory
  • AI Systems & Automation
  • Website & Content Audit

Resources

  • Case Studies
  • How I Work
  • Blog
  • Topics
  • CMS Hub
  • E-commerce Hub
  • B2B Website Strategy
  • Dashboard

Headless CMS

  • Payload CMS Developer
  • CMS Migration
  • Multi-Tenant CMS
  • Payload vs Sanity
  • Payload vs WordPress
  • Payload vs Contentful

Get in Touch

Ready to modernize your stack? Let's talk about what you're building.

Book a discovery callContact me →
© 2026Build with Matija•All rights reserved•Privacy Policy•Terms of Service
BuildWithMatija
Get In Touch

If you have a GA4 property and want Cursor, Claude Code, or Codex to query it directly, connect the official Google Analytics MCP server (analytics-mcp). Access is read-only through the analytics.readonly scope, so the agent can run reports and list properties but never touch your configuration or your data. The setup is the same pipx run analytics-mcp process everywhere; only the client config file changes between Cursor, Claude Code, and Codex.

I run this server across all three clients on the buildwithmatija repo, and Google's own README only documents the Gemini and Claude Code paths. This guide adds the Cursor and Codex configs I use day to day, plus a setup script that patches all three at once if you're working in this repo.

What the server gives you

The tools are backed by the Google Analytics Admin API and Google Analytics Data API:

ToolPurpose
get_account_summariesList GA accounts and properties your credentials can access
get_property_detailsReturn metadata for a property (timezone, currency, etc.)
list_google_ads_linksList Google Ads account links for a property
run_reportRun standard GA4 reports (dimensions, metrics, date ranges)
run_funnel_reportRun funnel reports
get_custom_dimensions_and_metricsList custom dimensions and metrics on a property
run_realtime_reportRealtime activity, typically the last 30 minutes (GA360 properties can report up to 60 minutes)

Two things you need before you start

Keep these separate in your head, because mixing them up is where most setups stall:

  1. A Google Cloud project with the Admin API and Data API enabled.
  2. GA4 Viewer access for whichever identity you authenticate with. Enabling the APIs in GCP grants nothing in GA4 on its own. You still have to add that identity inside GA4's own access management screen.

You'll also need Python 3.10+, pipx to run analytics-mcp in an isolated environment, and one auth path: a service account JSON for headless setups, or OAuth through Application Default Credentials for local dev. The Google Cloud SDK is optional and only needed for the OAuth path.

Step 1: Enable the APIs

In Google Cloud Console, enable the Admin API and Data API on your project, or run:

bash
# File: terminal
gcloud config set project YOUR_GCP_PROJECT_ID
gcloud services enable analyticsadmin.googleapis.com analyticsdata.googleapis.com

This step only touches GCP. GA4 access still happens in Step 5.

Step 2: Set up credentials

Pick one of these two paths. Don't run both.

Option A: Service account JSON (headless setups)

This is the fastest path for a server, but it produces a long-lived key file. Store it outside version control, restrict its permissions, and rotate it the moment you suspect it's exposed. Google's own README favors service account impersonation over a downloaded key for production use, and that's worth following once you move past local testing.

  1. In GCP, go to IAM & Admin → Service Accounts → Create service account (for example, analytics-mcp-reader).
  2. Under Keys → Add key → JSON, download the file somewhere gitignored, like keys/gc-service-key.json.
  3. In GA4 → Admin → Property access management, add the service account email (…@….iam.gserviceaccount.com) as Viewer.
  4. Point GOOGLE_APPLICATION_CREDENTIALS at that file:
bash
# File: terminal
export GOOGLE_APPLICATION_CREDENTIALS="/absolute/path/to/service-account.json"

You'll reuse this same path in every client config below.

Option B: OAuth user credentials (local development)

  1. Create an OAuth desktop client in GCP and download the client JSON, for example oauth-client.json.
  2. Log in with Application Default Credentials, scoped to read-only analytics access:
bash
# File: terminal
gcloud config set project YOUR_GCP_PROJECT_ID
gcloud services enable analyticsadmin.googleapis.com analyticsdata.googleapis.com

gcloud auth application-default login \
  --scopes https://www.googleapis.com/auth/analytics.readonly,https://www.googleapis.com/auth/cloud-platform \
  --client-id-file=/absolute/path/to/oauth-client.json
  1. gcloud prints the path to the credentials it saved:
text
Credentials saved to file: [/home/you/.config/gcloud/application_default_credentials.json]

That printed ADC path is what goes into GOOGLE_APPLICATION_CREDENTIALS for every client config. The OAuth client JSON from step 1 only exists to run the login command itself; once you've logged in, it has no further role in any config file. Your Google account also needs Viewer access on the GA4 property, granted inside GA4 directly.

Step 3: Smoke-test the server

bash
# File: terminal
pipx run analytics-mcp

You should see:

text
Starting MCP Stdio Server: Google Analytics MCP Server

The process sits there waiting on stdio, which is normal for an MCP server. Ctrl+C to exit.

Three environment variables are required for every client:

VariablePurpose
GOOGLE_APPLICATION_CREDENTIALSPath to the service account JSON or ADC file
GOOGLE_PROJECT_IDYour GCP project ID
GOOGLE_CLOUD_PROJECTSame project ID again

A quick test with explicit env vars:

bash
# File: terminal
GOOGLE_APPLICATION_CREDENTIALS="/absolute/path/to/credentials.json" \
GOOGLE_PROJECT_ID="YOUR_GCP_PROJECT_ID" \
GOOGLE_CLOUD_PROJECT="YOUR_GCP_PROJECT_ID" \
pipx run analytics-mcp

If pipx isn't on your PATH, use the full path, something like /home/you/.local/bin/pipx.

Step 4: Wire it into each client

Every client uses the same command (pipx), the same args (["run", "analytics-mcp"]), and the same three env vars. Only the file format changes. Restart the client after editing its config.

Cursor

Edit .cursor/mcp.json at your project root, or the global MCP settings inside Cursor:

json
{
  "mcpServers": {
    "analytics-mcp": {
      "command": "/home/you/.local/bin/pipx",
      "args": ["run", "analytics-mcp"],
      "env": {
        "GOOGLE_APPLICATION_CREDENTIALS": "/absolute/path/to/credentials.json",
        "GOOGLE_PROJECT_ID": "YOUR_GCP_PROJECT_ID",
        "GOOGLE_CLOUD_PROJECT": "YOUR_GCP_PROJECT_ID"
      }
    }
  }
}

If you already have other servers configured, merge this entry into the existing mcpServers object rather than replacing the file.

Restart Cursor, then try:

text
What can the analytics-mcp server do?
List my Google Analytics properties

Claude Code

Add the same shape to .mcp.json at the repo root, or register it through the CLI:

bash
# File: terminal
claude mcp add analytics-mcp \
  --scope user \
  -e "GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/credentials.json" \
  -e "GOOGLE_PROJECT_ID=YOUR_GCP_PROJECT_ID" \
  -e "GOOGLE_CLOUD_PROJECT=YOUR_GCP_PROJECT_ID" \
  -- pipx run analytics-mcp

Start a new session and run the same verification prompts as above.

Codex

Edit ~/.codex/config.toml for a user-wide setup, or .codex/config.toml inside the project. Codex uses a [mcp_servers.<name>] table, per the Codex MCP configuration docs:

toml
# File: ~/.codex/config.toml
[mcp_servers.analytics-mcp]
command = "pipx"
args = ["run", "analytics-mcp"]

[mcp_servers.analytics-mcp.env]
GOOGLE_APPLICATION_CREDENTIALS = "/absolute/path/to/credentials.json"
GOOGLE_PROJECT_ID = "YOUR_GCP_PROJECT_ID"
GOOGLE_CLOUD_PROJECT = "YOUR_GCP_PROJECT_ID"

On a laptop using OAuth/ADC, point the credentials path at your ADC file:

toml
GOOGLE_APPLICATION_CREDENTIALS = "/home/you/.config/gcloud/application_default_credentials.json"

Restart Codex, then ask:

text
What can the analytics-mcp server do?
What are the most popular events in the last 30 days?

A shortcut, if you're working in the buildwithmatija repo

This repo ships scripts/setup-google-analytics-mcp.sh, which patches .cursor/mcp.json, .mcp.json, and ~/.codex/config.toml in a single run:

bash
# File: terminal

# Service account JSON (headless / server)
./scripts/setup-google-analytics-mcp.sh keys/gc-service-key.json

# OAuth desktop client (browser login)
./scripts/setup-google-analytics-mcp.sh /path/to/oauth-client.json

In service account mode, it writes the key path straight into GOOGLE_APPLICATION_CREDENTIALS. In OAuth mode, it uses the client JSON only to run gcloud auth application-default login, then writes the resulting ADC path into the configs. The script prints the API enablement links and the service account email to add in GA4 when relevant. Restart Cursor, Claude Code, and Codex once it finishes. This script is specific to this repo; on any other machine, follow Steps 1 through 4 directly.

Step 5: Confirm GA4 access for real

This is the step people skip, and it's the most common reason the server connects but returns nothing. Enabling the GCP APIs never grants GA4 access by itself. Whatever identity you configured in Step 2 needs Viewer access inside GA4's own access management screen.

Auth pathWho needs Viewer on the GA4 property
OAuth / ADCYour Google account, the one used during gcloud auth application-default login
Service account JSONThe service account email (…@….iam.gserviceaccount.com)

Add it under GA4 → Admin → Property access management → +, with role Viewer. Without this, get_account_summaries can return empty results or permission errors even when every GCP API shows as enabled.

Verifying the setup

CheckExpected result
pipx run analytics-mcp"Starting MCP Stdio Server…"
MCP tools visible in the clientget_account_summaries, run_report, and the rest
"List my Google Analytics properties"Your property name and ID come back
run_report on a date rangeRows with actual metrics

The first prompt worth running confirms access before you ask anything analytical:

text
Use analytics-mcp to list the GA4 properties I can access. Then tell me which property ID I should use for my site.

A few more to try once that works:

text
What can the analytics-mcp server do?
List my Google Analytics properties
What are the top 20 events in the last 90 days?
How many page views did /tools/cms-picker get in the last 30 days?

Troubleshooting

SymptomLikely causeFix
MCP tools not listed in CursorServer didn't reload after a config changeRestart Cursor and validate the JSON in .cursor/mcp.json
get_account_summaries returns emptyThe configured identity lacks GA4 ViewerAdd Viewer access for your Google account (OAuth) or the service account email
403 / permission deniedAPIs disabled, or the wrong GCP project IDEnable the Admin and Data APIs, and check GOOGLE_PROJECT_ID
pipx: command not foundpipx isn't on PATHUse the full path, e.g. /home/you/.local/bin/pipx
Auth works in the terminal but not in the IDEThe MCP process started before the config updateFully restart the client and open a new session
Confusion right after OAuth loginThe OAuth client JSON got used as the credentials pathUse the ADC path gcloud printed, not the OAuth client JSON
Precondition check failed in logsGoogle auth boundary noiseUsually harmless if reports still return data
Report fails: "11 metrics"The Data API caps requests at 10 metricsSplit the request into two run_report calls
Funnel fails on pagePathThe Funnel API doesn't support pagePath in stepsUse pageLocation with a CONTAINS filter

Security notes

Treat the credentials here the same way you'd treat any production secret. Never commit service account keys, OAuth client JSON, or ADC files to version control. Grant Viewer only on the GA4 property, never Editor or Administrator. Use a dedicated service account per environment rather than reusing one across projects. For production or CI, lean toward service account impersonation or workload identity instead of a long-lived downloaded key whenever your setup allows it.

What this setup doesn't cover

This server reads GA4 data that already exists; it doesn't create it. It won't install GA4 tracking on your site, so you still need gtag, GTM, or an equivalent. It won't create custom events or mark key events inside GA4. Every tool is read-only, so nothing here writes back to your property, and none of it replaces the GA4 UI for complex explorations or exports. For funnel tracking, lead attribution, or conversion analysis, instrument those events in your application first. The MCP server can only read what GA4 has already collected.

FAQ

Does this MCP server work the same way across Cursor, Claude Code, and Codex? Yes. The underlying analytics-mcp process, the command, and the three environment variables are identical. Only the config file format changes: JSON for Cursor and Claude Code, TOML for Codex.

Can this server modify my GA4 property or data? No. Access is scoped to analytics.readonly, so every tool listed here reads data without the ability to change configuration, events, or settings.

Should I use a service account or OAuth? Service account JSON is the simpler choice for headless or server environments, since there's no browser login step. OAuth through Application Default Credentials fits local development better, especially if you're already authenticated with gcloud for other work.

Why does get_account_summaries return nothing even though I enabled the APIs? GCP API enablement and GA4 property access are managed separately. Add the relevant identity, your Google account or your service account email, as Viewer inside GA4's own access management screen.

Why did a report fail with a metrics limit error? The GA4 Data API allows a maximum of 10 metrics per run_report call. If you need more, split the request into two separate calls and combine the results yourself.

Wrapping up

Once the server is wired into your client of choice, GA4 questions stop requiring a trip to the Analytics UI. You can ask for top events, page view counts on a specific path, or which properties a given credential can see, all from inside Cursor, Claude Code, or Codex. The setup is identical everywhere except for the config file format, and the one step that trips people up is GA4 Viewer access, which lives outside GCP entirely.

Let me know in the comments if you have questions, and subscribe for more practical development guides.

Thanks, Matija