sovr-mcp-proxy 6.0.1 → 7.1.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 (40) hide show
  1. package/LICENSE +54 -19
  2. package/README.md +387 -164
  3. package/dist/auditDashboard.d.mts +208 -0
  4. package/dist/auditDashboard.d.ts +208 -0
  5. package/dist/auditDashboard.js +398 -0
  6. package/dist/auditDashboard.mjs +370 -0
  7. package/dist/cli.js +1553 -24
  8. package/dist/cli.mjs +185 -18
  9. package/dist/commandNormalizer.d.mts +95 -0
  10. package/dist/commandNormalizer.d.ts +95 -0
  11. package/dist/commandNormalizer.js +365 -0
  12. package/dist/commandNormalizer.mjs +336 -0
  13. package/dist/hooksAdapter.d.mts +122 -0
  14. package/dist/hooksAdapter.d.ts +122 -0
  15. package/dist/hooksAdapter.js +321 -0
  16. package/dist/hooksAdapter.mjs +291 -0
  17. package/dist/index.js +1065 -2
  18. package/dist/index.mjs +98 -2
  19. package/dist/mcpProxyInterceptor.d.mts +256 -0
  20. package/dist/mcpProxyInterceptor.d.ts +256 -0
  21. package/dist/mcpProxyInterceptor.js +579 -0
  22. package/dist/mcpProxyInterceptor.mjs +552 -0
  23. package/dist/semanticAnalyzer.d.mts +133 -0
  24. package/dist/semanticAnalyzer.d.ts +133 -0
  25. package/dist/semanticAnalyzer.js +701 -0
  26. package/dist/semanticAnalyzer.mjs +674 -0
  27. package/dist/teamPolicyManager.d.mts +202 -0
  28. package/dist/teamPolicyManager.d.ts +202 -0
  29. package/dist/teamPolicyManager.js +529 -0
  30. package/dist/teamPolicyManager.mjs +502 -0
  31. package/dist/toolReplacement.d.mts +108 -0
  32. package/dist/toolReplacement.d.ts +108 -0
  33. package/dist/toolReplacement.js +234 -0
  34. package/dist/toolReplacement.mjs +204 -0
  35. package/dist/whitelistEngine.d.mts +167 -0
  36. package/dist/whitelistEngine.d.ts +167 -0
  37. package/dist/whitelistEngine.js +435 -0
  38. package/dist/whitelistEngine.mjs +403 -0
  39. package/package.json +46 -41
  40. package/server.json +0 -14
package/dist/index.mjs CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  // src/index.ts
6
6
  import { spawn } from "child_process";
7
7
  import { EventEmitter } from "events";
8
- var PROXY_VERSION = "5.2.0";
8
+ var PROXY_VERSION = "7.0.0";
9
9
  var SOVR_MIN_VERSION_URL = "https://api.sovr.inc/api/sovr/v1/version/check";
10
10
  var SOVR_DASHBOARD_URL = "https://sovr.inc/dashboard/api-keys";
11
11
  function validateApiKey(key) {
@@ -823,11 +823,15 @@ var McpProxy = class extends EventEmitter {
823
823
  };
824
824
  async function cli(args) {
825
825
  const { PolicyEngine, DEFAULT_RULES } = await import("./engine-DWKHAJGE.mjs");
826
+ const { transformToolList, shouldIntercept, parseMode } = await import("./toolReplacement.mjs");
827
+ const { normalize: normalizeCommand, summarize: summarizeNormalization } = await import("./commandNormalizer.mjs");
826
828
  let upstreamCmd = "";
827
829
  let upstreamArgs = [];
828
830
  let rulesFile = null;
829
831
  let verbose = false;
830
832
  let startupTimeoutMs = 3e4;
833
+ let mode = "enforce";
834
+ let whitelistPreset = null;
831
835
  for (let i = 0; i < args.length; i++) {
832
836
  switch (args[i]) {
833
837
  case "--upstream":
@@ -849,14 +853,39 @@ async function cli(args) {
849
853
  case "-t":
850
854
  startupTimeoutMs = parseInt(args[++i] ?? "30000", 10);
851
855
  break;
856
+ case "--mode":
857
+ case "-m":
858
+ mode = args[++i] ?? "enforce";
859
+ break;
860
+ case "--whitelist":
861
+ case "-w":
862
+ whitelistPreset = args[++i] ?? null;
863
+ break;
864
+ default: {
865
+ const modeMatch = args[i]?.match(/^--mode=(.+)$/);
866
+ if (modeMatch) {
867
+ mode = modeMatch[1];
868
+ break;
869
+ }
870
+ const wlMatch = args[i]?.match(/^--whitelist=(.+)$/);
871
+ if (wlMatch) {
872
+ whitelistPreset = wlMatch[1];
873
+ break;
874
+ }
875
+ }
852
876
  }
853
877
  }
854
878
  if (!upstreamCmd) {
855
879
  process.stderr.write(
856
- 'Usage: sovr-mcp-proxy --upstream "command args..." [--rules policy.json] [--timeout 30000] [--verbose]\n'
880
+ 'Usage: sovr-mcp-proxy --upstream "command args..." [--mode=exclusive|enforce|advisory|monitor] [--whitelist=preset|path] [--verbose]\n'
857
881
  );
858
882
  process.exit(1);
859
883
  }
884
+ if (!["exclusive", "enforce", "advisory", "monitor"].includes(mode)) {
885
+ process.stderr.write(`[SOVR] Invalid mode: ${mode}. Must be: exclusive|enforce|advisory|monitor
886
+ `);
887
+ process.exit(1);
888
+ }
860
889
  let rules = DEFAULT_RULES;
861
890
  if (rulesFile) {
862
891
  const fs = await import("fs");
@@ -864,6 +893,26 @@ async function cli(args) {
864
893
  const parsed = JSON.parse(content);
865
894
  rules = parsed.rules ?? parsed;
866
895
  }
896
+ const { WhitelistEngine, PRESETS: WL_PRESETS } = await import("./whitelistEngine.mjs");
897
+ let whitelist = null;
898
+ if (whitelistPreset) {
899
+ const presetNames = Object.keys(WL_PRESETS);
900
+ if (presetNames.includes(whitelistPreset)) {
901
+ whitelist = new WhitelistEngine(WL_PRESETS[whitelistPreset]);
902
+ } else {
903
+ try {
904
+ const fs = await import("fs");
905
+ const content = fs.readFileSync(whitelistPreset, "utf-8");
906
+ const parsed = JSON.parse(content);
907
+ whitelist = new WhitelistEngine(parsed);
908
+ } catch (err) {
909
+ process.stderr.write(`[SOVR] Failed to load whitelist from ${whitelistPreset}: ${err.message}
910
+ `);
911
+ process.exit(1);
912
+ }
913
+ }
914
+ }
915
+ const validatedMode = parseMode(mode);
867
916
  const engine = new PolicyEngine({
868
917
  rules,
869
918
  audit_log: true,
@@ -876,6 +925,24 @@ async function cli(args) {
876
925
  }
877
926
  }
878
927
  });
928
+ process.stderr.write(`
929
+ `);
930
+ process.stderr.write(` \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
931
+ `);
932
+ process.stderr.write(` \u2551 SOVR MCP Proxy v${PROXY_VERSION} \u2551
933
+ `);
934
+ process.stderr.write(` \u2551 Mode: ${mode.toUpperCase().padEnd(40)}\u2551
935
+ `);
936
+ if (whitelist) {
937
+ process.stderr.write(` \u2551 Whitelist: ${(whitelistPreset ?? "custom").padEnd(35)}\u2551
938
+ `);
939
+ }
940
+ process.stderr.write(` \u2551 Upstream: ${upstreamCmd.substring(0, 36).padEnd(36)}\u2551
941
+ `);
942
+ process.stderr.write(` \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
943
+ `);
944
+ process.stderr.write(`
945
+ `);
879
946
  const proxy = new McpProxy({
880
947
  engine,
881
948
  upstream: { command: upstreamCmd, args: upstreamArgs },
@@ -892,8 +959,37 @@ async function cli(args) {
892
959
  `[ESCALATED] ${info.toolName}: ${info.decision.reason}
893
960
  `
894
961
  );
962
+ },
963
+ onIntercept: (info) => {
964
+ if (info.arguments?.command && typeof info.arguments.command === "string") {
965
+ const normalized = normalizeCommand(info.arguments.command);
966
+ if (verbose) {
967
+ process.stderr.write(`[SOVR] Normalized: ${summarizeNormalization(normalized)}
968
+ `);
969
+ if (normalized.suspicious) {
970
+ process.stderr.write(`[SOVR] \u26A0 Suspicious: ${normalized.suspicion_reasons.join(", ")}
971
+ `);
972
+ }
973
+ }
974
+ }
975
+ if (whitelist && info.arguments?.command && typeof info.arguments.command === "string") {
976
+ const wlResult = whitelist.evaluate(info.arguments.command);
977
+ if (!wlResult.allowed && (validatedMode === "enforce" || validatedMode === "exclusive")) {
978
+ if (verbose) {
979
+ process.stderr.write(`[SOVR] Whitelist DENIED: ${wlResult.reason}
980
+ `);
981
+ }
982
+ }
983
+ }
895
984
  }
896
985
  });
986
+ if (validatedMode === "exclusive") {
987
+ proxy.on("intercept", () => {
988
+ if (verbose) {
989
+ process.stderr.write("[SOVR] Exclusive mode: all tool calls routed through SOVR\n");
990
+ }
991
+ });
992
+ }
897
993
  await proxy.start();
898
994
  }
899
995
  var index_default = McpProxy;
@@ -0,0 +1,256 @@
1
+ /**
2
+ * SOVR MCP Proxy Interceptor — Universal Tool Call Interception
3
+ *
4
+ * P1-1: SOVR sits between the MCP client (LLM) and the MCP server (tools),
5
+ * intercepting ALL tool calls regardless of transport (stdio/SSE/HTTP).
6
+ *
7
+ * Architecture:
8
+ * [LLM Client] → [SOVR Proxy] → [Upstream MCP Server]
9
+ * ↓
10
+ * [Policy Engine]
11
+ * [Audit Trail]
12
+ * [Rate Limiter]
13
+ * [Semantic Analyzer]
14
+ *
15
+ * Unlike Tool Replacement (which replaces tools), this module transparently
16
+ * proxies ALL tools and applies policies at the protocol level.
17
+ */
18
+ interface InterceptorConfig {
19
+ /** Policy mode: block | warn | audit-only */
20
+ mode: 'block' | 'warn' | 'audit';
21
+ /** Maximum concurrent tool calls */
22
+ maxConcurrent: number;
23
+ /** Per-tool rate limits (calls per minute) */
24
+ rateLimits: Record<string, number>;
25
+ /** Global rate limit (calls per minute) */
26
+ globalRateLimit: number;
27
+ /** Tool-specific policies */
28
+ toolPolicies: ToolPolicy[];
29
+ /** Enable semantic analysis for tool arguments */
30
+ enableSemanticAnalysis: boolean;
31
+ /** Callback for human approval */
32
+ onApprovalRequired?: (request: InterceptedCall) => Promise<ApprovalResult>;
33
+ /** Callback for audit events */
34
+ onAuditEvent?: (event: AuditEvent) => void;
35
+ /** Timeout for upstream tool calls (ms) */
36
+ upstreamTimeout: number;
37
+ /** Max retries for transient failures */
38
+ maxRetries: number;
39
+ }
40
+ interface ToolPolicy {
41
+ /** Tool name pattern (glob) */
42
+ toolPattern: string;
43
+ /** Action to take */
44
+ action: 'allow' | 'block' | 'require-approval' | 'rate-limit' | 'transform';
45
+ /** Conditions for this policy */
46
+ conditions?: PolicyCondition[];
47
+ /** Argument transformations (for 'transform' action) */
48
+ transforms?: ArgumentTransform[];
49
+ /** Priority (higher = evaluated first) */
50
+ priority: number;
51
+ /** Human-readable description */
52
+ description: string;
53
+ }
54
+ interface PolicyCondition {
55
+ /** Field path in tool arguments (dot notation) */
56
+ field: string;
57
+ /** Operator */
58
+ operator: 'contains' | 'matches' | 'equals' | 'gt' | 'lt' | 'exists' | 'not-exists';
59
+ /** Value to compare against */
60
+ value: string | number | boolean;
61
+ }
62
+ interface ArgumentTransform {
63
+ /** Field path to transform */
64
+ field: string;
65
+ /** Transform type */
66
+ type: 'redact' | 'mask' | 'replace' | 'remove';
67
+ /** Replacement value (for 'replace') */
68
+ replacement?: string;
69
+ }
70
+ interface InterceptedCall {
71
+ /** Unique call ID */
72
+ id: string;
73
+ /** Timestamp */
74
+ timestamp: number;
75
+ /** Tool name */
76
+ toolName: string;
77
+ /** Original arguments */
78
+ arguments: Record<string, unknown>;
79
+ /** Matched policies */
80
+ matchedPolicies: ToolPolicy[];
81
+ /** Decision */
82
+ decision: InterceptDecision;
83
+ /** Semantic analysis result (if enabled) */
84
+ semanticResult?: SemanticAnalysisResult;
85
+ }
86
+ interface InterceptDecision {
87
+ /** Final action */
88
+ action: 'allow' | 'block' | 'require-approval' | 'transform';
89
+ /** Reason for decision */
90
+ reason: string;
91
+ /** Policy that triggered this decision */
92
+ triggeringPolicy?: ToolPolicy;
93
+ /** Risk score (0-100) */
94
+ riskScore: number;
95
+ /** Transformed arguments (if action is 'transform') */
96
+ transformedArguments?: Record<string, unknown>;
97
+ }
98
+ interface SemanticAnalysisResult {
99
+ /** Detected intent */
100
+ intent: string;
101
+ /** Risk category */
102
+ riskCategory: 'safe' | 'suspicious' | 'dangerous' | 'critical';
103
+ /** Confidence (0-1) */
104
+ confidence: number;
105
+ /** Explanation */
106
+ explanation: string;
107
+ }
108
+ interface ApprovalResult {
109
+ approved: boolean;
110
+ approver?: string;
111
+ reason?: string;
112
+ timestamp: number;
113
+ }
114
+ interface AuditEvent {
115
+ id: string;
116
+ timestamp: number;
117
+ type: 'intercept' | 'allow' | 'block' | 'approval-requested' | 'approval-granted' | 'approval-denied' | 'error' | 'rate-limited';
118
+ toolName: string;
119
+ arguments: Record<string, unknown>;
120
+ decision: InterceptDecision;
121
+ duration?: number;
122
+ error?: string;
123
+ upstreamResult?: unknown;
124
+ }
125
+ interface InterceptorStats {
126
+ totalCalls: number;
127
+ allowed: number;
128
+ blocked: number;
129
+ approvalRequested: number;
130
+ rateLimited: number;
131
+ errors: number;
132
+ avgLatencyMs: number;
133
+ callsByTool: Record<string, number>;
134
+ blocksByPolicy: Record<string, number>;
135
+ riskDistribution: {
136
+ safe: number;
137
+ suspicious: number;
138
+ dangerous: number;
139
+ critical: number;
140
+ };
141
+ }
142
+ declare class McpProxyInterceptor {
143
+ private config;
144
+ private rateLimiter;
145
+ private stats;
146
+ private auditLog;
147
+ private maxAuditLogSize;
148
+ private activeCalls;
149
+ private cleanupInterval;
150
+ constructor(config?: Partial<InterceptorConfig>);
151
+ /**
152
+ * Intercept a tool call — the core entry point.
153
+ * Returns the decision and optionally transformed arguments.
154
+ */
155
+ intercept(toolName: string, args: Record<string, unknown>): Promise<InterceptedCall>;
156
+ /**
157
+ * Wrap an upstream tool call with interception.
158
+ * If allowed, executes the upstream function; if blocked, returns error.
159
+ */
160
+ wrapToolCall<T>(toolName: string, args: Record<string, unknown>, upstream: (args: Record<string, unknown>) => Promise<T>): Promise<{
161
+ result?: T;
162
+ intercepted: InterceptedCall;
163
+ error?: string;
164
+ }>;
165
+ /** Get current statistics */
166
+ getStats(): InterceptorStats;
167
+ /** Get recent audit log */
168
+ getAuditLog(limit?: number): AuditEvent[];
169
+ /** Export audit log as CSV */
170
+ exportAuditCSV(): string;
171
+ /** Add a policy at runtime */
172
+ addPolicy(policy: ToolPolicy): void;
173
+ /** Remove policies matching a pattern */
174
+ removePolicies(toolPattern: string): number;
175
+ /** Reset statistics */
176
+ resetStats(): void;
177
+ /** Cleanup resources */
178
+ destroy(): void;
179
+ private emitAudit;
180
+ private trimAuditLog;
181
+ }
182
+ declare const PRESET_POLICIES: {
183
+ /** Block all destructive file operations */
184
+ noDestructiveFiles: {
185
+ toolPattern: string;
186
+ action: "block";
187
+ conditions: {
188
+ field: string;
189
+ operator: "matches";
190
+ value: string;
191
+ }[];
192
+ priority: number;
193
+ description: string;
194
+ };
195
+ /** Block all database write operations */
196
+ readOnlyDatabase: {
197
+ toolPattern: string;
198
+ action: "block";
199
+ conditions: {
200
+ field: string;
201
+ operator: "matches";
202
+ value: string;
203
+ }[];
204
+ priority: number;
205
+ description: string;
206
+ };
207
+ /** Require approval for payment operations */
208
+ approvePayments: {
209
+ toolPattern: string;
210
+ action: "require-approval";
211
+ priority: number;
212
+ description: string;
213
+ };
214
+ /** Redact secrets in tool arguments */
215
+ redactSecrets: {
216
+ toolPattern: string;
217
+ action: "transform";
218
+ conditions: {
219
+ field: string;
220
+ operator: "matches";
221
+ value: string;
222
+ }[];
223
+ transforms: ({
224
+ field: string;
225
+ type: "redact";
226
+ } | {
227
+ field: string;
228
+ type: "mask";
229
+ })[];
230
+ priority: number;
231
+ description: string;
232
+ };
233
+ /** Rate limit shell commands */
234
+ rateLimitShell: {
235
+ toolPattern: string;
236
+ action: "rate-limit";
237
+ priority: number;
238
+ description: string;
239
+ };
240
+ /** Allow read-only operations */
241
+ allowReadOnly: {
242
+ toolPattern: string;
243
+ action: "allow";
244
+ conditions: {
245
+ field: string;
246
+ operator: "matches";
247
+ value: string;
248
+ }[];
249
+ priority: number;
250
+ description: string;
251
+ };
252
+ };
253
+ /** Create a pre-configured interceptor with common security policies */
254
+ declare function createSecureInterceptor(overrides?: Partial<InterceptorConfig>): McpProxyInterceptor;
255
+
256
+ export { type ApprovalResult, type ArgumentTransform, type AuditEvent, type InterceptDecision, type InterceptedCall, type InterceptorConfig, type InterceptorStats, McpProxyInterceptor, PRESET_POLICIES, type PolicyCondition, type SemanticAnalysisResult, type ToolPolicy, createSecureInterceptor };
@@ -0,0 +1,256 @@
1
+ /**
2
+ * SOVR MCP Proxy Interceptor — Universal Tool Call Interception
3
+ *
4
+ * P1-1: SOVR sits between the MCP client (LLM) and the MCP server (tools),
5
+ * intercepting ALL tool calls regardless of transport (stdio/SSE/HTTP).
6
+ *
7
+ * Architecture:
8
+ * [LLM Client] → [SOVR Proxy] → [Upstream MCP Server]
9
+ * ↓
10
+ * [Policy Engine]
11
+ * [Audit Trail]
12
+ * [Rate Limiter]
13
+ * [Semantic Analyzer]
14
+ *
15
+ * Unlike Tool Replacement (which replaces tools), this module transparently
16
+ * proxies ALL tools and applies policies at the protocol level.
17
+ */
18
+ interface InterceptorConfig {
19
+ /** Policy mode: block | warn | audit-only */
20
+ mode: 'block' | 'warn' | 'audit';
21
+ /** Maximum concurrent tool calls */
22
+ maxConcurrent: number;
23
+ /** Per-tool rate limits (calls per minute) */
24
+ rateLimits: Record<string, number>;
25
+ /** Global rate limit (calls per minute) */
26
+ globalRateLimit: number;
27
+ /** Tool-specific policies */
28
+ toolPolicies: ToolPolicy[];
29
+ /** Enable semantic analysis for tool arguments */
30
+ enableSemanticAnalysis: boolean;
31
+ /** Callback for human approval */
32
+ onApprovalRequired?: (request: InterceptedCall) => Promise<ApprovalResult>;
33
+ /** Callback for audit events */
34
+ onAuditEvent?: (event: AuditEvent) => void;
35
+ /** Timeout for upstream tool calls (ms) */
36
+ upstreamTimeout: number;
37
+ /** Max retries for transient failures */
38
+ maxRetries: number;
39
+ }
40
+ interface ToolPolicy {
41
+ /** Tool name pattern (glob) */
42
+ toolPattern: string;
43
+ /** Action to take */
44
+ action: 'allow' | 'block' | 'require-approval' | 'rate-limit' | 'transform';
45
+ /** Conditions for this policy */
46
+ conditions?: PolicyCondition[];
47
+ /** Argument transformations (for 'transform' action) */
48
+ transforms?: ArgumentTransform[];
49
+ /** Priority (higher = evaluated first) */
50
+ priority: number;
51
+ /** Human-readable description */
52
+ description: string;
53
+ }
54
+ interface PolicyCondition {
55
+ /** Field path in tool arguments (dot notation) */
56
+ field: string;
57
+ /** Operator */
58
+ operator: 'contains' | 'matches' | 'equals' | 'gt' | 'lt' | 'exists' | 'not-exists';
59
+ /** Value to compare against */
60
+ value: string | number | boolean;
61
+ }
62
+ interface ArgumentTransform {
63
+ /** Field path to transform */
64
+ field: string;
65
+ /** Transform type */
66
+ type: 'redact' | 'mask' | 'replace' | 'remove';
67
+ /** Replacement value (for 'replace') */
68
+ replacement?: string;
69
+ }
70
+ interface InterceptedCall {
71
+ /** Unique call ID */
72
+ id: string;
73
+ /** Timestamp */
74
+ timestamp: number;
75
+ /** Tool name */
76
+ toolName: string;
77
+ /** Original arguments */
78
+ arguments: Record<string, unknown>;
79
+ /** Matched policies */
80
+ matchedPolicies: ToolPolicy[];
81
+ /** Decision */
82
+ decision: InterceptDecision;
83
+ /** Semantic analysis result (if enabled) */
84
+ semanticResult?: SemanticAnalysisResult;
85
+ }
86
+ interface InterceptDecision {
87
+ /** Final action */
88
+ action: 'allow' | 'block' | 'require-approval' | 'transform';
89
+ /** Reason for decision */
90
+ reason: string;
91
+ /** Policy that triggered this decision */
92
+ triggeringPolicy?: ToolPolicy;
93
+ /** Risk score (0-100) */
94
+ riskScore: number;
95
+ /** Transformed arguments (if action is 'transform') */
96
+ transformedArguments?: Record<string, unknown>;
97
+ }
98
+ interface SemanticAnalysisResult {
99
+ /** Detected intent */
100
+ intent: string;
101
+ /** Risk category */
102
+ riskCategory: 'safe' | 'suspicious' | 'dangerous' | 'critical';
103
+ /** Confidence (0-1) */
104
+ confidence: number;
105
+ /** Explanation */
106
+ explanation: string;
107
+ }
108
+ interface ApprovalResult {
109
+ approved: boolean;
110
+ approver?: string;
111
+ reason?: string;
112
+ timestamp: number;
113
+ }
114
+ interface AuditEvent {
115
+ id: string;
116
+ timestamp: number;
117
+ type: 'intercept' | 'allow' | 'block' | 'approval-requested' | 'approval-granted' | 'approval-denied' | 'error' | 'rate-limited';
118
+ toolName: string;
119
+ arguments: Record<string, unknown>;
120
+ decision: InterceptDecision;
121
+ duration?: number;
122
+ error?: string;
123
+ upstreamResult?: unknown;
124
+ }
125
+ interface InterceptorStats {
126
+ totalCalls: number;
127
+ allowed: number;
128
+ blocked: number;
129
+ approvalRequested: number;
130
+ rateLimited: number;
131
+ errors: number;
132
+ avgLatencyMs: number;
133
+ callsByTool: Record<string, number>;
134
+ blocksByPolicy: Record<string, number>;
135
+ riskDistribution: {
136
+ safe: number;
137
+ suspicious: number;
138
+ dangerous: number;
139
+ critical: number;
140
+ };
141
+ }
142
+ declare class McpProxyInterceptor {
143
+ private config;
144
+ private rateLimiter;
145
+ private stats;
146
+ private auditLog;
147
+ private maxAuditLogSize;
148
+ private activeCalls;
149
+ private cleanupInterval;
150
+ constructor(config?: Partial<InterceptorConfig>);
151
+ /**
152
+ * Intercept a tool call — the core entry point.
153
+ * Returns the decision and optionally transformed arguments.
154
+ */
155
+ intercept(toolName: string, args: Record<string, unknown>): Promise<InterceptedCall>;
156
+ /**
157
+ * Wrap an upstream tool call with interception.
158
+ * If allowed, executes the upstream function; if blocked, returns error.
159
+ */
160
+ wrapToolCall<T>(toolName: string, args: Record<string, unknown>, upstream: (args: Record<string, unknown>) => Promise<T>): Promise<{
161
+ result?: T;
162
+ intercepted: InterceptedCall;
163
+ error?: string;
164
+ }>;
165
+ /** Get current statistics */
166
+ getStats(): InterceptorStats;
167
+ /** Get recent audit log */
168
+ getAuditLog(limit?: number): AuditEvent[];
169
+ /** Export audit log as CSV */
170
+ exportAuditCSV(): string;
171
+ /** Add a policy at runtime */
172
+ addPolicy(policy: ToolPolicy): void;
173
+ /** Remove policies matching a pattern */
174
+ removePolicies(toolPattern: string): number;
175
+ /** Reset statistics */
176
+ resetStats(): void;
177
+ /** Cleanup resources */
178
+ destroy(): void;
179
+ private emitAudit;
180
+ private trimAuditLog;
181
+ }
182
+ declare const PRESET_POLICIES: {
183
+ /** Block all destructive file operations */
184
+ noDestructiveFiles: {
185
+ toolPattern: string;
186
+ action: "block";
187
+ conditions: {
188
+ field: string;
189
+ operator: "matches";
190
+ value: string;
191
+ }[];
192
+ priority: number;
193
+ description: string;
194
+ };
195
+ /** Block all database write operations */
196
+ readOnlyDatabase: {
197
+ toolPattern: string;
198
+ action: "block";
199
+ conditions: {
200
+ field: string;
201
+ operator: "matches";
202
+ value: string;
203
+ }[];
204
+ priority: number;
205
+ description: string;
206
+ };
207
+ /** Require approval for payment operations */
208
+ approvePayments: {
209
+ toolPattern: string;
210
+ action: "require-approval";
211
+ priority: number;
212
+ description: string;
213
+ };
214
+ /** Redact secrets in tool arguments */
215
+ redactSecrets: {
216
+ toolPattern: string;
217
+ action: "transform";
218
+ conditions: {
219
+ field: string;
220
+ operator: "matches";
221
+ value: string;
222
+ }[];
223
+ transforms: ({
224
+ field: string;
225
+ type: "redact";
226
+ } | {
227
+ field: string;
228
+ type: "mask";
229
+ })[];
230
+ priority: number;
231
+ description: string;
232
+ };
233
+ /** Rate limit shell commands */
234
+ rateLimitShell: {
235
+ toolPattern: string;
236
+ action: "rate-limit";
237
+ priority: number;
238
+ description: string;
239
+ };
240
+ /** Allow read-only operations */
241
+ allowReadOnly: {
242
+ toolPattern: string;
243
+ action: "allow";
244
+ conditions: {
245
+ field: string;
246
+ operator: "matches";
247
+ value: string;
248
+ }[];
249
+ priority: number;
250
+ description: string;
251
+ };
252
+ };
253
+ /** Create a pre-configured interceptor with common security policies */
254
+ declare function createSecureInterceptor(overrides?: Partial<InterceptorConfig>): McpProxyInterceptor;
255
+
256
+ export { type ApprovalResult, type ArgumentTransform, type AuditEvent, type InterceptDecision, type InterceptedCall, type InterceptorConfig, type InterceptorStats, McpProxyInterceptor, PRESET_POLICIES, type PolicyCondition, type SemanticAnalysisResult, type ToolPolicy, createSecureInterceptor };