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:
- First thought: Service account not added to GA4 → User added it → Still failed
- Second thought: APIs not enabled → User enabled them → Still failed
- Created debug endpoint to inspect env vars → Found trailing
\nin values - 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 productionGA4 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
🎯Tomorrow's Focus
- Test Analytics Insight Skill - Run
/analytics-insight weeklyto validate the full workflow - Add More Report Types - Consider adding funnel analysis and cohort reports
- Documentation - Write usage guide for the MCP server
Generated with ToonNotes Development Diary