@mcp-guardian/server 0.3.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.
- package/README.md +505 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +216 -0
- package/dist/cli.js.map +1 -0
- package/dist/clients/nvd-client.d.ts +17 -0
- package/dist/clients/nvd-client.d.ts.map +1 -0
- package/dist/clients/nvd-client.js +64 -0
- package/dist/clients/nvd-client.js.map +1 -0
- package/dist/clients/osv-client.d.ts +19 -0
- package/dist/clients/osv-client.d.ts.map +1 -0
- package/dist/clients/osv-client.js +60 -0
- package/dist/clients/osv-client.js.map +1 -0
- package/dist/clients/pricing-client.d.ts +16 -0
- package/dist/clients/pricing-client.d.ts.map +1 -0
- package/dist/clients/pricing-client.js +171 -0
- package/dist/clients/pricing-client.js.map +1 -0
- package/dist/config-parser.d.ts +24 -0
- package/dist/config-parser.d.ts.map +1 -0
- package/dist/config-parser.js +96 -0
- package/dist/config-parser.js.map +1 -0
- package/dist/container.d.ts +12 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +22 -0
- package/dist/container.js.map +1 -0
- package/dist/database/history-db.d.ts +28 -0
- package/dist/database/history-db.d.ts.map +1 -0
- package/dist/database/history-db.js +154 -0
- package/dist/database/history-db.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +247 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy/proxy-manager.d.ts +12 -0
- package/dist/proxy/proxy-manager.d.ts.map +1 -0
- package/dist/proxy/proxy-manager.js +37 -0
- package/dist/proxy/proxy-manager.js.map +1 -0
- package/dist/proxy/proxy-server.d.ts +26 -0
- package/dist/proxy/proxy-server.d.ts.map +1 -0
- package/dist/proxy/proxy-server.js +99 -0
- package/dist/proxy/proxy-server.js.map +1 -0
- package/dist/reporter/report-generator.d.ts +9 -0
- package/dist/reporter/report-generator.d.ts.map +1 -0
- package/dist/reporter/report-generator.js +145 -0
- package/dist/reporter/report-generator.js.map +1 -0
- package/dist/scanners/auth-prober.d.ts +13 -0
- package/dist/scanners/auth-prober.d.ts.map +1 -0
- package/dist/scanners/auth-prober.js +59 -0
- package/dist/scanners/auth-prober.js.map +1 -0
- package/dist/scanners/command-validator.d.ts +15 -0
- package/dist/scanners/command-validator.d.ts.map +1 -0
- package/dist/scanners/command-validator.js +50 -0
- package/dist/scanners/command-validator.js.map +1 -0
- package/dist/scanners/cve-checker.d.ts +15 -0
- package/dist/scanners/cve-checker.d.ts.map +1 -0
- package/dist/scanners/cve-checker.js +28 -0
- package/dist/scanners/cve-checker.js.map +1 -0
- package/dist/scanners/secret-scanner.d.ts +12 -0
- package/dist/scanners/secret-scanner.d.ts.map +1 -0
- package/dist/scanners/secret-scanner.js +72 -0
- package/dist/scanners/secret-scanner.js.map +1 -0
- package/dist/scanners/typo-squat-detector.d.ts +14 -0
- package/dist/scanners/typo-squat-detector.d.ts.map +1 -0
- package/dist/scanners/typo-squat-detector.js +82 -0
- package/dist/scanners/typo-squat-detector.js.map +1 -0
- package/dist/services/cost-auditor.d.ts +14 -0
- package/dist/services/cost-auditor.d.ts.map +1 -0
- package/dist/services/cost-auditor.js +90 -0
- package/dist/services/cost-auditor.js.map +1 -0
- package/dist/services/health-monitor.d.ts +8 -0
- package/dist/services/health-monitor.d.ts.map +1 -0
- package/dist/services/health-monitor.js +51 -0
- package/dist/services/health-monitor.js.map +1 -0
- package/dist/services/security-scanner.d.ts +20 -0
- package/dist/services/security-scanner.d.ts.map +1 -0
- package/dist/services/security-scanner.js +92 -0
- package/dist/services/security-scanner.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +35 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mcp-client.d.ts +33 -0
- package/dist/utils/mcp-client.d.ts.map +1 -0
- package/dist/utils/mcp-client.js +182 -0
- package/dist/utils/mcp-client.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +31 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +74 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/scoring.d.ts +9 -0
- package/dist/utils/scoring.d.ts.map +1 -0
- package/dist/utils/scoring.js +19 -0
- package/dist/utils/scoring.js.map +1 -0
- package/dist/utils/tls-checker.d.ts +13 -0
- package/dist/utils/tls-checker.d.ts.map +1 -0
- package/dist/utils/tls-checker.js +62 -0
- package/dist/utils/tls-checker.js.map +1 -0
- package/dist/utils/token-counter.d.ts +7 -0
- package/dist/utils/token-counter.d.ts.map +1 -0
- package/dist/utils/token-counter.js +16 -0
- package/dist/utils/token-counter.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HistoryDatabase } from '../database/history-db.js';
|
|
2
|
+
import { McpProxyServer } from './proxy-server.js';
|
|
3
|
+
import { McpServerConfig } from '../types.js';
|
|
4
|
+
export declare class ProxyManager {
|
|
5
|
+
private db;
|
|
6
|
+
private proxies;
|
|
7
|
+
constructor(db: HistoryDatabase);
|
|
8
|
+
getProxies(): McpProxyServer[];
|
|
9
|
+
startAll(configs: McpServerConfig[]): Promise<void>;
|
|
10
|
+
stopAll(): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=proxy-manager.d.ts.map
|
|
@@ -0,0 +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;AAG9C,qBAAa,YAAY;IAGX,OAAO,CAAC,EAAE;IAFtB,OAAO,CAAC,OAAO,CAAwB;gBAEnB,EAAE,EAAE,eAAe;IAEvC,UAAU,IAAI,cAAc,EAAE;IAIxB,QAAQ,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBzD,OAAO,IAAI,IAAI;CAOhB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { McpProxyServer } from './proxy-server.js';
|
|
2
|
+
import { Logger } from '../utils/logger.js';
|
|
3
|
+
export class ProxyManager {
|
|
4
|
+
db;
|
|
5
|
+
proxies = [];
|
|
6
|
+
constructor(db) {
|
|
7
|
+
this.db = db;
|
|
8
|
+
}
|
|
9
|
+
getProxies() {
|
|
10
|
+
return this.proxies;
|
|
11
|
+
}
|
|
12
|
+
async startAll(configs) {
|
|
13
|
+
for (const config of configs) {
|
|
14
|
+
if (config.transport === 'stdio' && config.command) {
|
|
15
|
+
try {
|
|
16
|
+
const proxy = new McpProxyServer(config.command, config.args || [], config.env || {}, this.db, config.name);
|
|
17
|
+
this.proxies.push(proxy);
|
|
18
|
+
Logger.info(`Proxy started for ${config.name} (${config.command})`);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
Logger.error(`Failed to start proxy for ${config.name}: ${err?.message}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else if (config.url) {
|
|
25
|
+
Logger.info(`SSE proxy for ${config.name} not yet supported — skipping`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
stopAll() {
|
|
30
|
+
for (const proxy of this.proxies) {
|
|
31
|
+
proxy.kill();
|
|
32
|
+
}
|
|
33
|
+
this.proxies = [];
|
|
34
|
+
Logger.info('All proxies stopped');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=proxy-manager.js.map
|
|
@@ -0,0 +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;AAE5C,MAAM,OAAO,YAAY;IAGH;IAFZ,OAAO,GAAqB,EAAE,CAAC;IAEvC,YAAoB,EAAmB;QAAnB,OAAE,GAAF,EAAE,CAAiB;IAAG,CAAC;IAE3C,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,CACZ,CAAC;oBACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACzB,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC;gBACtE,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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { HistoryDatabase } from '../database/history-db.js';
|
|
2
|
+
/**
|
|
3
|
+
* MCP Proxy Interceptor — sits between the AI client and an MCP server,
|
|
4
|
+
* capturing every JSON-RPC call's token usage for real cost auditing.
|
|
5
|
+
*/
|
|
6
|
+
export declare class McpProxyServer {
|
|
7
|
+
private child;
|
|
8
|
+
private tokenCounter;
|
|
9
|
+
private db;
|
|
10
|
+
private currentRequestId;
|
|
11
|
+
private requestStartTime;
|
|
12
|
+
private requestToolName;
|
|
13
|
+
private requestTokens;
|
|
14
|
+
private serverName;
|
|
15
|
+
constructor(command: string, args: string[], env: Record<string, string>, db: HistoryDatabase, serverName?: string);
|
|
16
|
+
get stdin(): NodeJS.WritableStream | null;
|
|
17
|
+
private setupStdout;
|
|
18
|
+
private setupStderr;
|
|
19
|
+
/**
|
|
20
|
+
* Called when the AI client writes a request to be proxied.
|
|
21
|
+
* Tracks tools/call requests for token counting.
|
|
22
|
+
*/
|
|
23
|
+
handleClientInput(raw: string): void;
|
|
24
|
+
kill(): void;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=proxy-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-server.d.ts","sourceRoot":"","sources":["../../src/proxy/proxy-server.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,EAAE,CAAkB;IAC5B,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,UAAU,CAAS;gBAGzB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,EAAE,EAAE,eAAe,EACnB,UAAU,CAAC,EAAE,MAAM;IAarB,IAAI,KAAK,IAAI,MAAM,CAAC,cAAc,GAAG,IAAI,CAExC;IAED,OAAO,CAAC,WAAW;IAqCnB,OAAO,CAAC,WAAW;IAMnB;;;OAGG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAepC,IAAI,IAAI,IAAI;CAOb"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { createInterface } from 'readline';
|
|
3
|
+
import { TokenCounter } from '../utils/token-counter.js';
|
|
4
|
+
import { Logger } from '../utils/logger.js';
|
|
5
|
+
/**
|
|
6
|
+
* MCP Proxy Interceptor — sits between the AI client and an MCP server,
|
|
7
|
+
* capturing every JSON-RPC call's token usage for real cost auditing.
|
|
8
|
+
*/
|
|
9
|
+
export class McpProxyServer {
|
|
10
|
+
child;
|
|
11
|
+
tokenCounter;
|
|
12
|
+
db;
|
|
13
|
+
currentRequestId = null;
|
|
14
|
+
requestStartTime = 0;
|
|
15
|
+
requestToolName = null;
|
|
16
|
+
requestTokens = 0;
|
|
17
|
+
serverName;
|
|
18
|
+
constructor(command, args, env, db, serverName) {
|
|
19
|
+
this.serverName = serverName || command.split('/').pop() || command;
|
|
20
|
+
this.child = spawn(command, args, {
|
|
21
|
+
env: { ...process.env, ...env },
|
|
22
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
23
|
+
});
|
|
24
|
+
this.tokenCounter = new TokenCounter();
|
|
25
|
+
this.db = db;
|
|
26
|
+
this.setupStdout();
|
|
27
|
+
this.setupStderr();
|
|
28
|
+
}
|
|
29
|
+
get stdin() {
|
|
30
|
+
return this.child.stdin;
|
|
31
|
+
}
|
|
32
|
+
setupStdout() {
|
|
33
|
+
const rl = createInterface({ input: this.child.stdout });
|
|
34
|
+
rl.on('line', (line) => {
|
|
35
|
+
try {
|
|
36
|
+
const msg = JSON.parse(line);
|
|
37
|
+
if (msg.id && msg.id === this.currentRequestId) {
|
|
38
|
+
// Response to our tracked tools/call request
|
|
39
|
+
const responseTokens = this.tokenCounter.count(line);
|
|
40
|
+
const record = {
|
|
41
|
+
serverName: this.serverName,
|
|
42
|
+
toolName: this.requestToolName || 'unknown',
|
|
43
|
+
requestTokens: this.requestTokens,
|
|
44
|
+
responseTokens,
|
|
45
|
+
totalTokens: this.requestTokens + responseTokens,
|
|
46
|
+
durationMs: Date.now() - this.requestStartTime,
|
|
47
|
+
timestamp: new Date().toISOString(),
|
|
48
|
+
};
|
|
49
|
+
// Await the DB write so tests can read immediately
|
|
50
|
+
this.db.addCallRecord(record).then(() => this.db.flush()).catch((err) => Logger.debug(`Proxy: failed to store call record: ${err?.message}`));
|
|
51
|
+
this.currentRequestId = null;
|
|
52
|
+
this.requestToolName = null;
|
|
53
|
+
}
|
|
54
|
+
// Forward response to client
|
|
55
|
+
process.stdout.write(line + '\n');
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Non-JSON line — forward as-is
|
|
59
|
+
process.stdout.write(line + '\n');
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
rl.on('close', () => {
|
|
63
|
+
Logger.debug(`[proxy:${this.serverName}] stdout closed`);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
setupStderr() {
|
|
67
|
+
this.child.stderr?.on('data', (data) => {
|
|
68
|
+
process.stderr.write(data);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Called when the AI client writes a request to be proxied.
|
|
73
|
+
* Tracks tools/call requests for token counting.
|
|
74
|
+
*/
|
|
75
|
+
handleClientInput(raw) {
|
|
76
|
+
try {
|
|
77
|
+
const msg = JSON.parse(raw);
|
|
78
|
+
if (msg.method === 'tools/call' && msg.id) {
|
|
79
|
+
this.requestStartTime = Date.now();
|
|
80
|
+
this.currentRequestId = msg.id;
|
|
81
|
+
this.requestToolName = msg.params?.name || 'unknown';
|
|
82
|
+
this.requestTokens = this.tokenCounter.count(raw);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Non-JSON input — forward as-is
|
|
87
|
+
}
|
|
88
|
+
this.child.stdin?.write(raw + '\n');
|
|
89
|
+
}
|
|
90
|
+
kill() {
|
|
91
|
+
try {
|
|
92
|
+
this.child.kill();
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Already dead
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=proxy-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-server.js","sourceRoot":"","sources":["../../src/proxy/proxy-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FullReport, SecurityReport, CostReport, HealthReport } from '../types.js';
|
|
2
|
+
export declare class ReportGenerator {
|
|
3
|
+
formatSecurityReports(reports: SecurityReport[]): string;
|
|
4
|
+
formatCostReports(reports: CostReport[]): string;
|
|
5
|
+
formatHealthReports(reports: HealthReport[]): string;
|
|
6
|
+
formatFullReport(report: FullReport): string;
|
|
7
|
+
toMarkdown(report: FullReport): string;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=report-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report-generator.d.ts","sourceRoot":"","sources":["../../src/reporter/report-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEnF,qBAAa,eAAe;IAC1B,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM;IA0CxD,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM;IAehD,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM;IAepD,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM;IAc5C,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM;CA2DvC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
export class ReportGenerator {
|
|
3
|
+
formatSecurityReports(reports) {
|
|
4
|
+
let out = chalk.bold.underline('\n🔒 Security Scan Results\n');
|
|
5
|
+
for (const r of reports) {
|
|
6
|
+
const grade = r.score >= 80 ? 'A' : r.score >= 60 ? 'B' : r.score >= 40 ? 'C' : 'D';
|
|
7
|
+
const gradeColor = r.score >= 80 ? chalk.green : r.score >= 60 ? chalk.yellow : chalk.red;
|
|
8
|
+
out += `\n${chalk.bold(r.serverName)} - Score: ${gradeColor(grade)} (${r.score})\n`;
|
|
9
|
+
if (r.cves.length > 0) {
|
|
10
|
+
out += ` CVEs: ${chalk.red(String(r.cves.length))} found\n`;
|
|
11
|
+
for (const c of r.cves) {
|
|
12
|
+
const sevColor = c.severity === 'CRITICAL' ? chalk.red : c.severity === 'HIGH' ? chalk.yellow : chalk.gray;
|
|
13
|
+
out += ` ${sevColor(`[${c.severity}]`)} ${c.id}: ${c.summary.substring(0, 80)}\n`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
out += ` CVEs: ${chalk.green('None')}\n`;
|
|
18
|
+
}
|
|
19
|
+
if (!r.authStatus.hasAuthentication)
|
|
20
|
+
out += ` ${chalk.red('⚠ No authentication detected')}\n`;
|
|
21
|
+
if (!r.authStatus.isTransportEncrypted)
|
|
22
|
+
out += ` ${chalk.yellow('⚠ Transport not encrypted')}\n`;
|
|
23
|
+
if (r.typoSquatRisk.length > 0) {
|
|
24
|
+
out += ` ${chalk.red('⚠ Possible typo-squatting detected:')}\n`;
|
|
25
|
+
for (const t of r.typoSquatRisk) {
|
|
26
|
+
out += ` "${t.suspiciousName}" → similar to "${t.similarityTo}" (distance: ${t.distance})\n`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (r.secretsFound.length > 0) {
|
|
30
|
+
out += ` ${chalk.red(`⚠ ${r.secretsFound.length} hardcoded secret(s) detected`)}\n`;
|
|
31
|
+
for (const s of r.secretsFound) {
|
|
32
|
+
out += ` ${chalk.yellow(s.type)} in ${s.location}\n`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (r.recommendations.length > 0) {
|
|
36
|
+
out += ` ${chalk.cyan('Recommendations:')}\n`;
|
|
37
|
+
for (const rec of r.recommendations) {
|
|
38
|
+
out += ` - ${rec}\n`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
formatCostReports(reports) {
|
|
45
|
+
let out = chalk.bold.underline('\n💰 Cost Audit\n');
|
|
46
|
+
for (const r of reports) {
|
|
47
|
+
out += `\n${chalk.bold(r.serverName)}: ${chalk.yellow(String(r.tokensUsed))} tokens, ${chalk.green(`$${r.estimatedCostUSD.toFixed(4)}`)} (${r.pricingModel})\n`;
|
|
48
|
+
out += ` Input: ${r.inputTokens} tokens, Output: ${r.outputTokens} tokens\n`;
|
|
49
|
+
for (const t of r.toolBreakdown) {
|
|
50
|
+
out += ` ${chalk.dim(t.toolName)}: ${t.tokens} tokens, ${t.calls} calls, $${t.cost.toFixed(4)}\n`;
|
|
51
|
+
}
|
|
52
|
+
if (r.note)
|
|
53
|
+
out += ` ${chalk.dim('ℹ️ ' + r.note)}\n`;
|
|
54
|
+
}
|
|
55
|
+
const grandTotal = reports.reduce((sum, r) => sum + r.estimatedCostUSD, 0);
|
|
56
|
+
out += `\n${chalk.bold(`Total estimated cost: $${grandTotal.toFixed(4)}`)}\n`;
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
formatHealthReports(reports) {
|
|
60
|
+
let out = chalk.bold.underline('\n❤️ Health Check\n');
|
|
61
|
+
for (const r of reports) {
|
|
62
|
+
const latencyColor = r.latencyMs > 2000 ? chalk.red : r.latencyMs > 500 ? chalk.yellow : chalk.green;
|
|
63
|
+
const successColor = r.successRate >= 0.9 ? chalk.green : r.successRate >= 0.7 ? chalk.yellow : chalk.red;
|
|
64
|
+
out += `\n${chalk.bold(r.serverName)}: ${latencyColor(`${r.latencyMs}ms`)} latency, ${successColor(`${(r.successRate * 100).toFixed(0)}%`)} success\n`;
|
|
65
|
+
out += ` Tools: ${r.toolCount}, Context Pressure: ${(r.contextPressure * 100).toFixed(0)}%\n`;
|
|
66
|
+
if (r.overloadWarning)
|
|
67
|
+
out += ` ${chalk.yellow(`⚠ Tool overload: ${r.toolCount} tools may confuse agents`)}\n`;
|
|
68
|
+
for (const rec of r.recommendations) {
|
|
69
|
+
out += ` - ${rec}\n`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
formatFullReport(report) {
|
|
75
|
+
return (chalk.bold.cyan(`\n═══════════════════════════════════════════\n`) +
|
|
76
|
+
chalk.bold.cyan(` MCP Guardian Report\n`) +
|
|
77
|
+
chalk.bold.cyan(` ${report.timestamp}\n`) +
|
|
78
|
+
chalk.bold.cyan(` Config: ${report.configPath}\n`) +
|
|
79
|
+
chalk.bold.cyan(`═══════════════════════════════════════════\n`) +
|
|
80
|
+
this.formatSecurityReports(report.security) +
|
|
81
|
+
this.formatCostReports(report.costs) +
|
|
82
|
+
this.formatHealthReports(report.health) +
|
|
83
|
+
`\n${chalk.bold.cyan('Overall Score: ')}${chalk.bold.white(`${report.overallScore}/100`)}\n`);
|
|
84
|
+
}
|
|
85
|
+
toMarkdown(report) {
|
|
86
|
+
let md = `# MCP Guardian Report\n\n**Timestamp:** ${report.timestamp} \n**Overall Score:** ${report.overallScore}/100\n\n`;
|
|
87
|
+
md += `## 🔒 Security\n\n`;
|
|
88
|
+
for (const s of report.security) {
|
|
89
|
+
md += `### ${s.serverName} — Score: ${s.score}\n\n`;
|
|
90
|
+
if (s.cves.length > 0) {
|
|
91
|
+
md += `| CVE | Severity | Summary |\n|-----|----------|--------|\n`;
|
|
92
|
+
for (const cve of s.cves) {
|
|
93
|
+
md += `| ${cve.id} | ${cve.severity} | ${cve.summary.substring(0, 100)} |\n`;
|
|
94
|
+
}
|
|
95
|
+
md += '\n';
|
|
96
|
+
}
|
|
97
|
+
if (!s.authStatus.hasAuthentication)
|
|
98
|
+
md += `⚠️ No authentication detected\n\n`;
|
|
99
|
+
if (!s.authStatus.isTransportEncrypted)
|
|
100
|
+
md += `⚠️ Transport not encrypted\n\n`;
|
|
101
|
+
if (s.typoSquatRisk.length > 0) {
|
|
102
|
+
md += `⚠️ **Typo-squat risks:**\n`;
|
|
103
|
+
for (const t of s.typoSquatRisk) {
|
|
104
|
+
md += `- \`${t.suspiciousName}\` similar to \`${t.similarityTo}\` (distance ${t.distance})\n`;
|
|
105
|
+
}
|
|
106
|
+
md += '\n';
|
|
107
|
+
}
|
|
108
|
+
if (s.secretsFound.length > 0) {
|
|
109
|
+
md += `⚠️ **Secrets found:**\n`;
|
|
110
|
+
for (const sec of s.secretsFound) {
|
|
111
|
+
md += `- \`${sec.type}\` in \`${sec.location}\`\n`;
|
|
112
|
+
}
|
|
113
|
+
md += '\n';
|
|
114
|
+
}
|
|
115
|
+
if (s.recommendations.length > 0) {
|
|
116
|
+
md += `**Recommendations:**\n`;
|
|
117
|
+
for (const rec of s.recommendations)
|
|
118
|
+
md += `- ${rec}\n`;
|
|
119
|
+
md += '\n';
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
md += `## 💰 Costs\n\n`;
|
|
123
|
+
for (const c of report.costs) {
|
|
124
|
+
md += `### ${c.serverName} — ${c.tokensUsed} tokens → $${c.estimatedCostUSD.toFixed(4)}\n\n`;
|
|
125
|
+
md += `| Tool | Calls | Tokens | Cost |\n|------|-------|--------|------|\n`;
|
|
126
|
+
for (const t of c.toolBreakdown) {
|
|
127
|
+
md += `| ${t.toolName} | ${t.calls} | ${t.tokens} | $${t.cost.toFixed(4)} |\n`;
|
|
128
|
+
}
|
|
129
|
+
md += '\n';
|
|
130
|
+
}
|
|
131
|
+
md += `## ❤️ Health\n\n`;
|
|
132
|
+
for (const h of report.health) {
|
|
133
|
+
md += `### ${h.serverName}\n\n`;
|
|
134
|
+
md += `- Latency: ${h.latencyMs}ms\n`;
|
|
135
|
+
md += `- Success rate: ${(h.successRate * 100).toFixed(0)}%\n`;
|
|
136
|
+
md += `- Tools: ${h.toolCount}\n`;
|
|
137
|
+
md += `- Context pressure: ${(h.contextPressure * 100).toFixed(0)}%\n`;
|
|
138
|
+
if (h.overloadWarning)
|
|
139
|
+
md += `⚠️ Tool overload warning (>15 tools)\n`;
|
|
140
|
+
md += '\n';
|
|
141
|
+
}
|
|
142
|
+
return md;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=report-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report-generator.js","sourceRoot":"","sources":["../../src/reporter/report-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { McpServerConfig, AuthStatus } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Probes MCP server configurations for authentication and transport security.
|
|
4
|
+
* Checks for API keys in environment variables, auth tokens in URLs, and
|
|
5
|
+
* whether the transport is encrypted (HTTPS/WSS vs plain HTTP/WS).
|
|
6
|
+
*/
|
|
7
|
+
export declare class AuthProber {
|
|
8
|
+
/**
|
|
9
|
+
* Probe a server config for authentication and transport security status.
|
|
10
|
+
*/
|
|
11
|
+
probe(server: McpServerConfig): AuthStatus;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=auth-prober.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-prober.d.ts","sourceRoot":"","sources":["../../src/scanners/auth-prober.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D;;;;GAIG;AACH,qBAAa,UAAU;IACrB;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE,eAAe,GAAG,UAAU;CAmD3C"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Probes MCP server configurations for authentication and transport security.
|
|
3
|
+
* Checks for API keys in environment variables, auth tokens in URLs, and
|
|
4
|
+
* whether the transport is encrypted (HTTPS/WSS vs plain HTTP/WS).
|
|
5
|
+
*/
|
|
6
|
+
export class AuthProber {
|
|
7
|
+
/**
|
|
8
|
+
* Probe a server config for authentication and transport security status.
|
|
9
|
+
*/
|
|
10
|
+
probe(server) {
|
|
11
|
+
// Check for auth tokens in environment variables
|
|
12
|
+
const authKeys = ['API_KEY', 'AUTH_TOKEN', 'MCP_API_KEY', 'SECRET', 'ACCESS_TOKEN', 'BEARER_TOKEN'];
|
|
13
|
+
let hasAuth = false;
|
|
14
|
+
let method;
|
|
15
|
+
if (server.env) {
|
|
16
|
+
for (const key of authKeys) {
|
|
17
|
+
const value = server.env[key] ?? server.env[key.toLowerCase()] ?? server.env[key.toUpperCase()];
|
|
18
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
19
|
+
hasAuth = true;
|
|
20
|
+
method = 'environment_variable';
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Check for credentials in URL
|
|
26
|
+
if (!hasAuth && server.url) {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = new URL(server.url);
|
|
29
|
+
if (parsed.username || parsed.password) {
|
|
30
|
+
hasAuth = true;
|
|
31
|
+
method = 'url_credentials';
|
|
32
|
+
}
|
|
33
|
+
// Check for auth query params
|
|
34
|
+
const authParams = ['api_key', 'apikey', 'token', 'auth', 'key'];
|
|
35
|
+
for (const param of authParams) {
|
|
36
|
+
if (parsed.searchParams.has(param)) {
|
|
37
|
+
hasAuth = true;
|
|
38
|
+
method = 'query_parameter';
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Invalid URL — skip
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Check transport encryption
|
|
48
|
+
const isEncrypted = server.transport === 'stdio' // local pipe is fine
|
|
49
|
+
|| server.url?.startsWith('https://')
|
|
50
|
+
|| server.url?.startsWith('wss://')
|
|
51
|
+
|| false;
|
|
52
|
+
return {
|
|
53
|
+
hasAuthentication: hasAuth,
|
|
54
|
+
method,
|
|
55
|
+
isTransportEncrypted: isEncrypted,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=auth-prober.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-prober.js","sourceRoot":"","sources":["../../src/scanners/auth-prober.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,OAAO,UAAU;IACrB;;OAEG;IACH,KAAK,CAAC,MAAuB;QAC3B,iDAAiD;QACjD,MAAM,QAAQ,GAAG,CAAC,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;QACpG,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,MAA0B,CAAC;QAE/B,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YACf,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;gBAChG,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACzD,OAAO,GAAG,IAAI,CAAC;oBACf,MAAM,GAAG,sBAAsB,CAAC;oBAChC,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,+BAA+B;QAC/B,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACnC,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;oBACvC,OAAO,GAAG,IAAI,CAAC;oBACf,MAAM,GAAG,iBAAiB,CAAC;gBAC7B,CAAC;gBACD,8BAA8B;gBAC9B,MAAM,UAAU,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;gBACjE,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;oBAC/B,IAAI,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;wBACnC,OAAO,GAAG,IAAI,CAAC;wBACf,MAAM,GAAG,iBAAiB,CAAC;wBAC3B,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,qBAAqB;YACvB,CAAC;QACH,CAAC;QAED,6BAA6B;QAC7B,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,KAAK,OAAO,CAAC,qBAAqB;eACjE,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,UAAU,CAAC;eAClC,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,QAAQ,CAAC;eAChC,KAAK,CAAC;QAEX,OAAO;YACL,iBAAiB,EAAE,OAAO;YAC1B,MAAM;YACN,oBAAoB,EAAE,WAAW;SAClC,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { McpServerConfig } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Detects potentially dangerous commands in MCP server configs.
|
|
4
|
+
* Flags: path traversal, shell metacharacters, non-standard executables.
|
|
5
|
+
*/
|
|
6
|
+
export interface CommandWarning {
|
|
7
|
+
serverName: string;
|
|
8
|
+
field: 'command' | 'args';
|
|
9
|
+
issue: string;
|
|
10
|
+
severity: 'HIGH' | 'MEDIUM' | 'LOW';
|
|
11
|
+
}
|
|
12
|
+
export declare class CommandValidator {
|
|
13
|
+
validate(server: McpServerConfig): CommandWarning[];
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=command-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-validator.d.ts","sourceRoot":"","sources":["../../src/scanners/command-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CACrC;AAoBD,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,cAAc,EAAE;CAmCpD"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const ALLOWED_EXECUTABLES = [
|
|
2
|
+
'npx', 'node', 'python', 'python3', 'uvx', 'deno', 'bun',
|
|
3
|
+
'docker', 'kubectl', 'aws', 'gcloud',
|
|
4
|
+
];
|
|
5
|
+
const SUSPICIOUS_PATTERNS = [
|
|
6
|
+
{ pattern: /\.\.\//, issue: 'Path traversal (../) detected', severity: 'HIGH' },
|
|
7
|
+
{ pattern: /;\s*\w/, issue: 'Shell command chaining (;) detected', severity: 'HIGH' },
|
|
8
|
+
{ pattern: /\|\s*\w/, issue: 'Pipe character (|) detected — possible command chaining', severity: 'HIGH' },
|
|
9
|
+
{ pattern: /\$\{/, issue: 'Shell variable expansion (${}) detected', severity: 'MEDIUM' },
|
|
10
|
+
{ pattern: /`[^`]+`/, issue: 'Backtick command substitution detected', severity: 'HIGH' },
|
|
11
|
+
{ pattern: /&&|\|\|/, issue: 'Shell logical operators (&&/||) detected', severity: 'HIGH' },
|
|
12
|
+
{ pattern: />\s*\//, issue: 'Output redirection (>) to absolute path detected', severity: 'MEDIUM' },
|
|
13
|
+
{ pattern: /\/etc\/passwd|\/etc\/shadow/, issue: 'Reference to sensitive system file detected', severity: 'HIGH' },
|
|
14
|
+
{ pattern: /rm\s+-rf/, issue: 'Destructive command (rm -rf) detected', severity: 'HIGH' },
|
|
15
|
+
{ pattern: /curl\s|wget\s/, issue: 'Network download tool detected in command', severity: 'MEDIUM' },
|
|
16
|
+
];
|
|
17
|
+
export class CommandValidator {
|
|
18
|
+
validate(server) {
|
|
19
|
+
const warnings = [];
|
|
20
|
+
// Check the command field
|
|
21
|
+
if (server.command) {
|
|
22
|
+
const cmdName = server.command.split('/').pop()?.split(' ')[0] || server.command;
|
|
23
|
+
if (!ALLOWED_EXECUTABLES.includes(cmdName) && !cmdName.startsWith('.')) {
|
|
24
|
+
warnings.push({
|
|
25
|
+
serverName: server.name,
|
|
26
|
+
field: 'command',
|
|
27
|
+
issue: `Unrecognized executable: ${cmdName}. Consider using npx or node.`,
|
|
28
|
+
severity: 'MEDIUM',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// Check for suspicious patterns
|
|
32
|
+
for (const { pattern, issue, severity } of SUSPICIOUS_PATTERNS) {
|
|
33
|
+
if (pattern.test(server.command)) {
|
|
34
|
+
warnings.push({ serverName: server.name, field: 'command', issue, severity });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Check args
|
|
39
|
+
if (server.args) {
|
|
40
|
+
const argsStr = server.args.join(' ');
|
|
41
|
+
for (const { pattern, issue, severity } of SUSPICIOUS_PATTERNS) {
|
|
42
|
+
if (pattern.test(argsStr)) {
|
|
43
|
+
warnings.push({ serverName: server.name, field: 'args', issue, severity });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return warnings;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=command-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-validator.js","sourceRoot":"","sources":["../../src/scanners/command-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CveFinding } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Checks packages for known CVEs using OSV.dev and (optionally) NVD.
|
|
4
|
+
*/
|
|
5
|
+
export declare class CveChecker {
|
|
6
|
+
private osv;
|
|
7
|
+
private nvd;
|
|
8
|
+
constructor();
|
|
9
|
+
/**
|
|
10
|
+
* Check a package for known vulnerabilities.
|
|
11
|
+
* Tries OSV.dev first (purl-based), falls back to NVD keyword search.
|
|
12
|
+
*/
|
|
13
|
+
check(packageName: string, version?: string): Promise<CveFinding[]>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=cve-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cve-checker.d.ts","sourceRoot":"","sources":["../../src/scanners/cve-checker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,GAAG,CAAY;;IAOvB;;;OAGG;IACG,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CAW1E"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { OsvClient } from '../clients/osv-client.js';
|
|
2
|
+
import { NvdClient } from '../clients/nvd-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Checks packages for known CVEs using OSV.dev and (optionally) NVD.
|
|
5
|
+
*/
|
|
6
|
+
export class CveChecker {
|
|
7
|
+
osv;
|
|
8
|
+
nvd;
|
|
9
|
+
constructor() {
|
|
10
|
+
this.osv = new OsvClient();
|
|
11
|
+
this.nvd = new NvdClient();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Check a package for known vulnerabilities.
|
|
15
|
+
* Tries OSV.dev first (purl-based), falls back to NVD keyword search.
|
|
16
|
+
*/
|
|
17
|
+
async check(packageName, version) {
|
|
18
|
+
// Try OSV first — it's faster and more accurate for npm packages
|
|
19
|
+
const osvResults = await this.osv.check(packageName, version);
|
|
20
|
+
if (osvResults.length > 0) {
|
|
21
|
+
return osvResults;
|
|
22
|
+
}
|
|
23
|
+
// Fall back to NVD keyword search
|
|
24
|
+
const nvdResults = await this.nvd.search(packageName);
|
|
25
|
+
return nvdResults;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=cve-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cve-checker.js","sourceRoot":"","sources":["../../src/scanners/cve-checker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD;;GAEG;AACH,MAAM,OAAO,UAAU;IACb,GAAG,CAAY;IACf,GAAG,CAAY;IAEvB;QACE,IAAI,CAAC,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK,CAAC,WAAmB,EAAE,OAAgB;QAC/C,iEAAiE;QACjE,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC9D,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,kCAAkC;QAClC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACtD,OAAO,UAAU,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { McpServerConfig, SecretFinding } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Scans MCP server configs for hardcoded secrets in environment variables
|
|
4
|
+
* and command-line arguments.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SecretScanner {
|
|
7
|
+
/**
|
|
8
|
+
* Scan a server config for hardcoded secrets.
|
|
9
|
+
*/
|
|
10
|
+
scan(server: McpServerConfig): SecretFinding[];
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=secret-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-scanner.d.ts","sourceRoot":"","sources":["../../src/scanners/secret-scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgC7D;;;GAGG;AACH,qBAAa,aAAa;IACxB;;OAEG;IACH,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,aAAa,EAAE;CAmC/C"}
|