claude-plugin-wordpress-manager 2.6.0 → 2.9.0

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/agents/wp-monitoring-agent.md +44 -0
  3. package/agents/wp-site-manager.md +19 -0
  4. package/docs/plans/2026-03-01-tier4-5-implementation.md +1783 -0
  5. package/docs/plans/2026-03-01-tier4-5-observability-automation-design.md +426 -0
  6. package/docs/plans/2026-03-01-wcop-reassessment-v2.6.0.md +403 -0
  7. package/hooks/hooks.json +9 -0
  8. package/package.json +10 -3
  9. package/servers/wp-rest-bridge/build/tools/cwv.d.ts +3 -0
  10. package/servers/wp-rest-bridge/build/tools/cwv.js +196 -0
  11. package/servers/wp-rest-bridge/build/tools/ga4.d.ts +3 -0
  12. package/servers/wp-rest-bridge/build/tools/ga4.js +323 -0
  13. package/servers/wp-rest-bridge/build/tools/index.js +15 -0
  14. package/servers/wp-rest-bridge/build/tools/plausible.d.ts +3 -0
  15. package/servers/wp-rest-bridge/build/tools/plausible.js +207 -0
  16. package/servers/wp-rest-bridge/build/tools/slack.d.ts +3 -0
  17. package/servers/wp-rest-bridge/build/tools/slack.js +129 -0
  18. package/servers/wp-rest-bridge/build/tools/wc-workflows.d.ts +3 -0
  19. package/servers/wp-rest-bridge/build/tools/wc-workflows.js +222 -0
  20. package/servers/wp-rest-bridge/build/wordpress.d.ts +18 -0
  21. package/servers/wp-rest-bridge/build/wordpress.js +139 -0
  22. package/skills/wordpress-router/SKILL.md +1 -1
  23. package/skills/wordpress-router/references/decision-tree.md +8 -2
  24. package/skills/wp-alerting/SKILL.md +142 -0
  25. package/skills/wp-alerting/references/alert-thresholds.md +79 -0
  26. package/skills/wp-alerting/references/escalation-paths.md +92 -0
  27. package/skills/wp-alerting/references/report-scheduling.md +142 -0
  28. package/skills/wp-alerting/references/slack-integration.md +109 -0
  29. package/skills/wp-alerting/scripts/alerting_inspect.mjs +150 -0
  30. package/skills/wp-analytics/SKILL.md +158 -0
  31. package/skills/wp-analytics/references/analytics-dashboards.md +83 -0
  32. package/skills/wp-analytics/references/cwv-monitoring.md +101 -0
  33. package/skills/wp-analytics/references/ga4-integration.md +76 -0
  34. package/skills/wp-analytics/references/plausible-setup.md +92 -0
  35. package/skills/wp-analytics/references/traffic-attribution.md +92 -0
  36. package/skills/wp-analytics/scripts/analytics_inspect.mjs +153 -0
  37. package/skills/wp-content-attribution/SKILL.md +1 -0
  38. package/skills/wp-content-optimization/SKILL.md +1 -0
  39. package/skills/wp-content-workflows/SKILL.md +142 -0
  40. package/skills/wp-content-workflows/references/content-lifecycle-hooks.md +131 -0
  41. package/skills/wp-content-workflows/references/multi-channel-actions.md +151 -0
  42. package/skills/wp-content-workflows/references/schedule-triggers.md +118 -0
  43. package/skills/wp-content-workflows/references/trigger-management.md +159 -0
  44. package/skills/wp-content-workflows/references/wp-action-hooks.md +114 -0
  45. package/skills/wp-content-workflows/scripts/workflow_inspect.mjs +202 -0
  46. package/skills/wp-monitoring/SKILL.md +2 -0
  47. package/skills/wp-search-console/SKILL.md +1 -0
  48. package/skills/wp-social-email/SKILL.md +1 -0
  49. package/skills/wp-webhooks/SKILL.md +1 -0
@@ -0,0 +1,323 @@
1
+ import { hasGA4, getGA4Auth, getGA4PropertyId } from '../wordpress.js';
2
+ import { google } from 'googleapis';
3
+ import { z } from 'zod';
4
+ // ── Zod Schemas ─────────────────────────────────────────────────
5
+ const ga4RunReportSchema = z.object({
6
+ dimensions: z.array(z.string()).describe('GA4 dimensions (e.g. pagePath, sessionSource, country)'),
7
+ metrics: z.array(z.string()).describe('GA4 metrics (e.g. screenPageViews, activeUsers, sessions)'),
8
+ start_date: z.string().describe('Start date in YYYY-MM-DD format'),
9
+ end_date: z.string().describe('End date in YYYY-MM-DD format'),
10
+ limit: z.number().optional().default(100)
11
+ .describe('Maximum number of rows to return (default 100)'),
12
+ }).strict();
13
+ const ga4GetRealtimeSchema = z.object({
14
+ metrics: z.array(z.string()).optional().default(['activeUsers'])
15
+ .describe('Real-time metrics (default: activeUsers)'),
16
+ dimensions: z.array(z.string()).optional()
17
+ .describe('Real-time dimensions (optional, e.g. unifiedScreenName)'),
18
+ }).strict();
19
+ const ga4TopPagesSchema = z.object({
20
+ start_date: z.string().describe('Start date in YYYY-MM-DD format'),
21
+ end_date: z.string().describe('End date in YYYY-MM-DD format'),
22
+ limit: z.number().optional().default(25)
23
+ .describe('Number of top pages to return (default 25)'),
24
+ }).strict();
25
+ const ga4TrafficSourcesSchema = z.object({
26
+ start_date: z.string().describe('Start date in YYYY-MM-DD format'),
27
+ end_date: z.string().describe('End date in YYYY-MM-DD format'),
28
+ limit: z.number().optional().default(25)
29
+ .describe('Number of traffic sources to return (default 25)'),
30
+ }).strict();
31
+ const ga4UserDemographicsSchema = z.object({
32
+ start_date: z.string().describe('Start date in YYYY-MM-DD format'),
33
+ end_date: z.string().describe('End date in YYYY-MM-DD format'),
34
+ breakdown: z.enum(['country', 'deviceCategory', 'browser']).optional().default('country')
35
+ .describe('Breakdown dimension (default: country)'),
36
+ limit: z.number().optional().default(25)
37
+ .describe('Number of rows to return (default 25)'),
38
+ }).strict();
39
+ const ga4ConversionEventsSchema = z.object({
40
+ start_date: z.string().describe('Start date in YYYY-MM-DD format'),
41
+ end_date: z.string().describe('End date in YYYY-MM-DD format'),
42
+ limit: z.number().optional().default(25)
43
+ .describe('Number of conversion events to return (default 25)'),
44
+ }).strict();
45
+ // ── Tool Definitions ────────────────────────────────────────────
46
+ export const ga4Tools = [
47
+ {
48
+ name: "ga4_run_report",
49
+ description: "Runs a custom GA4 report with specified dimensions, metrics, and date range",
50
+ inputSchema: {
51
+ type: "object",
52
+ properties: {
53
+ dimensions: {
54
+ type: "array",
55
+ items: { type: "string" },
56
+ description: "GA4 dimensions (e.g. pagePath, sessionSource, country)",
57
+ },
58
+ metrics: {
59
+ type: "array",
60
+ items: { type: "string" },
61
+ description: "GA4 metrics (e.g. screenPageViews, activeUsers, sessions)",
62
+ },
63
+ start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
64
+ end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
65
+ limit: { type: "number", description: "Maximum number of rows to return (default 100)" },
66
+ },
67
+ required: ["dimensions", "metrics", "start_date", "end_date"],
68
+ },
69
+ },
70
+ {
71
+ name: "ga4_get_realtime",
72
+ description: "Gets real-time active users and metrics from GA4",
73
+ inputSchema: {
74
+ type: "object",
75
+ properties: {
76
+ metrics: {
77
+ type: "array",
78
+ items: { type: "string" },
79
+ description: "Real-time metrics (default: activeUsers)",
80
+ },
81
+ dimensions: {
82
+ type: "array",
83
+ items: { type: "string" },
84
+ description: "Real-time dimensions (optional, e.g. unifiedScreenName)",
85
+ },
86
+ },
87
+ },
88
+ },
89
+ {
90
+ name: "ga4_top_pages",
91
+ description: "Gets top pages by pageviews from GA4 (convenience shortcut for ga4_run_report)",
92
+ inputSchema: {
93
+ type: "object",
94
+ properties: {
95
+ start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
96
+ end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
97
+ limit: { type: "number", description: "Number of top pages to return (default 25)" },
98
+ },
99
+ required: ["start_date", "end_date"],
100
+ },
101
+ },
102
+ {
103
+ name: "ga4_traffic_sources",
104
+ description: "Gets traffic breakdown by source/medium from GA4 (convenience shortcut for ga4_run_report)",
105
+ inputSchema: {
106
+ type: "object",
107
+ properties: {
108
+ start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
109
+ end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
110
+ limit: { type: "number", description: "Number of traffic sources to return (default 25)" },
111
+ },
112
+ required: ["start_date", "end_date"],
113
+ },
114
+ },
115
+ {
116
+ name: "ga4_user_demographics",
117
+ description: "Gets user demographics breakdown (country, device, or browser) from GA4 (convenience shortcut)",
118
+ inputSchema: {
119
+ type: "object",
120
+ properties: {
121
+ start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
122
+ end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
123
+ breakdown: {
124
+ type: "string",
125
+ enum: ["country", "deviceCategory", "browser"],
126
+ description: "Breakdown dimension (default: country)",
127
+ },
128
+ limit: { type: "number", description: "Number of rows to return (default 25)" },
129
+ },
130
+ required: ["start_date", "end_date"],
131
+ },
132
+ },
133
+ {
134
+ name: "ga4_conversion_events",
135
+ description: "Gets conversion events and rates from GA4 (convenience shortcut for ga4_run_report)",
136
+ inputSchema: {
137
+ type: "object",
138
+ properties: {
139
+ start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
140
+ end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
141
+ limit: { type: "number", description: "Number of conversion events to return (default 25)" },
142
+ },
143
+ required: ["start_date", "end_date"],
144
+ },
145
+ },
146
+ ];
147
+ // ── Handlers ────────────────────────────────────────────────────
148
+ export const ga4Handlers = {
149
+ ga4_run_report: async (params) => {
150
+ if (!hasGA4()) {
151
+ return { toolResult: { isError: true, content: [{ type: "text", text: "GA4 not configured. Add ga4_property_id and ga4_service_account_key to WP_SITES_CONFIG." }] } };
152
+ }
153
+ try {
154
+ const auth = await getGA4Auth();
155
+ const propertyId = getGA4PropertyId();
156
+ const { dimensions, metrics, start_date, end_date, limit } = params;
157
+ const analyticsdata = google.analyticsdata({ version: 'v1beta', auth });
158
+ const response = await analyticsdata.properties.runReport({
159
+ property: propertyId,
160
+ requestBody: {
161
+ dateRanges: [{ startDate: start_date, endDate: end_date }],
162
+ dimensions: dimensions.map(d => ({ name: d })),
163
+ metrics: metrics.map(m => ({ name: m })),
164
+ limit: String(limit || 100),
165
+ },
166
+ });
167
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
168
+ }
169
+ catch (error) {
170
+ const errorMessage = error.response?.data?.error?.message || error.message;
171
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error running GA4 report: ${errorMessage}` }] } };
172
+ }
173
+ },
174
+ ga4_get_realtime: async (params) => {
175
+ if (!hasGA4()) {
176
+ return { toolResult: { isError: true, content: [{ type: "text", text: "GA4 not configured. Add ga4_property_id and ga4_service_account_key to WP_SITES_CONFIG." }] } };
177
+ }
178
+ try {
179
+ const auth = await getGA4Auth();
180
+ const propertyId = getGA4PropertyId();
181
+ const { metrics, dimensions } = params;
182
+ const analyticsdata = google.analyticsdata({ version: 'v1beta', auth });
183
+ const requestBody = {
184
+ metrics: (metrics || ['activeUsers']).map(m => ({ name: m })),
185
+ };
186
+ if (dimensions && dimensions.length > 0) {
187
+ requestBody.dimensions = dimensions.map(d => ({ name: d }));
188
+ }
189
+ const response = await analyticsdata.properties.runRealtimeReport({
190
+ property: propertyId,
191
+ requestBody,
192
+ });
193
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
194
+ }
195
+ catch (error) {
196
+ const errorMessage = error.response?.data?.error?.message || error.message;
197
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting GA4 realtime data: ${errorMessage}` }] } };
198
+ }
199
+ },
200
+ ga4_top_pages: async (params) => {
201
+ if (!hasGA4()) {
202
+ return { toolResult: { isError: true, content: [{ type: "text", text: "GA4 not configured. Add ga4_property_id and ga4_service_account_key to WP_SITES_CONFIG." }] } };
203
+ }
204
+ try {
205
+ const auth = await getGA4Auth();
206
+ const propertyId = getGA4PropertyId();
207
+ const { start_date, end_date, limit } = params;
208
+ const analyticsdata = google.analyticsdata({ version: 'v1beta', auth });
209
+ const response = await analyticsdata.properties.runReport({
210
+ property: propertyId,
211
+ requestBody: {
212
+ dateRanges: [{ startDate: start_date, endDate: end_date }],
213
+ dimensions: [{ name: 'pagePath' }],
214
+ metrics: [
215
+ { name: 'screenPageViews' },
216
+ { name: 'activeUsers' },
217
+ { name: 'averageSessionDuration' },
218
+ ],
219
+ orderBys: [{ metric: { metricName: 'screenPageViews' }, desc: true }],
220
+ limit: String(limit || 25),
221
+ },
222
+ });
223
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
224
+ }
225
+ catch (error) {
226
+ const errorMessage = error.response?.data?.error?.message || error.message;
227
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting GA4 top pages: ${errorMessage}` }] } };
228
+ }
229
+ },
230
+ ga4_traffic_sources: async (params) => {
231
+ if (!hasGA4()) {
232
+ return { toolResult: { isError: true, content: [{ type: "text", text: "GA4 not configured. Add ga4_property_id and ga4_service_account_key to WP_SITES_CONFIG." }] } };
233
+ }
234
+ try {
235
+ const auth = await getGA4Auth();
236
+ const propertyId = getGA4PropertyId();
237
+ const { start_date, end_date, limit } = params;
238
+ const analyticsdata = google.analyticsdata({ version: 'v1beta', auth });
239
+ const response = await analyticsdata.properties.runReport({
240
+ property: propertyId,
241
+ requestBody: {
242
+ dateRanges: [{ startDate: start_date, endDate: end_date }],
243
+ dimensions: [
244
+ { name: 'sessionSource' },
245
+ { name: 'sessionMedium' },
246
+ ],
247
+ metrics: [
248
+ { name: 'sessions' },
249
+ { name: 'activeUsers' },
250
+ { name: 'conversions' },
251
+ ],
252
+ orderBys: [{ metric: { metricName: 'sessions' }, desc: true }],
253
+ limit: String(limit || 25),
254
+ },
255
+ });
256
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
257
+ }
258
+ catch (error) {
259
+ const errorMessage = error.response?.data?.error?.message || error.message;
260
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting GA4 traffic sources: ${errorMessage}` }] } };
261
+ }
262
+ },
263
+ ga4_user_demographics: async (params) => {
264
+ if (!hasGA4()) {
265
+ return { toolResult: { isError: true, content: [{ type: "text", text: "GA4 not configured. Add ga4_property_id and ga4_service_account_key to WP_SITES_CONFIG." }] } };
266
+ }
267
+ try {
268
+ const auth = await getGA4Auth();
269
+ const propertyId = getGA4PropertyId();
270
+ const { start_date, end_date, breakdown, limit } = params;
271
+ const analyticsdata = google.analyticsdata({ version: 'v1beta', auth });
272
+ const response = await analyticsdata.properties.runReport({
273
+ property: propertyId,
274
+ requestBody: {
275
+ dateRanges: [{ startDate: start_date, endDate: end_date }],
276
+ dimensions: [{ name: breakdown || 'country' }],
277
+ metrics: [
278
+ { name: 'activeUsers' },
279
+ { name: 'sessions' },
280
+ { name: 'screenPageViews' },
281
+ ],
282
+ orderBys: [{ metric: { metricName: 'activeUsers' }, desc: true }],
283
+ limit: String(limit || 25),
284
+ },
285
+ });
286
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
287
+ }
288
+ catch (error) {
289
+ const errorMessage = error.response?.data?.error?.message || error.message;
290
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting GA4 user demographics: ${errorMessage}` }] } };
291
+ }
292
+ },
293
+ ga4_conversion_events: async (params) => {
294
+ if (!hasGA4()) {
295
+ return { toolResult: { isError: true, content: [{ type: "text", text: "GA4 not configured. Add ga4_property_id and ga4_service_account_key to WP_SITES_CONFIG." }] } };
296
+ }
297
+ try {
298
+ const auth = await getGA4Auth();
299
+ const propertyId = getGA4PropertyId();
300
+ const { start_date, end_date, limit } = params;
301
+ const analyticsdata = google.analyticsdata({ version: 'v1beta', auth });
302
+ const response = await analyticsdata.properties.runReport({
303
+ property: propertyId,
304
+ requestBody: {
305
+ dateRanges: [{ startDate: start_date, endDate: end_date }],
306
+ dimensions: [{ name: 'eventName' }],
307
+ metrics: [
308
+ { name: 'eventCount' },
309
+ { name: 'conversions' },
310
+ { name: 'totalRevenue' },
311
+ ],
312
+ orderBys: [{ metric: { metricName: 'conversions' }, desc: true }],
313
+ limit: String(limit || 25),
314
+ },
315
+ });
316
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] } };
317
+ }
318
+ catch (error) {
319
+ const errorMessage = error.response?.data?.error?.message || error.message;
320
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting GA4 conversion events: ${errorMessage}` }] } };
321
+ }
322
+ },
323
+ };
@@ -19,6 +19,11 @@ import { mailchimpTools, mailchimpHandlers } from './mailchimp.js';
19
19
  import { bufferTools, bufferHandlers } from './buffer.js';
20
20
  import { sendgridTools, sendgridHandlers } from './sendgrid.js';
21
21
  import { gscTools, gscHandlers } from './gsc.js';
22
+ import { ga4Tools, ga4Handlers } from './ga4.js';
23
+ import { plausibleTools, plausibleHandlers } from './plausible.js';
24
+ import { cwvTools, cwvHandlers } from './cwv.js';
25
+ import { slackTools, slackHandlers } from './slack.js';
26
+ import { wcWorkflowTools, wcWorkflowHandlers } from './wc-workflows.js';
22
27
  // Combine all tools
23
28
  export const allTools = [
24
29
  ...unifiedContentTools, // 8 tools
@@ -42,6 +47,11 @@ export const allTools = [
42
47
  ...bufferTools, // 5 tools
43
48
  ...sendgridTools, // 6 tools
44
49
  ...gscTools, // 8 tools
50
+ ...ga4Tools, // 6 tools
51
+ ...plausibleTools, // 4 tools
52
+ ...cwvTools, // 4 tools
53
+ ...slackTools, // 3 tools
54
+ ...wcWorkflowTools, // 4 tools
45
55
  ];
46
56
  // Combine all handlers
47
57
  export const toolHandlers = {
@@ -66,4 +76,9 @@ export const toolHandlers = {
66
76
  ...bufferHandlers,
67
77
  ...sendgridHandlers,
68
78
  ...gscHandlers,
79
+ ...ga4Handlers,
80
+ ...plausibleHandlers,
81
+ ...cwvHandlers,
82
+ ...slackHandlers,
83
+ ...wcWorkflowHandlers,
69
84
  };
@@ -0,0 +1,3 @@
1
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ export declare const plausibleTools: Tool[];
3
+ export declare const plausibleHandlers: Record<string, Function>;
@@ -0,0 +1,207 @@
1
+ import { hasPlausible, makePlausibleRequest } from '../wordpress.js';
2
+ import { z } from 'zod';
3
+ // ── Zod Schemas ─────────────────────────────────────────────────
4
+ const periodEnum = z.enum(['day', '7d', '30d', 'month', '6mo', '12mo', 'custom']);
5
+ const plGetStatsSchema = z.object({
6
+ site_id: z.string().describe('Plausible site domain (e.g. "mysite.com")'),
7
+ period: periodEnum.optional().default('30d')
8
+ .describe('Time period (default: 30d)'),
9
+ date: z.string().optional()
10
+ .describe('Date in YYYY-MM-DD format (or date range for custom period: "2024-01-01,2024-01-31")'),
11
+ metrics: z.string().optional().default('visitors,pageviews,bounce_rate,visit_duration')
12
+ .describe('Comma-separated metrics (default: visitors,pageviews,bounce_rate,visit_duration)'),
13
+ }).strict();
14
+ const plGetTimeseriesSchema = z.object({
15
+ site_id: z.string().describe('Plausible site domain (e.g. "mysite.com")'),
16
+ period: periodEnum.optional().default('30d')
17
+ .describe('Time period (default: 30d)'),
18
+ date: z.string().optional()
19
+ .describe('Date in YYYY-MM-DD format (or date range for custom period)'),
20
+ metrics: z.string().optional().default('visitors,pageviews')
21
+ .describe('Comma-separated metrics (default: visitors,pageviews)'),
22
+ interval: z.enum(['date', 'month']).optional().default('date')
23
+ .describe('Data point interval (default: date)'),
24
+ }).strict();
25
+ const plGetBreakdownSchema = z.object({
26
+ site_id: z.string().describe('Plausible site domain (e.g. "mysite.com")'),
27
+ property: z.enum([
28
+ 'event:page',
29
+ 'visit:source',
30
+ 'visit:country',
31
+ 'visit:device',
32
+ 'visit:browser',
33
+ 'visit:os',
34
+ 'visit:utm_medium',
35
+ 'visit:utm_source',
36
+ 'visit:utm_campaign',
37
+ ]).describe('Property to break down by'),
38
+ period: periodEnum.optional().default('30d')
39
+ .describe('Time period (default: 30d)'),
40
+ date: z.string().optional()
41
+ .describe('Date in YYYY-MM-DD format (or date range for custom period)'),
42
+ metrics: z.string().optional().default('visitors,pageviews')
43
+ .describe('Comma-separated metrics (default: visitors,pageviews)'),
44
+ limit: z.number().optional().default(100)
45
+ .describe('Maximum number of results (default: 100)'),
46
+ }).strict();
47
+ const plGetRealtimeSchema = z.object({
48
+ site_id: z.string().describe('Plausible site domain (e.g. "mysite.com")'),
49
+ }).strict();
50
+ // ── Tool Definitions ────────────────────────────────────────────
51
+ export const plausibleTools = [
52
+ {
53
+ name: "pl_get_stats",
54
+ description: "Gets aggregate statistics from Plausible Analytics (visitors, pageviews, bounce rate, visit duration)",
55
+ inputSchema: {
56
+ type: "object",
57
+ properties: {
58
+ site_id: { type: "string", description: 'Plausible site domain (e.g. "mysite.com")' },
59
+ period: {
60
+ type: "string",
61
+ enum: ["day", "7d", "30d", "month", "6mo", "12mo", "custom"],
62
+ description: "Time period (default: 30d)",
63
+ },
64
+ date: { type: "string", description: 'Date in YYYY-MM-DD format (or date range for custom period: "2024-01-01,2024-01-31")' },
65
+ metrics: { type: "string", description: "Comma-separated metrics (default: visitors,pageviews,bounce_rate,visit_duration)" },
66
+ },
67
+ required: ["site_id"],
68
+ },
69
+ },
70
+ {
71
+ name: "pl_get_timeseries",
72
+ description: "Gets time-series data points from Plausible Analytics for charting trends over time",
73
+ inputSchema: {
74
+ type: "object",
75
+ properties: {
76
+ site_id: { type: "string", description: 'Plausible site domain (e.g. "mysite.com")' },
77
+ period: {
78
+ type: "string",
79
+ enum: ["day", "7d", "30d", "month", "6mo", "12mo", "custom"],
80
+ description: "Time period (default: 30d)",
81
+ },
82
+ date: { type: "string", description: "Date in YYYY-MM-DD format (or date range for custom period)" },
83
+ metrics: { type: "string", description: "Comma-separated metrics (default: visitors,pageviews)" },
84
+ interval: {
85
+ type: "string",
86
+ enum: ["date", "month"],
87
+ description: "Data point interval (default: date)",
88
+ },
89
+ },
90
+ required: ["site_id"],
91
+ },
92
+ },
93
+ {
94
+ name: "pl_get_breakdown",
95
+ description: "Gets a breakdown of stats by property (page, source, country, device, browser, OS, UTM params) from Plausible Analytics",
96
+ inputSchema: {
97
+ type: "object",
98
+ properties: {
99
+ site_id: { type: "string", description: 'Plausible site domain (e.g. "mysite.com")' },
100
+ property: {
101
+ type: "string",
102
+ enum: [
103
+ "event:page",
104
+ "visit:source",
105
+ "visit:country",
106
+ "visit:device",
107
+ "visit:browser",
108
+ "visit:os",
109
+ "visit:utm_medium",
110
+ "visit:utm_source",
111
+ "visit:utm_campaign",
112
+ ],
113
+ description: "Property to break down by",
114
+ },
115
+ period: {
116
+ type: "string",
117
+ enum: ["day", "7d", "30d", "month", "6mo", "12mo", "custom"],
118
+ description: "Time period (default: 30d)",
119
+ },
120
+ date: { type: "string", description: "Date in YYYY-MM-DD format (or date range for custom period)" },
121
+ metrics: { type: "string", description: "Comma-separated metrics (default: visitors,pageviews)" },
122
+ limit: { type: "number", description: "Maximum number of results (default: 100)" },
123
+ },
124
+ required: ["site_id", "property"],
125
+ },
126
+ },
127
+ {
128
+ name: "pl_get_realtime",
129
+ description: "Gets the number of current visitors on the site from Plausible Analytics",
130
+ inputSchema: {
131
+ type: "object",
132
+ properties: {
133
+ site_id: { type: "string", description: 'Plausible site domain (e.g. "mysite.com")' },
134
+ },
135
+ required: ["site_id"],
136
+ },
137
+ },
138
+ ];
139
+ // ── Handlers ────────────────────────────────────────────────────
140
+ export const plausibleHandlers = {
141
+ pl_get_stats: async (params) => {
142
+ if (!hasPlausible()) {
143
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Plausible Analytics not configured. Add plausible_api_key to WP_SITES_CONFIG." }] } };
144
+ }
145
+ try {
146
+ const { site_id, period, date, metrics } = plGetStatsSchema.parse(params);
147
+ const queryParams = { site_id, period, metrics };
148
+ if (date)
149
+ queryParams.date = date;
150
+ const response = await makePlausibleRequest('GET', 'stats/aggregate', queryParams);
151
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
152
+ }
153
+ catch (error) {
154
+ const errorMessage = error.response?.data?.error || error.message;
155
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting Plausible stats: ${errorMessage}` }] } };
156
+ }
157
+ },
158
+ pl_get_timeseries: async (params) => {
159
+ if (!hasPlausible()) {
160
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Plausible Analytics not configured. Add plausible_api_key to WP_SITES_CONFIG." }] } };
161
+ }
162
+ try {
163
+ const { site_id, period, date, metrics, interval } = plGetTimeseriesSchema.parse(params);
164
+ const queryParams = { site_id, period, metrics, interval };
165
+ if (date)
166
+ queryParams.date = date;
167
+ const response = await makePlausibleRequest('GET', 'stats/timeseries', queryParams);
168
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
169
+ }
170
+ catch (error) {
171
+ const errorMessage = error.response?.data?.error || error.message;
172
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting Plausible timeseries: ${errorMessage}` }] } };
173
+ }
174
+ },
175
+ pl_get_breakdown: async (params) => {
176
+ if (!hasPlausible()) {
177
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Plausible Analytics not configured. Add plausible_api_key to WP_SITES_CONFIG." }] } };
178
+ }
179
+ try {
180
+ const { site_id, property, period, date, metrics, limit } = plGetBreakdownSchema.parse(params);
181
+ const queryParams = { site_id, property, period, metrics, limit };
182
+ if (date)
183
+ queryParams.date = date;
184
+ const response = await makePlausibleRequest('GET', 'stats/breakdown', queryParams);
185
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] } };
186
+ }
187
+ catch (error) {
188
+ const errorMessage = error.response?.data?.error || error.message;
189
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting Plausible breakdown: ${errorMessage}` }] } };
190
+ }
191
+ },
192
+ pl_get_realtime: async (params) => {
193
+ if (!hasPlausible()) {
194
+ return { toolResult: { isError: true, content: [{ type: "text", text: "Plausible Analytics not configured. Add plausible_api_key to WP_SITES_CONFIG." }] } };
195
+ }
196
+ try {
197
+ const { site_id } = plGetRealtimeSchema.parse(params);
198
+ const queryParams = { site_id };
199
+ const response = await makePlausibleRequest('GET', 'stats/realtime/visitors', queryParams);
200
+ return { toolResult: { content: [{ type: "text", text: JSON.stringify({ visitors: response }, null, 2) }] } };
201
+ }
202
+ catch (error) {
203
+ const errorMessage = error.response?.data?.error || error.message;
204
+ return { toolResult: { isError: true, content: [{ type: "text", text: `Error getting Plausible realtime visitors: ${errorMessage}` }] } };
205
+ }
206
+ },
207
+ };
@@ -0,0 +1,3 @@
1
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ export declare const slackTools: Tool[];
3
+ export declare const slackHandlers: Record<string, Function>;