Skip to main content
Glama
google-analytics-mcp

google-analytics-mcp

Google Analytics MCP

A Model Context Protocol (MCP) server for Google Analytics 4. Connect Claude (or any MCP-compatible AI client) directly to your GA4 properties to query traffic, analyse user behaviour, inspect events, run funnel analysis, and more — all in natural language.

The server speaks the MCP authorization spec (2025-06-18), so it works as a remote connector anywhere Claude supports custom MCP servers — claude.ai (personal), Claude Desktop, and Claude Teams. Add one URL, click "Connect", sign in with Google, done. For a Teams plan, the org owner adds the URL once and each member individually authenticates on first use.

What you can do

Property Management

  • List all accessible GA4 accounts and their properties

Reporting & Analytics

  • Page views, active users, events, traffic sources, and device metrics

  • Run fully custom reports with any GA4 metric and dimension combination

  • Funnel analysis — track user drop-off across multi-step flows (experimental)

Real-time & Discovery

  • Active users in the last 30 minutes (Realtime API)

  • List all valid dimensions and metrics for a property — useful for building custom reports


Related MCP server: analytics-mcp

How auth works

There are two modes. Pick one.

Mode A — Local STDIO (one user, no server)

Use this if you only want it on your own machine. setup_local_auth.py runs the Google OAuth flow once and stores your token in ~/.config/google-analytics-mcp/token.json. Claude Desktop launches server.py as a subprocess. No Firestore, no Cloud Run, no public URL.

Mode B — Remote HTTP server (Claude Teams, claude.ai, multi-user)

The MCP server is also an OAuth 2.1 authorization server. When Claude connects:

  1. Claude discovers our metadata at /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server.

  2. Claude registers itself via Dynamic Client Registration (POST /oauth/register).

  3. Claude redirects the user to /oauth/authorize. We delegate identification to Google OAuth.

  4. After Google login, we issue our own opaque bearer token to Claude — Google credentials never leave the server.

  5. On each /mcp request Claude sends our bearer; we map it server-side to the right user's stored Google credentials and call the GA4 APIs.

The ?user=email query string from older versions is gone — there are no per-user URLs to copy around.


Prerequisites

  • Python 3.10+

  • A Google Analytics 4 property

  • A Google Cloud project


Step 1 — Set up Google Cloud

1a. Create a project and enable the GA4 APIs

  1. Go to the Google Cloud Console.

  2. Create or select a project.

  3. APIs & Services → Library, enable both:

    • Google Analytics Data API

    • Google Analytics Admin API

1b. Create OAuth 2.0 credentials

  1. APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID.

  2. Application type: Web application.

  3. Add Authorized redirect URIs:

    • http://localhost:8080/auth/callback (local dev / setup_local_auth.py)

    • https://YOUR-CLOUD-RUN-URL/auth/callback (remote deployment — add after deploy)

  4. Click Create, then Download JSON → save as client_secret.json in the project root (gitignored). You can also copy the Client ID / Client Secret straight into env vars.

  1. APIs & Services → OAuth consent screen.

  2. Choose Internal for a Google Workspace org (recommended for teams), or External for personal/individual use.

  3. Add scopes:

    • https://www.googleapis.com/auth/analytics

    • https://www.googleapis.com/auth/analytics.readonly

  4. If using External in Testing mode, add each user's email under Test users.

1d. Enable Firestore (Mode B only)

The server stores OAuth bearer tokens and per-user Google credentials in Firestore.

  1. In Cloud Console, Firestore → Create database → Native mode, pick a region.

  2. Grant the Cloud Run service account Cloud Datastore User role under IAM & Admin → IAM.


Step 2 — Install

git clone https://github.com/dhawalshah/google-analytics-mcp
cd google-analytics-mcp
pip install -r requirements.txt
cp .env.example .env       # fill in values

Step 3 — Mode A: Local STDIO

python setup_local_auth.py

A browser opens, you sign in with Google, the script writes ~/.config/google-analytics-mcp/token.json.

Then add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):

{
  "mcpServers": {
    "google-analytics": {
      "command": "python",
      "args": ["/absolute/path/to/google-analytics-mcp/server.py"],
      "env": {
        "OAUTH_CONFIG_PATH": "/absolute/path/to/client_secret.json",
        "MCP_USER_EMAIL": "you@yourcompany.com"
      }
    }
  }
}

Restart Claude Desktop. You're done — skip the rest.


Step 3 — Mode B: Remote HTTP server (Claude Teams / claude.ai)

Deploy to Cloud Run

gcloud run deploy google-analytics-mcp \
  --source . \
  --region YOUR_REGION \
  --project YOUR_PROJECT_ID \
  --platform managed \
  --port 8080 \
  --allow-unauthenticated \
  --set-env-vars "GCP_PROJECT_ID=your-project-id,BASE_URL=https://YOUR-SERVICE-URL.run.app,GOOGLE_CLIENT_ID=...,GOOGLE_CLIENT_SECRET=...,ALLOWED_DOMAINS=yourcompany.com"

Recommended: store GOOGLE_CLIENT_SECRET as a Cloud Run secret rather than a plain env var.

After it's up, go back to APIs & Services → Credentials → your OAuth client and add the live callback URL:

https://YOUR-SERVICE-URL.run.app/auth/callback

Connect from Claude

Claude Teams (org owner adds it once for everyone):

  • Settings → Connectors → Add custom connector

  • URL: https://YOUR-SERVICE-URL.run.app/mcp

  • Each member clicks Connect, signs in with Google, done.

claude.ai personal:

  • Settings → Connectors → Add custom connector

  • URL: https://YOUR-SERVICE-URL.run.app/mcp

Claude Desktop with a remote server:

{
  "mcpServers": {
    "google-analytics": {
      "url": "https://YOUR-SERVICE-URL.run.app/mcp"
    }
  }
}

Claude Desktop will run the OAuth dance the first time you use it.


Environment Variables

Variable

Required

Description

BASE_URL

Mode B

Public URL of this service. Used for OAuth metadata and as the canonical resource URI tokens are bound to.

GCP_PROJECT_ID

Mode B

GCP project hosting Firestore.

GOOGLE_CLIENT_ID

Mode B†

Google OAuth client ID.

GOOGLE_CLIENT_SECRET

Mode B†

Google OAuth client secret.

OAUTH_CONFIG_PATH

Mode B†

Alternative to the two above: path to client_secret.json.

GOOGLE_REDIRECT_URI

No

Override the Google callback URL. Defaults to ${BASE_URL}/auth/callback.

ALLOWED_DOMAINS

No

Comma-separated email domain allowlist (e.g. acme.com,beta.com). Empty = no restriction.

MCP_USER_EMAIL

Mode A

Your email — set in Claude Desktop config.

PORT

No

HTTP port (default 8080).

LOG_LEVEL

No

Python log level (default INFO).

† Set either GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET or OAUTH_CONFIG_PATH.


Available Tools

Tool

Description

list_properties

List all accessible GA4 accounts and their properties

get_page_views

Page views by path or any dimension for a date range

get_active_users

Active user counts by date or any dimension

get_events

Event counts by event name or any dimension

get_traffic_sources

Sessions and users by source/medium

get_device_metrics

Sessions and page views split by device category

get_realtime_users

Active users in the last 30 minutes (Realtime API)

get_property_metadata

List all valid dimensions and metrics for a property

run_funnel_report

Multi-step funnel analysis — track drop-off across a user flow (experimental, v1alpha)

run_report

Fully custom report — any GA4 metrics and dimensions


Example Prompts

Show me page views for the last 30 days
How many active users do we have right now?
What are our top traffic sources this month?
Which device type drives the most sessions?
Show me a funnel from homepage to purchase for last quarter
What custom dimensions does this property have?
Run a report showing sessions and bounce rate by country for January

OAuth endpoint reference (Mode B)

For developers who want to verify the implementation or write their own MCP client.

Endpoint

Spec

Purpose

GET /.well-known/oauth-protected-resource

RFC 9728

Advertises the canonical resource URI and authorization server.

GET /.well-known/oauth-authorization-server

RFC 8414

Authorization server metadata.

POST /oauth/register

RFC 7591

Dynamic Client Registration.

GET /oauth/authorize

OAuth 2.1

Starts the auth code flow with PKCE; redirects to Google.

GET /auth/callback

—

Google redirects here; we mint our authorization code and bounce back to the MCP client.

POST /oauth/token

OAuth 2.1

Authorization code + refresh token grants.

A GET /mcp without a valid bearer returns 401 with a WWW-Authenticate: Bearer resource_metadata="…" header pointing at the protected-resource metadata document, which is how a standards-compliant MCP client discovers the rest.


Attribution

Forked from gomarble-ai/google-analytics-mcp-server, with additions:

  • Local STDIO mode with token stored in ~/.config/google-analytics-mcp/token.json

  • setup_local_auth.py — one-shot local auth script

  • Multi-user HTTP server mode acting as an OAuth 2.1 authorization server (DCR + PKCE + RFC 8707 resource indicators)

  • Per-user OAuth token storage in Firestore

  • Google Cloud Run deployment support

  • 3 additional tools: realtime users, property metadata, funnel reports


About Dhawal Shah

I run a 40-plus person digital marketing agency out of Singapore, and I build the automation my own teams use. This server is one of those tools rather than a weekend project: it runs against live GA4 accounts every week, which is why the read-only surface is wide and the write surface is deliberately narrow.

Fourteen years building companies across Asia behind it. 5,000+ campaigns, 400+ brands, 30+ startups advised, and 300+ training sessions for teams including Sony, Toyota, DHL and Interpol. I am also an Accredited Director with the Singapore Institute of Directors, which in practice means I get asked what breaks, who is accountable and what it costs before anyone asks what it can do.

I write up the routines and agents I actually run at dhawalshah.net.

Worth reading alongside this repo: Claude Code for Marketing: Every Channel from One Terminal.


License

MIT

Available Tools

10 tools
get_active_usersGet Active UsersA

Get active users metrics for a specific date range from Google Analytics 4.

Inputs: end_date (required), start_date (required), property_id (required), dimensions. Returns: object

get_device_metricsGet Device MetricsB

Get device metrics for a specific date range from Google Analytics 4.

Inputs: end_date (required), start_date (required), property_id (required), dimensions. Returns: object

get_eventsGet EventsC

Get event metrics for a specific date range from Google Analytics 4.

Inputs: end_date (required), start_date (required), property_id (required), dimensions. Returns: object

get_page_viewsGet Page ViewsB

Get page view metrics for a specific date range from Google Analytics 4.

Inputs: end_date (required), start_date (required), property_id (required), dimensions. Returns: object

get_property_metadataGet Property MetadataA

List all valid dimensions and metrics available for a Google Analytics 4 property.

Use this before calling run_report to discover which metric and dimension names are valid for a specific property. Different properties may have custom dimensions and metrics in addition to the standard GA4 ones.

Inputs: property_id (required). Returns: object

get_realtime_usersGet Realtime UsersA

Get active users in the last 30 minutes from Google Analytics 4.

This uses the Realtime API — a different endpoint from standard reports. Data reflects activity within the last 30 minutes only; no date range applies.

Inputs: property_id (required), dimensions. Returns: object

get_traffic_sourcesGet Traffic SourcesC

Get traffic source metrics for a specific date range from Google Analytics 4.

Inputs: end_date (required), start_date (required), property_id (required), dimensions. Returns: object

list_propertiesList PropertiesA

List all Google Analytics 4 accounts with their associated properties in a hierarchical structure.

Inputs: account_id. Returns: object

run_funnel_reportRun Funnel ReportA

Run a funnel analysis report for a Google Analytics 4 property.

WARNING: EXPERIMENTAL: This uses the GA4 Data API v1alpha endpoint which is unstable and may break or change without notice.

A funnel shows how many users complete each step in a sequence — e.g. homepage -> product page -> add to cart -> purchase.

Each step in steps must be a dict with:

  • "name": human-readable step label (e.g. "Homepage")

  • "filterExpression": a GA4 funnel filter expression dict

STEP FORMAT EXAMPLES:

Page path step: { "name": "Homepage", "filterExpression": { "funnelFieldFilter": { "fieldName": "pagePath", "stringFilter": {"matchType": "EXACT", "value": "/"} } } }

Event step: { "name": "Purchase", "filterExpression": { "funnelEventFilter": { "eventName": "purchase" } } }

Inputs: steps (required), end_date (required), start_date (required), property_id (required), +1 more. Returns: object

run_reportRun ReportA

Execute a comprehensive Google Analytics 4 report with full customization capabilities.

IMPORTANT: Use STRING ARRAYS for metrics and dimensions, NOT objects!

CORRECT FORMAT:

  • metrics: ["sessions", "totalUsers", "screenPageViews"]

  • dimensions: ["country", "deviceCategory"]

INCORRECT FORMAT (will fail):

  • metrics: [{"name": "sessions"}]

  • dimensions: [{"name": "country"}]

VALID GA4 METRICS:

  • sessions, totalUsers, activeUsers, newUsers

  • screenPageViews, pageviews, bounceRate, engagementRate

  • averageSessionDuration, userEngagementDuration, engagedSessions

  • conversions, totalRevenue, purchaseRevenue

  • eventCount, eventsPerSession

COMMON METRIC MISTAKES:

  • uniquePageviews (not valid) → use screenPageViews

  • pageViews (not valid) → use screenPageViews

  • users (not valid) → use totalUsers or activeUsers

  • sessionDuration (not valid) → use averageSessionDuration

  • conversionsPerSession (not valid) → use eventsPerSession

  • conversionRate (not valid) → calculate manually

VALID GA4 DIMENSIONS:

  • country, city, region, continent

  • deviceCategory, operatingSystem, browser

  • source, medium, campaignName, sessionDefaultChannelGroup

  • pagePath, pageTitle, landingPage

  • date, month, year, hour, dayOfWeek

  • sessionSource, sessionMedium, sessionCampaignName

COMMON DIMENSION MISTAKES:

  • channelGroup (not valid) → use sessionDefaultChannelGroup

  • sessionCampaign (not valid) → use sessionCampaignName

  • campaign (not valid) → use campaignName

SORTING (order_bys) - EXPERIMENTAL:

  • For metrics: [{"metric": {"metricName": "sessions"}, "desc": true}]

  • For dimensions: [{"dimension": {"dimensionName": "country"}, "desc": false}]

  • WARNING: Sorting may fail due to JSON parsing issues. Test without sorting first.

Inputs: metrics (required), end_date (required), start_date (required), property_id (required), +7 more. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 10 tools

    Disambiguation4/5

    Most tools are clearly distinct by metric type (page views, active users, events, traffic sources, devices, realtime users). However, get_active_users and get_realtime_users both measure active users, differing only by time window, which could cause confusion. run_report and run_funnel_report are distinct but run_report's broad scope overlaps somewhat with the individual metric getters.

    Naming Consistency4/5

    Tool names follow a consistent get_<metric>_metrics pattern, with list_properties, get_property_metadata, run_report, and run_funnel_report as readable exceptions. The naming is mostly consistent, though run_report and run_funnel_report use a different verb style than the get_* tools.

    Tool Count5/5

    10 tools is well-scoped for a Google Analytics MCP server. Each tool covers a distinct reporting need, and the count is within the ideal 3-15 range.

    Completeness4/5

    The server covers property discovery, metadata exploration, standard reports, realtime data, and funnel analysis. Minor gaps include no tool for creating/updating properties or managing audiences, but the core analytics querying surface is well covered.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      A local MCP server for Google Analytics 4 that provides tools for SEO and paid reporting, enabling queries on organic and paid search performance, landing pages, channels, campaigns, and real-time data.
      10
      13 npm
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server for querying Google Analytics accounts, properties, reports, and realtime data using the Data API and Admin API.
      1
      Apache 2.0
    • A
      license
      Not graded
      quality
      D
      maintenance
      A GCP-hosted MCP server for Google Analytics GA4 where each user logs in with their own Google account and queries are scoped to that user's permissions.
      Apache 2.0
    • F
      license
      Not graded
      quality
      D
      maintenance
      Production-ready MCP server integrating Google Search Console, GA4, and PageSpeed Insights for SEO and analytics intelligence, enabling natural-language queries to Google analytics data.
      -