@wwhat/mcp-stdio-client 1.0.0 → 1.0.3
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/dist/index.js +359 -61
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ async function mcpRequest(method, params) {
|
|
|
38
38
|
method: 'POST',
|
|
39
39
|
headers: {
|
|
40
40
|
'Content-Type': 'application/json',
|
|
41
|
+
'Accept': 'application/json, text/event-stream',
|
|
41
42
|
'X-API-Key': API_KEY,
|
|
42
43
|
},
|
|
43
44
|
body: JSON.stringify({
|
|
@@ -64,15 +65,77 @@ async function main() {
|
|
|
64
65
|
name: 'wwhat-analytics',
|
|
65
66
|
version: '1.0.0',
|
|
66
67
|
});
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// Tool 1: list_sources
|
|
70
|
+
// ============================================================================
|
|
71
|
+
server.tool('list_sources', `List all analytics sources (GA4 properties) connected to your account.
|
|
72
|
+
|
|
73
|
+
PURPOSE:
|
|
74
|
+
Returns the source_id values needed for all other analytics tools. Call this first to discover available data sources.
|
|
75
|
+
|
|
76
|
+
OUTPUT INCLUDES:
|
|
77
|
+
- source_id: Unique identifier to use with other tools
|
|
78
|
+
- name: Human-readable property name
|
|
79
|
+
- property_id: GA4 property ID
|
|
80
|
+
- status: Connection status (active, pending, error)
|
|
81
|
+
- last_processed: When data was last synced (if include_details=true)
|
|
82
|
+
- data_range: Available date range (if include_details=true)
|
|
83
|
+
|
|
84
|
+
TYPICAL WORKFLOW:
|
|
85
|
+
1. Call list_sources to get available source_ids
|
|
86
|
+
2. Use a source_id with get_weekly_insights or query_analytics_data`, {
|
|
87
|
+
include_details: z
|
|
88
|
+
.boolean()
|
|
89
|
+
.default(false)
|
|
90
|
+
.describe('Include last_processed date, data_range, and sync status for each source'),
|
|
91
|
+
}, async (params) => {
|
|
92
|
+
const result = await mcpRequest('tools/call', {
|
|
93
|
+
name: 'list_sources',
|
|
94
|
+
arguments: params,
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
content: result.content.map((c) => ({ type: 'text', text: c.text })),
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
// ============================================================================
|
|
101
|
+
// Tool 2: get_weekly_insights
|
|
102
|
+
// ============================================================================
|
|
103
|
+
server.tool('get_weekly_insights', `Get AI-generated weekly analytics insights for a specific week.
|
|
104
|
+
|
|
105
|
+
PURPOSE:
|
|
106
|
+
Returns pre-analyzed insight cards highlighting the most important traffic changes, anomalies, and opportunities for a given week. This is higher-level than raw data queries.
|
|
107
|
+
|
|
108
|
+
WHAT YOU GET:
|
|
109
|
+
- Insight cards with titles, descriptions, and severity ratings
|
|
110
|
+
- Traffic change summaries (site-wide and per-segment)
|
|
111
|
+
- Landing page drop explainers (root cause analysis)
|
|
112
|
+
- Actionable recommendations
|
|
113
|
+
|
|
114
|
+
INSIGHT TYPES:
|
|
115
|
+
- traffic_drop: Significant decrease in sessions/users
|
|
116
|
+
- traffic_spike: Unusual increase in traffic
|
|
117
|
+
- conversion_change: Conversion rate shifts
|
|
118
|
+
- channel_shift: Traffic source changes
|
|
119
|
+
- device_shift: Mobile/desktop mix changes
|
|
120
|
+
- geo_shift: Geographic traffic changes
|
|
121
|
+
|
|
122
|
+
SEVERITY LEVELS:
|
|
123
|
+
- critical: >30% change, requires immediate attention
|
|
124
|
+
- significant: 20-30% change, should investigate
|
|
125
|
+
- moderate: 10-20% change, worth noting
|
|
126
|
+
- minor: <10% change, informational
|
|
127
|
+
|
|
128
|
+
TYPICAL WORKFLOW:
|
|
129
|
+
1. Call get_weekly_insights for overview
|
|
130
|
+
2. Use query_analytics_data to drill into specific insights
|
|
131
|
+
3. Use analyze_url for page-specific deep dives`, {
|
|
132
|
+
source_id: z.string().describe('The analytics source/property ID (get from list_sources)'),
|
|
133
|
+
week_start_date: z.string().describe('Monday of the week to analyze (ISO format: YYYY-MM-DD, e.g., "2025-01-13")'),
|
|
134
|
+
include_lp_explainers: z.boolean().default(true).describe('Include AI-generated root cause analysis for landing page drops'),
|
|
72
135
|
significance_filter: z
|
|
73
136
|
.enum(['all', 'critical', 'significant', 'moderate', 'minor'])
|
|
74
137
|
.default('all')
|
|
75
|
-
.describe('Filter insights
|
|
138
|
+
.describe('Filter to only show insights at or above this severity level'),
|
|
76
139
|
}, async (params) => {
|
|
77
140
|
const result = await mcpRequest('tools/call', {
|
|
78
141
|
name: 'get_weekly_insights',
|
|
@@ -82,66 +145,287 @@ async function main() {
|
|
|
82
145
|
content: result.content.map((c) => ({ type: 'text', text: c.text })),
|
|
83
146
|
};
|
|
84
147
|
});
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
148
|
+
// ============================================================================
|
|
149
|
+
// Tool 3: query_analytics_data (Universal Query Interface)
|
|
150
|
+
// ============================================================================
|
|
151
|
+
server.tool('query_analytics_data', `Universal query interface for analytics data. Query any combination of dimensions and metrics with flexible filtering, sorting, and comparisons.
|
|
152
|
+
|
|
153
|
+
AVAILABLE DIMENSIONS (use in filters, group_by, breakdown_by):
|
|
154
|
+
┌─────────────────────────────────┬────────────────────────────────────────────────────┐
|
|
155
|
+
│ Dimension │ Description & Example Values │
|
|
156
|
+
├─────────────────────────────────┼────────────────────────────────────────────────────┤
|
|
157
|
+
│ landingPage │ URL path: "/", "/blog/guide", "/pricing" │
|
|
158
|
+
│ deviceCategory │ "desktop", "mobile", "tablet" │
|
|
159
|
+
│ sessionDefaultChannelGrouping │ "Organic Search", "Direct", "Paid Search", │
|
|
160
|
+
│ │ "Social", "Email", "Referral", "Display" │
|
|
161
|
+
│ country │ "United States", "United Kingdom", "Germany" │
|
|
162
|
+
│ region │ State/province: "California", "Ontario" │
|
|
163
|
+
│ city │ "New York", "London", "San Francisco" │
|
|
164
|
+
│ newVsReturning │ "new" or "returning" │
|
|
165
|
+
│ browser │ "Chrome", "Safari", "Firefox", "Edge" │
|
|
166
|
+
│ sessionSource │ "google", "facebook", "newsletter", "(direct)" │
|
|
167
|
+
│ sessionMedium │ "organic", "cpc", "referral", "email", "(none)" │
|
|
168
|
+
└─────────────────────────────────┴────────────────────────────────────────────────────┘
|
|
169
|
+
|
|
170
|
+
AVAILABLE METRICS (use in metric parameter):
|
|
171
|
+
┌──────────────┬────────────────────────────────────────────────────────────────┐
|
|
172
|
+
│ Metric │ Description │
|
|
173
|
+
├──────────────┼────────────────────────────────────────────────────────────────┤
|
|
174
|
+
│ sessions │ Number of sessions (default) - most common for traffic analysis│
|
|
175
|
+
│ visitors │ Unique visitors (totalUsers) │
|
|
176
|
+
│ conversions │ Total conversions - mapped per source config │
|
|
177
|
+
│ leads │ Lead-type conversions (form fills, signups) │
|
|
178
|
+
│ purchases │ Purchase/transaction conversions │
|
|
179
|
+
│ revenue │ Revenue in dollars │
|
|
180
|
+
│ bounceRate │ Bounce rate percentage (0-100) │
|
|
181
|
+
└──────────────┴────────────────────────────────────────────────────────────────┘
|
|
182
|
+
|
|
183
|
+
COMPARISON TYPES (returned in each row's comparisons object):
|
|
184
|
+
- W1: Week-over-week change (vs previous week) - best for recent trends
|
|
185
|
+
- L4WAVG: Change vs last 4-week average - smooths out weekly variance
|
|
186
|
+
- LY4WAVG: Change vs same period last year - accounts for seasonality
|
|
187
|
+
|
|
188
|
+
Each comparison includes:
|
|
189
|
+
- previous: Previous period value
|
|
190
|
+
- current: Current period value
|
|
191
|
+
- change: Absolute change
|
|
192
|
+
- changePercent: Percentage change
|
|
193
|
+
|
|
194
|
+
OUTPUT STRUCTURE:
|
|
195
|
+
{
|
|
196
|
+
"status": "data_found",
|
|
197
|
+
"summary": {
|
|
198
|
+
"totalRows": 25,
|
|
199
|
+
"primaryMetric": "sessions",
|
|
200
|
+
"totalValue": 15420,
|
|
201
|
+
"dropsCount": 8, // Rows with >10% drop
|
|
202
|
+
"gainsCount": 5, // Rows with >10% gain
|
|
203
|
+
"topByChange": [...], // Top 3 gainers
|
|
204
|
+
"bottomByChange": [...] // Top 3 losers
|
|
205
|
+
},
|
|
206
|
+
"rows": [{
|
|
207
|
+
"dimensions": { "landingPage": "/blog/guide" },
|
|
208
|
+
"metrics": { "sessions": 1250, "conversions": 45 },
|
|
209
|
+
"comparisons": {
|
|
210
|
+
"w1": { "sessions": { "previous": 1400, "changePercent": -10.7 } }
|
|
211
|
+
},
|
|
212
|
+
"shareOfTotal": 8.1
|
|
213
|
+
}],
|
|
214
|
+
"insights": [{ "type": "drop", "severity": "significant", "message": "..." }]
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
COMMON USE CASES:
|
|
218
|
+
|
|
219
|
+
1. Find all traffic drops this week:
|
|
220
|
+
{ only_drops: true, sort_by: "change_w1", sort_order: "asc" }
|
|
221
|
+
|
|
222
|
+
2. Analyze blog performance:
|
|
223
|
+
{ filters: [{ dimension: "landingPage", operator: "startsWith", value: "/blog/" }], group_by: ["landingPage"] }
|
|
224
|
+
|
|
225
|
+
3. Channel performance breakdown:
|
|
226
|
+
{ group_by: ["sessionDefaultChannelGrouping"], metric: "conversions" }
|
|
227
|
+
|
|
228
|
+
4. Mobile vs Desktop comparison:
|
|
229
|
+
{ group_by: ["deviceCategory"] }
|
|
230
|
+
|
|
231
|
+
5. Top converting pages:
|
|
232
|
+
{ group_by: ["landingPage"], metric: "conversions", sort_by: "value", min_value: 5 }
|
|
233
|
+
|
|
234
|
+
6. Pages losing traffic from Google:
|
|
235
|
+
{ filters: [{ dimension: "sessionSource", operator: "equals", value: "google" }], only_drops: true, group_by: ["landingPage"] }`, {
|
|
236
|
+
source_id: z.string().describe('The analytics source/property ID (get from list_sources)'),
|
|
237
|
+
week_start_date: z.string().describe('Monday of the week to analyze (ISO format: YYYY-MM-DD, e.g., "2025-01-13")'),
|
|
238
|
+
filters: z.array(z.object({
|
|
239
|
+
dimension: z.string().describe('Dimension name (see AVAILABLE DIMENSIONS above)'),
|
|
240
|
+
operator: z.enum(['equals', 'contains', 'startsWith', 'endsWith', 'in']).describe('equals: exact match | contains: substring | startsWith/endsWith: prefix/suffix | in: match any value in array'),
|
|
241
|
+
value: z.union([z.string(), z.array(z.string())]).describe('Value to match. For "in" operator, provide array like ["value1", "value2"]'),
|
|
242
|
+
})).optional().describe('Filter rows by dimension values. Multiple filters are AND-ed together'),
|
|
243
|
+
group_by: z.array(z.string()).optional().describe('Aggregate and group results by these dimensions. Example: ["landingPage"] returns one row per unique page with summed metrics'),
|
|
244
|
+
breakdown_by: z.array(z.string()).optional().describe('For each result row, include a nested breakdown. Example: breakdown_by=["deviceCategory"] adds desktop/mobile/tablet split to each row'),
|
|
245
|
+
metric: z.string().optional().default('sessions').describe('Primary metric for sorting/filtering: sessions, visitors, conversions, leads, purchases, revenue, bounceRate'),
|
|
246
|
+
min_value: z.number().optional().describe('Exclude rows where primary metric < this value. Example: min_value=100 for pages with 100+ sessions'),
|
|
247
|
+
min_change_percent: z.number().optional().describe('Only rows with |W/W change| >= this %. Example: 20 returns rows with ≥20% increase OR ≥20% decrease'),
|
|
248
|
+
only_drops: z.boolean().optional().describe('Only show rows with negative week-over-week change (find traffic/conversion losses)'),
|
|
249
|
+
only_gains: z.boolean().optional().describe('Only show rows with positive week-over-week change (find growth)'),
|
|
250
|
+
sort_by: z.enum(['value', 'change_w1', 'change_l4wavg', 'change_ly4wavg', 'z_score']).optional().default('value').describe('Sort by: value (metric amount), change_w1 (W/W %), change_l4wavg (vs 4-week avg %), change_ly4wavg (vs last year %)'),
|
|
251
|
+
sort_order: z.enum(['asc', 'desc']).optional().default('desc').describe('desc: highest/best first | asc: lowest/worst first'),
|
|
252
|
+
comparison_type: z.enum(['W1', 'L4WAVG', 'LY4WAVG', 'all']).optional().default('all').describe('Which comparisons to include in response: W1, L4WAVG, LY4WAVG, or all'),
|
|
253
|
+
limit: z.number().optional().default(100).describe('Maximum rows to return (default: 100, max: 500)'),
|
|
254
|
+
include_insights: z.boolean().optional().default(true).describe('Auto-detect notable changes (>15%) and include as insights array'),
|
|
255
|
+
fetch_if_missing: z.boolean().optional().default(false).describe('If no data found, return instructions for fetching from GA4 API'),
|
|
114
256
|
}, async (params) => {
|
|
115
257
|
const result = await mcpRequest('tools/call', {
|
|
116
|
-
name: '
|
|
258
|
+
name: 'query_analytics_data',
|
|
117
259
|
arguments: params,
|
|
118
260
|
});
|
|
119
261
|
return {
|
|
120
262
|
content: result.content.map((c) => ({ type: 'text', text: c.text })),
|
|
121
263
|
};
|
|
122
264
|
});
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
265
|
+
// ============================================================================
|
|
266
|
+
// Tool 4: analyze_url
|
|
267
|
+
// ============================================================================
|
|
268
|
+
server.tool('analyze_url', `Deep-dive analysis for a specific URL or landing page.
|
|
269
|
+
|
|
270
|
+
PURPOSE:
|
|
271
|
+
Get comprehensive performance data for a single page, including traffic metrics, comparisons, and breakdowns by device/channel/country. More focused than query_analytics_data when you know the exact page.
|
|
272
|
+
|
|
273
|
+
WHAT YOU GET:
|
|
274
|
+
- Core metrics: sessions, visitors, bounce rate, conversions, revenue
|
|
275
|
+
- Week-over-week and 4-week average comparisons
|
|
276
|
+
- Share of total site traffic
|
|
277
|
+
- Breakdowns by:
|
|
278
|
+
- deviceCategory (desktop/mobile/tablet split)
|
|
279
|
+
- sessionDefaultChannelGrouping (organic/direct/paid/social)
|
|
280
|
+
- country (geographic distribution)
|
|
281
|
+
- newVsReturning (new vs returning visitors)
|
|
282
|
+
- Auto-detected insights (drops, growth, anomalies)
|
|
283
|
+
|
|
284
|
+
URL MATCHING:
|
|
285
|
+
- Partial match: "/blog" matches "/blog/post-1", "/blog/post-2"
|
|
286
|
+
- Exact match: Use full path for specific page
|
|
287
|
+
- Domain optional: Both "example.com/page" and "/page" work
|
|
288
|
+
|
|
289
|
+
OUTPUT STRUCTURE:
|
|
290
|
+
{
|
|
291
|
+
"status": "data_found",
|
|
292
|
+
"url": "/blog/guide",
|
|
293
|
+
"metrics": { "sessions": 1250, "visitors": 980, "bounceRate": 45.2, "conversions": 32 },
|
|
294
|
+
"comparisons": {
|
|
295
|
+
"w1": { "sessions": { "previous": 1400, "changePercent": -10.7 } },
|
|
296
|
+
"l4wavg": { "sessions": { "previous": 1180, "changePercent": 5.9 } }
|
|
297
|
+
},
|
|
298
|
+
"shareOfSiteTraffic": 8.1,
|
|
299
|
+
"breakdowns": [
|
|
300
|
+
{ "dimension": "deviceCategory", "values": [{ "value": "mobile", "sessions": 650, "share": 52 }] }
|
|
301
|
+
],
|
|
302
|
+
"insights": [{ "type": "drop", "message": "Mobile traffic down 18% W/W" }]
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
WHEN DATA IS MISSING:
|
|
306
|
+
Returns status="needs_fetch" with instructions to fetch from GA4 API.
|
|
307
|
+
|
|
308
|
+
TYPICAL WORKFLOW:
|
|
309
|
+
1. Use get_weekly_insights to identify problematic pages
|
|
310
|
+
2. Call analyze_url for deep dive on specific page
|
|
311
|
+
3. Use query_analytics_data for cross-page comparisons`, {
|
|
312
|
+
source_id: z.string().describe('The analytics source/property ID (get from list_sources)'),
|
|
313
|
+
url: z.string().describe('URL path to analyze. Examples: "/blog/guide", "/pricing", "example.com/page". Partial paths match multiple pages.'),
|
|
314
|
+
week_start_date: z.string().describe('Monday of the week to analyze (ISO format: YYYY-MM-DD)'),
|
|
315
|
+
include_breakdowns: z.boolean().optional().default(true).describe('Include device, channel, country, and new/returning breakdowns'),
|
|
316
|
+
fetch_if_missing: z.boolean().optional().default(false).describe('If data not found, return fetch instructions instead of empty result'),
|
|
129
317
|
}, async (params) => {
|
|
130
318
|
const result = await mcpRequest('tools/call', {
|
|
131
|
-
name: '
|
|
319
|
+
name: 'analyze_url',
|
|
320
|
+
arguments: params,
|
|
321
|
+
});
|
|
322
|
+
return {
|
|
323
|
+
content: result.content.map((c) => ({ type: 'text', text: c.text })),
|
|
324
|
+
};
|
|
325
|
+
});
|
|
326
|
+
// ============================================================================
|
|
327
|
+
// Tool 5: get_source_config
|
|
328
|
+
// ============================================================================
|
|
329
|
+
server.tool('get_source_config', `Get the configuration and metric mappings for an analytics source.
|
|
330
|
+
|
|
331
|
+
PURPOSE:
|
|
332
|
+
Understand how GA4 events and metrics are mapped to internal metrics (conversions, leads, purchases, revenue). Essential for interpreting metric values correctly.
|
|
333
|
+
|
|
334
|
+
WHAT YOU GET:
|
|
335
|
+
- Metric mappings: Which GA4 events count as conversions, leads, purchases
|
|
336
|
+
- Revenue configuration: Currency, event mapping
|
|
337
|
+
- Funnel stage assignments: How metrics map to acquisition/engagement/conversion/monetization
|
|
338
|
+
- Custom dimension mappings: Any custom dimensions configured
|
|
339
|
+
|
|
340
|
+
EXAMPLE OUTPUT:
|
|
341
|
+
{
|
|
342
|
+
"sourceId": "src_abc123",
|
|
343
|
+
"name": "My Website",
|
|
344
|
+
"metricMappings": {
|
|
345
|
+
"conversions": { "events": ["form_submit", "signup", "purchase"], "aggregation": "sum" },
|
|
346
|
+
"leads": { "events": ["form_submit", "signup"], "aggregation": "sum" },
|
|
347
|
+
"purchases": { "events": ["purchase"], "aggregation": "sum" },
|
|
348
|
+
"revenue": { "events": ["purchase"], "property": "value", "currency": "USD" }
|
|
349
|
+
},
|
|
350
|
+
"funnelConfig": {
|
|
351
|
+
"acquisition": ["sessions", "visitors"],
|
|
352
|
+
"engagement": ["pageviews", "time_on_site"],
|
|
353
|
+
"conversion": ["conversions", "leads"],
|
|
354
|
+
"monetization": ["purchases", "revenue"]
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
USE CASES:
|
|
359
|
+
- Verify what counts as a "conversion" before analyzing conversion data
|
|
360
|
+
- Understand revenue calculation methodology
|
|
361
|
+
- Debug metric discrepancies between GA4 and insights`, {
|
|
362
|
+
source_id: z.string().describe('The analytics source/property ID (get from list_sources)'),
|
|
363
|
+
}, async (params) => {
|
|
364
|
+
const result = await mcpRequest('tools/call', {
|
|
365
|
+
name: 'get_source_config',
|
|
132
366
|
arguments: params,
|
|
133
367
|
});
|
|
134
368
|
return {
|
|
135
369
|
content: result.content.map((c) => ({ type: 'text', text: c.text })),
|
|
136
370
|
};
|
|
137
371
|
});
|
|
138
|
-
//
|
|
139
|
-
|
|
372
|
+
// ============================================================================
|
|
373
|
+
// Tool 6: get_funnel_definition
|
|
374
|
+
// ============================================================================
|
|
375
|
+
server.tool('get_funnel_definition', `Get the standard marketing funnel structure and stage definitions.
|
|
376
|
+
|
|
377
|
+
PURPOSE:
|
|
378
|
+
Returns the funnel framework used to categorize and analyze metrics. Helps understand how different metrics relate across the customer journey.
|
|
379
|
+
|
|
380
|
+
FUNNEL STAGES:
|
|
381
|
+
┌─────────────────┬────────────────────────────────────────────────────────────┐
|
|
382
|
+
│ Stage │ Metrics & Purpose │
|
|
383
|
+
├─────────────────┼────────────────────────────────────────────────────────────┤
|
|
384
|
+
│ ACQUISITION │ sessions, visitors, newUsers │
|
|
385
|
+
│ │ How people find and arrive at your site │
|
|
386
|
+
├─────────────────┼────────────────────────────────────────────────────────────┤
|
|
387
|
+
│ ENGAGEMENT │ pageviews, avgSessionDuration, bounceRate, pagesPerSession │
|
|
388
|
+
│ │ How people interact with your content │
|
|
389
|
+
├─────────────────┼────────────────────────────────────────────────────────────┤
|
|
390
|
+
│ CONVERSION │ conversions, leads, signups, formSubmits │
|
|
391
|
+
│ │ Actions that indicate interest/intent │
|
|
392
|
+
├─────────────────┼────────────────────────────────────────────────────────────┤
|
|
393
|
+
│ MONETIZATION │ purchases, revenue, transactions, avgOrderValue │
|
|
394
|
+
│ │ Revenue-generating actions │
|
|
395
|
+
└─────────────────┴────────────────────────────────────────────────────────────┘
|
|
396
|
+
|
|
397
|
+
OUTPUT INCLUDES:
|
|
398
|
+
- Stage definitions with associated metrics
|
|
399
|
+
- Stage-to-stage conversion rate calculations
|
|
400
|
+
- Benchmark ranges for each metric
|
|
401
|
+
- Metric interdependencies
|
|
402
|
+
|
|
403
|
+
USE CASES:
|
|
404
|
+
- Understand which metrics to focus on at each funnel stage
|
|
405
|
+
- Identify where in the funnel problems are occurring
|
|
406
|
+
- Plan analysis strategy based on business goals`, {}, async () => {
|
|
407
|
+
const result = await mcpRequest('tools/call', {
|
|
408
|
+
name: 'get_funnel_definition',
|
|
409
|
+
arguments: {},
|
|
410
|
+
});
|
|
411
|
+
return {
|
|
412
|
+
content: result.content.map((c) => ({ type: 'text', text: c.text })),
|
|
413
|
+
};
|
|
414
|
+
});
|
|
415
|
+
// ============================================================================
|
|
416
|
+
// Tool 7: trigger_analytics_workflow (Future Implementation)
|
|
417
|
+
// ============================================================================
|
|
418
|
+
server.tool('trigger_analytics_workflow', `[COMING SOON] Trigger data processing workflow for a specific week.
|
|
419
|
+
|
|
420
|
+
PURPOSE:
|
|
421
|
+
Initiates the analytics processing pipeline to fetch fresh data from GA4 and generate insights. Use when data is missing or stale.
|
|
422
|
+
|
|
423
|
+
NOTE: This tool is planned for a future release. Currently, data processing is handled automatically on a schedule.`, {
|
|
140
424
|
source_id: z.string().describe('The analytics source/property ID'),
|
|
141
|
-
week_start_date: z.string().describe('
|
|
142
|
-
force_refresh: z.boolean().default(false).describe('
|
|
143
|
-
wait_for_completion: z.boolean().default(false).describe('
|
|
144
|
-
timeout_seconds: z.number().max(600).default(300).describe('
|
|
425
|
+
week_start_date: z.string().describe('Monday of the week to process (ISO format: YYYY-MM-DD)'),
|
|
426
|
+
force_refresh: z.boolean().default(false).describe('Re-process even if data already exists'),
|
|
427
|
+
wait_for_completion: z.boolean().default(false).describe('Wait for workflow to complete before returning'),
|
|
428
|
+
timeout_seconds: z.number().max(600).default(300).describe('Max wait time if wait_for_completion=true'),
|
|
145
429
|
}, async (params) => {
|
|
146
430
|
const result = await mcpRequest('tools/call', {
|
|
147
431
|
name: 'trigger_analytics_workflow',
|
|
@@ -151,10 +435,17 @@ async function main() {
|
|
|
151
435
|
content: result.content.map((c) => ({ type: 'text', text: c.text })),
|
|
152
436
|
};
|
|
153
437
|
});
|
|
154
|
-
//
|
|
155
|
-
|
|
438
|
+
// ============================================================================
|
|
439
|
+
// Tool 8: get_workflow_status (Future Implementation)
|
|
440
|
+
// ============================================================================
|
|
441
|
+
server.tool('get_workflow_status', `[COMING SOON] Check status of a running analytics workflow.
|
|
442
|
+
|
|
443
|
+
PURPOSE:
|
|
444
|
+
Poll for completion status after triggering a workflow with trigger_analytics_workflow.
|
|
445
|
+
|
|
446
|
+
NOTE: This tool is planned for a future release alongside trigger_analytics_workflow.`, {
|
|
156
447
|
invocation_id: z.string().describe('The invocation ID returned by trigger_analytics_workflow'),
|
|
157
|
-
source_id: z.string().describe('The analytics source/property ID
|
|
448
|
+
source_id: z.string().describe('The analytics source/property ID'),
|
|
158
449
|
}, async (params) => {
|
|
159
450
|
const result = await mcpRequest('tools/call', {
|
|
160
451
|
name: 'get_workflow_status',
|
|
@@ -164,15 +455,22 @@ async function main() {
|
|
|
164
455
|
content: result.content.map((c) => ({ type: 'text', text: c.text })),
|
|
165
456
|
};
|
|
166
457
|
});
|
|
167
|
-
//
|
|
168
|
-
|
|
458
|
+
// ============================================================================
|
|
459
|
+
// Tool 9: get_ga4_data (Future Implementation)
|
|
460
|
+
// ============================================================================
|
|
461
|
+
server.tool('get_ga4_data', `[COMING SOON] Direct GA4 API data fetch for custom queries.
|
|
462
|
+
|
|
463
|
+
PURPOSE:
|
|
464
|
+
Fetch raw data directly from Google Analytics 4 API for custom analysis not covered by standard tools.
|
|
465
|
+
|
|
466
|
+
NOTE: This tool is planned for a future release. Currently, use query_analytics_data for pre-processed data with comparisons and insights.`, {
|
|
169
467
|
source_id: z.string().describe('The analytics source/property ID'),
|
|
170
468
|
date_range: z
|
|
171
469
|
.object({
|
|
172
|
-
start_date: z.string().describe('Start date (ISO format)'),
|
|
173
|
-
end_date: z.string().describe('End date (ISO format)'),
|
|
470
|
+
start_date: z.string().describe('Start date (ISO format: YYYY-MM-DD)'),
|
|
471
|
+
end_date: z.string().describe('End date (ISO format: YYYY-MM-DD)'),
|
|
174
472
|
})
|
|
175
|
-
.describe('Date range to fetch
|
|
473
|
+
.describe('Date range to fetch'),
|
|
176
474
|
dimensions: z
|
|
177
475
|
.array(z.enum([
|
|
178
476
|
'landingPage',
|
|
@@ -186,8 +484,8 @@ async function main() {
|
|
|
186
484
|
'region',
|
|
187
485
|
]))
|
|
188
486
|
.optional()
|
|
189
|
-
.describe('Dimensions to
|
|
190
|
-
filters: z.record(z.string()).optional().describe('
|
|
487
|
+
.describe('Dimensions to include'),
|
|
488
|
+
filters: z.record(z.string()).optional().describe('Dimension filters as key-value pairs'),
|
|
191
489
|
metrics: z
|
|
192
490
|
.array(z.enum([
|
|
193
491
|
'sessions',
|
|
@@ -201,8 +499,8 @@ async function main() {
|
|
|
201
499
|
'totalRevenue',
|
|
202
500
|
]))
|
|
203
501
|
.default(['sessions', 'totalUsers'])
|
|
204
|
-
.describe('Metrics to
|
|
205
|
-
fetch_if_missing: z.boolean().default(true).describe('
|
|
502
|
+
.describe('Metrics to fetch'),
|
|
503
|
+
fetch_if_missing: z.boolean().default(true).describe('Fetch from GA4 API if not in cache'),
|
|
206
504
|
}, async (params) => {
|
|
207
505
|
const result = await mcpRequest('tools/call', {
|
|
208
506
|
name: 'get_ga4_data',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wwhat/mcp-stdio-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Stdio wrapper for wwhat MCP server - enables Cursor/Claude Desktop integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"ga4"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.25.0",
|
|
32
32
|
"zod": "^3.23.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|