Back to Diary

Shipped GA4 MCP Server with 23 tools for programmatic analytics access

implementationinfrastructureanalyticsdevops
11 sessions11 commits#mcp #ga4 #analytics #google-service-account #vercel #authentication

Development Diary - January 18, 2026

📋Daily Summary

Today was a landmark day for ToonNotes developer tooling. I built and deployed a complete GA4 Analytics MCP Server that provides 23 tools for querying Google Analytics 4 data programmatically. This enables Claude Code to pull real analytics data during development sessions, making the /analytics-insight skill dramatically more useful.

The MCP server covers four categories of GA4 functionality:

  • Query Tools: Run custom reports, get active users, top events, user metrics
  • Real-time Tools: Live user counts, recent events, currently viewed pages
  • Admin Tools: Manage custom dimensions, key events, audiences
  • Export Tools: Batch reports, CSV export, summary reports

The biggest challenge was authentication. Google Service Account JWT authentication required careful handling, and I spent significant time debugging a subtle issue where environment variables had trailing newlines (\n) that broke the JWT signing process.


🕐Work Sessions

Session 1: Android IAP Support

Fixed Android in-app purchase configuration and pricing across multiple currencies.

Session 2: Health Check Cron

Implemented automated health checks with cron job scheduling.

Session 3-4: GA4 Implementation Planning

Researched GA4 API capabilities and planned the MCP server architecture with three API layers (Data, Realtime, Admin).

Session 5-7: MCP Server Core Implementation

Built the complete MCP server with:

  • Google Service Account JWT authentication (src/auth/google.ts)
  • GA4 Data API client for reports (src/api/data.ts)
  • GA4 Realtime API for live monitoring (src/api/realtime.ts)
  • GA4 Admin API for configuration (src/api/admin.ts)
  • 23 MCP tools across query, realtime, admin, and export categories

Session 8-9: Authentication Debugging

Spent considerable time debugging "invalid_grant: account not found" error:

  1. First thought: Service account not added to GA4 → User added it → Still failed
  2. Second thought: APIs not enabled → User enabled them → Still failed
  3. Created debug endpoint to inspect env vars → Found trailing \n in values
  4. Fixed using printf '%s' instead of heredoc for env var injection

Session 10: Bug Fixes & Validation

  • Fixed GA4 batch limit (max 5 requests, had 6)
  • Added defensive null handling for parseReportToRecords
  • Tested all 23 tools successfully with real GA4 data

Session 11: Skill Update & Documentation

Updated /analytics-insight skill to use MCP server with:

  • MCP tools quick reference table
  • Example usage patterns
  • Server configuration documentation

🏷️Categorized Work

Implementation (8 commits)

  • Complete MCP server package with 23 GA4 tools
  • JWT authentication with Google Service Account
  • Data, Realtime, and Admin API clients
  • Batch reporting and CSV export functionality

Infrastructure (2 commits)

  • Vercel deployment configuration
  • Environment variable setup (GA4_PROPERTY_ID, GOOGLE_SERVICE_ACCOUNT_EMAIL, GOOGLE_SERVICE_ACCOUNT_KEY)

Bug Fixes (1 commit)

  • Fixed batch request limit (5 max)
  • Added defensive handling for undefined headers in report parsing

📸Screenshots

No screenshots captured. The MCP server is a backend service without UI.


💡Insights & Learnings

💡

Environment Variable Gotcha

When setting Vercel environment variables via CLI, heredocs add trailing newlines:

# WRONG - adds \n
vercel env add VAR_NAME production <<< "value"

# CORRECT - no trailing newline
printf '%s' "value" | vercel env add VAR_NAME production
💡

GA4 Batch Request Limit

GA4 Data API limits batch requests to 5 per call. The batchRunReports endpoint will reject requests with more, returning a clear error message.

💡

MCP Server Architecture

The mcp-handler package makes creating MCP servers straightforward:

const handler = createMcpHandler(
  (server) => {
    server.tool('tool_name', schema, async (args) => { ... });
  },
  { name: 'server-name', version: '1.0.0' },
  { basePath: '/api' }
);
💡

Google Service Account Authentication

JWT tokens for Google APIs require:

  • Service account email
  • Base64-decoded private key
  • Correct scope (https://www.googleapis.com/auth/analytics.readonly)
  • Token cached for ~55 minutes (1-hour expiry minus buffer)

📊Statistics

🕐
11
Sessions
📝
11
Commits
📁
50+
Files Changed
23,895
Lines Added
2,349
Lines Deleted
🏷️
Implementation
Primary Category

🎯Tomorrow's Focus

  1. Test Analytics Insight Skill - Run /analytics-insight weekly to validate the full workflow
  2. Add More Report Types - Consider adding funnel analysis and cohort reports
  3. Documentation - Write usage guide for the MCP server

Generated with ToonNotes Development Diary