contextguard 0.1.7 → 0.2.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 (60) hide show
  1. package/LICENSE +23 -17
  2. package/README.md +157 -109
  3. package/dist/agent.d.ts +24 -0
  4. package/dist/agent.js +369 -0
  5. package/dist/cli.d.ts +11 -0
  6. package/dist/cli.js +266 -0
  7. package/dist/config.d.ts +23 -0
  8. package/dist/config.js +56 -0
  9. package/dist/database.d.ts +116 -0
  10. package/dist/database.js +291 -0
  11. package/dist/index.d.ts +16 -0
  12. package/dist/index.js +18 -0
  13. package/dist/init.d.ts +7 -0
  14. package/dist/init.js +173 -0
  15. package/dist/lib/supabase-client.d.ts +27 -0
  16. package/dist/lib/supabase-client.js +97 -0
  17. package/dist/logger.d.ts +36 -0
  18. package/dist/logger.js +145 -0
  19. package/dist/mcp-security-wrapper.d.ts +84 -0
  20. package/dist/mcp-security-wrapper.js +394 -120
  21. package/dist/mcp-traceability-integration.d.ts +118 -0
  22. package/dist/mcp-traceability-integration.js +302 -0
  23. package/dist/policy.d.ts +30 -0
  24. package/dist/policy.js +273 -0
  25. package/dist/premium-features.d.ts +364 -0
  26. package/dist/premium-features.js +950 -0
  27. package/dist/security-logger.d.ts +45 -0
  28. package/dist/security-logger.js +125 -0
  29. package/dist/security-policy.d.ts +55 -0
  30. package/dist/security-policy.js +140 -0
  31. package/dist/semantic-detector.d.ts +21 -0
  32. package/dist/semantic-detector.js +49 -0
  33. package/dist/sse-proxy.d.ts +21 -0
  34. package/dist/sse-proxy.js +276 -0
  35. package/dist/supabase-client.d.ts +27 -0
  36. package/dist/supabase-client.js +89 -0
  37. package/dist/types/database.types.d.ts +220 -0
  38. package/dist/types/database.types.js +8 -0
  39. package/dist/types/mcp.d.ts +27 -0
  40. package/dist/types/mcp.js +15 -0
  41. package/dist/types/types.d.ts +65 -0
  42. package/dist/types/types.js +8 -0
  43. package/dist/types.d.ts +84 -0
  44. package/dist/types.js +8 -0
  45. package/dist/wrapper.d.ts +115 -0
  46. package/dist/wrapper.js +417 -0
  47. package/package.json +35 -10
  48. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -57
  49. package/CONTRIBUTING.md +0 -532
  50. package/SECURITY.md +0 -254
  51. package/assets/demo.mp4 +0 -0
  52. package/eslint.config.mts +0 -23
  53. package/examples/config/config.json +0 -19
  54. package/examples/mcp-server/demo.js +0 -228
  55. package/examples/mcp-server/package-lock.json +0 -978
  56. package/examples/mcp-server/package.json +0 -16
  57. package/examples/mcp-server/pnpm-lock.yaml +0 -745
  58. package/src/mcp-security-wrapper.ts +0 -529
  59. package/test/test-server.ts +0 -295
  60. package/tsconfig.json +0 -16
@@ -0,0 +1,950 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Amir Mironi
4
+ *
5
+ * Premium/Enterprise Features for ContextGuard
6
+ * These features require a valid license key
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.ContextTracker = exports.MCPTraceabilityManager = exports.SLAMonitor = exports.PrioritySupport = exports.ComplianceReporter = exports.MLDetectionEngine = exports.SSOProvider = exports.CustomRulesEngine = exports.TeamCollaboration = exports.DashboardAnalytics = exports.LicenseManager = exports.LicenseTier = void 0;
43
+ const fs = __importStar(require("fs"));
44
+ const crypto = __importStar(require("crypto"));
45
+ var LicenseTier;
46
+ (function (LicenseTier) {
47
+ LicenseTier["FREE"] = "free";
48
+ LicenseTier["PRO"] = "pro";
49
+ LicenseTier["ENTERPRISE"] = "enterprise";
50
+ })(LicenseTier || (exports.LicenseTier = LicenseTier = {}));
51
+ /**
52
+ * License Manager - Validates and manages license keys
53
+ */
54
+ class LicenseManager {
55
+ constructor(licenseFilePath = ".contextguard-license") {
56
+ this.licenseInfo = null;
57
+ this.licenseFilePath = licenseFilePath;
58
+ this.loadLicense();
59
+ }
60
+ loadLicense() {
61
+ try {
62
+ if (fs.existsSync(this.licenseFilePath)) {
63
+ const licenseData = JSON.parse(fs.readFileSync(this.licenseFilePath, "utf-8"));
64
+ this.licenseInfo = {
65
+ ...licenseData,
66
+ expiresAt: new Date(licenseData.expiresAt),
67
+ };
68
+ }
69
+ else {
70
+ // Default to free tier
71
+ this.licenseInfo = {
72
+ tier: LicenseTier.FREE,
73
+ key: "free",
74
+ expiresAt: new Date("2099-12-31"),
75
+ features: [],
76
+ };
77
+ }
78
+ }
79
+ catch (error) {
80
+ console.error("Failed to load license:", error);
81
+ this.licenseInfo = {
82
+ tier: LicenseTier.FREE,
83
+ key: "free",
84
+ expiresAt: new Date("2099-12-31"),
85
+ features: [],
86
+ };
87
+ }
88
+ }
89
+ validateLicense() {
90
+ if (!this.licenseInfo)
91
+ return false;
92
+ if (this.licenseInfo.tier === LicenseTier.FREE)
93
+ return true;
94
+ return new Date() < this.licenseInfo.expiresAt;
95
+ }
96
+ getTier() {
97
+ return this.licenseInfo?.tier || LicenseTier.FREE;
98
+ }
99
+ hasFeature(feature) {
100
+ if (!this.licenseInfo)
101
+ return false;
102
+ if (this.licenseInfo.tier === LicenseTier.FREE)
103
+ return false;
104
+ return this.licenseInfo.features.includes(feature);
105
+ }
106
+ getLicenseInfo() {
107
+ return this.licenseInfo;
108
+ }
109
+ }
110
+ exports.LicenseManager = LicenseManager;
111
+ /**
112
+ * Web Dashboard Analytics - Collects and aggregates security metrics
113
+ * PRO FEATURE
114
+ */
115
+ class DashboardAnalytics {
116
+ constructor(licenseManager) {
117
+ this.analyticsData = [];
118
+ this.maxStoredEvents = 10000;
119
+ this.licenseManager = licenseManager;
120
+ }
121
+ trackEvent(eventType, severity, metadata) {
122
+ if (!this.licenseManager.hasFeature("dashboard")) {
123
+ console.warn("Dashboard analytics requires a Pro license. Upgrade at https://contextguard.dev/pro");
124
+ return;
125
+ }
126
+ const event = {
127
+ timestamp: new Date(),
128
+ eventType,
129
+ severity,
130
+ metadata,
131
+ };
132
+ this.analyticsData.push(event);
133
+ // Keep only recent events to prevent memory issues
134
+ if (this.analyticsData.length > this.maxStoredEvents) {
135
+ this.analyticsData = this.analyticsData.slice(-this.maxStoredEvents);
136
+ }
137
+ }
138
+ getMetrics(timeRange) {
139
+ if (!this.licenseManager.hasFeature("dashboard")) {
140
+ return { error: "Dashboard analytics requires a Pro license" };
141
+ }
142
+ const now = Date.now();
143
+ const ranges = {
144
+ "1h": 60 * 60 * 1000,
145
+ "24h": 24 * 60 * 60 * 1000,
146
+ "7d": 7 * 24 * 60 * 60 * 1000,
147
+ "30d": 30 * 24 * 60 * 60 * 1000,
148
+ };
149
+ const cutoff = now - ranges[timeRange];
150
+ const filteredEvents = this.analyticsData.filter((e) => e.timestamp.getTime() > cutoff);
151
+ return {
152
+ totalEvents: filteredEvents.length,
153
+ eventsByType: this.groupBy(filteredEvents, "eventType"),
154
+ eventsBySeverity: this.groupBy(filteredEvents, "severity"),
155
+ timeline: this.getTimeline(filteredEvents),
156
+ };
157
+ }
158
+ groupBy(events, field) {
159
+ const grouped = {};
160
+ for (const event of events) {
161
+ const key = String(event[field]);
162
+ grouped[key] = (grouped[key] || 0) + 1;
163
+ }
164
+ return grouped;
165
+ }
166
+ getTimeline(events) {
167
+ const timeline = {};
168
+ for (const event of events) {
169
+ const hour = new Date(event.timestamp).toISOString().slice(0, 13);
170
+ timeline[hour] = (timeline[hour] || 0) + 1;
171
+ }
172
+ return Object.entries(timeline).map(([time, count]) => ({ time, count }));
173
+ }
174
+ }
175
+ exports.DashboardAnalytics = DashboardAnalytics;
176
+ /**
177
+ * Team Collaboration Manager
178
+ * PRO FEATURE
179
+ */
180
+ class TeamCollaboration {
181
+ constructor(licenseManager) {
182
+ this.teamMembers = new Map();
183
+ this.licenseManager = licenseManager;
184
+ }
185
+ addMember(member) {
186
+ if (!this.licenseManager.hasFeature("team-collaboration")) {
187
+ console.warn("Team collaboration requires a Pro license. Upgrade at https://contextguard.dev/pro");
188
+ return false;
189
+ }
190
+ const licenseInfo = this.licenseManager.getLicenseInfo();
191
+ if (licenseInfo?.maxUsers && this.teamMembers.size >= licenseInfo.maxUsers) {
192
+ console.warn(`Maximum team size (${licenseInfo.maxUsers}) reached`);
193
+ return false;
194
+ }
195
+ this.teamMembers.set(member.userId, member);
196
+ return true;
197
+ }
198
+ removeMember(userId) {
199
+ if (!this.licenseManager.hasFeature("team-collaboration")) {
200
+ return false;
201
+ }
202
+ return this.teamMembers.delete(userId);
203
+ }
204
+ getMember(userId) {
205
+ return this.teamMembers.get(userId);
206
+ }
207
+ listMembers() {
208
+ if (!this.licenseManager.hasFeature("team-collaboration")) {
209
+ return [];
210
+ }
211
+ return Array.from(this.teamMembers.values());
212
+ }
213
+ hasPermission(userId, permission) {
214
+ const member = this.teamMembers.get(userId);
215
+ if (!member)
216
+ return false;
217
+ return member.permissions.includes(permission) || member.role === "ADMIN";
218
+ }
219
+ }
220
+ exports.TeamCollaboration = TeamCollaboration;
221
+ /**
222
+ * Custom Detection Rules Engine
223
+ * PRO FEATURE
224
+ */
225
+ class CustomRulesEngine {
226
+ constructor(licenseManager) {
227
+ this.rules = new Map();
228
+ this.licenseManager = licenseManager;
229
+ }
230
+ addRule(rule) {
231
+ if (!this.licenseManager.hasFeature("custom-rules")) {
232
+ console.warn("Custom detection rules require a Pro license. Upgrade at https://contextguard.dev/pro");
233
+ return false;
234
+ }
235
+ this.rules.set(rule.id, rule);
236
+ return true;
237
+ }
238
+ removeRule(ruleId) {
239
+ if (!this.licenseManager.hasFeature("custom-rules")) {
240
+ return false;
241
+ }
242
+ return this.rules.delete(ruleId);
243
+ }
244
+ evaluateRules(text) {
245
+ if (!this.licenseManager.hasFeature("custom-rules")) {
246
+ return [];
247
+ }
248
+ const results = [];
249
+ for (const rule of this.rules.values()) {
250
+ if (!rule.enabled)
251
+ continue;
252
+ const matches = text.match(rule.pattern);
253
+ if (matches && matches.length > 0) {
254
+ results.push({ rule, matches: Array.from(matches) });
255
+ }
256
+ }
257
+ return results;
258
+ }
259
+ listRules() {
260
+ if (!this.licenseManager.hasFeature("custom-rules")) {
261
+ return [];
262
+ }
263
+ return Array.from(this.rules.values());
264
+ }
265
+ }
266
+ exports.CustomRulesEngine = CustomRulesEngine;
267
+ /**
268
+ * SSO/SAML Authentication Provider
269
+ * ENTERPRISE FEATURE
270
+ */
271
+ class SSOProvider {
272
+ constructor(licenseManager) {
273
+ this.samlConfig = null;
274
+ this.licenseManager = licenseManager;
275
+ }
276
+ configureSAML(config) {
277
+ if (!this.licenseManager.hasFeature("sso-saml")) {
278
+ console.warn("SSO/SAML requires an Enterprise license. Contact sales@contextguard.dev");
279
+ return false;
280
+ }
281
+ this.samlConfig = config;
282
+ return true;
283
+ }
284
+ validateSAMLToken(token) {
285
+ if (!this.licenseManager.hasFeature("sso-saml")) {
286
+ return { valid: false };
287
+ }
288
+ // Placeholder implementation
289
+ // In production, this would validate against SAML IdP
290
+ console.log("SAML token validation (placeholder):", token.substring(0, 20));
291
+ return { valid: true, userId: "saml-user-123" };
292
+ }
293
+ }
294
+ exports.SSOProvider = SSOProvider;
295
+ /**
296
+ * Advanced ML-Based Detection
297
+ * PRO FEATURE
298
+ */
299
+ class MLDetectionEngine {
300
+ constructor(licenseManager) {
301
+ this.anomalyThreshold = 0.75;
302
+ this.licenseManager = licenseManager;
303
+ }
304
+ detectAnomalies(text, _context) {
305
+ if (!this.licenseManager.hasFeature("ml-detection")) {
306
+ console.warn("ML-based detection requires a Pro license. Upgrade at https://contextguard.dev/pro");
307
+ return { isAnomaly: false, confidence: 0 };
308
+ }
309
+ // Placeholder implementation
310
+ // In production, this would use a trained ML model
311
+ const suspiciousPatterns = [
312
+ /eval\(/gi,
313
+ /exec\(/gi,
314
+ /system\(/gi,
315
+ /__import__/gi,
316
+ ];
317
+ let suspicionScore = 0;
318
+ for (const pattern of suspiciousPatterns) {
319
+ if (pattern.test(text)) {
320
+ suspicionScore += 0.3;
321
+ }
322
+ }
323
+ const isAnomaly = suspicionScore >= this.anomalyThreshold;
324
+ return {
325
+ isAnomaly,
326
+ confidence: Math.min(suspicionScore, 1.0),
327
+ reason: isAnomaly ? "Suspicious code execution patterns detected" : undefined,
328
+ };
329
+ }
330
+ }
331
+ exports.MLDetectionEngine = MLDetectionEngine;
332
+ /**
333
+ * Compliance Reporting Generator
334
+ * PRO FEATURE
335
+ */
336
+ class ComplianceReporter {
337
+ constructor(licenseManager) {
338
+ this.licenseManager = licenseManager;
339
+ }
340
+ generateReport(standard, _events) {
341
+ if (!this.licenseManager.hasFeature("compliance-reports")) {
342
+ console.warn("Compliance reports require a Pro license. Upgrade at https://contextguard.dev/pro");
343
+ return null;
344
+ }
345
+ const reportId = crypto.randomBytes(16).toString("hex");
346
+ const findings = [];
347
+ // Placeholder compliance checks
348
+ switch (standard) {
349
+ case "SOC2":
350
+ findings.push({
351
+ control: "CC6.1 - Logical Access Controls",
352
+ status: "PASS",
353
+ details: "Access controls are properly implemented",
354
+ });
355
+ findings.push({
356
+ control: "CC7.2 - System Monitoring",
357
+ status: "PASS",
358
+ details: "Security monitoring is active",
359
+ });
360
+ break;
361
+ case "GDPR":
362
+ findings.push({
363
+ control: "Article 32 - Security of Processing",
364
+ status: "PASS",
365
+ details: "Appropriate security measures in place",
366
+ });
367
+ break;
368
+ case "HIPAA":
369
+ findings.push({
370
+ control: "164.312(a)(1) - Access Control",
371
+ status: "PASS",
372
+ details: "Access controls implemented",
373
+ });
374
+ break;
375
+ }
376
+ const hasFailures = findings.some((f) => f.status === "FAIL");
377
+ const hasWarnings = findings.some((f) => f.status === "WARNING");
378
+ return {
379
+ reportId,
380
+ generatedAt: new Date(),
381
+ standard,
382
+ findings,
383
+ status: hasFailures ? "FAIL" : hasWarnings ? "WARNING" : "PASS",
384
+ };
385
+ }
386
+ exportReport(report, format) {
387
+ if (format === "JSON") {
388
+ return JSON.stringify(report, null, 2);
389
+ }
390
+ // PDF generation would require additional libraries
391
+ return `Compliance Report - ${report.standard} (PDF export requires additional setup)`;
392
+ }
393
+ }
394
+ exports.ComplianceReporter = ComplianceReporter;
395
+ /**
396
+ * Priority Support Manager
397
+ * PRO/ENTERPRISE FEATURE
398
+ */
399
+ class PrioritySupport {
400
+ constructor(licenseManager) {
401
+ this.licenseManager = licenseManager;
402
+ }
403
+ createTicket(subject, description, priority) {
404
+ if (!this.licenseManager.hasFeature("priority-support")) {
405
+ console.warn("Priority support requires a Pro license. Upgrade at https://contextguard.dev/pro");
406
+ return null;
407
+ }
408
+ const ticketId = `TICKET-${Date.now()}`;
409
+ const tier = this.licenseManager.getTier();
410
+ const slaHours = tier === LicenseTier.ENTERPRISE
411
+ ? priority === "CRITICAL"
412
+ ? "1 hour"
413
+ : "4 hours"
414
+ : "24 hours";
415
+ console.log(`Support ticket created: ${ticketId} (SLA: ${slaHours})`);
416
+ return { ticketId, sla: slaHours };
417
+ }
418
+ }
419
+ exports.PrioritySupport = PrioritySupport;
420
+ /**
421
+ * SLA Monitor
422
+ * ENTERPRISE FEATURE
423
+ */
424
+ class SLAMonitor {
425
+ constructor(licenseManager) {
426
+ this.downtimeEvents = [];
427
+ this.licenseManager = licenseManager;
428
+ this.uptimeStart = new Date();
429
+ }
430
+ recordDowntime() {
431
+ if (!this.licenseManager.hasFeature("sla-guarantees")) {
432
+ return;
433
+ }
434
+ this.downtimeEvents.push({ start: new Date() });
435
+ }
436
+ recordUptime() {
437
+ if (!this.licenseManager.hasFeature("sla-guarantees")) {
438
+ return;
439
+ }
440
+ const lastEvent = this.downtimeEvents[this.downtimeEvents.length - 1];
441
+ if (lastEvent && !lastEvent.end) {
442
+ lastEvent.end = new Date();
443
+ }
444
+ }
445
+ getUptimePercentage() {
446
+ if (!this.licenseManager.hasFeature("sla-guarantees")) {
447
+ return 0;
448
+ }
449
+ const totalTime = Date.now() - this.uptimeStart.getTime();
450
+ let totalDowntime = 0;
451
+ for (const event of this.downtimeEvents) {
452
+ const end = event.end || new Date();
453
+ totalDowntime += end.getTime() - event.start.getTime();
454
+ }
455
+ return ((totalTime - totalDowntime) / totalTime) * 100;
456
+ }
457
+ }
458
+ exports.SLAMonitor = SLAMonitor;
459
+ class MCPTraceabilityManager {
460
+ constructor(licenseManager, persistenceEnabled = true) {
461
+ this.traces = new Map();
462
+ this.maxTraces = 100000; // Keep last 100k traces in memory
463
+ this.persistenceEnabled = true;
464
+ this.licenseManager = licenseManager;
465
+ this.persistenceEnabled = persistenceEnabled;
466
+ }
467
+ /**
468
+ * Record a new trace entry
469
+ */
470
+ recordTrace(trace) {
471
+ if (!this.licenseManager.hasFeature("traceability")) {
472
+ console.warn("Traceability requires a Pro license. Upgrade at https://contextguard.dev/pro");
473
+ return null;
474
+ }
475
+ const traceId = crypto.randomBytes(16).toString("hex");
476
+ const fullTrace = {
477
+ ...trace,
478
+ traceId,
479
+ timestamp: new Date(),
480
+ };
481
+ this.traces.set(traceId, fullTrace);
482
+ // Cleanup old traces if limit exceeded
483
+ if (this.traces.size > this.maxTraces) {
484
+ const oldestKeys = Array.from(this.traces.keys()).slice(0, this.traces.size - this.maxTraces);
485
+ for (const key of oldestKeys) {
486
+ this.traces.delete(key);
487
+ }
488
+ }
489
+ // Persist to storage if enabled
490
+ if (this.persistenceEnabled) {
491
+ this.persistTrace(fullTrace).catch((err) => console.error("Failed to persist trace:", err));
492
+ }
493
+ return traceId;
494
+ }
495
+ /**
496
+ * Query traces with filters
497
+ */
498
+ queryTraces(query) {
499
+ if (!this.licenseManager.hasFeature("traceability")) {
500
+ return [];
501
+ }
502
+ let results = Array.from(this.traces.values());
503
+ // Apply filters
504
+ if (query.userId) {
505
+ results = results.filter((t) => t.userId === query.userId);
506
+ }
507
+ if (query.userIds && query.userIds.length > 0) {
508
+ results = results.filter((t) => query.userIds.includes(t.userId));
509
+ }
510
+ if (query.mcpServerName) {
511
+ results = results.filter((t) => t.mcpServerName === query.mcpServerName);
512
+ }
513
+ if (query.toolName) {
514
+ results = results.filter((t) => t.toolName === query.toolName);
515
+ }
516
+ if (query.sessionId) {
517
+ results = results.filter((t) => t.sessionId === query.sessionId);
518
+ }
519
+ if (query.status) {
520
+ results = results.filter((t) => t.status === query.status);
521
+ }
522
+ if (query.threatDetected !== undefined) {
523
+ results = results.filter((t) => t.threatDetected === query.threatDetected);
524
+ }
525
+ if (query.startDate) {
526
+ results = results.filter((t) => t.timestamp >= query.startDate);
527
+ }
528
+ if (query.endDate) {
529
+ results = results.filter((t) => t.timestamp <= query.endDate);
530
+ }
531
+ // Sort
532
+ const sortBy = query.sortBy || "timestamp";
533
+ const sortOrder = query.sortOrder || "desc";
534
+ results.sort((a, b) => {
535
+ const aVal = a[sortBy];
536
+ const bVal = b[sortBy];
537
+ const comparison = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
538
+ return sortOrder === "asc" ? comparison : -comparison;
539
+ });
540
+ // Pagination
541
+ const offset = query.offset || 0;
542
+ const limit = query.limit || 100;
543
+ return results.slice(offset, offset + limit);
544
+ }
545
+ /**
546
+ * Get trace by ID
547
+ */
548
+ getTrace(traceId) {
549
+ if (!this.licenseManager.hasFeature("traceability")) {
550
+ return null;
551
+ }
552
+ return this.traces.get(traceId) || null;
553
+ }
554
+ /**
555
+ * Get usage statistics
556
+ */
557
+ getUsageStatistics(query) {
558
+ if (!this.licenseManager.hasFeature("traceability")) {
559
+ return this.getEmptyStatistics();
560
+ }
561
+ const traces = query ? this.queryTraces(query) : Array.from(this.traces.values());
562
+ const uniqueUsers = new Set(traces.map((t) => t.userId));
563
+ const uniqueMCPServers = new Set(traces.map((t) => t.mcpServerName));
564
+ const uniqueTools = new Set(traces.map((t) => t.toolName));
565
+ // By MCP Server
566
+ const byMCPServer = {};
567
+ for (const trace of traces) {
568
+ if (!byMCPServer[trace.mcpServerName]) {
569
+ byMCPServer[trace.mcpServerName] = {
570
+ count: 0,
571
+ successRate: 0,
572
+ avgExecutionTimeMs: 0,
573
+ totalTokensUsed: 0,
574
+ };
575
+ }
576
+ const stats = byMCPServer[trace.mcpServerName];
577
+ stats.count++;
578
+ stats.avgExecutionTimeMs += trace.executionTimeMs;
579
+ stats.totalTokensUsed += trace.tokensUsed || 0;
580
+ if (trace.status === "success") {
581
+ stats.successRate++;
582
+ }
583
+ }
584
+ // Calculate averages and percentages
585
+ for (const serverName in byMCPServer) {
586
+ const stats = byMCPServer[serverName];
587
+ stats.avgExecutionTimeMs /= stats.count;
588
+ stats.successRate = (stats.successRate / stats.count) * 100;
589
+ }
590
+ // By Tool
591
+ const byTool = {};
592
+ for (const trace of traces) {
593
+ if (!byTool[trace.toolName]) {
594
+ byTool[trace.toolName] = {
595
+ count: 0,
596
+ successRate: 0,
597
+ avgExecutionTimeMs: 0,
598
+ };
599
+ }
600
+ const stats = byTool[trace.toolName];
601
+ stats.count++;
602
+ stats.avgExecutionTimeMs += trace.executionTimeMs;
603
+ if (trace.status === "success") {
604
+ stats.successRate++;
605
+ }
606
+ }
607
+ for (const toolName in byTool) {
608
+ const stats = byTool[toolName];
609
+ stats.avgExecutionTimeMs /= stats.count;
610
+ stats.successRate = (stats.successRate / stats.count) * 100;
611
+ }
612
+ // By User
613
+ const byUser = {};
614
+ for (const trace of traces) {
615
+ if (!byUser[trace.userId]) {
616
+ byUser[trace.userId] = {
617
+ count: 0,
618
+ mcpServersUsed: [],
619
+ toolsUsed: [],
620
+ totalExecutionTimeMs: 0,
621
+ };
622
+ }
623
+ const stats = byUser[trace.userId];
624
+ stats.count++;
625
+ stats.totalExecutionTimeMs += trace.executionTimeMs;
626
+ if (!stats.mcpServersUsed.includes(trace.mcpServerName)) {
627
+ stats.mcpServersUsed.push(trace.mcpServerName);
628
+ }
629
+ if (!stats.toolsUsed.includes(trace.toolName)) {
630
+ stats.toolsUsed.push(trace.toolName);
631
+ }
632
+ }
633
+ // Security events
634
+ const securityEvents = {
635
+ totalThreats: traces.filter((t) => t.threatDetected).length,
636
+ threatsBySeverity: {},
637
+ blockedRequests: traces.filter((t) => t.status === "blocked").length,
638
+ };
639
+ // Timeline (hourly buckets)
640
+ const timeline = [];
641
+ const timelineBuckets = {};
642
+ for (const trace of traces) {
643
+ const hour = new Date(trace.timestamp).toISOString().slice(0, 13);
644
+ if (!timelineBuckets[hour]) {
645
+ timelineBuckets[hour] = { count: 0, success: 0, failure: 0 };
646
+ }
647
+ timelineBuckets[hour].count++;
648
+ if (trace.status === "success") {
649
+ timelineBuckets[hour].success++;
650
+ }
651
+ else {
652
+ timelineBuckets[hour].failure++;
653
+ }
654
+ }
655
+ for (const [hour, data] of Object.entries(timelineBuckets)) {
656
+ timeline.push({
657
+ timestamp: new Date(hour),
658
+ count: data.count,
659
+ successCount: data.success,
660
+ failureCount: data.failure,
661
+ });
662
+ }
663
+ timeline.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
664
+ return {
665
+ totalTraces: traces.length,
666
+ uniqueUsers: uniqueUsers.size,
667
+ uniqueMCPServers: uniqueMCPServers.size,
668
+ uniqueTools: uniqueTools.size,
669
+ byMCPServer,
670
+ byTool,
671
+ byUser,
672
+ securityEvents,
673
+ timeline,
674
+ };
675
+ }
676
+ /**
677
+ * Export traces for compliance/audit
678
+ */
679
+ exportTraces(query, format) {
680
+ if (!this.licenseManager.hasFeature("traceability")) {
681
+ return "";
682
+ }
683
+ const traces = this.queryTraces(query);
684
+ if (format === "JSON") {
685
+ return JSON.stringify(traces, null, 2);
686
+ }
687
+ else {
688
+ // CSV format
689
+ const headers = [
690
+ "traceId",
691
+ "timestamp",
692
+ "userId",
693
+ "mcpServerName",
694
+ "toolName",
695
+ "status",
696
+ "executionTimeMs",
697
+ "threatDetected",
698
+ ];
699
+ const rows = traces.map((t) => [
700
+ t.traceId,
701
+ t.timestamp.toISOString(),
702
+ t.userId,
703
+ t.mcpServerName,
704
+ t.toolName,
705
+ t.status,
706
+ t.executionTimeMs.toString(),
707
+ t.threatDetected.toString(),
708
+ ]);
709
+ return [
710
+ headers.join(","),
711
+ ...rows.map((row) => row.join(",")),
712
+ ].join("\n");
713
+ }
714
+ }
715
+ /**
716
+ * Get user activity timeline
717
+ */
718
+ getUserActivityTimeline(userId, startDate, endDate) {
719
+ return this.queryTraces({
720
+ userId,
721
+ startDate,
722
+ endDate,
723
+ sortBy: "timestamp",
724
+ sortOrder: "asc",
725
+ });
726
+ }
727
+ /**
728
+ * Detect anomalous usage patterns
729
+ */
730
+ detectAnomalies(userId) {
731
+ if (!this.licenseManager.hasFeature("traceability")) {
732
+ return [];
733
+ }
734
+ const anomalies = [];
735
+ const traces = userId
736
+ ? this.queryTraces({ userId })
737
+ : Array.from(this.traces.values());
738
+ // Detect high failure rate
739
+ const failureRate = traces.filter((t) => t.status === "failure").length / traces.length;
740
+ if (failureRate > 0.3) {
741
+ anomalies.push({
742
+ type: "high_failure_rate",
743
+ severity: "HIGH",
744
+ description: `High failure rate detected: ${(failureRate * 100).toFixed(1)}%`,
745
+ traces: traces.filter((t) => t.status === "failure"),
746
+ });
747
+ }
748
+ // Detect unusual tool usage
749
+ const toolCounts = {};
750
+ for (const trace of traces) {
751
+ toolCounts[trace.toolName] = (toolCounts[trace.toolName] || 0) + 1;
752
+ }
753
+ const avgToolUsage = Object.values(toolCounts).reduce((a, b) => a + b, 0) /
754
+ Object.keys(toolCounts).length;
755
+ for (const [tool, count] of Object.entries(toolCounts)) {
756
+ if (count > avgToolUsage * 5) {
757
+ anomalies.push({
758
+ type: "unusual_tool_usage",
759
+ severity: "MEDIUM",
760
+ description: `Tool "${tool}" used ${count} times (${(count / avgToolUsage).toFixed(1)}x average)`,
761
+ traces: traces.filter((t) => t.toolName === tool),
762
+ });
763
+ }
764
+ }
765
+ // Detect security threats
766
+ const threatsDetected = traces.filter((t) => t.threatDetected);
767
+ if (threatsDetected.length > 0) {
768
+ anomalies.push({
769
+ type: "security_threats",
770
+ severity: "HIGH",
771
+ description: `${threatsDetected.length} security threats detected`,
772
+ traces: threatsDetected,
773
+ });
774
+ }
775
+ return anomalies;
776
+ }
777
+ async persistTrace(trace) {
778
+ // In production, this would write to a database
779
+ // For now, we'll append to a log file
780
+ const logEntry = JSON.stringify(trace) + "\n";
781
+ fs.appendFileSync("mcp_traces.log", logEntry);
782
+ }
783
+ getEmptyStatistics() {
784
+ return {
785
+ totalTraces: 0,
786
+ uniqueUsers: 0,
787
+ uniqueMCPServers: 0,
788
+ uniqueTools: 0,
789
+ byMCPServer: {},
790
+ byTool: {},
791
+ byUser: {},
792
+ securityEvents: {
793
+ totalThreats: 0,
794
+ threatsBySeverity: {},
795
+ blockedRequests: 0,
796
+ },
797
+ timeline: [],
798
+ };
799
+ }
800
+ }
801
+ exports.MCPTraceabilityManager = MCPTraceabilityManager;
802
+ /**
803
+ * Context Tracker - Track context usage and data flow
804
+ * PRO FEATURE
805
+ */
806
+ class ContextTracker {
807
+ constructor(licenseManager) {
808
+ this.activeContexts = new Map();
809
+ this.licenseManager = licenseManager;
810
+ }
811
+ /**
812
+ * Start tracking context for a session
813
+ */
814
+ startTracking(sessionId) {
815
+ if (!this.licenseManager.hasFeature("traceability")) {
816
+ return;
817
+ }
818
+ this.activeContexts.set(sessionId, {
819
+ filesAccessed: [],
820
+ envVarsAccessed: [],
821
+ externalApisCalled: [],
822
+ databaseQueries: [],
823
+ });
824
+ }
825
+ /**
826
+ * Record file access
827
+ */
828
+ recordFileAccess(sessionId, path, operation, size) {
829
+ if (!this.licenseManager.hasFeature("traceability")) {
830
+ return;
831
+ }
832
+ const context = this.activeContexts.get(sessionId);
833
+ if (context) {
834
+ context.filesAccessed.push({ path, operation, size });
835
+ }
836
+ }
837
+ /**
838
+ * Record environment variable access
839
+ */
840
+ recordEnvVarAccess(sessionId, varName) {
841
+ if (!this.licenseManager.hasFeature("traceability")) {
842
+ return;
843
+ }
844
+ const context = this.activeContexts.get(sessionId);
845
+ if (context && !context.envVarsAccessed.includes(varName)) {
846
+ context.envVarsAccessed.push(varName);
847
+ }
848
+ }
849
+ /**
850
+ * Record external API call
851
+ */
852
+ recordApiCall(sessionId, url, method, statusCode) {
853
+ if (!this.licenseManager.hasFeature("traceability")) {
854
+ return;
855
+ }
856
+ const context = this.activeContexts.get(sessionId);
857
+ if (context) {
858
+ context.externalApisCalled.push({ url, method, statusCode });
859
+ }
860
+ }
861
+ /**
862
+ * Record database query
863
+ */
864
+ recordDatabaseQuery(sessionId, query, database, rowsAffected) {
865
+ if (!this.licenseManager.hasFeature("traceability")) {
866
+ return;
867
+ }
868
+ const context = this.activeContexts.get(sessionId);
869
+ if (context) {
870
+ if (!context.databaseQueries) {
871
+ context.databaseQueries = [];
872
+ }
873
+ context.databaseQueries.push({ query, database, rowsAffected });
874
+ }
875
+ }
876
+ /**
877
+ * Get context snapshot
878
+ */
879
+ getContextSnapshot(sessionId) {
880
+ if (!this.licenseManager.hasFeature("traceability")) {
881
+ return null;
882
+ }
883
+ return this.activeContexts.get(sessionId) || null;
884
+ }
885
+ /**
886
+ * Stop tracking and return final snapshot
887
+ */
888
+ stopTracking(sessionId) {
889
+ if (!this.licenseManager.hasFeature("traceability")) {
890
+ return null;
891
+ }
892
+ const context = this.activeContexts.get(sessionId);
893
+ this.activeContexts.delete(sessionId);
894
+ return context || null;
895
+ }
896
+ /**
897
+ * Analyze context for security risks
898
+ */
899
+ analyzeContextSecurity(context) {
900
+ if (!this.licenseManager.hasFeature("traceability")) {
901
+ return [];
902
+ }
903
+ const risks = [];
904
+ // Check for sensitive file access
905
+ const sensitiveFiles = context.filesAccessed.filter((f) => f.path.includes(".env") ||
906
+ f.path.includes("secret") ||
907
+ f.path.includes("password") ||
908
+ f.path.includes(".ssh") ||
909
+ f.path.includes("credentials"));
910
+ if (sensitiveFiles.length > 0) {
911
+ risks.push({
912
+ risk: "sensitive_file_access",
913
+ severity: "HIGH",
914
+ details: `Accessed ${sensitiveFiles.length} sensitive files`,
915
+ });
916
+ }
917
+ // Check for excessive file writes
918
+ const writeOperations = context.filesAccessed.filter((f) => f.operation === "write" || f.operation === "delete");
919
+ if (writeOperations.length > 50) {
920
+ risks.push({
921
+ risk: "excessive_file_writes",
922
+ severity: "MEDIUM",
923
+ details: `Performed ${writeOperations.length} write/delete operations`,
924
+ });
925
+ }
926
+ // Check for external API calls to unknown domains
927
+ const externalCalls = context.externalApisCalled.filter((api) => !api.url.includes("localhost") && !api.url.includes("127.0.0.1"));
928
+ if (externalCalls.length > 0) {
929
+ risks.push({
930
+ risk: "external_api_calls",
931
+ severity: "MEDIUM",
932
+ details: `Made ${externalCalls.length} external API calls`,
933
+ });
934
+ }
935
+ // Check for sensitive environment variables
936
+ const sensitiveEnvVars = context.envVarsAccessed.filter((v) => v.includes("KEY") ||
937
+ v.includes("SECRET") ||
938
+ v.includes("TOKEN") ||
939
+ v.includes("PASSWORD"));
940
+ if (sensitiveEnvVars.length > 0) {
941
+ risks.push({
942
+ risk: "sensitive_env_access",
943
+ severity: "HIGH",
944
+ details: `Accessed ${sensitiveEnvVars.length} sensitive environment variables`,
945
+ });
946
+ }
947
+ return risks;
948
+ }
949
+ }
950
+ exports.ContextTracker = ContextTracker;