@mcp-fe/event-tracker 0.0.15 → 0.0.16
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/README.md +455 -6
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -1,11 +1,460 @@
|
|
|
1
|
-
# event-tracker
|
|
1
|
+
# @mcp-fe/event-tracker
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Framework-agnostic event tracking library for the MCP-FE (Model Context Protocol - Frontend Edge) ecosystem. This library provides a simple, clean API for tracking user interactions and making them available to AI agents through the MCP protocol.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Overview
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
`@mcp-fe/event-tracker` is a lightweight wrapper around [`@mcp-fe/mcp-worker`](../mcp-worker/README.md) that provides an ergonomic API for tracking user events in any JavaScript application. It serves as the foundation for framework-specific integrations like [`@mcp-fe/react-event-tracker`](../react-event-tracker/README.md).
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
### Key Features
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- **Framework Agnostic**: Works with any JavaScript framework or vanilla JS
|
|
12
|
+
- **Simple API**: Clean, intuitive functions for common tracking needs
|
|
13
|
+
- **Rich Event Data**: Captures element details, metadata, and context
|
|
14
|
+
- **Connection Management**: Built-in WebSocket connection status monitoring
|
|
15
|
+
- **Authentication Support**: Token-based authentication for user-specific events
|
|
16
|
+
- **TypeScript Support**: Full type definitions included
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @mcp-fe/event-tracker
|
|
22
|
+
# or
|
|
23
|
+
pnpm add @mcp-fe/event-tracker
|
|
24
|
+
# or
|
|
25
|
+
yarn add @mcp-fe/event-tracker
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Dependencies
|
|
29
|
+
|
|
30
|
+
This package requires [`@mcp-fe/mcp-worker`](../mcp-worker/README.md) which is automatically installed as a dependency. Make sure to set up the worker files as described in the mcp-worker documentation.
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import {
|
|
36
|
+
initEventTracker,
|
|
37
|
+
trackEvent,
|
|
38
|
+
trackNavigation,
|
|
39
|
+
trackClick
|
|
40
|
+
} from '@mcp-fe/event-tracker';
|
|
41
|
+
|
|
42
|
+
// Initialize the event tracker
|
|
43
|
+
await initEventTracker({
|
|
44
|
+
backendWsUrl: 'ws://localhost:3001'
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Track user interactions
|
|
48
|
+
await trackNavigation('/home', '/products');
|
|
49
|
+
await trackClick(document.getElementById('buy-button'));
|
|
50
|
+
|
|
51
|
+
// Track custom events
|
|
52
|
+
await trackEvent({
|
|
53
|
+
type: 'custom',
|
|
54
|
+
metadata: {
|
|
55
|
+
eventName: 'purchase_completed',
|
|
56
|
+
orderId: '12345',
|
|
57
|
+
amount: 99.99
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## API Reference
|
|
63
|
+
|
|
64
|
+
### Initialization
|
|
65
|
+
|
|
66
|
+
#### `initEventTracker(options?)`
|
|
67
|
+
|
|
68
|
+
Initialize the event tracking system. This sets up the underlying MCP worker.
|
|
69
|
+
|
|
70
|
+
**Parameters:**
|
|
71
|
+
- `options?: ServiceWorkerRegistration | WorkerClientInitOptions`
|
|
72
|
+
|
|
73
|
+
**WorkerClientInitOptions:**
|
|
74
|
+
```typescript
|
|
75
|
+
interface WorkerClientInitOptions {
|
|
76
|
+
sharedWorkerUrl?: string; // Default: '/mcp-shared-worker.js'
|
|
77
|
+
serviceWorkerUrl?: string; // Default: '/mcp-service-worker.js'
|
|
78
|
+
backendWsUrl?: string; // Default: 'ws://localhost:3001'
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Examples:**
|
|
83
|
+
```typescript
|
|
84
|
+
// Basic initialization
|
|
85
|
+
await initEventTracker();
|
|
86
|
+
|
|
87
|
+
// With custom WebSocket URL
|
|
88
|
+
await initEventTracker({
|
|
89
|
+
backendWsUrl: 'wss://my-mcp-server.com/ws'
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// With custom worker paths
|
|
93
|
+
await initEventTracker({
|
|
94
|
+
sharedWorkerUrl: '/assets/workers/mcp-shared-worker.js',
|
|
95
|
+
backendWsUrl: 'ws://localhost:3001'
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Using existing ServiceWorker registration
|
|
99
|
+
const registration = await navigator.serviceWorker.register('/mcp-service-worker.js');
|
|
100
|
+
await initEventTracker(registration);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Event Tracking
|
|
104
|
+
|
|
105
|
+
#### `trackEvent(eventData)`
|
|
106
|
+
|
|
107
|
+
Track a generic user event with custom data.
|
|
108
|
+
|
|
109
|
+
**Parameters:**
|
|
110
|
+
- `eventData: UserEventData`
|
|
111
|
+
|
|
112
|
+
**UserEventData Interface:**
|
|
113
|
+
```typescript
|
|
114
|
+
interface UserEventData {
|
|
115
|
+
type: 'navigation' | 'click' | 'input' | 'custom';
|
|
116
|
+
path?: string; // Current page path
|
|
117
|
+
from?: string; // Previous location (navigation events)
|
|
118
|
+
to?: string; // Next location (navigation events)
|
|
119
|
+
element?: string; // HTML element tag name
|
|
120
|
+
elementId?: string; // Element ID attribute
|
|
121
|
+
elementClass?: string; // Element CSS classes
|
|
122
|
+
elementText?: string; // Element text content (truncated to 100 chars)
|
|
123
|
+
metadata?: Record<string, unknown>; // Additional event data
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Example:**
|
|
128
|
+
```typescript
|
|
129
|
+
await trackEvent({
|
|
130
|
+
type: 'custom',
|
|
131
|
+
path: '/dashboard',
|
|
132
|
+
metadata: {
|
|
133
|
+
eventName: 'feature_used',
|
|
134
|
+
feature: 'export_data',
|
|
135
|
+
format: 'csv',
|
|
136
|
+
recordCount: 150
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### `trackNavigation(from, to, path?)`
|
|
142
|
+
|
|
143
|
+
Track navigation between routes or pages.
|
|
144
|
+
|
|
145
|
+
**Parameters:**
|
|
146
|
+
- `from: string` - Previous route/URL
|
|
147
|
+
- `to: string` - Current route/URL
|
|
148
|
+
- `path?: string` - Optional explicit path (defaults to `to`)
|
|
149
|
+
|
|
150
|
+
**Example:**
|
|
151
|
+
```typescript
|
|
152
|
+
// Basic navigation tracking
|
|
153
|
+
await trackNavigation('/home', '/products');
|
|
154
|
+
|
|
155
|
+
// With explicit path
|
|
156
|
+
await trackNavigation('/users/123', '/users/456', '/users');
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### `trackClick(element, path?, metadata?)`
|
|
160
|
+
|
|
161
|
+
Track click events on HTML elements with automatic element data extraction.
|
|
162
|
+
|
|
163
|
+
**Parameters:**
|
|
164
|
+
- `element: HTMLElement` - The clicked element
|
|
165
|
+
- `path?: string` - Current page path (defaults to `window.location.pathname`)
|
|
166
|
+
- `metadata?: Record<string, unknown>` - Additional click data
|
|
167
|
+
|
|
168
|
+
**Example:**
|
|
169
|
+
```typescript
|
|
170
|
+
// Track button click
|
|
171
|
+
const button = document.getElementById('submit-btn');
|
|
172
|
+
await trackClick(button);
|
|
173
|
+
|
|
174
|
+
// With additional metadata
|
|
175
|
+
const link = document.querySelector('a[data-product-id="123"]');
|
|
176
|
+
await trackClick(link, '/products', {
|
|
177
|
+
productId: '123',
|
|
178
|
+
category: 'electronics',
|
|
179
|
+
price: 299.99
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Event listener example
|
|
183
|
+
document.addEventListener('click', async (event) => {
|
|
184
|
+
if (event.target instanceof HTMLElement) {
|
|
185
|
+
await trackClick(event.target);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
#### `trackInput(element, value?, path?)`
|
|
191
|
+
|
|
192
|
+
Track input changes in forms with debouncing and value length tracking.
|
|
193
|
+
|
|
194
|
+
**Parameters:**
|
|
195
|
+
- `element: HTMLElement` - The input element
|
|
196
|
+
- `value?: string` - Input value (stored securely with length tracking)
|
|
197
|
+
- `path?: string` - Current page path
|
|
198
|
+
|
|
199
|
+
**Example:**
|
|
200
|
+
```typescript
|
|
201
|
+
// Track input change
|
|
202
|
+
const emailInput = document.getElementById('email');
|
|
203
|
+
await trackInput(emailInput, emailInput.value);
|
|
204
|
+
|
|
205
|
+
// Event listener with debouncing
|
|
206
|
+
let timeoutId;
|
|
207
|
+
document.addEventListener('input', (event) => {
|
|
208
|
+
if (event.target instanceof HTMLInputElement) {
|
|
209
|
+
clearTimeout(timeoutId);
|
|
210
|
+
timeoutId = setTimeout(async () => {
|
|
211
|
+
await trackInput(event.target, event.target.value);
|
|
212
|
+
}, 1000); // 1 second debounce
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### `trackCustom(eventName, metadata?, path?)`
|
|
218
|
+
|
|
219
|
+
Convenient wrapper for tracking custom business events.
|
|
220
|
+
|
|
221
|
+
**Parameters:**
|
|
222
|
+
- `eventName: string` - Name of the custom event
|
|
223
|
+
- `metadata?: Record<string, unknown>` - Event-specific data
|
|
224
|
+
- `path?: string` - Current page path
|
|
225
|
+
|
|
226
|
+
**Example:**
|
|
227
|
+
```typescript
|
|
228
|
+
// Track business events
|
|
229
|
+
await trackCustom('purchase_completed', {
|
|
230
|
+
orderId: '12345',
|
|
231
|
+
amount: 99.99,
|
|
232
|
+
currency: 'USD',
|
|
233
|
+
items: ['product-1', 'product-2']
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
await trackCustom('search_performed', {
|
|
237
|
+
query: 'javascript tutorials',
|
|
238
|
+
results: 42,
|
|
239
|
+
filters: ['beginner', 'video']
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
await trackCustom('error_occurred', {
|
|
243
|
+
errorType: 'validation',
|
|
244
|
+
field: 'email',
|
|
245
|
+
message: 'Invalid email format'
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Connection Management
|
|
250
|
+
|
|
251
|
+
#### `getConnectionStatus()`
|
|
252
|
+
|
|
253
|
+
Check if the MCP worker is connected to the proxy server.
|
|
254
|
+
|
|
255
|
+
**Returns:** `Promise<boolean>`
|
|
256
|
+
|
|
257
|
+
**Example:**
|
|
258
|
+
```typescript
|
|
259
|
+
const isConnected = await getConnectionStatus();
|
|
260
|
+
if (!isConnected) {
|
|
261
|
+
console.warn('MCP connection lost, events may not be available to AI agents');
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### `onConnectionStatus(callback)` / `offConnectionStatus(callback)`
|
|
266
|
+
|
|
267
|
+
Subscribe to connection status changes.
|
|
268
|
+
|
|
269
|
+
**Parameters:**
|
|
270
|
+
- `callback: (connected: boolean) => void` - Status change callback
|
|
271
|
+
|
|
272
|
+
**Example:**
|
|
273
|
+
```typescript
|
|
274
|
+
const handleConnectionChange = (connected) => {
|
|
275
|
+
console.log('MCP connection:', connected ? 'Connected' : 'Disconnected');
|
|
276
|
+
|
|
277
|
+
// Update UI indicator
|
|
278
|
+
const indicator = document.getElementById('connection-status');
|
|
279
|
+
indicator.className = connected ? 'connected' : 'disconnected';
|
|
280
|
+
indicator.textContent = connected ? '🟢 Connected' : '🔴 Offline';
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// Start listening
|
|
284
|
+
onConnectionStatus(handleConnectionChange);
|
|
285
|
+
|
|
286
|
+
// Stop listening (e.g., on component unmount)
|
|
287
|
+
offConnectionStatus(handleConnectionChange);
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Authentication
|
|
291
|
+
|
|
292
|
+
#### `setAuthToken(token)`
|
|
293
|
+
|
|
294
|
+
Set authentication token for associating events with specific users.
|
|
295
|
+
|
|
296
|
+
**Parameters:**
|
|
297
|
+
- `token: string` - Authentication token (e.g., JWT)
|
|
298
|
+
|
|
299
|
+
**Example:**
|
|
300
|
+
```typescript
|
|
301
|
+
// After user login
|
|
302
|
+
async function handleLogin(credentials) {
|
|
303
|
+
const response = await authenticateUser(credentials);
|
|
304
|
+
|
|
305
|
+
// Set token for MCP tracking
|
|
306
|
+
setAuthToken(response.accessToken);
|
|
307
|
+
|
|
308
|
+
// Track login event
|
|
309
|
+
await trackCustom('user_logged_in', {
|
|
310
|
+
userId: response.user.id,
|
|
311
|
+
method: 'password'
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// On logout
|
|
316
|
+
async function handleLogout() {
|
|
317
|
+
await trackCustom('user_logged_out');
|
|
318
|
+
|
|
319
|
+
// Clear authentication
|
|
320
|
+
setAuthToken('');
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
## Integration with AI Agents
|
|
326
|
+
|
|
327
|
+
Once events are tracked and stored, AI agents can query them through the MCP protocol:
|
|
328
|
+
|
|
329
|
+
```json
|
|
330
|
+
{
|
|
331
|
+
"jsonrpc": "2.0",
|
|
332
|
+
"method": "tools/call",
|
|
333
|
+
"params": {
|
|
334
|
+
"name": "get_user_events",
|
|
335
|
+
"arguments": {
|
|
336
|
+
"type": "click",
|
|
337
|
+
"limit": 10,
|
|
338
|
+
"startTime": 1705712400000
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
This enables AI agents to:
|
|
345
|
+
- Provide context-aware customer support
|
|
346
|
+
- Debug user interface issues
|
|
347
|
+
- Analyze user behavior patterns
|
|
348
|
+
- Guide users through complex workflows
|
|
349
|
+
- Understand error scenarios and user frustration points
|
|
350
|
+
|
|
351
|
+
## Best Practices
|
|
352
|
+
|
|
353
|
+
### Event Granularity
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
// ✅ Good: Track meaningful interactions
|
|
357
|
+
await trackClick(submitButton, '/checkout', {
|
|
358
|
+
step: 'payment',
|
|
359
|
+
amount: totalAmount
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// ❌ Too granular: Don't track every mouseover
|
|
363
|
+
document.addEventListener('mouseover', trackEvent); // Avoid this
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Sensitive Data
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
// ✅ Good: Track input activity without sensitive values
|
|
370
|
+
await trackInput(passwordInput, undefined, '/login'); // Don't pass actual password
|
|
371
|
+
|
|
372
|
+
// ✅ Good: Track metadata about sensitive operations
|
|
373
|
+
await trackCustom('payment_submitted', {
|
|
374
|
+
amount: 99.99,
|
|
375
|
+
currency: 'USD',
|
|
376
|
+
// Don't include card numbers or CVV
|
|
377
|
+
});
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Performance
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
// ✅ Good: Debounce high-frequency events
|
|
384
|
+
let searchTimeout;
|
|
385
|
+
searchInput.addEventListener('input', () => {
|
|
386
|
+
clearTimeout(searchTimeout);
|
|
387
|
+
searchTimeout = setTimeout(async () => {
|
|
388
|
+
await trackInput(searchInput, searchInput.value);
|
|
389
|
+
}, 500);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// ✅ Good: Batch related events
|
|
393
|
+
await Promise.all([
|
|
394
|
+
trackCustom('form_submitted'),
|
|
395
|
+
trackNavigation('/form', '/success')
|
|
396
|
+
]);
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## Error Handling
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
// Wrap tracking calls in try-catch for production resilience
|
|
403
|
+
async function safeTrackEvent(eventData) {
|
|
404
|
+
try {
|
|
405
|
+
await trackEvent(eventData);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
// Log error but don't break user experience
|
|
408
|
+
console.warn('Failed to track event:', error);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Check connection before critical tracking
|
|
413
|
+
const isConnected = await getConnectionStatus();
|
|
414
|
+
if (isConnected) {
|
|
415
|
+
await trackCustom('critical_business_event', eventData);
|
|
416
|
+
} else {
|
|
417
|
+
// Store locally or queue for later
|
|
418
|
+
localStorage.setItem('pending_events', JSON.stringify([eventData]));
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Troubleshooting
|
|
423
|
+
|
|
424
|
+
### Events Not Being Stored
|
|
425
|
+
|
|
426
|
+
1. **Check worker initialization**: Ensure `initEventTracker()` completed successfully
|
|
427
|
+
2. **Verify worker files**: Make sure MCP worker files are in your public directory
|
|
428
|
+
3. **Check connection**: Use `getConnectionStatus()` to verify proxy connection
|
|
429
|
+
|
|
430
|
+
### Connection Issues
|
|
431
|
+
|
|
432
|
+
1. **Proxy server**: Verify the MCP proxy server is running at the specified WebSocket URL
|
|
433
|
+
2. **CORS**: Check browser console for CORS errors
|
|
434
|
+
3. **WebSocket**: Verify WebSocket connection in browser Developer Tools
|
|
435
|
+
|
|
436
|
+
### Memory Usage
|
|
437
|
+
|
|
438
|
+
1. **Event cleanup**: Periodically clean old events from IndexedDB
|
|
439
|
+
2. **Debouncing**: Use appropriate debouncing for high-frequency events
|
|
440
|
+
3. **Selective tracking**: Only track events that provide value to AI agents
|
|
441
|
+
|
|
442
|
+
## Requirements
|
|
443
|
+
|
|
444
|
+
- **Modern Browser**: ES2020+ support
|
|
445
|
+
- **MCP Worker Setup**: Requires [`@mcp-fe/mcp-worker`](../mcp-worker/README.md) configuration
|
|
446
|
+
- **MCP Proxy Server**: A running MCP proxy server to collect events
|
|
447
|
+
|
|
448
|
+
## Related Packages
|
|
449
|
+
|
|
450
|
+
- **[@mcp-fe/mcp-worker](../mcp-worker/README.md)**: Core MCP worker implementation
|
|
451
|
+
- **[@mcp-fe/react-event-tracker](../react-event-tracker/README.md)**: React-specific integration
|
|
452
|
+
- **[Main MCP-FE Project](../../README.md)**: Complete ecosystem documentation
|
|
453
|
+
|
|
454
|
+
## Credits
|
|
455
|
+
|
|
456
|
+
Created and maintained with ❤️ by [Michal Kopecký](https://github.com/kopecmi8).
|
|
457
|
+
|
|
458
|
+
## License
|
|
459
|
+
|
|
460
|
+
Licensed under the Apache License, Version 2.0. See the [LICENSE](../../LICENSE) file for details.
|
package/package.json
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-fe/event-tracker",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
+
"homepage": "https://mcp-fe.ai",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/mcp-fe/mcp-fe.git",
|
|
9
|
+
"directory": "libs/event-tracker"
|
|
10
|
+
},
|
|
5
11
|
"private": false,
|
|
6
12
|
"type": "module",
|
|
7
13
|
"main": "./index.js",
|
|
8
14
|
"types": "./index.d.ts",
|
|
9
15
|
"dependencies": {
|
|
10
|
-
"@mcp-fe/mcp-worker": "0.0.
|
|
16
|
+
"@mcp-fe/mcp-worker": "0.0.16"
|
|
11
17
|
},
|
|
12
18
|
"publishConfig": {
|
|
13
19
|
"access": "public"
|