@mcp-guardian/server 0.4.0 → 0.5.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 (91) hide show
  1. package/README.md +105 -8
  2. package/dist/auth/auth-types.d.ts +40 -0
  3. package/dist/auth/auth-types.d.ts.map +1 -0
  4. package/dist/auth/auth-types.js +5 -0
  5. package/dist/auth/auth-types.js.map +1 -0
  6. package/dist/auth/dashboard-auth.d.ts +97 -0
  7. package/dist/auth/dashboard-auth.d.ts.map +1 -0
  8. package/dist/auth/dashboard-auth.js +319 -0
  9. package/dist/auth/dashboard-auth.js.map +1 -0
  10. package/dist/auth/dpop.d.ts +38 -0
  11. package/dist/auth/dpop.d.ts.map +1 -0
  12. package/dist/auth/dpop.js +72 -0
  13. package/dist/auth/dpop.js.map +1 -0
  14. package/dist/auth/oauth.d.ts +25 -0
  15. package/dist/auth/oauth.d.ts.map +1 -0
  16. package/dist/auth/oauth.js +96 -0
  17. package/dist/auth/oauth.js.map +1 -0
  18. package/dist/auth/redis-session-cache.d.ts +21 -0
  19. package/dist/auth/redis-session-cache.d.ts.map +1 -0
  20. package/dist/auth/redis-session-cache.js +74 -0
  21. package/dist/auth/redis-session-cache.js.map +1 -0
  22. package/dist/auth/session-cache.d.ts +47 -0
  23. package/dist/auth/session-cache.d.ts.map +1 -0
  24. package/dist/auth/session-cache.js +91 -0
  25. package/dist/auth/session-cache.js.map +1 -0
  26. package/dist/cli.js +23 -5
  27. package/dist/cli.js.map +1 -1
  28. package/dist/database/database-interface.d.ts +17 -0
  29. package/dist/database/database-interface.d.ts.map +1 -0
  30. package/dist/database/database-interface.js +2 -0
  31. package/dist/database/database-interface.js.map +1 -0
  32. package/dist/database/postgres-db.d.ts +18 -0
  33. package/dist/database/postgres-db.d.ts.map +1 -0
  34. package/dist/database/postgres-db.js +118 -0
  35. package/dist/database/postgres-db.js.map +1 -0
  36. package/dist/index.js +1 -1
  37. package/dist/policy/policy-watcher.d.ts +24 -0
  38. package/dist/policy/policy-watcher.d.ts.map +1 -0
  39. package/dist/policy/policy-watcher.js +68 -0
  40. package/dist/policy/policy-watcher.js.map +1 -0
  41. package/dist/policy/shell-tokenizer.d.ts +92 -0
  42. package/dist/policy/shell-tokenizer.d.ts.map +1 -0
  43. package/dist/policy/shell-tokenizer.js +300 -0
  44. package/dist/policy/shell-tokenizer.js.map +1 -0
  45. package/dist/proxy/http-proxy-server.d.ts +26 -0
  46. package/dist/proxy/http-proxy-server.d.ts.map +1 -0
  47. package/dist/proxy/http-proxy-server.js +172 -0
  48. package/dist/proxy/http-proxy-server.js.map +1 -0
  49. package/dist/proxy/proxy-manager.d.ts +3 -1
  50. package/dist/proxy/proxy-manager.d.ts.map +1 -1
  51. package/dist/proxy/proxy-manager.js +10 -3
  52. package/dist/proxy/proxy-manager.js.map +1 -1
  53. package/dist/proxy/proxy-server.d.ts +15 -8
  54. package/dist/proxy/proxy-server.d.ts.map +1 -1
  55. package/dist/proxy/proxy-server.js +80 -26
  56. package/dist/proxy/proxy-server.js.map +1 -1
  57. package/dist/utils/circuit-breaker.d.ts +29 -0
  58. package/dist/utils/circuit-breaker.d.ts.map +1 -0
  59. package/dist/utils/circuit-breaker.js +81 -0
  60. package/dist/utils/circuit-breaker.js.map +1 -0
  61. package/dist/utils/dashboard-server.d.ts +19 -0
  62. package/dist/utils/dashboard-server.d.ts.map +1 -0
  63. package/dist/utils/dashboard-server.js +258 -0
  64. package/dist/utils/dashboard-server.js.map +1 -0
  65. package/dist/utils/metrics.d.ts +17 -0
  66. package/dist/utils/metrics.d.ts.map +1 -0
  67. package/dist/utils/metrics.js +79 -0
  68. package/dist/utils/metrics.js.map +1 -0
  69. package/dist/utils/mtls-config.d.ts +27 -0
  70. package/dist/utils/mtls-config.d.ts.map +1 -0
  71. package/dist/utils/mtls-config.js +82 -0
  72. package/dist/utils/mtls-config.js.map +1 -0
  73. package/dist/utils/payload-normalizer.d.ts +62 -0
  74. package/dist/utils/payload-normalizer.d.ts.map +1 -0
  75. package/dist/utils/payload-normalizer.js +240 -0
  76. package/dist/utils/payload-normalizer.js.map +1 -0
  77. package/dist/utils/policy-auditor.d.ts +24 -0
  78. package/dist/utils/policy-auditor.d.ts.map +1 -0
  79. package/dist/utils/policy-auditor.js +58 -0
  80. package/dist/utils/policy-auditor.js.map +1 -0
  81. package/dist/utils/redis-rate-limiter.d.ts +22 -0
  82. package/dist/utils/redis-rate-limiter.d.ts.map +1 -0
  83. package/dist/utils/redis-rate-limiter.js +61 -0
  84. package/dist/utils/redis-rate-limiter.js.map +1 -0
  85. package/dist/utils/structured-logger.d.ts +1 -1
  86. package/dist/utils/structured-logger.d.ts.map +1 -1
  87. package/dist/utils/tracing.d.ts +7 -0
  88. package/dist/utils/tracing.d.ts.map +1 -0
  89. package/dist/utils/tracing.js +34 -0
  90. package/dist/utils/tracing.js.map +1 -0
  91. package/package.json +2 -1
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Shell Command Tokenizer & Semantic Analyzer
3
+ *
4
+ * Parses tool argument strings into tokenized AST nodes for semantic
5
+ * security analysis. Goes beyond regex pattern matching by understanding
6
+ * shell grammar: pipelines, redirects, command substitutions, logical chains.
7
+ *
8
+ * This is the semantic detection layer that addresses the architectural
9
+ * limitation of regex-only detection. Instead of pattern-matching "$(rm -rf /)"
10
+ * we parse it as a CommandSubstitution AST node and then analyze the inner
11
+ * command semantically.
12
+ */
13
+ export var TokenType;
14
+ (function (TokenType) {
15
+ TokenType["WORD"] = "WORD";
16
+ TokenType["STRING"] = "STRING";
17
+ TokenType["VARIABLE"] = "VARIABLE";
18
+ TokenType["COMMAND_SUBSTITUTION"] = "COMMAND_SUBSTITUTION";
19
+ TokenType["BACKTICK_SUBSTITUTION"] = "BACKTICK_SUBSTITUTION";
20
+ TokenType["PIPE"] = "PIPE";
21
+ TokenType["REDIRECT"] = "REDIRECT";
22
+ TokenType["SEMICOLON"] = "SEMICOLON";
23
+ TokenType["AND_IF"] = "AND_IF";
24
+ TokenType["OR_IF"] = "OR_IF";
25
+ TokenType["BACKGROUND"] = "BACKGROUND";
26
+ TokenType["SUBSHELL"] = "SUBSHELL";
27
+ })(TokenType || (TokenType = {}));
28
+ /**
29
+ * ShellTokenizer parses shell-like input into an AST without executing anything.
30
+ * It's a security analyzer, not a full POSIX shell parser — focus is on detecting
31
+ * execution patterns that signal malicious intent.
32
+ */
33
+ export class ShellTokenizer {
34
+ DANGEROUS_COMMANDS = new Set([
35
+ 'rm', 'dd', 'mkfs', 'fdisk', 'shred',
36
+ 'chmod', 'chown', 'passwd', 'mount', 'umount',
37
+ 'iptables', 'nc', 'curl', 'wget', 'telnet',
38
+ 'eval', 'exec', 'source', 'bash', 'sh', 'zsh',
39
+ 'python', 'perl', 'ruby', 'node', 'php',
40
+ 'ssh', 'scp', 'rsync',
41
+ 'kill', 'pkill', 'reboot', 'shutdown', 'halt',
42
+ 'tcpdump', 'nmap', 'traceroute',
43
+ ]);
44
+ /**
45
+ * Tokenize a string that may contain shell syntax.
46
+ */
47
+ tokenize(input) {
48
+ const warnings = [];
49
+ const tokens = [];
50
+ let pos = 0;
51
+ while (pos < input.length) {
52
+ // Skip whitespace
53
+ if (/\s/.test(input[pos])) {
54
+ pos++;
55
+ continue;
56
+ }
57
+ const result = this.nextToken(input, pos);
58
+ if (!result)
59
+ break;
60
+ tokens.push(result.token);
61
+ pos = result.nextPos;
62
+ if (result.token.type === TokenType.WORD) {
63
+ const word = result.token.value.toLowerCase();
64
+ if (this.DANGEROUS_COMMANDS.has(word)) {
65
+ warnings.push(`Dangerous command detected: '${result.token.value}'`);
66
+ }
67
+ }
68
+ }
69
+ return { commands: tokens, warnings };
70
+ }
71
+ /**
72
+ * Parse the next token starting at position pos.
73
+ */
74
+ nextToken(input, pos) {
75
+ const ch = input[pos];
76
+ if (ch === undefined)
77
+ return null;
78
+ // ── Pipe ──────────────────────────────────────────
79
+ if (ch === '|' && input[pos + 1] !== '|') {
80
+ return {
81
+ token: { type: TokenType.PIPE, value: '|', start: pos, end: pos + 1 },
82
+ nextPos: pos + 1,
83
+ };
84
+ }
85
+ // ── Logical operators && || ────────────────────────
86
+ if (ch === '&' && input[pos + 1] === '&') {
87
+ return {
88
+ token: { type: TokenType.AND_IF, value: '&&', start: pos, end: pos + 2 },
89
+ nextPos: pos + 2,
90
+ };
91
+ }
92
+ if (ch === '|' && input[pos + 1] === '|') {
93
+ return {
94
+ token: { type: TokenType.OR_IF, value: '||', start: pos, end: pos + 2 },
95
+ nextPos: pos + 2,
96
+ };
97
+ }
98
+ // ── Semicolon ─────────────────────────────────────
99
+ if (ch === ';') {
100
+ return {
101
+ token: { type: TokenType.SEMICOLON, value: ';', start: pos, end: pos + 1 },
102
+ nextPos: pos + 1,
103
+ };
104
+ }
105
+ // ── Background & ──────────────────────────────────
106
+ if (ch === '&') {
107
+ return {
108
+ token: { type: TokenType.BACKGROUND, value: '&', start: pos, end: pos + 1 },
109
+ nextPos: pos + 1,
110
+ };
111
+ }
112
+ // ── Redirect > >> < << <<< >& ─────────────────────
113
+ if (ch === '>' || ch === '<') {
114
+ let end = pos + 1;
115
+ if (input[end] === '>' || input[end] === ch)
116
+ end++;
117
+ if (input[end] === '&' && ch === '>')
118
+ end++;
119
+ return {
120
+ token: { type: TokenType.REDIRECT, value: input.slice(pos, end), start: pos, end },
121
+ nextPos: end,
122
+ };
123
+ }
124
+ // ── Command substitution $(...) ────────────────────
125
+ if (ch === '$' && input[pos + 1] === '(') {
126
+ return this.parseDelimited(input, pos, '$(', ')', TokenType.COMMAND_SUBSTITUTION);
127
+ }
128
+ // ── Backtick substitution `...` ────────────────────
129
+ if (ch === '`') {
130
+ return this.parseDelimited(input, pos, '`', '`', TokenType.BACKTICK_SUBSTITUTION);
131
+ }
132
+ // ── Variable ${...} or $NAME ─────────────────────
133
+ if (ch === '$') {
134
+ if (input[pos + 1] === '{') {
135
+ return this.parseDelimited(input, pos, '${', '}', TokenType.VARIABLE);
136
+ }
137
+ // Simple variable: $NAME, $1, $@, $?
138
+ let end = pos + 1;
139
+ if (/[A-Za-z0-9_?!@#*]/.test(input[end] || '')) {
140
+ end++;
141
+ while (end < input.length && /[A-Za-z0-9_]/.test(input[end]))
142
+ end++;
143
+ }
144
+ return {
145
+ token: { type: TokenType.VARIABLE, value: input.slice(pos, end), start: pos, end },
146
+ nextPos: end,
147
+ };
148
+ }
149
+ // ── Subshell (...) ────────────────────────────────
150
+ if (ch === '(') {
151
+ return this.parseDelimited(input, pos, '(', ')', TokenType.SUBSHELL);
152
+ }
153
+ // ── Single-quoted string ──────────────────────────
154
+ if (ch === "'") {
155
+ const end = input.indexOf("'", pos + 1);
156
+ if (end === -1) {
157
+ // Unterminated — consume rest
158
+ return {
159
+ token: { type: TokenType.STRING, value: input.slice(pos), start: pos, end: input.length },
160
+ nextPos: input.length,
161
+ };
162
+ }
163
+ return {
164
+ token: { type: TokenType.STRING, value: input.slice(pos, end + 1), start: pos, end: end + 1 },
165
+ nextPos: end + 1,
166
+ };
167
+ }
168
+ // ── Double-quoted string ──────────────────────────
169
+ if (ch === '"') {
170
+ const end = input.indexOf('"', pos + 1);
171
+ if (end === -1) {
172
+ return {
173
+ token: { type: TokenType.STRING, value: input.slice(pos), start: pos, end: input.length },
174
+ nextPos: input.length,
175
+ };
176
+ }
177
+ return {
178
+ token: { type: TokenType.STRING, value: input.slice(pos, end + 1), start: pos, end: end + 1 },
179
+ nextPos: end + 1,
180
+ };
181
+ }
182
+ // ── Word (unquoted command/argument) ──────────────
183
+ let end = pos;
184
+ while (end < input.length &&
185
+ !/\s/.test(input[end]) &&
186
+ !'|&;<>$`\'"()'.includes(input[end])) {
187
+ end++;
188
+ }
189
+ if (end > pos) {
190
+ return {
191
+ token: { type: TokenType.WORD, value: input.slice(pos, end), start: pos, end },
192
+ nextPos: end,
193
+ };
194
+ }
195
+ // Consume unknown char
196
+ return {
197
+ token: { type: TokenType.WORD, value: ch, start: pos, end: pos + 1 },
198
+ nextPos: pos + 1,
199
+ };
200
+ }
201
+ /**
202
+ * Parse a delimited token like $(...), ${...}, `...`, (...).
203
+ * Recursively tokenizes inner content.
204
+ */
205
+ parseDelimited(input, pos, open, close, type) {
206
+ let depth = 1;
207
+ let index = pos + open.length;
208
+ const start = pos;
209
+ while (index < input.length && depth > 0) {
210
+ if (input.slice(index, index + open.length) === open && type === TokenType.SUBSHELL) {
211
+ depth++;
212
+ index += open.length;
213
+ continue;
214
+ }
215
+ if (input.slice(index, index + close.length) === close) {
216
+ depth--;
217
+ if (depth === 0) {
218
+ index += close.length;
219
+ break;
220
+ }
221
+ }
222
+ index++;
223
+ }
224
+ const inner = input.slice(start + open.length, index - close.length);
225
+ const innerAst = this.tokenize(inner);
226
+ return {
227
+ token: {
228
+ type,
229
+ value: input.slice(start, index),
230
+ start,
231
+ end: index,
232
+ children: innerAst.commands.length > 0 ? innerAst.commands : undefined,
233
+ },
234
+ nextPos: index,
235
+ };
236
+ }
237
+ /**
238
+ * Analyze a token for risk.
239
+ */
240
+ analyzeRisk(tokens) {
241
+ const risk = {
242
+ hasCommandSubstitution: false,
243
+ hasPipes: false,
244
+ hasRedirects: false,
245
+ hasLogicalChains: false,
246
+ dangerousCommands: [],
247
+ shellMetacharacters: [],
248
+ };
249
+ const walkTokens = (list) => {
250
+ for (const token of list) {
251
+ switch (token.type) {
252
+ case TokenType.COMMAND_SUBSTITUTION:
253
+ case TokenType.BACKTICK_SUBSTITUTION:
254
+ risk.hasCommandSubstitution = true;
255
+ if (token.children)
256
+ walkTokens(token.children);
257
+ break;
258
+ case TokenType.PIPE:
259
+ risk.hasPipes = true;
260
+ break;
261
+ case TokenType.REDIRECT:
262
+ risk.hasRedirects = true;
263
+ break;
264
+ case TokenType.AND_IF:
265
+ case TokenType.OR_IF:
266
+ risk.hasLogicalChains = true;
267
+ break;
268
+ case TokenType.WORD:
269
+ if (this.DANGEROUS_COMMANDS.has(token.value.toLowerCase())) {
270
+ if (!risk.dangerousCommands.includes(token.value)) {
271
+ risk.dangerousCommands.push(token.value);
272
+ }
273
+ }
274
+ break;
275
+ case TokenType.SUBSHELL:
276
+ risk.shellMetacharacters.push('(...)');
277
+ if (token.children)
278
+ walkTokens(token.children);
279
+ break;
280
+ case TokenType.VARIABLE:
281
+ risk.shellMetacharacters.push(token.value);
282
+ break;
283
+ default:
284
+ break;
285
+ }
286
+ }
287
+ };
288
+ walkTokens(tokens);
289
+ return risk;
290
+ }
291
+ /**
292
+ * Full semantic analysis: tokenize + assess risk.
293
+ */
294
+ analyze(input) {
295
+ const ast = this.tokenize(input);
296
+ const risk = this.analyzeRisk(ast.commands);
297
+ return { ast, risk };
298
+ }
299
+ }
300
+ //# sourceMappingURL=shell-tokenizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-tokenizer.js","sourceRoot":"","sources":["../../src/policy/shell-tokenizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { HistoryDatabase } from '../database/history-db.js';
2
+ import { PolicyEngine } from '../policy/policy-engine.js';
3
+ import { OAuthValidator } from '../auth/oauth.js';
4
+ import { MtlsConfig } from '../utils/mtls-config.js';
5
+ /**
6
+ * HTTP/SSE Proxy for remote MCP servers.
7
+ * Reuses the same auth, policy, circuit breaker, and metrics stack as the stdio proxy.
8
+ */
9
+ export declare class HttpProxyServer {
10
+ private serverName;
11
+ private targetUrl;
12
+ private policyEngine;
13
+ private authValidator;
14
+ private sessionCache;
15
+ private circuitBreaker;
16
+ private tokenCounter;
17
+ private db;
18
+ private port;
19
+ private server;
20
+ private httpsAgent;
21
+ constructor(targetUrl: string, serverName: string, policyEngine?: PolicyEngine, authValidator?: OAuthValidator, db?: HistoryDatabase, port?: number, mtlsConfig?: MtlsConfig);
22
+ start(): Promise<void>;
23
+ private handleRequest;
24
+ stop(): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=http-proxy-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-proxy-server.d.ts","sourceRoot":"","sources":["../../src/proxy/http-proxy-server.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIlD,OAAO,EAAE,UAAU,EAAmB,MAAM,yBAAyB,CAAC;AAItE;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,EAAE,CAAkB;IAC5B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,MAAM,CAAgD;IAC9D,OAAO,CAAC,UAAU,CAAyB;gBAGzC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,YAAY,EAC3B,aAAa,CAAC,EAAE,cAAc,EAC9B,EAAE,CAAC,EAAE,eAAe,EACpB,IAAI,GAAE,MAAa,EACnB,UAAU,CAAC,EAAE,UAAU;IAkBnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAOd,aAAa;IAgIrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5B"}
@@ -0,0 +1,172 @@
1
+ import { createServer } from 'http';
2
+ import { request as httpReq } from 'http';
3
+ import { request as httpsReq } from 'https';
4
+ import { randomUUID } from 'crypto';
5
+ import { TokenCounter } from '../utils/token-counter.js';
6
+ import { HistoryDatabase } from '../database/history-db.js';
7
+ import { OAuthValidator } from '../auth/oauth.js';
8
+ import { SessionCache } from '../auth/session-cache.js';
9
+ import { CircuitBreaker } from '../utils/circuit-breaker.js';
10
+ import { createMtlsAgent } from '../utils/mtls-config.js';
11
+ import * as Metrics from '../utils/metrics.js';
12
+ import { Logger } from '../utils/logger.js';
13
+ /**
14
+ * HTTP/SSE Proxy for remote MCP servers.
15
+ * Reuses the same auth, policy, circuit breaker, and metrics stack as the stdio proxy.
16
+ */
17
+ export class HttpProxyServer {
18
+ serverName;
19
+ targetUrl;
20
+ policyEngine;
21
+ authValidator;
22
+ sessionCache;
23
+ circuitBreaker;
24
+ tokenCounter;
25
+ db;
26
+ port;
27
+ server = null;
28
+ httpsAgent;
29
+ constructor(targetUrl, serverName, policyEngine, authValidator, db, port = 4000, mtlsConfig) {
30
+ this.serverName = serverName;
31
+ this.targetUrl = targetUrl.replace(/\/$/, '');
32
+ this.policyEngine = policyEngine || null;
33
+ this.authValidator = authValidator || null;
34
+ this.sessionCache = authValidator ? new SessionCache() : null;
35
+ this.circuitBreaker = new CircuitBreaker(this.serverName, { resetTimeoutMs: 15000 });
36
+ this.tokenCounter = new TokenCounter();
37
+ this.db = db || new HistoryDatabase(':memory:');
38
+ this.port = port;
39
+ this.httpsAgent = createMtlsAgent(mtlsConfig || { enabled: false, rejectUnauthorized: true });
40
+ Metrics.circuitBreakerState.set({ server_name: this.serverName }, 0);
41
+ if (this.httpsAgent) {
42
+ Logger.info(`[http-proxy:${this.serverName}] mTLS enabled for upstream connection`);
43
+ }
44
+ }
45
+ async start() {
46
+ this.server = createServer((req, res) => this.handleRequest(req, res));
47
+ this.server.listen(this.port, () => {
48
+ Logger.info(`[http-proxy:${this.serverName}] Listening on http://0.0.0.0:${this.port} → ${this.targetUrl}`);
49
+ });
50
+ }
51
+ async handleRequest(req, res) {
52
+ const requestId = randomUUID();
53
+ const start = Date.now();
54
+ // ── Auth check ───────────────────────────────────────────
55
+ let agentIdentity;
56
+ let authnSuccess = false;
57
+ if (this.authValidator) {
58
+ const authHeader = req.headers['authorization'];
59
+ const token = OAuthValidator.extractToken(authHeader);
60
+ if (!token && this.authValidator.getConfig().required) {
61
+ res.writeHead(401, { 'Content-Type': 'application/json' });
62
+ res.end(JSON.stringify({ error: 'Authentication required' }));
63
+ return;
64
+ }
65
+ if (token) {
66
+ const result = await this.authValidator.validate(token);
67
+ authnSuccess = result.valid;
68
+ if (result.identity)
69
+ agentIdentity = result.identity;
70
+ if (!result.valid && this.authValidator.getConfig().required) {
71
+ res.writeHead(403, { 'Content-Type': 'application/json' });
72
+ res.end(JSON.stringify({ error: `Authentication failed: ${result.error}` }));
73
+ return;
74
+ }
75
+ }
76
+ }
77
+ // ── Circuit breaker ──────────────────────────────────────
78
+ if (!this.circuitBreaker.allowRequest()) {
79
+ res.writeHead(503, { 'Content-Type': 'application/json' });
80
+ res.end(JSON.stringify({ error: 'Service unavailable — circuit breaker open' }));
81
+ Metrics.requestsTotal.inc({ server_name: this.serverName, decision: 'block', authn_success: String(authnSuccess) });
82
+ return;
83
+ }
84
+ // ── Read body ────────────────────────────────────────────
85
+ const chunks = [];
86
+ for await (const chunk of req)
87
+ chunks.push(chunk);
88
+ const body = Buffer.concat(chunks).toString();
89
+ // ── Policy evaluation (if tools/call) ────────────────────
90
+ if (this.policyEngine) {
91
+ try {
92
+ const msg = JSON.parse(body);
93
+ if (msg.method === 'tools/call') {
94
+ const toolName = msg.params?.name || 'unknown';
95
+ const tokens = this.tokenCounter.count(body);
96
+ const context = {
97
+ serverName: this.serverName,
98
+ toolName,
99
+ arguments: msg.params?.arguments,
100
+ requestId,
101
+ requestTokens: tokens,
102
+ timestamp: new Date().toISOString(),
103
+ agentIdentity,
104
+ };
105
+ const decision = this.policyEngine.evaluate(context);
106
+ if (decision.action === 'block') {
107
+ Metrics.blockedRequestsTotal.inc({ server_name: this.serverName, block_reason: `policy:${decision.rule}`, rule: decision.rule });
108
+ Metrics.requestsTotal.inc({ server_name: this.serverName, decision: 'block', authn_success: String(authnSuccess) });
109
+ res.writeHead(403, { 'Content-Type': 'application/json' });
110
+ res.end(JSON.stringify({
111
+ jsonrpc: '2.0',
112
+ id: msg.id,
113
+ error: { code: -32001, message: `Blocked by MCP Guardian policy: ${decision.reason}` },
114
+ }));
115
+ return;
116
+ }
117
+ }
118
+ }
119
+ catch {
120
+ // Not JSON — forward to target anyway
121
+ }
122
+ }
123
+ // ── Forward to upstream ──────────────────────────────────
124
+ try {
125
+ const upstreamUrl = new URL(this.targetUrl + (req.url || '/'));
126
+ const isHttps = upstreamUrl.protocol === 'https:';
127
+ const reqOpts = {
128
+ hostname: upstreamUrl.hostname,
129
+ port: upstreamUrl.port || (isHttps ? 443 : 80),
130
+ path: upstreamUrl.pathname + upstreamUrl.search,
131
+ method: req.method,
132
+ headers: { ...req.headers, host: upstreamUrl.hostname },
133
+ };
134
+ // Attach mTLS agent for HTTPS connections
135
+ if (isHttps && this.httpsAgent) {
136
+ reqOpts.agent = this.httpsAgent;
137
+ }
138
+ const proxyReq = (isHttps ? httpsReq : httpReq)(reqOpts, (upstreamRes) => {
139
+ res.writeHead(upstreamRes.statusCode || 200, upstreamRes.headers);
140
+ upstreamRes.pipe(res);
141
+ this.circuitBreaker.recordSuccess();
142
+ Metrics.circuitBreakerState.set({ server_name: this.serverName }, this.circuitBreaker.getState() === 'OPEN' ? 1 : 0);
143
+ Metrics.proxyLatencyMs.observe({ server_name: this.serverName }, Date.now() - start);
144
+ Metrics.requestsTotal.inc({ server_name: this.serverName, decision: 'pass', authn_success: String(authnSuccess) });
145
+ });
146
+ proxyReq.on('error', (err) => {
147
+ this.circuitBreaker.recordFailure();
148
+ Metrics.circuitBreakerState.set({ server_name: this.serverName }, 1);
149
+ if (!res.headersSent) {
150
+ res.writeHead(502, { 'Content-Type': 'application/json' });
151
+ res.end(JSON.stringify({ error: `Upstream error: ${err.message}` }));
152
+ }
153
+ });
154
+ proxyReq.write(body);
155
+ proxyReq.end();
156
+ }
157
+ catch (err) {
158
+ this.circuitBreaker.recordFailure();
159
+ if (!res.headersSent) {
160
+ res.writeHead(500, { 'Content-Type': 'application/json' });
161
+ res.end(JSON.stringify({ error: `Proxy error: ${err.message}` }));
162
+ }
163
+ }
164
+ }
165
+ async stop() {
166
+ if (this.server) {
167
+ await new Promise(r => this.server.close(() => r()));
168
+ this.server = null;
169
+ }
170
+ }
171
+ }
172
+ //# sourceMappingURL=http-proxy-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-proxy-server.js","sourceRoot":"","sources":["../../src/proxy/http-proxy-server.ts"],"names":[],"mappings":"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"}
@@ -2,11 +2,13 @@ import { HistoryDatabase } from '../database/history-db.js';
2
2
  import { McpProxyServer } from './proxy-server.js';
3
3
  import { McpServerConfig } from '../types.js';
4
4
  import { PolicyEngine } from '../policy/policy-engine.js';
5
+ import { OAuthValidator } from '../auth/oauth.js';
5
6
  export declare class ProxyManager {
6
7
  private db;
7
8
  private policyEngine?;
9
+ private authValidator?;
8
10
  private proxies;
9
- constructor(db: HistoryDatabase, policyEngine?: PolicyEngine | undefined);
11
+ constructor(db: HistoryDatabase, policyEngine?: PolicyEngine | undefined, authValidator?: OAuthValidator | undefined);
10
12
  getProxies(): McpProxyServer[];
11
13
  startAll(configs: McpServerConfig[]): Promise<void>;
12
14
  stopAll(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"proxy-manager.d.ts","sourceRoot":"","sources":["../../src/proxy/proxy-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,qBAAa,YAAY;IAIrB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,YAAY,CAAC;IAJvB,OAAO,CAAC,OAAO,CAAwB;gBAG7B,EAAE,EAAE,eAAe,EACnB,YAAY,CAAC,EAAE,YAAY,YAAA;IAGrC,UAAU,IAAI,cAAc,EAAE;IAIxB,QAAQ,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBzD,OAAO,IAAI,IAAI;CAOhB"}
1
+ {"version":3,"file":"proxy-manager.d.ts","sourceRoot":"","sources":["../../src/proxy/proxy-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,qBAAa,YAAY;IAIrB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,YAAY,CAAC;IACrB,OAAO,CAAC,aAAa,CAAC;IALxB,OAAO,CAAC,OAAO,CAAwB;gBAG7B,EAAE,EAAE,eAAe,EACnB,YAAY,CAAC,EAAE,YAAY,YAAA,EAC3B,aAAa,CAAC,EAAE,cAAc,YAAA;IAGxC,UAAU,IAAI,cAAc,EAAE;IAIxB,QAAQ,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BzD,OAAO,IAAI,IAAI;CAOhB"}
@@ -3,10 +3,12 @@ import { Logger } from '../utils/logger.js';
3
3
  export class ProxyManager {
4
4
  db;
5
5
  policyEngine;
6
+ authValidator;
6
7
  proxies = [];
7
- constructor(db, policyEngine) {
8
+ constructor(db, policyEngine, authValidator) {
8
9
  this.db = db;
9
10
  this.policyEngine = policyEngine;
11
+ this.authValidator = authValidator;
10
12
  }
11
13
  getProxies() {
12
14
  return this.proxies;
@@ -15,9 +17,14 @@ export class ProxyManager {
15
17
  for (const config of configs) {
16
18
  if (config.transport === 'stdio' && config.command) {
17
19
  try {
18
- const proxy = new McpProxyServer(config.command, config.args || [], config.env || {}, this.db, config.name, this.policyEngine);
20
+ const proxy = new McpProxyServer(config.command, config.args || [], config.env || {}, this.db, config.name, this.policyEngine, this.authValidator);
19
21
  this.proxies.push(proxy);
20
- Logger.info(`Proxy started for ${config.name} (${config.command})${this.policyEngine ? ` [policy: ${this.policyEngine.getMode()}]` : ''}`);
22
+ const extras = [];
23
+ if (this.policyEngine)
24
+ extras.push(`policy: ${this.policyEngine.getMode()}`);
25
+ if (this.authValidator)
26
+ extras.push('auth: OAuth 2.1');
27
+ Logger.info(`Proxy started for ${config.name} (${config.command})${extras.length ? ` [${extras.join(', ')}]` : ''}`);
21
28
  }
22
29
  catch (err) {
23
30
  Logger.error(`Failed to start proxy for ${config.name}: ${err?.message}`);
@@ -1 +1 @@
1
- {"version":3,"file":"proxy-manager.js","sourceRoot":"","sources":["../../src/proxy/proxy-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAG5C,MAAM,OAAO,YAAY;IAIb;IACA;IAJF,OAAO,GAAqB,EAAE,CAAC;IAEvC,YACU,EAAmB,EACnB,YAA2B;QAD3B,OAAE,GAAF,EAAE,CAAiB;QACnB,iBAAY,GAAZ,YAAY,CAAe;IAClC,CAAC;IAEJ,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAA0B;QACvC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,SAAS,KAAK,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnD,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,IAAI,cAAc,CAC9B,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,IAAI,IAAI,EAAE,EACjB,MAAM,CAAC,GAAG,IAAI,EAAE,EAChB,IAAI,CAAC,EAAE,EACP,MAAM,CAAC,IAAI,EACX,IAAI,CAAC,YAAY,CAClB,CAAC;oBACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACzB,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7I,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAClB,MAAM,CAAC,KAAK,CAAC,6BAA6B,MAAM,CAAC,IAAI,KAAK,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC;iBAAM,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,IAAI,+BAA+B,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACrC,CAAC;CACF"}
1
+ {"version":3,"file":"proxy-manager.js","sourceRoot":"","sources":["../../src/proxy/proxy-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAI5C,MAAM,OAAO,YAAY;IAIb;IACA;IACA;IALF,OAAO,GAAqB,EAAE,CAAC;IAEvC,YACU,EAAmB,EACnB,YAA2B,EAC3B,aAA8B;QAF9B,OAAE,GAAF,EAAE,CAAiB;QACnB,iBAAY,GAAZ,YAAY,CAAe;QAC3B,kBAAa,GAAb,aAAa,CAAiB;IACrC,CAAC;IAEJ,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAA0B;QACvC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,SAAS,KAAK,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnD,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,IAAI,cAAc,CAC9B,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,IAAI,IAAI,EAAE,EACjB,MAAM,CAAC,GAAG,IAAI,EAAE,EAChB,IAAI,CAAC,EAAE,EACP,MAAM,CAAC,IAAI,EACX,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,aAAa,CACnB,CAAC;oBACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACzB,MAAM,MAAM,GAAa,EAAE,CAAC;oBAC5B,IAAI,IAAI,CAAC,YAAY;wBAAE,MAAM,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;oBAC7E,IAAI,IAAI,CAAC,aAAa;wBAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;oBACvD,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACvH,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAClB,MAAM,CAAC,KAAK,CAAC,6BAA6B,MAAM,CAAC,IAAI,KAAK,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC;iBAAM,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,IAAI,+BAA+B,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACrC,CAAC;CACF"}
@@ -1,12 +1,13 @@
1
1
  import { HistoryDatabase } from '../database/history-db.js';
2
2
  import { PolicyEngine } from '../policy/policy-engine.js';
3
+ import { OAuthValidator } from '../auth/oauth.js';
3
4
  /**
4
- * MCP Proxy Interceptor — sits between the AI client and an MCP server,
5
- * capturing every JSON-RPC call's token usage for real cost auditing.
5
+ * MCP Proxy Interceptor — sits between the AI client and an MCP server.
6
6
  *
7
7
  * v0.4: Integrated PolicyEngine for active blocking of malicious tool calls.
8
- * If policyEngine is provided, every tools/call is evaluated before forwarding.
9
- * Blocked calls return a JSON-RPC error to the client instead of reaching the server.
8
+ * v0.5: OAuth 2.1 JWT validation validates bearer tokens before policy evaluation.
9
+ * If authValidator is provided, every tools/call requires a valid JWT.
10
+ * Unauthenticated calls are blocked with a JSON-RPC auth error.
10
11
  */
11
12
  export declare class McpProxyServer {
12
13
  private child;
@@ -19,16 +20,22 @@ export declare class McpProxyServer {
19
20
  private requestArguments;
20
21
  private serverName;
21
22
  private policyEngine;
22
- constructor(command: string, args: string[], env: Record<string, string>, db: HistoryDatabase, serverName?: string, policyEngine?: PolicyEngine);
23
+ private authValidator;
24
+ constructor(command: string, args: string[], env: Record<string, string>, db: HistoryDatabase, serverName?: string, policyEngine?: PolicyEngine, authValidator?: OAuthValidator);
23
25
  get stdin(): NodeJS.WritableStream | null;
24
26
  private setupStdout;
25
27
  private setupStderr;
28
+ /**
29
+ * Send a JSON-RPC 2.0 error response to the client.
30
+ */
31
+ private sendError;
26
32
  /**
27
33
  * Called when the AI client writes a request to be proxied.
28
- * Evaluates tools/call against policy engine before forwarding.
29
- * Blocked calls receive a JSON-RPC error response.
34
+ * 1. Validate OAuth 2.1 JWT (if configured)
35
+ * 2. Evaluate against policy engine
36
+ * 3. Forward or block
30
37
  */
31
- handleClientInput(raw: string): void;
38
+ handleClientInput(raw: string): Promise<void>;
32
39
  kill(): void;
33
40
  }
34
41
  //# sourceMappingURL=proxy-server.d.ts.map