Skip to main content
Glama
devopsbrandmirchi

GA4 Analytics MCP V2

GA4 Analytics MCP V2

Multi-operator Google Analytics 4 connector for Claude.ai Custom Connectors, hosted on Google Cloud Run.

This is Version 2. It is a separate application from V1. Do not reuse V1 secrets, OAuth clients, Cloud Run services, or Git remotes.

Operator A or Operator B
  → same Claude Custom Connector URL
  → https://<v2-host>/mcp
  → MCP OAuth (Claude → V2)
  → Google OAuth (operator's own Google account)
  → operator credentials + active GA4 property in Firestore
  → GA4 Admin / Data APIs

There is no local stdio server and no Supabase.

Architecture

Two OAuth layers are linked:

  1. Claude → V2: MCP OAuth 2.1 (protected resource metadata, DCR, CIMD, PKCE).

  2. V2 → Google: Google sign-in happens inside MCP authorize. The MCP access token sub is the Google account subject (sub). Email is display-only.

Each operator has:

  • their own encrypted Google refresh token

  • their own accessible GA4 property list (from Google Admin API)

  • their own persisted active property

Operator A cannot use Operator B's Google credential or select a property that Google account A cannot access.

Related MCP server: GA4 MCP Server

MCP tools

Tool

Purpose

ga4_get_operator

Authenticated operator (email + internal operatorId). No tokens.

ga4_list_properties

Properties visible to that Google account, with isActive

ga4_get_active_property

Currently selected property

ga4_set_active_property

Switch after a live allow-list check

ga4_get_metadata

Dimensions/metrics for the active or newly authorized property

ga4_run_report

Historical GA4 report

ga4_run_realtime_report

Last ~30 minutes

Report tools use the stored active property when propertyId is omitted. A supplied propertyId is accepted only if the authenticated Google account can access it, and then becomes the new active property.

Local development

cd D:\MCP_Servers\Ga4McpV2
npm install
copy .env.example .env.local

Fill in .env.local with V2 values. Do not copy V1 secrets.

Optional Firestore emulator:

gcloud emulators firestore start --host-port=localhost:8080

Set FIRESTORE_EMULATOR_HOST=localhost:8080 and FIRESTORE_PROJECT_ID in .env.local.

npm run dev
npm test
npm run build
  • App: http://localhost:3000

  • MCP: http://localhost:3000/mcp

  • Health: http://localhost:3000/health

  • Google callback: http://localhost:3000/oauth/google/callback

Claude.ai cannot reach localhost. Deploy V2 to Cloud Run before adding the Custom Connector.

Environment variables

Variable

Required

Purpose

APP_BASE_URL

Yes

Public origin, no trailing slash

GOOGLE_CLIENT_ID

Yes

V2 Google OAuth web client

GOOGLE_CLIENT_SECRET

Yes

V2 Google OAuth secret

GOOGLE_REDIRECT_URI

No

Defaults to ${APP_BASE_URL}/oauth/google/callback

MCP_TOKEN_SECRET

Yes

Signs MCP JWTs

OAUTH_STATE_SECRET

Yes

Signs Google state and encrypts pending-authorize cookies

TOKEN_ENCRYPTION_KEY

Yes

Encrypts Google refresh tokens at rest

FIRESTORE_PROJECT_ID

Production

Firestore project

FIRESTORE_EMULATOR_HOST

Local/test

Firestore emulator host

MCP_OAUTH_CLIENT_ID

No

Optional pre-registered Claude confidential client

MCP_OAUTH_CLIENT_SECRET

No

Pair for the optional confidential client

V2 does not use GOOGLE_REFRESH_TOKEN or MCP_AUTH_TOKEN.

Google Cloud configuration

Use a new Google Cloud project when possible. If you share a project with V1, still create a distinct Cloud Run service, Artifact Registry repo, OAuth client, and secrets.

Enable:

  • Cloud Run

  • Cloud Build

  • Artifact Registry

  • Firestore

  • Secret Manager

  • Google Analytics Admin API

  • Google Analytics Data API

Suggested resource names (placeholders — replace with your project):

  • Cloud Run service: ga4-mcp-v2

  • Artifact Registry: ga4-mcp-v2

  • Firestore collection: operators

Cloud Run service account should have:

  • roles/datastore.user on the V2 Firestore database

  • roles/secretmanager.secretAccessor on V2 secrets only

Do not grant the service account Secret Manager admin or access to V1 secrets.

Google OAuth client (V2 only)

Create a new OAuth Web application. Do not edit the V1 client.

Consent screen:

  • User type: External (or Internal for Workspace-only)

  • App name: something like GA4 MCP Connector V2

  • Scopes:

    • openid

    • email

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

  • Add test users while the app is in Testing

  • Publishing is required for non-test users because Analytics scopes are sensitive

Authorized redirect URI:

https://<v2-cloud-run-url>/oauth/google/callback

Locally:

http://localhost:3000/oauth/google/callback

Claude Custom Connector

  1. Deploy V2 and set APP_BASE_URL to the Cloud Run URL.

  2. In Claude, add a Custom Connector.

  3. URL: https://<v2-host>/mcp

  4. Each operator completes Google sign-in from their own Claude account.

  5. If the Google account has multiple GA4 properties, they pick one. That choice persists until they switch.

Testing

npm test

Unit tests cover:

  • MCP OAuth metadata, DCR, PKCE, and Google-bound JWT sub

  • Operator isolation (credentials and property allow-lists)

  • Persistent active property

  • Token refresh / rotation

  • Revoked Google grants

  • Structured log redaction

No live V1 credentials are used.

Deployment (do not run until requested)

Documented only. V1 deployment must stay untouched.

.\scripts\cloud-run-setup.ps1 -ProjectId YOUR_V2_PROJECT_ID
.\scripts\cloud-run-deploy.ps1 -ProjectId YOUR_V2_PROJECT_ID
.\scripts\cloud-run-set-env.ps1 `
  -ProjectId YOUR_V2_PROJECT_ID `
  -AppBaseUrl https://YOUR_V2_CLOUD_RUN_URL `
  -GoogleClientId YOUR_V2_CLIENT_ID `
  -GoogleClientSecret YOUR_V2_CLIENT_SECRET `
  -McpTokenSecret YOUR_MCP_TOKEN_SECRET `
  -OauthStateSecret YOUR_OAUTH_STATE_SECRET `
  -TokenEncryptionKey YOUR_TOKEN_ENCRYPTION_KEY

Prefer Secret Manager references for production secrets instead of plaintext env values when you wire the service.

After deploy:

  1. Add the Cloud Run callback URI to the V2 OAuth client.

  2. Confirm Firestore is created in Native mode.

  3. Add https://<v2-host>/mcp in Claude.

Security considerations

  • Refresh tokens are encrypted with AES-256-GCM before Firestore writes.

  • MCP tools never return access tokens, refresh tokens, or authorization codes.

  • Logs redact tokens, secrets, cookies, and authorization codes.

  • Property IDs from Claude are checked against the live Admin API list for that operator.

  • Tools fail closed if no operator context is bound to the request.

  • HTTPS-only cookies in production.

Git

This repository is V2 only. The V1 remote is git@github.com:devopsbrandmirchi/Ga4McpServer.git and must never be added here. Create a new GitHub repository when you are ready to publish V2.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Connects Google Analytics 4 data to Claude, Cursor and other MCP clients, enabling natural language queries of website traffic, user behavior, and analytics data with access to 200+ GA4 dimensions and metrics.
    10
    241
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Connects MCP clients like Claude Desktop to Google Analytics 4 Data API, enabling natural language queries for reports, top pages, traffic sources, conversions, realtime users, and period comparisons.
    7
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables LLM applications to query and analyze Google Analytics 4 data through standard MCP interfaces, supporting service account and OAuth2 authentication.
    5
    24
    MIT