@dcyfr/ai 1.0.3 → 1.0.4
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 +27 -1
- package/README.md +343 -4
- package/dist/ai/index.d.ts +2 -0
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +2 -0
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/mcp/index.d.ts +14 -2
- package/dist/ai/mcp/index.d.ts.map +1 -1
- package/dist/ai/mcp/index.js +11 -1
- package/dist/ai/mcp/index.js.map +1 -1
- package/dist/ai/mcp/servers/analytics/index.d.ts +19 -0
- package/dist/ai/mcp/servers/analytics/index.d.ts.map +1 -0
- package/dist/ai/mcp/servers/analytics/index.js +556 -0
- package/dist/ai/mcp/servers/analytics/index.js.map +1 -0
- package/dist/ai/mcp/servers/content-manager/content-provider.d.ts +61 -0
- package/dist/ai/mcp/servers/content-manager/content-provider.d.ts.map +1 -0
- package/dist/ai/mcp/servers/content-manager/content-provider.js +8 -0
- package/dist/ai/mcp/servers/content-manager/content-provider.js.map +1 -0
- package/dist/ai/mcp/servers/content-manager/index.d.ts +19 -0
- package/dist/ai/mcp/servers/content-manager/index.d.ts.map +1 -0
- package/dist/ai/mcp/servers/content-manager/index.js +236 -0
- package/dist/ai/mcp/servers/content-manager/index.js.map +1 -0
- package/dist/ai/mcp/servers/design-tokens/index.d.ts +19 -0
- package/dist/ai/mcp/servers/design-tokens/index.d.ts.map +1 -0
- package/dist/ai/mcp/servers/design-tokens/index.js +422 -0
- package/dist/ai/mcp/servers/design-tokens/index.js.map +1 -0
- package/dist/ai/mcp/servers/design-tokens/token-provider.d.ts +59 -0
- package/dist/ai/mcp/servers/design-tokens/token-provider.d.ts.map +1 -0
- package/dist/ai/mcp/servers/design-tokens/token-provider.js +8 -0
- package/dist/ai/mcp/servers/design-tokens/token-provider.js.map +1 -0
- package/dist/ai/mcp/servers/promptintel/index.d.ts +19 -0
- package/dist/ai/mcp/servers/promptintel/index.d.ts.map +1 -0
- package/dist/ai/mcp/servers/promptintel/index.js +323 -0
- package/dist/ai/mcp/servers/promptintel/index.js.map +1 -0
- package/dist/ai/mcp/servers/shared/cache.d.ts +62 -0
- package/dist/ai/mcp/servers/shared/cache.d.ts.map +1 -0
- package/dist/ai/mcp/servers/shared/cache.js +117 -0
- package/dist/ai/mcp/servers/shared/cache.js.map +1 -0
- package/dist/ai/mcp/servers/shared/promptintel-client.d.ts +53 -0
- package/dist/ai/mcp/servers/shared/promptintel-client.d.ts.map +1 -0
- package/dist/ai/mcp/servers/shared/promptintel-client.js +185 -0
- package/dist/ai/mcp/servers/shared/promptintel-client.js.map +1 -0
- package/dist/ai/mcp/servers/shared/promptintel-types.d.ts +85 -0
- package/dist/ai/mcp/servers/shared/promptintel-types.d.ts.map +1 -0
- package/dist/ai/mcp/servers/shared/promptintel-types.js +7 -0
- package/dist/ai/mcp/servers/shared/promptintel-types.js.map +1 -0
- package/dist/ai/mcp/servers/shared/rate-limiter.d.ts +54 -0
- package/dist/ai/mcp/servers/shared/rate-limiter.d.ts.map +1 -0
- package/dist/ai/mcp/servers/shared/rate-limiter.js +122 -0
- package/dist/ai/mcp/servers/shared/rate-limiter.js.map +1 -0
- package/dist/ai/mcp/servers/shared/redis-client.d.ts +54 -0
- package/dist/ai/mcp/servers/shared/redis-client.d.ts.map +1 -0
- package/dist/ai/mcp/servers/shared/redis-client.js +225 -0
- package/dist/ai/mcp/servers/shared/redis-client.js.map +1 -0
- package/dist/ai/mcp/servers/shared/types.d.ts +292 -0
- package/dist/ai/mcp/servers/shared/types.d.ts.map +1 -0
- package/dist/ai/mcp/servers/shared/types.js +6 -0
- package/dist/ai/mcp/servers/shared/types.js.map +1 -0
- package/dist/ai/mcp/servers/shared/utils.d.ts +41 -0
- package/dist/ai/mcp/servers/shared/utils.d.ts.map +1 -0
- package/dist/ai/mcp/servers/shared/utils.js +183 -0
- package/dist/ai/mcp/servers/shared/utils.js.map +1 -0
- package/dist/ai/memory/config.d.ts +87 -0
- package/dist/ai/memory/config.d.ts.map +1 -0
- package/dist/ai/memory/config.js +154 -0
- package/dist/ai/memory/config.js.map +1 -0
- package/dist/ai/memory/dcyfr-memory.d.ts +63 -0
- package/dist/ai/memory/dcyfr-memory.d.ts.map +1 -0
- package/dist/ai/memory/dcyfr-memory.js +270 -0
- package/dist/ai/memory/dcyfr-memory.js.map +1 -0
- package/dist/ai/memory/index.d.ts +15 -0
- package/dist/ai/memory/index.d.ts.map +1 -0
- package/dist/ai/memory/index.js +15 -0
- package/dist/ai/memory/index.js.map +1 -0
- package/dist/ai/memory/mem0-client.d.ts +108 -0
- package/dist/ai/memory/mem0-client.d.ts.map +1 -0
- package/dist/ai/memory/mem0-client.js +166 -0
- package/dist/ai/memory/mem0-client.js.map +1 -0
- package/dist/ai/memory/types.d.ts +175 -0
- package/dist/ai/memory/types.d.ts.map +1 -0
- package/dist/ai/memory/types.js +10 -0
- package/dist/ai/memory/types.js.map +1 -0
- package/package.json +24 -2
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics MCP Server
|
|
3
|
+
* Provides AI assistants with direct access to Redis analytics data
|
|
4
|
+
*
|
|
5
|
+
* Tools:
|
|
6
|
+
* - analytics:getPageViews - Query page view data
|
|
7
|
+
* - analytics:getTrending - Find trending content
|
|
8
|
+
* - analytics:getEngagement - Query interaction metrics
|
|
9
|
+
* - analytics:searchActivity - Search activity logs
|
|
10
|
+
* - analytics:getMilestones - List achievement milestones
|
|
11
|
+
*
|
|
12
|
+
* Resources:
|
|
13
|
+
* - analytics://recent - Last 24h metrics
|
|
14
|
+
* - analytics://top-pages - Most viewed pages
|
|
15
|
+
* - analytics://milestones/production - Production milestones
|
|
16
|
+
* - analytics://engagement/summary - Overall engagement stats
|
|
17
|
+
*/
|
|
18
|
+
import { FastMCP } from 'fastmcp';
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
import { redis } from '../shared/redis-client.js';
|
|
21
|
+
import { filterProductionData, warnProductionFallback, isWithinTimeRange, sortByProperty, limitResults, handleToolError, logToolExecution, measurePerformance, getTimeRangeMs, } from '../shared/utils.js';
|
|
22
|
+
import { analyticsCache } from '../shared/cache.js';
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Server Configuration
|
|
25
|
+
// ============================================================================
|
|
26
|
+
const server = new FastMCP({
|
|
27
|
+
name: 'dcyfr-analytics',
|
|
28
|
+
version: '1.0.0',
|
|
29
|
+
instructions: 'Provides access to dcyfr-labs analytics data from Redis. Use these tools to query page views, trending content, engagement metrics, and milestones. All data is environment-aware (filters test data in production).',
|
|
30
|
+
});
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// Tool 1: Get Page Views
|
|
33
|
+
// ============================================================================
|
|
34
|
+
server.addTool({
|
|
35
|
+
name: 'analytics:getPageViews',
|
|
36
|
+
description: 'Get page view analytics for a specific path or all pages. Returns view count and optional trend data.',
|
|
37
|
+
parameters: z.object({
|
|
38
|
+
path: z.string().optional().describe('Page path (e.g., /blog, /work)'),
|
|
39
|
+
timeRange: z
|
|
40
|
+
.enum(['24h', '7d', '30d', 'all'])
|
|
41
|
+
.optional()
|
|
42
|
+
.default('7d')
|
|
43
|
+
.describe('Time range for analytics'),
|
|
44
|
+
}),
|
|
45
|
+
annotations: {
|
|
46
|
+
readOnlyHint: true,
|
|
47
|
+
openWorldHint: false,
|
|
48
|
+
},
|
|
49
|
+
execute: async (args, { log }) => {
|
|
50
|
+
try {
|
|
51
|
+
const { result, durationMs } = await measurePerformance(async () => {
|
|
52
|
+
const cacheKey = `pageviews:${args.path || 'all'}:${args.timeRange}`;
|
|
53
|
+
const cached = analyticsCache.get(cacheKey);
|
|
54
|
+
if (cached) {
|
|
55
|
+
log.info('Returning cached page views');
|
|
56
|
+
return cached;
|
|
57
|
+
}
|
|
58
|
+
// Query Redis for page views using actual key pattern: views:post:*
|
|
59
|
+
const keys = await redis.keys('views:post:*');
|
|
60
|
+
// Filter out daily tracking keys (views:post:{id}:day:{date})
|
|
61
|
+
const baseKeys = keys.filter((key) => !key.includes(':day:'));
|
|
62
|
+
if (!baseKeys || baseKeys.length === 0) {
|
|
63
|
+
warnProductionFallback('views:post:*');
|
|
64
|
+
return {
|
|
65
|
+
path: args.path || 'all',
|
|
66
|
+
views: 0,
|
|
67
|
+
timeRange: args.timeRange,
|
|
68
|
+
message: 'No analytics data available',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
let data;
|
|
72
|
+
if (args.path) {
|
|
73
|
+
// Try to find a matching key for the specific path
|
|
74
|
+
// Path could be post slug or full path
|
|
75
|
+
const matchingKey = baseKeys.find((k) => k.includes(args.path));
|
|
76
|
+
if (matchingKey) {
|
|
77
|
+
const views = parseInt((await redis.get(matchingKey)) || '0', 10);
|
|
78
|
+
data = {
|
|
79
|
+
path: args.path,
|
|
80
|
+
views,
|
|
81
|
+
timeRange: args.timeRange || '7d',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
data = {
|
|
86
|
+
path: args.path,
|
|
87
|
+
views: 0,
|
|
88
|
+
timeRange: args.timeRange || '7d',
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Sum all views across all posts
|
|
94
|
+
let totalViews = 0;
|
|
95
|
+
for (const key of baseKeys) {
|
|
96
|
+
const value = await redis.get(key);
|
|
97
|
+
totalViews += parseInt(value || '0', 10);
|
|
98
|
+
}
|
|
99
|
+
data = {
|
|
100
|
+
path: 'all',
|
|
101
|
+
views: totalViews,
|
|
102
|
+
timeRange: args.timeRange || '7d',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
analyticsCache.set(cacheKey, data, 60000); // 1 minute cache
|
|
106
|
+
return data;
|
|
107
|
+
}, 'getPageViews');
|
|
108
|
+
logToolExecution('analytics:getPageViews', args, true, durationMs);
|
|
109
|
+
return JSON.stringify(result, null, 2);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
logToolExecution('analytics:getPageViews', args, false);
|
|
113
|
+
return handleToolError(error);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
// ============================================================================
|
|
118
|
+
// Tool 2: Get Trending Content
|
|
119
|
+
// ============================================================================
|
|
120
|
+
server.addTool({
|
|
121
|
+
name: 'analytics:getTrending',
|
|
122
|
+
description: 'Get trending content based on page views. Returns top pages sorted by views.',
|
|
123
|
+
parameters: z.object({
|
|
124
|
+
limit: z.number().optional().default(10).describe('Maximum number of results to return'),
|
|
125
|
+
timeRange: z
|
|
126
|
+
.enum(['24h', '7d', '30d', 'all'])
|
|
127
|
+
.optional()
|
|
128
|
+
.default('7d')
|
|
129
|
+
.describe('Time range for trending analysis'),
|
|
130
|
+
}),
|
|
131
|
+
annotations: {
|
|
132
|
+
readOnlyHint: true,
|
|
133
|
+
openWorldHint: false,
|
|
134
|
+
},
|
|
135
|
+
execute: async (args, { log }) => {
|
|
136
|
+
try {
|
|
137
|
+
const { result, durationMs } = await measurePerformance(async () => {
|
|
138
|
+
const cacheKey = `trending:${args.timeRange}:${args.limit}`;
|
|
139
|
+
const cached = analyticsCache.get(cacheKey);
|
|
140
|
+
if (cached) {
|
|
141
|
+
log.info('Returning cached trending content');
|
|
142
|
+
return cached;
|
|
143
|
+
}
|
|
144
|
+
// Query Redis for all post views using actual key pattern: views:post:*
|
|
145
|
+
const keys = await redis.keys('views:post:*');
|
|
146
|
+
// Filter out daily tracking keys (views:post:{id}:day:{date})
|
|
147
|
+
const baseKeys = keys.filter((key) => !key.includes(':day:'));
|
|
148
|
+
if (!baseKeys || baseKeys.length === 0) {
|
|
149
|
+
warnProductionFallback('views:post:*');
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
// Get all view counts and map to post IDs
|
|
153
|
+
const trendingItems = [];
|
|
154
|
+
for (const key of baseKeys) {
|
|
155
|
+
const postId = key.replace('views:post:', '');
|
|
156
|
+
const views = parseInt((await redis.get(key)) || '0', 10);
|
|
157
|
+
if (views > 0) {
|
|
158
|
+
trendingItems.push({
|
|
159
|
+
path: `/blog/${postId}`,
|
|
160
|
+
views,
|
|
161
|
+
rank: 0, // Will be set after sorting
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const sorted = sortByProperty(trendingItems, 'views', 'desc');
|
|
166
|
+
const limited = limitResults(sorted, args.limit);
|
|
167
|
+
// Update ranks after sorting
|
|
168
|
+
limited.forEach((item, index) => {
|
|
169
|
+
item.rank = index + 1;
|
|
170
|
+
});
|
|
171
|
+
analyticsCache.set(cacheKey, limited, 60000); // 1 minute cache
|
|
172
|
+
return limited;
|
|
173
|
+
}, 'getTrending');
|
|
174
|
+
logToolExecution('analytics:getTrending', args, true, durationMs);
|
|
175
|
+
return JSON.stringify(result, null, 2);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
logToolExecution('analytics:getTrending', args, false);
|
|
179
|
+
return handleToolError(error);
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
// ============================================================================
|
|
184
|
+
// Tool 3: Get Engagement Metrics
|
|
185
|
+
// ============================================================================
|
|
186
|
+
server.addTool({
|
|
187
|
+
name: 'analytics:getEngagement',
|
|
188
|
+
description: 'Get engagement metrics (clicks, shares, interactions) from Redis. Filter by content type and time range.',
|
|
189
|
+
parameters: z.object({
|
|
190
|
+
contentType: z.string().optional().describe('Content type filter (e.g., blog, project, all)'),
|
|
191
|
+
timeRange: z
|
|
192
|
+
.enum(['1h', '24h', '7d', '30d', 'all'])
|
|
193
|
+
.optional()
|
|
194
|
+
.default('7d')
|
|
195
|
+
.describe('Time range for engagement data'),
|
|
196
|
+
}),
|
|
197
|
+
annotations: {
|
|
198
|
+
readOnlyHint: true,
|
|
199
|
+
openWorldHint: false,
|
|
200
|
+
},
|
|
201
|
+
execute: async (args, { log }) => {
|
|
202
|
+
try {
|
|
203
|
+
const { result, durationMs } = await measurePerformance(async () => {
|
|
204
|
+
const cacheKey = `engagement:${args.contentType || 'all'}:${args.timeRange}`;
|
|
205
|
+
const cached = analyticsCache.get(cacheKey);
|
|
206
|
+
if (cached) {
|
|
207
|
+
log.info('Returning cached engagement metrics');
|
|
208
|
+
return cached;
|
|
209
|
+
}
|
|
210
|
+
// Query Redis for likes and bookmarks using all content type patterns
|
|
211
|
+
const [postLikes, projectLikes, activityLikes, postBookmarks, projectBookmarks, activityBookmarks,] = await Promise.all([
|
|
212
|
+
redis.keys('likes:post:*'),
|
|
213
|
+
redis.keys('likes:project:*'),
|
|
214
|
+
redis.keys('likes:activity:*'),
|
|
215
|
+
redis.keys('bookmarks:post:*'),
|
|
216
|
+
redis.keys('bookmarks:project:*'),
|
|
217
|
+
redis.keys('bookmarks:activity:*'),
|
|
218
|
+
]);
|
|
219
|
+
const likeKeys = [...postLikes, ...projectLikes, ...activityLikes];
|
|
220
|
+
const bookmarkKeys = [...postBookmarks, ...projectBookmarks, ...activityBookmarks];
|
|
221
|
+
if ((!likeKeys || likeKeys.length === 0) && (!bookmarkKeys || bookmarkKeys.length === 0)) {
|
|
222
|
+
warnProductionFallback('likes:* and bookmarks:*');
|
|
223
|
+
return {
|
|
224
|
+
totalLikes: 0,
|
|
225
|
+
totalBookmarks: 0,
|
|
226
|
+
totalInteractions: 0,
|
|
227
|
+
timeRange: args.timeRange,
|
|
228
|
+
contentType: args.contentType || 'all',
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// Sum all likes
|
|
232
|
+
let totalLikes = 0;
|
|
233
|
+
for (const key of likeKeys) {
|
|
234
|
+
const value = await redis.get(key);
|
|
235
|
+
totalLikes += parseInt(value || '0', 10);
|
|
236
|
+
}
|
|
237
|
+
// Sum all bookmarks
|
|
238
|
+
let totalBookmarks = 0;
|
|
239
|
+
for (const key of bookmarkKeys) {
|
|
240
|
+
const value = await redis.get(key);
|
|
241
|
+
totalBookmarks += parseInt(value || '0', 10);
|
|
242
|
+
}
|
|
243
|
+
// Aggregate engagement metrics
|
|
244
|
+
const metrics = {
|
|
245
|
+
totalLikes,
|
|
246
|
+
totalBookmarks,
|
|
247
|
+
totalInteractions: totalLikes + totalBookmarks,
|
|
248
|
+
timeRange: args.timeRange,
|
|
249
|
+
contentType: args.contentType || 'all',
|
|
250
|
+
};
|
|
251
|
+
analyticsCache.set(cacheKey, metrics, 60000); // 1 minute cache
|
|
252
|
+
return metrics;
|
|
253
|
+
}, 'getEngagement');
|
|
254
|
+
logToolExecution('analytics:getEngagement', args, true, durationMs);
|
|
255
|
+
return JSON.stringify(result, null, 2);
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
logToolExecution('analytics:getEngagement', args, false);
|
|
259
|
+
return handleToolError(error);
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
// ============================================================================
|
|
264
|
+
// Tool 4: Search Activity Logs
|
|
265
|
+
// ============================================================================
|
|
266
|
+
server.addTool({
|
|
267
|
+
name: 'analytics:searchActivity',
|
|
268
|
+
description: 'Search activity logs by keyword, type, or date range. Returns matching activity entries.',
|
|
269
|
+
parameters: z.object({
|
|
270
|
+
query: z.string().optional().describe('Search query keyword'),
|
|
271
|
+
activityType: z
|
|
272
|
+
.string()
|
|
273
|
+
.optional()
|
|
274
|
+
.describe('Activity type filter (e.g., pageview, click, share)'),
|
|
275
|
+
timeRange: z
|
|
276
|
+
.enum(['1h', '24h', '7d', '30d', 'all'])
|
|
277
|
+
.optional()
|
|
278
|
+
.default('24h')
|
|
279
|
+
.describe('Time range for activity search'),
|
|
280
|
+
limit: z.number().optional().default(50).describe('Maximum number of results'),
|
|
281
|
+
}),
|
|
282
|
+
annotations: {
|
|
283
|
+
readOnlyHint: true,
|
|
284
|
+
openWorldHint: false,
|
|
285
|
+
},
|
|
286
|
+
execute: async (args, { log }) => {
|
|
287
|
+
try {
|
|
288
|
+
const { result, durationMs } = await measurePerformance(async () => {
|
|
289
|
+
const cacheKey = `activity:${args.query || ''}:${args.activityType || ''}:${args.timeRange}`;
|
|
290
|
+
const cached = analyticsCache.get(cacheKey);
|
|
291
|
+
if (cached) {
|
|
292
|
+
log.info('Returning cached activity search results');
|
|
293
|
+
return cached;
|
|
294
|
+
}
|
|
295
|
+
// Query Redis for view history using actual key pattern: views:history:post:*
|
|
296
|
+
// This returns sorted sets with timestamps of views
|
|
297
|
+
const historyKeys = await redis.keys('views:history:post:*');
|
|
298
|
+
if (!historyKeys || historyKeys.length === 0) {
|
|
299
|
+
warnProductionFallback('views:history:post:*');
|
|
300
|
+
return [];
|
|
301
|
+
}
|
|
302
|
+
// Get recent activity from view history sorted sets
|
|
303
|
+
const activities = [];
|
|
304
|
+
for (const key of historyKeys) {
|
|
305
|
+
const postId = key.replace('views:history:post:', '');
|
|
306
|
+
// Get recent entries from sorted set (within time range)
|
|
307
|
+
const now = Date.now();
|
|
308
|
+
const timeRangeMs = getTimeRangeMs(args.timeRange || '24h');
|
|
309
|
+
const minScore = now - timeRangeMs;
|
|
310
|
+
// zrange with byScore option returns members with scores between min and max (replaces deprecated zrangebyscore)
|
|
311
|
+
const entries = await redis.zrange(key, minScore, now, { byScore: true });
|
|
312
|
+
for (const entry of entries) {
|
|
313
|
+
const timestamp = parseInt(entry, 10);
|
|
314
|
+
activities.push({
|
|
315
|
+
type: 'pageview',
|
|
316
|
+
path: `/blog/${postId}`,
|
|
317
|
+
timestamp,
|
|
318
|
+
data: { postId },
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// Filter by activity type
|
|
323
|
+
if (args.activityType && args.activityType !== 'pageview') {
|
|
324
|
+
// Currently only pageview activity is tracked
|
|
325
|
+
return [];
|
|
326
|
+
}
|
|
327
|
+
// Filter by query keyword
|
|
328
|
+
let filtered = activities;
|
|
329
|
+
if (args.query) {
|
|
330
|
+
const queryLower = args.query.toLowerCase();
|
|
331
|
+
filtered = activities.filter((activity) => activity.path.toLowerCase().includes(queryLower) ||
|
|
332
|
+
activity.data.postId?.toString().toLowerCase().includes(queryLower));
|
|
333
|
+
}
|
|
334
|
+
// Sort by timestamp descending
|
|
335
|
+
filtered.sort((a, b) => b.timestamp - a.timestamp);
|
|
336
|
+
// Limit results
|
|
337
|
+
const limited = limitResults(filtered, args.limit);
|
|
338
|
+
analyticsCache.set(cacheKey, limited, 60000); // 1 minute cache
|
|
339
|
+
return limited;
|
|
340
|
+
}, 'searchActivity');
|
|
341
|
+
logToolExecution('analytics:searchActivity', args, true, durationMs);
|
|
342
|
+
return JSON.stringify(result, null, 2);
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
logToolExecution('analytics:searchActivity', args, false);
|
|
346
|
+
return handleToolError(error);
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
// ============================================================================
|
|
351
|
+
// Tool 5: Get Milestones
|
|
352
|
+
// ============================================================================
|
|
353
|
+
server.addTool({
|
|
354
|
+
name: 'analytics:getMilestones',
|
|
355
|
+
description: 'Get achievement milestones. Filters test data in production environments.',
|
|
356
|
+
parameters: z.object({
|
|
357
|
+
includeTest: z
|
|
358
|
+
.boolean()
|
|
359
|
+
.optional()
|
|
360
|
+
.default(false)
|
|
361
|
+
.describe('Include test milestones (ignored in production)'),
|
|
362
|
+
}),
|
|
363
|
+
annotations: {
|
|
364
|
+
readOnlyHint: true,
|
|
365
|
+
openWorldHint: false,
|
|
366
|
+
},
|
|
367
|
+
execute: async (args, { log }) => {
|
|
368
|
+
try {
|
|
369
|
+
const { result, durationMs } = await measurePerformance(async () => {
|
|
370
|
+
const cacheKey = `milestones:${args.includeTest}`;
|
|
371
|
+
const cached = analyticsCache.get(cacheKey);
|
|
372
|
+
if (cached) {
|
|
373
|
+
log.info('Returning cached milestones');
|
|
374
|
+
return cached;
|
|
375
|
+
}
|
|
376
|
+
const milestonesData = await redis.get('analytics:milestones');
|
|
377
|
+
if (!milestonesData) {
|
|
378
|
+
warnProductionFallback('analytics:milestones');
|
|
379
|
+
return [];
|
|
380
|
+
}
|
|
381
|
+
const allMilestones = JSON.parse(milestonesData);
|
|
382
|
+
// Filter production data (automatically excludes test data in prod)
|
|
383
|
+
const filtered = filterProductionData(allMilestones);
|
|
384
|
+
analyticsCache.set(cacheKey, filtered, 300000); // 5 minute cache
|
|
385
|
+
return filtered;
|
|
386
|
+
}, 'getMilestones');
|
|
387
|
+
logToolExecution('analytics:getMilestones', args, true, durationMs);
|
|
388
|
+
return JSON.stringify(result, null, 2);
|
|
389
|
+
}
|
|
390
|
+
catch (error) {
|
|
391
|
+
logToolExecution('analytics:getMilestones', args, false);
|
|
392
|
+
return handleToolError(error);
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
// ============================================================================
|
|
397
|
+
// Resource 1: Recent Metrics (Last 24h)
|
|
398
|
+
// ============================================================================
|
|
399
|
+
server.addResource({
|
|
400
|
+
uri: 'analytics://recent',
|
|
401
|
+
name: 'Recent Analytics (24h)',
|
|
402
|
+
mimeType: 'application/json',
|
|
403
|
+
description: 'Summary of analytics from the last 24 hours',
|
|
404
|
+
async load() {
|
|
405
|
+
try {
|
|
406
|
+
const cacheKey = 'resource:recent';
|
|
407
|
+
const cached = analyticsCache.get(cacheKey);
|
|
408
|
+
if (cached) {
|
|
409
|
+
return { text: JSON.stringify(cached, null, 2) };
|
|
410
|
+
}
|
|
411
|
+
// Query actual Redis keys
|
|
412
|
+
const [allViewKeys, milestonesData] = await Promise.all([
|
|
413
|
+
redis.keys('views:post:*'),
|
|
414
|
+
redis.get('analytics:milestones'),
|
|
415
|
+
]);
|
|
416
|
+
// Filter out daily tracking keys
|
|
417
|
+
const viewKeys = allViewKeys.filter((key) => !key.includes(':day:'));
|
|
418
|
+
// Sum all views
|
|
419
|
+
let totalViews = 0;
|
|
420
|
+
for (const key of viewKeys) {
|
|
421
|
+
const value = await redis.get(key);
|
|
422
|
+
totalViews += parseInt(value || '0', 10);
|
|
423
|
+
}
|
|
424
|
+
const milestones = milestonesData ? JSON.parse(milestonesData) : [];
|
|
425
|
+
const recent24h = milestones.filter((m) => isWithinTimeRange(m.achievedAt, '24h'));
|
|
426
|
+
const summary = {
|
|
427
|
+
totalViews,
|
|
428
|
+
topPages: [],
|
|
429
|
+
recentActivity: [],
|
|
430
|
+
milestones: filterProductionData(recent24h),
|
|
431
|
+
generatedAt: Date.now(),
|
|
432
|
+
};
|
|
433
|
+
analyticsCache.set(cacheKey, summary, 60000); // 1 minute cache
|
|
434
|
+
return { text: JSON.stringify(summary, null, 2) };
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
return { text: handleToolError(error) };
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
});
|
|
441
|
+
// ============================================================================
|
|
442
|
+
// Resource 2: Top Pages (Most Viewed)
|
|
443
|
+
// ============================================================================
|
|
444
|
+
server.addResource({
|
|
445
|
+
uri: 'analytics://top-pages',
|
|
446
|
+
name: 'Top Pages by Views',
|
|
447
|
+
mimeType: 'application/json',
|
|
448
|
+
description: 'Most viewed pages sorted by traffic',
|
|
449
|
+
async load() {
|
|
450
|
+
try {
|
|
451
|
+
const cacheKey = 'resource:top-pages';
|
|
452
|
+
const cached = analyticsCache.get(cacheKey);
|
|
453
|
+
if (cached) {
|
|
454
|
+
return { text: JSON.stringify(cached, null, 2) };
|
|
455
|
+
}
|
|
456
|
+
// Query actual Redis keys
|
|
457
|
+
const allViewKeys = await redis.keys('views:post:*');
|
|
458
|
+
const viewKeys = allViewKeys.filter((key) => !key.includes(':day:'));
|
|
459
|
+
if (!viewKeys || viewKeys.length === 0) {
|
|
460
|
+
return {
|
|
461
|
+
text: JSON.stringify({ message: 'No page view data available', pages: [] }, null, 2),
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
// Get all view counts
|
|
465
|
+
const pages = [];
|
|
466
|
+
for (const key of viewKeys) {
|
|
467
|
+
const postId = key.replace('views:post:', '');
|
|
468
|
+
const views = parseInt((await redis.get(key)) || '0', 10);
|
|
469
|
+
if (views > 0) {
|
|
470
|
+
pages.push({ path: `/blog/${postId}`, views });
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
const topPages = pages.sort((a, b) => b.views - a.views).slice(0, 20); // Top 20 pages
|
|
474
|
+
const result = {
|
|
475
|
+
topPages,
|
|
476
|
+
totalPages: pages.length,
|
|
477
|
+
generatedAt: Date.now(),
|
|
478
|
+
};
|
|
479
|
+
analyticsCache.set(cacheKey, result, 300000); // 5 minute cache
|
|
480
|
+
return { text: JSON.stringify(result, null, 2) };
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
return { text: handleToolError(error) };
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
// ============================================================================
|
|
488
|
+
// Resource 3: Engagement Summary
|
|
489
|
+
// ============================================================================
|
|
490
|
+
server.addResource({
|
|
491
|
+
uri: 'analytics://engagement/summary',
|
|
492
|
+
name: 'Engagement Summary',
|
|
493
|
+
mimeType: 'application/json',
|
|
494
|
+
description: 'Overall engagement statistics and trends',
|
|
495
|
+
async load() {
|
|
496
|
+
try {
|
|
497
|
+
const cacheKey = 'resource:engagement-summary';
|
|
498
|
+
const cached = analyticsCache.get(cacheKey);
|
|
499
|
+
if (cached) {
|
|
500
|
+
return { text: JSON.stringify(cached, null, 2) };
|
|
501
|
+
}
|
|
502
|
+
// Query actual Redis keys for likes and bookmarks across all content types
|
|
503
|
+
const [postLikes, projectLikes, activityLikes, postBookmarks, projectBookmarks, activityBookmarks,] = await Promise.all([
|
|
504
|
+
redis.keys('likes:post:*'),
|
|
505
|
+
redis.keys('likes:project:*'),
|
|
506
|
+
redis.keys('likes:activity:*'),
|
|
507
|
+
redis.keys('bookmarks:post:*'),
|
|
508
|
+
redis.keys('bookmarks:project:*'),
|
|
509
|
+
redis.keys('bookmarks:activity:*'),
|
|
510
|
+
]);
|
|
511
|
+
const likeKeys = [...postLikes, ...projectLikes, ...activityLikes];
|
|
512
|
+
const bookmarkKeys = [...postBookmarks, ...projectBookmarks, ...activityBookmarks];
|
|
513
|
+
if ((!likeKeys || likeKeys.length === 0) && (!bookmarkKeys || bookmarkKeys.length === 0)) {
|
|
514
|
+
return {
|
|
515
|
+
text: JSON.stringify({
|
|
516
|
+
message: 'No engagement data available',
|
|
517
|
+
totalLikes: 0,
|
|
518
|
+
totalBookmarks: 0,
|
|
519
|
+
totalInteractions: 0,
|
|
520
|
+
}, null, 2),
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
// Sum all likes
|
|
524
|
+
let totalLikes = 0;
|
|
525
|
+
for (const key of likeKeys) {
|
|
526
|
+
const value = await redis.get(key);
|
|
527
|
+
totalLikes += parseInt(value || '0', 10);
|
|
528
|
+
}
|
|
529
|
+
// Sum all bookmarks
|
|
530
|
+
let totalBookmarks = 0;
|
|
531
|
+
for (const key of bookmarkKeys) {
|
|
532
|
+
const value = await redis.get(key);
|
|
533
|
+
totalBookmarks += parseInt(value || '0', 10);
|
|
534
|
+
}
|
|
535
|
+
const summary = {
|
|
536
|
+
totalLikes,
|
|
537
|
+
totalBookmarks,
|
|
538
|
+
totalInteractions: totalLikes + totalBookmarks,
|
|
539
|
+
generatedAt: Date.now(),
|
|
540
|
+
};
|
|
541
|
+
analyticsCache.set(cacheKey, summary, 300000); // 5 minute cache
|
|
542
|
+
return { text: JSON.stringify(summary, null, 2) };
|
|
543
|
+
}
|
|
544
|
+
catch (error) {
|
|
545
|
+
return { text: handleToolError(error) };
|
|
546
|
+
}
|
|
547
|
+
},
|
|
548
|
+
});
|
|
549
|
+
// ============================================================================
|
|
550
|
+
// Start Server
|
|
551
|
+
// ============================================================================
|
|
552
|
+
server.start({
|
|
553
|
+
transportType: 'stdio',
|
|
554
|
+
});
|
|
555
|
+
console.warn('✅ Analytics MCP Server started (stdio mode)');
|
|
556
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/ai/mcp/servers/analytics/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContentProvider Interface
|
|
3
|
+
*
|
|
4
|
+
* Abstraction for content sources to decouple Content Manager MCP from dcyfr-labs.
|
|
5
|
+
* Implementations can read from filesystem, database, CMS, or any other source.
|
|
6
|
+
*/
|
|
7
|
+
export interface ContentMetadata {
|
|
8
|
+
title: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
date?: string;
|
|
11
|
+
tags?: string[];
|
|
12
|
+
category?: string;
|
|
13
|
+
published?: boolean;
|
|
14
|
+
wordCount?: number;
|
|
15
|
+
readingTime?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface ContentItem {
|
|
18
|
+
filePath: string;
|
|
19
|
+
slug: string;
|
|
20
|
+
type: 'blog' | 'project';
|
|
21
|
+
metadata: ContentMetadata;
|
|
22
|
+
excerpt?: string;
|
|
23
|
+
body?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ContentSearchOptions {
|
|
26
|
+
query?: string;
|
|
27
|
+
tags?: string[];
|
|
28
|
+
category?: string;
|
|
29
|
+
limit?: number;
|
|
30
|
+
includeUnpublished?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* ContentProvider interface for abstracting content sources
|
|
34
|
+
*/
|
|
35
|
+
export interface ContentProvider {
|
|
36
|
+
/**
|
|
37
|
+
* List all content items of a given type
|
|
38
|
+
*/
|
|
39
|
+
listContent(type: 'blog' | 'project', options?: ContentSearchOptions): Promise<ContentItem[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Get a specific content item by slug
|
|
42
|
+
*/
|
|
43
|
+
getContent(slug: string, type: 'blog' | 'project'): Promise<ContentItem | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Search content by query string
|
|
46
|
+
*/
|
|
47
|
+
searchContent(query: string, type?: 'blog' | 'project'): Promise<ContentItem[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Get all unique tags across content
|
|
50
|
+
*/
|
|
51
|
+
getTags(type?: 'blog' | 'project'): Promise<string[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Get content by tag
|
|
54
|
+
*/
|
|
55
|
+
getContentByTag(tag: string, type?: 'blog' | 'project'): Promise<ContentItem[]>;
|
|
56
|
+
/**
|
|
57
|
+
* Get content by category
|
|
58
|
+
*/
|
|
59
|
+
getContentByCategory(category: string, type?: 'blog' | 'project'): Promise<ContentItem[]>;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=content-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-provider.d.ts","sourceRoot":"","sources":["../../../../../packages/ai/mcp/servers/content-manager/content-provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAE9F;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAEhF;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAEhF;;OAEG;IACH,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEtD;;OAEG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAEhF;;OAEG;IACH,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CAC3F"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContentProvider Interface
|
|
3
|
+
*
|
|
4
|
+
* Abstraction for content sources to decouple Content Manager MCP from dcyfr-labs.
|
|
5
|
+
* Implementations can read from filesystem, database, CMS, or any other source.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=content-provider.js.map
|