mcp-ga4 1.1.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 drak-marketing
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,88 +1,169 @@
1
1
  # mcp-ga4
2
2
 
3
- Ask Google Analytics 4 questions in plain English using Claude.
3
+ MCP server for Google Analytics 4 -- run reports, realtime data, custom dimensions, and property management via Claude.
4
4
 
5
- ## Quickstart (2 steps)
5
+ ## Features
6
6
 
7
- ### 1. Setup
7
+ - 9 tools covering reporting, realtime data, custom dimensions/metrics, data streams, and feedback
8
+ - Two configuration modes: single-property (env vars) and multi-client (config.json)
9
+ - Supports both service account and OAuth credentials
10
+ - Relative date support (today, yesterday, 7daysAgo, 30daysAgo, 90daysAgo)
11
+ - Built on official Google SDKs with resilience patterns
12
+
13
+ ## Installation
8
14
 
9
15
  ```bash
10
- npx mcp-ga4-setup
16
+ npm install mcp-ga4
11
17
  ```
12
18
 
13
- This will:
14
- - Ask for your GA4 property ID (find it in GA4 > Admin > Property Details)
15
- - Open your browser to sign in with Google
16
- - Verify the connection works
17
- - Generate the Claude Code configuration snippet
18
-
19
- **Note:** You may see a "Google hasn't verified this app" warning during sign-in.
20
- Click **Advanced** then **Go to mcp-ga4 (unsafe)** to continue. This is safe --
21
- the app only requests read-only access to your analytics data.
19
+ Or clone the repository:
22
20
 
23
- ### 2. Restart Claude Code
24
-
25
- The setup wizard automatically registers the GA4 server with Claude Code.
26
- Just restart Claude Code to pick it up:
21
+ ```bash
22
+ git clone https://github.com/drak-marketing/mcp-ga4.git
23
+ cd mcp-ga4
24
+ npm install
25
+ npm run build
26
+ ```
27
27
 
28
- - **CLI:** Exit and reopen `claude`
29
- - **Desktop app:** Quit and reopen the app
28
+ ## Configuration
30
29
 
31
- That's it. No config files to edit, no JSON to paste. Just `npx` and restart.
30
+ ### Mode 1: Single Property (env vars)
32
31
 
33
- ## Usage
32
+ Set environment variables to connect to a single GA4 property:
34
33
 
35
- Once configured, just ask Claude questions about your analytics:
34
+ ```bash
35
+ GA4_PROPERTY_ID=123456789
36
+ GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
37
+ ```
36
38
 
37
- - "What were my top 10 pages last week?"
38
- - "Show me traffic by source for the past 30 days"
39
- - "What's my bounce rate trend this month?"
40
- - "Which campaigns drove the most conversions?"
41
- - "What devices are my users on?"
42
- - "Show me real-time active users"
39
+ For OAuth credentials instead of a service account:
43
40
 
44
- ## Feedback
41
+ ```bash
42
+ GA4_PROPERTY_ID=123456789
43
+ GA4_CREDENTIALS_FILE=/path/to/oauth-credentials.json
44
+ ```
45
45
 
46
- If a query doesn't return what you expected, tell Claude! It will log the
47
- pattern using the built-in `ga4_suggest_improvement` tool so the tool can
48
- be improved for everyone.
46
+ ### Mode 2: Multi-Client (config.json)
49
47
 
50
- You can also say "send feedback" to Claude to report bugs or request features.
48
+ Create a `config.json` in the project root to map multiple GA4 properties to project directories. The server auto-detects which property to use based on the caller's working directory.
51
49
 
52
- ## Troubleshooting
50
+ ```json
51
+ {
52
+ "credentials_file": "/path/to/oauth-credentials.json",
53
+ "clients": {
54
+ "client-a": {
55
+ "name": "Client A",
56
+ "folder": "/path/to/client-a/project",
57
+ "property_id": "123456789"
58
+ },
59
+ "client-b": {
60
+ "name": "Client B",
61
+ "folder": "/path/to/client-b/project",
62
+ "property_id": "987654321"
63
+ }
64
+ }
65
+ }
66
+ ```
53
67
 
54
- **"No refresh token received"**
55
- Go to https://myaccount.google.com/permissions, remove "mcp-ga4", then re-run `npx mcp-ga4-setup`.
68
+ ## Usage
56
69
 
57
- **"Connection failed" / "Permission denied"**
58
- Your Google account may not have access to the GA4 property. Check your access at
59
- GA4 > Admin > Account Access Management.
70
+ ### Claude Code (.mcp.json)
60
71
 
61
- **Token expired**
62
- Re-run `npx mcp-ga4-setup` to refresh your credentials.
72
+ Single-property mode:
63
73
 
64
- ## Advanced: Multi-Property Setup
74
+ ```json
75
+ {
76
+ "mcpServers": {
77
+ "ga4": {
78
+ "command": "npx",
79
+ "args": ["mcp-ga4"],
80
+ "env": {
81
+ "GA4_PROPERTY_ID": "123456789",
82
+ "GOOGLE_APPLICATION_CREDENTIALS": "/path/to/credentials.json"
83
+ }
84
+ }
85
+ }
86
+ }
87
+ ```
65
88
 
66
- For managing multiple GA4 properties, create `~/.config/mcp-ga4/config.json`:
89
+ Multi-client mode:
67
90
 
68
91
  ```json
69
92
  {
70
- "credentials_file": "~/.config/mcp-ga4/credentials.json",
71
- "clients": {
72
- "my-site": {
73
- "name": "My Website",
74
- "folder": "/path/to/project",
75
- "property_id": "123456789"
76
- },
77
- "other-site": {
78
- "name": "Other Site",
79
- "folder": "/path/to/other",
80
- "property_id": "987654321"
93
+ "mcpServers": {
94
+ "ga4": {
95
+ "command": "node",
96
+ "args": ["/path/to/mcp-ga4/dist/index.js"]
81
97
  }
82
98
  }
83
99
  }
84
100
  ```
85
101
 
102
+ ## Common Query Patterns
103
+
104
+ **Top pages:**
105
+ dimensions=`pagePath`, metrics=`screenPageViews`, order_by=`screenPageViews`
106
+
107
+ **Traffic sources:**
108
+ dimensions=`sessionSource,sessionMedium`, metrics=`sessions,totalUsers`
109
+
110
+ **Daily trend:**
111
+ dimensions=`date`, metrics=`sessions,totalUsers`
112
+
113
+ **Campaign performance:**
114
+ dimensions=`sessionCampaignName`, metrics=`sessions,conversions`
115
+
116
+ **Device breakdown:**
117
+ dimensions=`deviceCategory`, metrics=`sessions,totalUsers`
118
+
119
+ ## Tools
120
+
121
+ | Tool | Description |
122
+ |------|-------------|
123
+ | `ga4_get_client_context` | Returns the active GA4 property ID and client name |
124
+ | `ga4_run_report` | Run a standard GA4 report with dimensions, metrics, date range, and filters |
125
+ | `ga4_realtime_report` | Query realtime data (last 30 minutes) |
126
+ | `ga4_list_custom_dimensions` | List all custom dimensions for the property |
127
+ | `ga4_create_custom_dimension` | Create a new custom dimension |
128
+ | `ga4_list_custom_metrics` | List all custom metrics for the property |
129
+ | `ga4_list_data_streams` | List web/app data streams and their measurement IDs |
130
+ | `ga4_send_feedback` | Submit feedback on a query result |
131
+ | `ga4_suggest_improvement` | Suggest a new query pattern or improvement |
132
+
133
+ ## Date Formats
134
+
135
+ Use `YYYY-MM-DD` for absolute dates, or these relative shortcuts:
136
+
137
+ - `today`
138
+ - `yesterday`
139
+ - `7daysAgo`
140
+ - `30daysAgo`
141
+ - `90daysAgo`
142
+
143
+ ## Common Dimensions and Metrics
144
+
145
+ **Dimensions:** date, dateHour, eventName, pagePath, pageTitle, sessionSource, sessionMedium, sessionCampaignName, country, city, deviceCategory, browser, operatingSystem, landingPage, pageReferrer, newVsReturning, firstUserSource, firstUserMedium, firstUserCampaignName
146
+
147
+ **Metrics:** sessions, totalUsers, newUsers, activeUsers, screenPageViews, eventCount, conversions, engagedSessions, engagementRate, averageSessionDuration, bounceRate, sessionsPerUser, screenPageViewsPerSession, userEngagementDuration
148
+
149
+ ## Data Freshness
150
+
151
+ - Standard reports: 24-48 hour delay
152
+ - Realtime reports: last 30 minutes only
153
+
154
+ ## Architecture
155
+
156
+ Built on:
157
+
158
+ - `@google-analytics/data` -- GA4 Data API for reports
159
+ - `@google-analytics/admin` -- GA4 Admin API for property management
160
+ - `cockatiel` -- resilience (retry, circuit breaker)
161
+ - `pino` -- structured logging
162
+
86
163
  ## License
87
164
 
88
165
  MIT
166
+
167
+ ## Author
168
+
169
+ Built by Mark Harnett / [drak-marketing](https://github.com/drak-marketing)
@@ -0,0 +1,10 @@
1
+ {
2
+ "credentials_file": "/path/to/credentials.json",
3
+ "clients": {
4
+ "my-site": {
5
+ "name": "My Website",
6
+ "folder": "/path/to/project",
7
+ "property_id": "123456789"
8
+ }
9
+ }
10
+ }
@@ -0,0 +1 @@
1
+ {"sha":"efdf904","builtAt":"2026-04-08T23:39:17.959Z"}
package/dist/errors.d.ts CHANGED
@@ -1,15 +1,12 @@
1
- /**
2
- * Typed errors and classification for GA4 API calls.
3
- */
4
- export declare class GA4AuthError extends Error {
1
+ export declare class Ga4AuthError extends Error {
5
2
  readonly cause?: unknown | undefined;
6
3
  constructor(message: string, cause?: unknown | undefined);
7
4
  }
8
- export declare class GA4RateLimitError extends Error {
5
+ export declare class Ga4RateLimitError extends Error {
9
6
  readonly retryAfterMs: number;
10
7
  constructor(retryAfterMs: number, cause?: unknown);
11
8
  }
12
- export declare class GA4ServiceError extends Error {
9
+ export declare class Ga4ServiceError extends Error {
13
10
  readonly cause?: unknown | undefined;
14
11
  constructor(message: string, cause?: unknown | undefined);
15
12
  }
package/dist/errors.js CHANGED
@@ -1,59 +1,42 @@
1
- /**
2
- * Typed errors and classification for GA4 API calls.
3
- */
4
- export class GA4AuthError extends Error {
1
+ export class Ga4AuthError extends Error {
5
2
  cause;
6
3
  constructor(message, cause) {
7
4
  super(message);
8
5
  this.cause = cause;
9
- this.name = "GA4AuthError";
6
+ this.name = "Ga4AuthError";
10
7
  }
11
8
  }
12
- export class GA4RateLimitError extends Error {
9
+ export class Ga4RateLimitError extends Error {
13
10
  retryAfterMs;
14
11
  constructor(retryAfterMs, cause) {
15
12
  super(`Rate limited, retry after ${retryAfterMs}ms`);
16
- this.name = "GA4RateLimitError";
17
13
  this.retryAfterMs = retryAfterMs;
14
+ this.name = "Ga4RateLimitError";
18
15
  this.cause = cause;
19
16
  }
20
17
  }
21
- export class GA4ServiceError extends Error {
18
+ export class Ga4ServiceError extends Error {
22
19
  cause;
23
20
  constructor(message, cause) {
24
21
  super(message);
25
22
  this.cause = cause;
26
- this.name = "GA4ServiceError";
23
+ this.name = "Ga4ServiceError";
27
24
  }
28
25
  }
29
26
  export function classifyError(error) {
30
- const message = typeof error?.message === "string" ? error.message : String(error);
31
- const status = error?.status || error?.code;
32
- // Auth failures
33
- if (status === 401 ||
34
- status === 403 ||
35
- message.includes("invalid_grant") ||
36
- message.includes("Token has been expired") ||
37
- message.includes("refresh token") ||
38
- message.includes("UNAUTHENTICATED") ||
39
- message.includes("PERMISSION_DENIED")) {
40
- return new GA4AuthError(`Auth failed: ${message}. Re-run mcp-ga4-setup to refresh credentials.`, error);
27
+ const message = error?.message || String(error);
28
+ const code = error?.code || error?.status;
29
+ if (code === 401 || code === 403 || code === 7 || code === 16 ||
30
+ message.includes("PERMISSION_DENIED") || message.includes("UNAUTHENTICATED") ||
31
+ message.includes("invalid_grant")) {
32
+ return new Ga4AuthError(`Auth failed: ${message}. Check credentials.`, error);
41
33
  }
42
- // Rate limiting
43
- if (status === 429 || message.includes("RESOURCE_EXHAUSTED")) {
44
- const retryMs = 60_000;
45
- return new GA4RateLimitError(retryMs, error);
34
+ if (code === 429 || code === 8 || message.includes("RESOURCE_EXHAUSTED") || message.includes("rateLimitExceeded")) {
35
+ return new Ga4RateLimitError(60_000, error);
46
36
  }
47
- // Server errors
48
- if ((typeof status === "number" && status >= 500) ||
49
- message.includes("INTERNAL")) {
50
- return new GA4ServiceError(`GA4 API server error: ${message}`, error);
51
- }
52
- if (!(error instanceof Error)) {
53
- const wrapped = new Error(message);
54
- wrapped.name = "GA4Error";
55
- wrapped.cause = error;
56
- return wrapped;
37
+ if (code >= 500 || code === 13 || code === 14 ||
38
+ message.includes("INTERNAL") || message.includes("UNAVAILABLE")) {
39
+ return new Ga4ServiceError(`GA4 API server error: ${message}`, error);
57
40
  }
58
41
  return error;
59
42
  }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,2 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * mcp-ga4 -- MCP server for querying Google Analytics 4 via natural language.
4
- *
5
- * Supports two config modes:
6
- * 1. Single-property (env vars): GA4_PROPERTY_ID + GOOGLE_APPLICATION_CREDENTIALS
7
- * 2. Multi-client (config.json): MCP_GA4_CONFIG or ~/.config/mcp-ga4/config.json
8
- */
9
2
  export {};