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,65 @@
1
+ /**
2
+ * Copyright (c) 2025 Amir Mironi
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ /**
8
+ * Re-export AgentPolicy from database types
9
+ */
10
+ export type { AgentPolicy } from "./database.types";
11
+ /**
12
+ * Security event severity levels
13
+ */
14
+ export type SecuritySeverity = "LOW" | "MEDIUM" | "HIGH" | "CRITICAL";
15
+ /**
16
+ * Security event logged by the system
17
+ */
18
+ export interface SecurityEvent {
19
+ /** ISO timestamp of the event */
20
+ timestamp: string;
21
+ /** Type of security event */
22
+ eventType: string;
23
+ /** Severity level */
24
+ severity: SecuritySeverity;
25
+ /** Additional event details */
26
+ details: Record<string, unknown>;
27
+ /** Session identifier */
28
+ sessionId: string;
29
+ }
30
+ /**
31
+ * MCP JSON-RPC message structure
32
+ */
33
+ export interface MCPMessage {
34
+ /** JSON-RPC version */
35
+ jsonrpc: string;
36
+ /** Request/response ID */
37
+ id?: string | number;
38
+ /** Method name for requests */
39
+ method?: string;
40
+ /** Method parameters */
41
+ params?: {
42
+ name?: string;
43
+ arguments?: Record<string, string>;
44
+ path?: string;
45
+ filePath?: string;
46
+ [key: string]: unknown;
47
+ };
48
+ /** Response result */
49
+ result?: unknown;
50
+ /** Error object */
51
+ error?: unknown;
52
+ }
53
+ /**
54
+ * Statistics about security events
55
+ */
56
+ export interface SecurityStatistics {
57
+ /** Total number of events logged */
58
+ totalEvents: number;
59
+ /** Events grouped by type */
60
+ eventsByType: Record<string, number>;
61
+ /** Events grouped by severity */
62
+ eventsBySeverity: Record<string, number>;
63
+ /** Most recent events */
64
+ recentEvents: SecurityEvent[];
65
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Amir Mironi
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Copyright (c) 2025 Amir Mironi
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ /**
8
+ * Security configuration options for the MCP wrapper
9
+ */
10
+ export interface CgPolicyType {
11
+ /** Maximum number of tool calls allowed per minute (default: 30) */
12
+ maxToolCallsPerMinute?: number;
13
+ /** Patterns to block in tool calls */
14
+ blockedPatterns?: string[];
15
+ /** Allowed file paths for file operations (empty = all allowed) */
16
+ allowedFilePaths?: string[];
17
+ /** Number of violations before triggering alerts (default: 5) */
18
+ alertThreshold?: number;
19
+ /** Enable prompt injection detection (default: true) */
20
+ enablePromptInjectionDetection?: boolean;
21
+ /** Enable sensitive data detection (default: true) */
22
+ enableSensitiveDataDetection?: boolean;
23
+ /** Path to security log file */
24
+ logPath?: string;
25
+ /** Enable pro features (requires license) */
26
+ enableProFeatures?: boolean;
27
+ /** License file path for pro features */
28
+ licenseFilePath?: string;
29
+ }
30
+ /**
31
+ * Security event severity levels
32
+ */
33
+ export type SecuritySeverity = "LOW" | "MEDIUM" | "HIGH" | "CRITICAL";
34
+ /**
35
+ * Security event logged by the system
36
+ */
37
+ export interface SecurityEvent {
38
+ /** ISO timestamp of the event */
39
+ timestamp: string;
40
+ /** Type of security event */
41
+ eventType: string;
42
+ /** Severity level */
43
+ severity: SecuritySeverity;
44
+ /** Additional event details */
45
+ details: Record<string, unknown>;
46
+ /** Session identifier */
47
+ sessionId: string;
48
+ }
49
+ /**
50
+ * MCP JSON-RPC message structure
51
+ */
52
+ export interface MCPMessage {
53
+ /** JSON-RPC version */
54
+ jsonrpc: string;
55
+ /** Request/response ID */
56
+ id?: string | number;
57
+ /** Method name for requests */
58
+ method?: string;
59
+ /** Method parameters */
60
+ params?: {
61
+ name?: string;
62
+ arguments?: Record<string, string>;
63
+ path?: string;
64
+ filePath?: string;
65
+ [key: string]: unknown;
66
+ };
67
+ /** Response result */
68
+ result?: unknown;
69
+ /** Error object */
70
+ error?: unknown;
71
+ }
72
+ /**
73
+ * Statistics about security events
74
+ */
75
+ export interface SecurityStatistics {
76
+ /** Total number of events logged */
77
+ totalEvents: number;
78
+ /** Events grouped by type */
79
+ eventsByType: Record<string, number>;
80
+ /** Events grouped by severity */
81
+ eventsBySeverity: Record<string, number>;
82
+ /** Most recent events */
83
+ recentEvents: SecurityEvent[];
84
+ }
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Amir Mironi
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Copyright (c) 2025 Amir Mironi
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { SecurityConfig } from "./types";
8
+ import { SecurityLogger } from "./security-logger";
9
+ import { MCPTraceabilityManager } from "./premium-features";
10
+ /**
11
+ * MCP Security Wrapper
12
+ * Wraps MCP servers with security monitoring and optional pro features
13
+ */
14
+ export declare class MCPSecurityWrapper {
15
+ private serverCommand;
16
+ private policy;
17
+ private logger;
18
+ private process;
19
+ private toolCallTimestamps;
20
+ private sessionId;
21
+ private clientMessageBuffer;
22
+ private serverMessageBuffer;
23
+ private licenseManager?;
24
+ private traceabilityManager?;
25
+ private contextTracker?;
26
+ private proFeaturesEnabled;
27
+ private databaseReporter?;
28
+ private databaseEnabled;
29
+ constructor(serverCommand: string[], config?: SecurityConfig);
30
+ /**
31
+ * Generate a unique session ID
32
+ * @returns 8-character hex session ID
33
+ */
34
+ private generateSessionId;
35
+ /**
36
+ * Initialize pro features if license is valid
37
+ * @param licenseFilePath - Path to license file
38
+ */
39
+ private initializeProFeatures;
40
+ /**
41
+ * Initialize database reporting for UI integration
42
+ * @param dbConfig - Database configuration
43
+ */
44
+ private initializeDatabaseReporting;
45
+ /**
46
+ * Start the MCP server wrapper
47
+ */
48
+ start(): Promise<void>;
49
+ /**
50
+ * Handle client input (buffered line-by-line)
51
+ * @param input - Raw input from client
52
+ */
53
+ private handleClientInput;
54
+ /**
55
+ * Process a single client message
56
+ * @param line - JSON-RPC message line
57
+ */
58
+ private processClientMessage;
59
+ /**
60
+ * Handle tool call with security checks and traceability
61
+ * @param message - MCP message
62
+ * @returns Violations and block status
63
+ */
64
+ private handleToolCall;
65
+ /**
66
+ * Extract file paths from message parameters
67
+ * @param message - MCP message
68
+ * @returns Array of file paths
69
+ */
70
+ private extractFilePaths;
71
+ /**
72
+ * Handle security violations
73
+ * @param message - Original message
74
+ * @param violations - List of violations
75
+ * @param shouldBlock - Whether to block the request
76
+ */
77
+ private handleViolations;
78
+ /**
79
+ * Handle parse errors
80
+ * @param err - Error object
81
+ * @param line - Original line that failed to parse
82
+ */
83
+ private handleParseError;
84
+ /**
85
+ * Handle server output (buffered line-by-line)
86
+ * @param output - Raw output from server
87
+ */
88
+ private handleServerOutput;
89
+ /**
90
+ * Process a single server message
91
+ * @param line - JSON-RPC message line
92
+ */
93
+ private processServerMessage;
94
+ /**
95
+ * Handle sensitive data leak in server response
96
+ * @param message - Server message
97
+ * @param violations - List of violations
98
+ */
99
+ private handleSensitiveDataLeak;
100
+ /**
101
+ * Handle process exit
102
+ * @param code - Exit code
103
+ */
104
+ private handleProcessExit;
105
+ /**
106
+ * Get the security logger instance
107
+ * @returns SecurityLogger instance
108
+ */
109
+ getLogger(): SecurityLogger;
110
+ /**
111
+ * Get the traceability manager (pro feature)
112
+ * @returns MCPTraceabilityManager instance or undefined
113
+ */
114
+ getTraceabilityManager(): MCPTraceabilityManager | undefined;
115
+ }
@@ -0,0 +1,417 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Amir Mironi
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.MCPSecurityWrapper = void 0;
10
+ const child_process_1 = require("child_process");
11
+ const crypto_1 = require("crypto");
12
+ const security_policy_1 = require("./security-policy");
13
+ const security_logger_1 = require("./security-logger");
14
+ const config_1 = require("./config");
15
+ const premium_features_1 = require("./premium-features");
16
+ const database_1 = require("./database");
17
+ /**
18
+ * MCP Security Wrapper
19
+ * Wraps MCP servers with security monitoring and optional pro features
20
+ */
21
+ class MCPSecurityWrapper {
22
+ constructor(serverCommand, config = {}) {
23
+ this.process = null;
24
+ this.toolCallTimestamps = [];
25
+ this.clientMessageBuffer = "";
26
+ this.serverMessageBuffer = "";
27
+ this.proFeaturesEnabled = false;
28
+ this.databaseEnabled = false;
29
+ const fullConfig = (0, config_1.mergeConfig)(config);
30
+ this.serverCommand = serverCommand;
31
+ this.policy = new security_policy_1.SecurityPolicy(fullConfig);
32
+ this.logger = new security_logger_1.SecurityLogger(fullConfig.logPath);
33
+ this.sessionId = this.generateSessionId();
34
+ // Initialize pro features if enabled
35
+ if (fullConfig.enableProFeatures) {
36
+ this.initializeProFeatures(fullConfig.licenseFilePath);
37
+ }
38
+ // Initialize database reporting if enabled
39
+ if (fullConfig.enableDatabaseReporting) {
40
+ this.initializeDatabaseReporting(fullConfig.database);
41
+ }
42
+ }
43
+ /**
44
+ * Generate a unique session ID
45
+ * @returns 8-character hex session ID
46
+ */
47
+ generateSessionId() {
48
+ return (0, crypto_1.createHash)("md5")
49
+ .update(Date.now().toString())
50
+ .digest("hex")
51
+ .substring(0, 8);
52
+ }
53
+ /**
54
+ * Initialize pro features if license is valid
55
+ * @param licenseFilePath - Path to license file
56
+ */
57
+ initializeProFeatures(licenseFilePath) {
58
+ try {
59
+ this.licenseManager = new premium_features_1.LicenseManager(licenseFilePath);
60
+ if (this.licenseManager.validateLicense()) {
61
+ this.proFeaturesEnabled = true;
62
+ this.traceabilityManager = new premium_features_1.MCPTraceabilityManager(this.licenseManager);
63
+ this.contextTracker = new premium_features_1.ContextTracker(this.licenseManager);
64
+ console.log(`✓ Pro features enabled (${this.licenseManager.getTier()} tier)`);
65
+ }
66
+ else {
67
+ console.warn("⚠ Invalid or expired license. Pro features disabled.");
68
+ }
69
+ }
70
+ catch (error) {
71
+ console.warn("⚠ Failed to initialize pro features:", error);
72
+ }
73
+ }
74
+ /**
75
+ * Initialize database reporting for UI integration
76
+ * @param dbConfig - Database configuration
77
+ */
78
+ initializeDatabaseReporting(dbConfig) {
79
+ try {
80
+ const databaseConfig = {
81
+ type: dbConfig.type || "json",
82
+ dbPath: dbConfig.path,
83
+ batchSize: dbConfig.batchSize,
84
+ flushIntervalMs: dbConfig.flushIntervalMs,
85
+ enabled: true,
86
+ };
87
+ this.databaseReporter = database_1.DatabaseReporterFactory.create(databaseConfig);
88
+ this.databaseEnabled = true;
89
+ console.log(`✓ Database reporting enabled (${databaseConfig.type})`);
90
+ }
91
+ catch (error) {
92
+ console.warn("⚠ Failed to initialize database reporting:", error);
93
+ }
94
+ }
95
+ /**
96
+ * Start the MCP server wrapper
97
+ */
98
+ async start() {
99
+ this.process = (0, child_process_1.spawn)(this.serverCommand[0], this.serverCommand.slice(1), {
100
+ stdio: ["pipe", "pipe", "pipe"],
101
+ });
102
+ if (!this.process.stdout || !this.process.stdin || !this.process.stderr) {
103
+ throw new Error("Failed to create child process streams");
104
+ }
105
+ this.logger.logEvent("SERVER_START", "LOW", {
106
+ command: this.serverCommand.join(" "),
107
+ pid: this.process.pid,
108
+ proFeaturesEnabled: this.proFeaturesEnabled,
109
+ }, this.sessionId);
110
+ // Pipe stderr to parent process
111
+ this.process.stderr.pipe(process.stderr);
112
+ // Handle server output
113
+ this.process.stdout.on("data", (data) => {
114
+ const output = data.toString();
115
+ this.handleServerOutput(output);
116
+ });
117
+ // Handle client input
118
+ process.stdin.on("data", (data) => {
119
+ const input = data.toString();
120
+ this.handleClientInput(input);
121
+ });
122
+ // Handle process exit
123
+ this.process.on("exit", (code) => {
124
+ this.handleProcessExit(code);
125
+ });
126
+ // Handle process errors
127
+ this.process.on("error", (err) => {
128
+ this.logger.logEvent("SERVER_ERROR", "HIGH", { error: err.message }, this.sessionId);
129
+ console.error("Server process error:", err);
130
+ });
131
+ }
132
+ /**
133
+ * Handle client input (buffered line-by-line)
134
+ * @param input - Raw input from client
135
+ */
136
+ handleClientInput(input) {
137
+ this.clientMessageBuffer += input;
138
+ const lines = this.clientMessageBuffer.split("\n");
139
+ this.clientMessageBuffer = lines.pop() || "";
140
+ for (const line of lines) {
141
+ if (line.trim()) {
142
+ this.processClientMessage(line);
143
+ }
144
+ }
145
+ }
146
+ /**
147
+ * Process a single client message
148
+ * @param line - JSON-RPC message line
149
+ */
150
+ processClientMessage(line) {
151
+ try {
152
+ const message = JSON.parse(line);
153
+ this.logger.logEvent("CLIENT_REQUEST", "LOW", {
154
+ method: message.method,
155
+ id: message.id,
156
+ }, this.sessionId);
157
+ const violations = [];
158
+ let shouldBlock = false;
159
+ // Handle tool calls with security checks
160
+ if (message.method === "tools/call") {
161
+ const result = this.handleToolCall(message);
162
+ violations.push(...result.violations);
163
+ shouldBlock = result.shouldBlock;
164
+ }
165
+ // Handle violations
166
+ if (violations.length > 0) {
167
+ this.handleViolations(message, violations, shouldBlock);
168
+ if (shouldBlock) {
169
+ return; // Don't forward blocked requests
170
+ }
171
+ }
172
+ // Forward to server
173
+ if (this.process && this.process.stdin) {
174
+ this.process.stdin.write(line + "\n");
175
+ }
176
+ }
177
+ catch (err) {
178
+ this.handleParseError(err, line);
179
+ // Forward unparseable messages
180
+ if (this.process && this.process.stdin) {
181
+ this.process.stdin.write(line + "\n");
182
+ }
183
+ }
184
+ }
185
+ /**
186
+ * Handle tool call with security checks and traceability
187
+ * @param message - MCP message
188
+ * @returns Violations and block status
189
+ */
190
+ handleToolCall(message) {
191
+ const violations = [];
192
+ let shouldBlock = false;
193
+ // Rate limiting
194
+ const now = Date.now();
195
+ this.toolCallTimestamps.push(now);
196
+ // Clean up old timestamps
197
+ const oneMinuteAgo = now - 60000;
198
+ this.toolCallTimestamps = this.toolCallTimestamps.filter((t) => t > oneMinuteAgo);
199
+ if (!this.policy.checkRateLimit(this.toolCallTimestamps)) {
200
+ violations.push("Rate limit exceeded for tool calls");
201
+ shouldBlock = true;
202
+ this.logger.logEvent("RATE_LIMIT_EXCEEDED", "HIGH", {
203
+ method: message.method,
204
+ toolName: message.params?.name,
205
+ }, this.sessionId);
206
+ }
207
+ // Check parameters for security issues
208
+ const paramsStr = JSON.stringify(message.params);
209
+ violations.push(...this.policy.checkPromptInjection(paramsStr));
210
+ violations.push(...this.policy.checkSensitiveData(paramsStr));
211
+ // Check file paths
212
+ const filePathParams = this.extractFilePaths(message);
213
+ for (const filePath of filePathParams) {
214
+ violations.push(...this.policy.checkFileAccess(filePath));
215
+ // Track file access in pro features
216
+ if (this.contextTracker) {
217
+ this.contextTracker.recordFileAccess(this.sessionId, filePath, "read");
218
+ }
219
+ }
220
+ // Log tool call
221
+ this.logger.logEvent("TOOL_CALL", violations.length > 0 ? "HIGH" : "LOW", {
222
+ toolName: message.params?.name,
223
+ hasViolations: violations.length > 0,
224
+ violations,
225
+ }, this.sessionId);
226
+ // Report to database if enabled
227
+ if (this.databaseEnabled && this.databaseReporter) {
228
+ this.databaseReporter.reportToolCall(this.sessionId, message.params?.name || "unknown", message.params || {}, violations, shouldBlock).catch(err => console.error("Database reporting error:", err));
229
+ }
230
+ return { violations, shouldBlock };
231
+ }
232
+ /**
233
+ * Extract file paths from message parameters
234
+ * @param message - MCP message
235
+ * @returns Array of file paths
236
+ */
237
+ extractFilePaths(message) {
238
+ return [
239
+ message.params?.arguments?.path,
240
+ message.params?.arguments?.filePath,
241
+ message.params?.arguments?.file,
242
+ message.params?.arguments?.directory,
243
+ message.params?.path,
244
+ message.params?.filePath,
245
+ ].filter((path) => typeof path === "string");
246
+ }
247
+ /**
248
+ * Handle security violations
249
+ * @param message - Original message
250
+ * @param violations - List of violations
251
+ * @param shouldBlock - Whether to block the request
252
+ */
253
+ handleViolations(message, violations, shouldBlock) {
254
+ const event = {
255
+ timestamp: new Date().toISOString(),
256
+ sessionId: this.sessionId,
257
+ eventType: "SECURITY_VIOLATION",
258
+ severity: "CRITICAL",
259
+ details: {
260
+ violations,
261
+ message: message,
262
+ blocked: shouldBlock,
263
+ },
264
+ };
265
+ this.logger.logEvent(event.eventType, event.severity, event.details, event.sessionId);
266
+ // Report to database if enabled
267
+ if (this.databaseEnabled && this.databaseReporter) {
268
+ this.databaseReporter.reportEvent(event, {
269
+ method: message.method,
270
+ toolName: message.params?.name,
271
+ }).catch(err => console.error("Database reporting error:", err));
272
+ }
273
+ console.error(`\n⚠️ SECURITY VIOLATIONS DETECTED:\n${violations.join("\n")}\n`);
274
+ if (shouldBlock) {
275
+ console.error("🚫 REQUEST BLOCKED\n");
276
+ // Send error response
277
+ if (message.id !== undefined) {
278
+ const errorResponse = {
279
+ jsonrpc: message.jsonrpc,
280
+ id: message.id,
281
+ error: {
282
+ code: -32000,
283
+ message: "Security violation: Request blocked",
284
+ data: { violations },
285
+ },
286
+ };
287
+ process.stdout.write(JSON.stringify(errorResponse) + "\n");
288
+ }
289
+ }
290
+ }
291
+ /**
292
+ * Handle parse errors
293
+ * @param err - Error object
294
+ * @param line - Original line that failed to parse
295
+ */
296
+ handleParseError(err, line) {
297
+ this.logger.logEvent("PARSE_ERROR", "MEDIUM", {
298
+ error: err instanceof Error ? err.message : String(err),
299
+ line: line.substring(0, 100),
300
+ }, this.sessionId);
301
+ console.error(`Failed to parse client message: ${err}`);
302
+ }
303
+ /**
304
+ * Handle server output (buffered line-by-line)
305
+ * @param output - Raw output from server
306
+ */
307
+ handleServerOutput(output) {
308
+ this.serverMessageBuffer += output;
309
+ const lines = this.serverMessageBuffer.split("\n");
310
+ this.serverMessageBuffer = lines.pop() || "";
311
+ for (const line of lines) {
312
+ if (line.trim()) {
313
+ this.processServerMessage(line);
314
+ }
315
+ }
316
+ }
317
+ /**
318
+ * Process a single server message
319
+ * @param line - JSON-RPC message line
320
+ */
321
+ processServerMessage(line) {
322
+ let shouldForward = true;
323
+ try {
324
+ const message = JSON.parse(line);
325
+ // Check for sensitive data in response
326
+ const violations = [];
327
+ const responseStr = JSON.stringify(message.result || message);
328
+ violations.push(...this.policy.checkSensitiveData(responseStr));
329
+ if (violations.length > 0) {
330
+ this.handleSensitiveDataLeak(message, violations);
331
+ shouldForward = false;
332
+ }
333
+ else {
334
+ this.logger.logEvent("SERVER_RESPONSE", "LOW", {
335
+ id: message.id,
336
+ hasError: !!message.error,
337
+ }, this.sessionId);
338
+ }
339
+ }
340
+ catch (err) {
341
+ // Log parse errors for server output
342
+ this.logger.logEvent("SERVER_PARSE_ERROR", "LOW", {
343
+ error: err instanceof Error ? err.message : String(err),
344
+ line: line.substring(0, 100),
345
+ }, this.sessionId);
346
+ }
347
+ // Forward the line if not blocked
348
+ if (shouldForward) {
349
+ process.stdout.write(line + "\n");
350
+ }
351
+ }
352
+ /**
353
+ * Handle sensitive data leak in server response
354
+ * @param message - Server message
355
+ * @param violations - List of violations
356
+ */
357
+ handleSensitiveDataLeak(message, violations) {
358
+ this.logger.logEvent("SENSITIVE_DATA_LEAK", "CRITICAL", {
359
+ violations,
360
+ responseId: message.id,
361
+ }, this.sessionId);
362
+ console.error(`\n🚨 SENSITIVE DATA DETECTED IN RESPONSE:\n${violations.join("\n")}\n`);
363
+ console.error("🚫 RESPONSE BLOCKED\n");
364
+ // Send sanitized error response
365
+ if (message.id !== undefined) {
366
+ const errorResponse = {
367
+ jsonrpc: message.jsonrpc,
368
+ id: message.id,
369
+ error: {
370
+ code: -32001,
371
+ message: "Security violation: Response contains sensitive data",
372
+ data: { violations },
373
+ },
374
+ };
375
+ process.stdout.write(JSON.stringify(errorResponse) + "\n");
376
+ }
377
+ }
378
+ /**
379
+ * Handle process exit
380
+ * @param code - Exit code
381
+ */
382
+ async handleProcessExit(code) {
383
+ this.logger.logEvent("SERVER_EXIT", "MEDIUM", { exitCode: code }, this.sessionId);
384
+ console.error("\n=== MCP Security Statistics ===");
385
+ console.error(JSON.stringify(this.logger.getStatistics(), null, 2));
386
+ // Flush and close database reporter
387
+ if (this.databaseEnabled && this.databaseReporter) {
388
+ try {
389
+ await this.databaseReporter.flush();
390
+ await this.databaseReporter.close();
391
+ console.log("✓ Database events flushed");
392
+ }
393
+ catch (error) {
394
+ console.error("Failed to flush database:", error);
395
+ }
396
+ }
397
+ // Use setImmediate to allow pending I/O to complete
398
+ setImmediate(() => {
399
+ process.exit(code || 0);
400
+ });
401
+ }
402
+ /**
403
+ * Get the security logger instance
404
+ * @returns SecurityLogger instance
405
+ */
406
+ getLogger() {
407
+ return this.logger;
408
+ }
409
+ /**
410
+ * Get the traceability manager (pro feature)
411
+ * @returns MCPTraceabilityManager instance or undefined
412
+ */
413
+ getTraceabilityManager() {
414
+ return this.traceabilityManager;
415
+ }
416
+ }
417
+ exports.MCPSecurityWrapper = MCPSecurityWrapper;