Skip to main content
Glama
ccsmatt

Google Analytics 4 MCP Server

by ccsmatt

Google Analytics 4 MCP Server

A read-only Model Context Protocol server that lets Claude query Google Analytics 4. Deploy it once (for example on Railway), add it to your Claude Team plan as a custom connector, and anyone on the team can ask things like:

  • "Which channels drove the most sessions and key events last month?"

  • "Top 20 landing pages from Organic Search in the last 28 days, with engagement rate"

  • "Compare this month's sessions by device to last month"

  • "How many people are on the site right now, and from which countries?"

It is read-only: it only ever requests the https://www.googleapis.com/auth/analytics.readonly scope and has no tools that change anything in GA4.

Based on ccsmatt/gsc-mcp-server, a fork of sofianbettayeb/gsc-mcp-server by Sofian Bettayeb (MIT). The HTTP transport and deployment setup come from that project; the Search Console tools were replaced with GA4 tools.

Tools

Tool

What it does

ga_list_properties

Lists GA4 accounts and properties the Google account can read, with property IDs

ga_get_property

Details for one property: time zone, currency, data streams (website URL, measurement ID)

ga_run_report

Historical report (Data API runReport): date ranges, dimensions, metrics, filters, sorting, row limit (default 100, max 1000)

ga_run_realtime_report

Last 30 minutes of activity (runRealtimeReport)

ga_get_metadata

Custom dimensions and metrics on a property (optionally all standard ones too)

Related MCP server: Google Analytics MCP Server

How it works

  • One HTTP endpoint, POST /mcp (stateless streamable HTTP), plus GET /healthz for health checks.

  • Every /mcp request must carry Authorization: Bearer <MCP_AUTH_TOKEN>. The server refuses to start if MCP_AUTH_TOKEN is not set.

  • The server reads GA4 as one Google account (whoever created the refresh token). Everyone who uses the connector sees what that account can see, so use an account with Viewer access to exactly the properties your team should query.

  • All credentials come from environment variables. Nothing is written to disk.

Environment variables

Variable

Required

Description

GOOGLE_CLIENT_ID

yes

OAuth client ID (Desktop app type)

GOOGLE_CLIENT_SECRET

yes

OAuth client secret

GOOGLE_REFRESH_TOKEN

yes

From npm run setup-auth (step 3)

MCP_AUTH_TOKEN

yes

Long random string Claude must send as a Bearer token

PORT

no

Listen port (default 8080; Railway sets this for you)

1. Google Cloud setup

  1. Go to Google Cloud Console and create a project (or pick an existing one).

  2. Enable the two APIs (APIs & Services > Library), searching for each:

    • Google Analytics Data API

    • Google Analytics Admin API

  3. Configure the OAuth consent screen (Google Auth Platform):

    • Branding: app name (e.g. "GA4 MCP"), your support email.

    • Audience:

      • If your Google account is part of a Google Workspace organization, choose Internal. Tokens don't expire and no verification is needed.

      • Otherwise choose External, add yourself as a test user, then Publish app (set to In production). Apps left in Testing issue refresh tokens that expire after 7 days. An unverified production app shows an "unverified app" warning during consent; as the owner you can click Advanced > Go to ... (unsafe) to continue.

    • Data Access: add the scope https://www.googleapis.com/auth/analytics.readonly (shown as ".../auth/analytics.readonly").

2. Create the OAuth client

  1. Google Auth Platform > Clients > Create client.

  2. Application type: Desktop app. Give it a name and click Create.

  3. Copy the Client ID and Client secret. Don't download the JSON into this repo (it's git-ignored, but there's no need for it).

Make sure the Google account you'll sign in with has at least Viewer access on each GA4 property (GA4 > Admin > Property access management).

3. Get a refresh token

You need Node.js 22+ and a copy of this repo.

git clone https://github.com/ccsmatt/ga-mcp-server.git
cd ga-mcp-server
npm install

Then run the helper with your client ID and secret as environment variables.

PowerShell (Windows):

$env:GOOGLE_CLIENT_ID = "your-client-id.apps.googleusercontent.com"
$env:GOOGLE_CLIENT_SECRET = "your-client-secret"
npm run setup-auth

macOS / Linux:

GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com" GOOGLE_CLIENT_SECRET="your-client-secret" npm run setup-auth

The script:

  1. Prints a Google consent URL. Open it in an incognito/private window and sign in with the Google account that has GA4 access.

  2. After you approve, your browser goes to http://localhost/?code=... and shows a "can't connect" page. That's expected.

  3. Copy the full address from the address bar (or just the code value) and paste it into the terminal.

  4. The script prints only the refresh token. Copy it somewhere safe for step 5 (e.g. your password manager).

Nothing is written to disk. Close the terminal afterwards so the client secret isn't left in its environment.

If you get invalid_grant, the code expired or was already used; run it again and paste promptly.

4. Choose an MCP auth token

MCP_AUTH_TOKEN is the password Claude uses to call your server. Generate a long random one:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

5. Deploy to Railway

  1. In Railway, click New Project > Deploy from GitHub repo and pick ga-mcp-server. Railway finds the Dockerfile and builds with it.

  2. Open the service > Variables and add:

    • GOOGLE_CLIENT_ID

    • GOOGLE_CLIENT_SECRET

    • GOOGLE_REFRESH_TOKEN

    • MCP_AUTH_TOKEN

    Don't set PORT; Railway provides it.

  3. Settings > Networking > Generate Domain to get a public URL like https://ga-mcp-server-production.up.railway.app.

  4. Optional: Settings > Deploy > Healthcheck Path = /healthz.

  5. Check it: opening https://<your-domain>/healthz should show {"status":"ok"}. The deploy logs should say ga-mcp-server listening on port .... If the logs say a variable is missing, fix it under Variables (Railway redeploys automatically).

Your MCP endpoint is https://<your-domain>/mcp.

6. Add it to Claude (Team plan)

An Owner of the Claude Team organization does this once:

  1. Go to Organization settings > Connectors, select Add, then Custom (choose Web if asked).

  2. Name: e.g. "Google Analytics 4". MCP server URL: https://<your-domain>/mcp.

  3. Authentication: No sign-in.

  4. Request headers: choose header name authorization, value Bearer <your MCP_AUTH_TOKEN>. Type the word Bearer, a space, then the token; Claude sends the value exactly as entered. Mark it Required.

  5. Click Add.

Team members then go to Customize > Connectors, find the connector with the Custom label and click Connect. In a chat, turn it on from the + menu > Connectors.

Request header authentication is in beta for a limited set of organizations. If you don't see Request headers in the dialog, your org doesn't have it yet, and this server (which only accepts the header) can't be added from claude.ai until it does. It still works from Claude Code, which supports headers today.

To change the token later, update MCP_AUTH_TOKEN in Railway, then remove and re-add the connector with the new header (headers can't be edited after saving).

Claude Code (CLI)

claude mcp add --transport http ga4 https://<your-domain>/mcp --header "Authorization: Bearer <your MCP_AUTH_TOKEN>"

Local development

cp .env.example .env    # fill in real values; .env is git-ignored
npm run build
npm start               # or: npm run dev

npm start doesn't load .env by itself; export the variables in your shell first (or use your editor's env support). Then check http://localhost:8080/healthz.

Troubleshooting

Message

Fix

Permission denied (403)

The Google account needs Viewer access on that GA4 property, or the property ID is wrong.

API is not enabled

Enable both Google Analytics Data API and Google Analytics Admin API in the same Cloud project as the OAuth client.

invalid_grant

Refresh token revoked or expired (7-day expiry if the consent screen is External + Testing). Re-run npm run setup-auth and update GOOGLE_REFRESH_TOKEN.

Google rejected the OAuth client

GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET don't match the client used to create the refresh token.

401 Unauthorized from /mcp

The connector isn't sending Authorization: Bearer <MCP_AUTH_TOKEN>, or the value doesn't match exactly (check for a missing Bearer ).

Server exits at startup

Read the deploy log: it names the missing variable.

Security notes

  • Never commit .env, OAuth client JSON or tokens. .gitignore and .dockerignore block the usual file names.

  • The refresh token grants read access to every GA4 property the Google account can see. Store it only in Railway variables. Revoke it any time at Google Account permissions.

  • Anyone with MCP_AUTH_TOKEN and the URL can read that GA4 data. Rotate it if it leaks.

Privacy

See PRIVACY.md and TERMS.md.

License

MIT. See LICENSE. Originally derived from gsc-mcp-server by Sofian Bettayeb.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Enables LLM applications to query Google Analytics 4 data through standard MCP interfaces, supporting real-time data, custom reports, and metadata discovery.
    5
    56 npm
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables querying Google Analytics 4 properties using natural language through MCP clients. Supports customizable reports with any dimensions and metrics, listing properties, and real-time data.
    4
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables querying Google Analytics 4 data through MCP tools for running reports, listing properties, getting real-time metrics, and exploring metadata.
    9 npm
    MIT