A read-only Google Analytics 4 MCP server with per-user Google OAuth.
The MCP server acts as its own OAuth 2.1 resource/authorization server. During authorization it delegates identity and GA4 consent to Google, stores Google refresh tokens encrypted, and issues opaque MCP access/refresh tokens to the MCP client.
list_ga4_propertiesget_ga4_metadatacheck_ga4_compatibilityrun_ga4_reportrun_ga4_realtime_reportga4_overviewga4_top_pagesga4_traffic_sources
All GA4 access uses only:
https://www.googleapis.com/auth/analytics.readonly
MCP client / ChatGPT
|
| OAuth 2.1 + PKCE
v
GA4 MCP
|
| Google OAuth
v
Google Analytics Data API
The Google access/refresh token is never returned to the MCP client. MCP access and refresh tokens are opaque random values; only SHA-256 hashes of them are stored. Google tokens are encrypted at rest with AES-256-GCM.
- Node.js 20+
- PostgreSQL
- A Google Cloud OAuth Web Application
- Google Analytics Data API enabled
- Google Analytics Admin API enabled
Create an OAuth 2.0 Client ID of type Web application.
Add this redirect URI, replacing the host with your deployment domain:
https://YOUR_DOMAIN/oauth/google/callback
Enable:
- Google Analytics Data API
- Google Analytics Admin API
Configure the OAuth consent screen. Public use of the Analytics read-only scope may require Google OAuth app verification before opening the service broadly.
Copy .env.example and configure:
PORT=3000
PUBLIC_BASE_URL=https://YOUR_DOMAIN
DATABASE_URL=postgres://...
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
TOKEN_ENCRYPTION_KEY_BASE64=...
Generate the encryption key with:
openssl rand -base64 32PUBLIC_BASE_URL must be the exact public HTTPS origin. The MCP URL is automatically ${PUBLIC_BASE_URL}/mcp.
npm install
npm run devFor a real OAuth callback, use an HTTPS tunnel or a deployed HTTPS domain and register that callback URL in Google Cloud.
The repository contains a Dockerfile, so it can be deployed to services such as Railway, Render, Fly.io, Cloud Run, or another container host. Attach PostgreSQL and set the environment variables above.
The server creates its required tables on startup.
- MCP endpoint:
/mcp - Protected Resource Metadata:
/.well-known/oauth-protected-resource/mcp - Authorization Server Metadata:
/.well-known/oauth-authorization-server - Dynamic Client Registration:
/oauth/register - Authorization endpoint:
/oauth/authorize - Token endpoint:
/oauth/token - Revocation endpoint:
/oauth/revoke - Google callback:
/oauth/google/callback
The OAuth flow requires Authorization Code + PKCE S256. Dynamic Client Registration is provided for MCP clients that still use DCR. MCP 2026-07-28 deprecates DCR in favor of Client ID Metadata Documents, so CIMD support is a sensible follow-up before treating this as a generic long-term MCP identity provider.
- GA4 access is read-only.
- PKCE S256 is mandatory.
- OAuth authorization codes are short-lived and one-time use.
- MCP access tokens expire after one hour.
- MCP refresh tokens rotate and expire after 30 days.
- Google refresh tokens are encrypted at rest.
- MCP access/refresh tokens are stored only as hashes.
- Redirect URIs must be HTTPS, except loopback HTTP for local clients.
- Access tokens are bound to this MCP resource when a
resourceparameter is supplied.
- Deploy behind HTTPS.
- Use managed PostgreSQL with backups.
- Configure the Google OAuth consent screen and verification.
- Add a real privacy policy and terms page for your domain.
- Test the full login flow with at least two separate Google accounts.
- Verify that one account can never read another account's GA4 properties.
- Add rate limiting on
/oauth/register,/oauth/token, and/mcp. - Add monitoring for Google token refresh failures and OAuth errors without logging tokens.
No license has been selected yet.