@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,24 @@
|
|
|
1
|
+
import { McpServerConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parses MCP configuration files from various clients.
|
|
4
|
+
* Supports aggregation across multiple config files with deduplication.
|
|
5
|
+
*/
|
|
6
|
+
export declare class ConfigParser {
|
|
7
|
+
/**
|
|
8
|
+
* Find all known MCP config files on the system.
|
|
9
|
+
*/
|
|
10
|
+
static findConfigPaths(): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Parse a single MCP config file into an array of server configs.
|
|
13
|
+
*/
|
|
14
|
+
static parse(filePath: string): McpServerConfig[];
|
|
15
|
+
/**
|
|
16
|
+
* Parse all discoverable configs, merge with deduplication, and return unified list.
|
|
17
|
+
* First config file takes priority for servers with the same name.
|
|
18
|
+
*/
|
|
19
|
+
static parseAll(): {
|
|
20
|
+
servers: McpServerConfig[];
|
|
21
|
+
sourcePaths: string[];
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=config-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-parser.d.ts","sourceRoot":"","sources":["../src/config-parser.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C;;;GAGG;AACH,qBAAa,YAAY;IACvB;;OAEG;IACH,MAAM,CAAC,eAAe,IAAI,MAAM,EAAE;IA2BlC;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,EAAE;IA6BjD;;;OAGG;IACH,MAAM,CAAC,QAAQ,IAAI;QAAE,OAAO,EAAE,eAAe,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE;CAuBzE"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
/**
|
|
5
|
+
* Parses MCP configuration files from various clients.
|
|
6
|
+
* Supports aggregation across multiple config files with deduplication.
|
|
7
|
+
*/
|
|
8
|
+
export class ConfigParser {
|
|
9
|
+
/**
|
|
10
|
+
* Find all known MCP config files on the system.
|
|
11
|
+
*/
|
|
12
|
+
static findConfigPaths() {
|
|
13
|
+
const home = os.homedir();
|
|
14
|
+
const candidates = [
|
|
15
|
+
// Cline — VS Code
|
|
16
|
+
path.join(home, 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
|
|
17
|
+
path.join(home, '.config', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
|
|
18
|
+
path.join(home, 'AppData', 'Roaming', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
|
|
19
|
+
// Cline — VS Code Insiders
|
|
20
|
+
path.join(home, 'Library', 'Application Support', 'Code - Insiders', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
|
|
21
|
+
// Claude Desktop
|
|
22
|
+
path.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
|
|
23
|
+
path.join(home, '.config', 'Claude', 'claude_desktop_config.json'),
|
|
24
|
+
// Cursor
|
|
25
|
+
path.join(home, '.cursor', 'mcp.json'),
|
|
26
|
+
// Windsurf
|
|
27
|
+
path.join(home, '.codeium', 'windsurf', 'mcp_config.json'),
|
|
28
|
+
];
|
|
29
|
+
return candidates.filter((p) => {
|
|
30
|
+
try {
|
|
31
|
+
return fs.existsSync(p);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parse a single MCP config file into an array of server configs.
|
|
40
|
+
*/
|
|
41
|
+
static parse(filePath) {
|
|
42
|
+
const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
43
|
+
// Normalize different schemas
|
|
44
|
+
let servers;
|
|
45
|
+
if (raw.mcpServers && typeof raw.mcpServers === 'object') {
|
|
46
|
+
servers = raw.mcpServers;
|
|
47
|
+
}
|
|
48
|
+
else if (raw.servers && typeof raw.servers === 'object') {
|
|
49
|
+
servers = raw.servers;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Assume the file itself is a flat map of server name → config
|
|
53
|
+
servers = raw;
|
|
54
|
+
}
|
|
55
|
+
return Object.entries(servers).map(([name, config]) => {
|
|
56
|
+
const cfg = config;
|
|
57
|
+
return {
|
|
58
|
+
name,
|
|
59
|
+
command: typeof cfg.command === 'string' ? cfg.command : undefined,
|
|
60
|
+
args: Array.isArray(cfg.args) ? cfg.args : undefined,
|
|
61
|
+
env: cfg.env && typeof cfg.env === 'object' ? cfg.env : undefined,
|
|
62
|
+
url: typeof cfg.url === 'string' ? cfg.url : undefined,
|
|
63
|
+
transport: (cfg.transport === 'sse' ? 'sse' : 'stdio'),
|
|
64
|
+
packageName: typeof cfg.packageName === 'string' ? cfg.packageName : undefined,
|
|
65
|
+
version: typeof cfg.version === 'string' ? cfg.version : undefined,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Parse all discoverable configs, merge with deduplication, and return unified list.
|
|
71
|
+
* First config file takes priority for servers with the same name.
|
|
72
|
+
*/
|
|
73
|
+
static parseAll() {
|
|
74
|
+
const paths = ConfigParser.findConfigPaths();
|
|
75
|
+
if (paths.length === 0)
|
|
76
|
+
return { servers: [], sourcePaths: [] };
|
|
77
|
+
const seen = new Set();
|
|
78
|
+
const allServers = [];
|
|
79
|
+
for (const p of paths) {
|
|
80
|
+
try {
|
|
81
|
+
const parsed = ConfigParser.parse(p);
|
|
82
|
+
for (const server of parsed) {
|
|
83
|
+
if (!seen.has(server.name)) {
|
|
84
|
+
seen.add(server.name);
|
|
85
|
+
allServers.push(server);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Skip unparseable files
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { servers: allServers, sourcePaths: paths };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=config-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-parser.js","sourceRoot":"","sources":["../src/config-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SecurityScanner } from './services/security-scanner.js';
|
|
2
|
+
import { CostAuditor } from './services/cost-auditor.js';
|
|
3
|
+
import { HealthMonitor } from './services/health-monitor.js';
|
|
4
|
+
import { HistoryDatabase } from './database/history-db.js';
|
|
5
|
+
export interface Container {
|
|
6
|
+
db: HistoryDatabase;
|
|
7
|
+
securityScanner: SecurityScanner;
|
|
8
|
+
costAuditor: CostAuditor;
|
|
9
|
+
healthMonitor: HealthMonitor;
|
|
10
|
+
}
|
|
11
|
+
export declare function createContainer(dbPath?: string): Container;
|
|
12
|
+
//# sourceMappingURL=container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAG3D,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,eAAe,CAAC;IACpB,eAAe,EAAE,eAAe,CAAC;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAY1D"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CveChecker } from './scanners/cve-checker.js';
|
|
2
|
+
import { AuthProber } from './scanners/auth-prober.js';
|
|
3
|
+
import { TypoSquatDetector } from './scanners/typo-squat-detector.js';
|
|
4
|
+
import { SecretScanner } from './scanners/secret-scanner.js';
|
|
5
|
+
import { SecurityScanner } from './services/security-scanner.js';
|
|
6
|
+
import { CostAuditor } from './services/cost-auditor.js';
|
|
7
|
+
import { HealthMonitor } from './services/health-monitor.js';
|
|
8
|
+
import { HistoryDatabase } from './database/history-db.js';
|
|
9
|
+
import { PricingClient } from './clients/pricing-client.js';
|
|
10
|
+
export function createContainer(dbPath) {
|
|
11
|
+
const db = new HistoryDatabase(dbPath);
|
|
12
|
+
const cveChecker = new CveChecker();
|
|
13
|
+
const authProber = new AuthProber();
|
|
14
|
+
const typoDetector = new TypoSquatDetector();
|
|
15
|
+
const secretScanner = new SecretScanner();
|
|
16
|
+
const securityScanner = new SecurityScanner(cveChecker, authProber, typoDetector, secretScanner);
|
|
17
|
+
const pricingClient = new PricingClient();
|
|
18
|
+
const costAuditor = new CostAuditor(pricingClient, db);
|
|
19
|
+
const healthMonitor = new HealthMonitor(db);
|
|
20
|
+
return { db, securityScanner, costAuditor, healthMonitor };
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAS5D,MAAM,UAAU,eAAe,CAAC,MAAe;IAC7C,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IACpC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IACpC,MAAM,YAAY,GAAG,IAAI,iBAAiB,EAAE,CAAC;IAC7C,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;IAC1C,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;IACjG,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;IAC1C,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,EAAE,CAAC,CAAC;IAE5C,OAAO,EAAE,EAAE,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ProxyCallRecord } from '../types.js';
|
|
2
|
+
export interface CallRecordRow {
|
|
3
|
+
tool_name: string;
|
|
4
|
+
request_tokens: number;
|
|
5
|
+
response_tokens: number;
|
|
6
|
+
total_tokens: number;
|
|
7
|
+
duration_ms: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class HistoryDatabase {
|
|
10
|
+
private db;
|
|
11
|
+
private dbPath;
|
|
12
|
+
private initialized;
|
|
13
|
+
private dirty;
|
|
14
|
+
private saveTimer;
|
|
15
|
+
private isInMemory;
|
|
16
|
+
constructor(dbPath?: string);
|
|
17
|
+
private ensureInitialized;
|
|
18
|
+
private scheduleFlush;
|
|
19
|
+
flush(): void;
|
|
20
|
+
getRecentSuccessRate(serverName: string): Promise<number>;
|
|
21
|
+
addSecurityScan(serverName: string, score: number, cveCount: number, details: unknown): Promise<void>;
|
|
22
|
+
addCostRecord(serverName: string, tokens: number, cost: number): Promise<void>;
|
|
23
|
+
addHealthCheck(serverName: string, latency: number, success: boolean, toolCount: number): Promise<void>;
|
|
24
|
+
addCallRecord(record: ProxyCallRecord): Promise<void>;
|
|
25
|
+
getCallRecordsForServer(serverName: string): Promise<ProxyCallRecord[]>;
|
|
26
|
+
close(): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=history-db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-db.d.ts","sourceRoot":"","sources":["../../src/database/history-db.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,UAAU,CAAkB;gBAExB,MAAM,CAAC,EAAE,MAAM;YAMb,iBAAiB;IAoE/B,OAAO,CAAC,aAAa;IASrB,KAAK,IAAI,IAAI;IAcP,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAazD,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IASrG,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9E,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASvG,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IASrD,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAkB7E,KAAK,IAAI,IAAI;CAOd"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import initSqlJs from 'sql.js';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
export class HistoryDatabase {
|
|
6
|
+
db;
|
|
7
|
+
dbPath;
|
|
8
|
+
initialized = false;
|
|
9
|
+
dirty = false;
|
|
10
|
+
saveTimer = null;
|
|
11
|
+
isInMemory = false;
|
|
12
|
+
constructor(dbPath) {
|
|
13
|
+
// ':memory:' means in-memory DB — never persist to disk
|
|
14
|
+
this.isInMemory = dbPath === ':memory:';
|
|
15
|
+
this.dbPath = dbPath || process.env['MCP_GUARDIAN_DB_PATH'] || path.join(os.homedir(), '.mcp-guardian', 'history.db');
|
|
16
|
+
}
|
|
17
|
+
async ensureInitialized() {
|
|
18
|
+
if (this.initialized)
|
|
19
|
+
return;
|
|
20
|
+
if (!this.isInMemory) {
|
|
21
|
+
const dir = path.dirname(this.dbPath);
|
|
22
|
+
if (!fs.existsSync(dir)) {
|
|
23
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const SQL = await initSqlJs();
|
|
27
|
+
if (!this.isInMemory && fs.existsSync(this.dbPath)) {
|
|
28
|
+
const buffer = fs.readFileSync(this.dbPath);
|
|
29
|
+
this.db = new SQL.Database(buffer);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
this.db = new SQL.Database();
|
|
33
|
+
}
|
|
34
|
+
this.db.run(`
|
|
35
|
+
CREATE TABLE IF NOT EXISTS security_scans (
|
|
36
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37
|
+
timestamp TEXT DEFAULT (datetime('now')),
|
|
38
|
+
server_name TEXT NOT NULL,
|
|
39
|
+
score INTEGER NOT NULL,
|
|
40
|
+
cve_count INTEGER NOT NULL DEFAULT 0,
|
|
41
|
+
details TEXT
|
|
42
|
+
)
|
|
43
|
+
`);
|
|
44
|
+
this.db.run(`
|
|
45
|
+
CREATE TABLE IF NOT EXISTS cost_records (
|
|
46
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
47
|
+
timestamp TEXT DEFAULT (datetime('now')),
|
|
48
|
+
server_name TEXT NOT NULL,
|
|
49
|
+
tokens_used INTEGER NOT NULL,
|
|
50
|
+
cost_usd REAL NOT NULL
|
|
51
|
+
)
|
|
52
|
+
`);
|
|
53
|
+
this.db.run(`
|
|
54
|
+
CREATE TABLE IF NOT EXISTS health_checks (
|
|
55
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
56
|
+
timestamp TEXT DEFAULT (datetime('now')),
|
|
57
|
+
server_name TEXT NOT NULL,
|
|
58
|
+
latency_ms INTEGER NOT NULL,
|
|
59
|
+
success INTEGER NOT NULL,
|
|
60
|
+
tool_count INTEGER NOT NULL
|
|
61
|
+
)
|
|
62
|
+
`);
|
|
63
|
+
this.db.run(`
|
|
64
|
+
CREATE TABLE IF NOT EXISTS call_records (
|
|
65
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
66
|
+
timestamp TEXT DEFAULT (datetime('now')),
|
|
67
|
+
server_name TEXT NOT NULL,
|
|
68
|
+
tool_name TEXT NOT NULL,
|
|
69
|
+
request_tokens INTEGER NOT NULL DEFAULT 0,
|
|
70
|
+
response_tokens INTEGER NOT NULL DEFAULT 0,
|
|
71
|
+
total_tokens INTEGER NOT NULL DEFAULT 0,
|
|
72
|
+
duration_ms INTEGER NOT NULL DEFAULT 0
|
|
73
|
+
)
|
|
74
|
+
`);
|
|
75
|
+
this.db.run('CREATE INDEX IF NOT EXISTS idx_security_server ON security_scans(server_name)');
|
|
76
|
+
this.db.run('CREATE INDEX IF NOT EXISTS idx_cost_server ON cost_records(server_name)');
|
|
77
|
+
this.db.run('CREATE INDEX IF NOT EXISTS idx_health_server ON health_checks(server_name)');
|
|
78
|
+
this.db.run('CREATE INDEX IF NOT EXISTS idx_call_server ON call_records(server_name)');
|
|
79
|
+
this.initialized = true;
|
|
80
|
+
}
|
|
81
|
+
scheduleFlush() {
|
|
82
|
+
this.dirty = true;
|
|
83
|
+
if (!this.saveTimer) {
|
|
84
|
+
this.saveTimer = setTimeout(() => {
|
|
85
|
+
this.flush();
|
|
86
|
+
}, 1000);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
flush() {
|
|
90
|
+
if (this.dirty && this.db) {
|
|
91
|
+
if (!this.isInMemory) {
|
|
92
|
+
const data = this.db.export();
|
|
93
|
+
fs.writeFileSync(this.dbPath, data);
|
|
94
|
+
}
|
|
95
|
+
this.dirty = false;
|
|
96
|
+
}
|
|
97
|
+
if (this.saveTimer) {
|
|
98
|
+
clearTimeout(this.saveTimer);
|
|
99
|
+
this.saveTimer = null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async getRecentSuccessRate(serverName) {
|
|
103
|
+
await this.ensureInitialized();
|
|
104
|
+
const result = this.db.exec('SELECT AVG(success) as avg FROM health_checks WHERE server_name = ? ORDER BY timestamp DESC LIMIT 10', [serverName]);
|
|
105
|
+
if (result.length > 0 && result[0].values.length > 0) {
|
|
106
|
+
const avg = result[0].values[0][0];
|
|
107
|
+
return typeof avg === 'number' ? avg : 1;
|
|
108
|
+
}
|
|
109
|
+
return 1;
|
|
110
|
+
}
|
|
111
|
+
async addSecurityScan(serverName, score, cveCount, details) {
|
|
112
|
+
await this.ensureInitialized();
|
|
113
|
+
this.db.run('INSERT INTO security_scans (server_name, score, cve_count, details) VALUES (?, ?, ?, ?)', [serverName, score, cveCount, JSON.stringify(details)]);
|
|
114
|
+
this.scheduleFlush();
|
|
115
|
+
}
|
|
116
|
+
async addCostRecord(serverName, tokens, cost) {
|
|
117
|
+
await this.ensureInitialized();
|
|
118
|
+
this.db.run('INSERT INTO cost_records (server_name, tokens_used, cost_usd) VALUES (?, ?, ?)', [serverName, tokens, cost]);
|
|
119
|
+
this.scheduleFlush();
|
|
120
|
+
}
|
|
121
|
+
async addHealthCheck(serverName, latency, success, toolCount) {
|
|
122
|
+
await this.ensureInitialized();
|
|
123
|
+
this.db.run('INSERT INTO health_checks (server_name, latency_ms, success, tool_count) VALUES (?, ?, ?, ?)', [serverName, latency, success ? 1 : 0, toolCount]);
|
|
124
|
+
this.scheduleFlush();
|
|
125
|
+
}
|
|
126
|
+
async addCallRecord(record) {
|
|
127
|
+
await this.ensureInitialized();
|
|
128
|
+
this.db.run('INSERT INTO call_records (server_name, tool_name, request_tokens, response_tokens, total_tokens, duration_ms) VALUES (?, ?, ?, ?, ?, ?)', [record.serverName, record.toolName, record.requestTokens, record.responseTokens, record.totalTokens, record.durationMs]);
|
|
129
|
+
this.scheduleFlush();
|
|
130
|
+
}
|
|
131
|
+
async getCallRecordsForServer(serverName) {
|
|
132
|
+
await this.ensureInitialized();
|
|
133
|
+
const result = this.db.exec('SELECT server_name, tool_name, request_tokens, response_tokens, total_tokens, duration_ms, timestamp FROM call_records WHERE server_name = ?', [serverName]);
|
|
134
|
+
if (result.length === 0)
|
|
135
|
+
return [];
|
|
136
|
+
return result[0].values.map((row) => ({
|
|
137
|
+
serverName: row[0],
|
|
138
|
+
toolName: row[1],
|
|
139
|
+
requestTokens: row[2],
|
|
140
|
+
responseTokens: row[3],
|
|
141
|
+
totalTokens: row[4],
|
|
142
|
+
durationMs: row[5],
|
|
143
|
+
timestamp: row[6],
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
close() {
|
|
147
|
+
this.flush();
|
|
148
|
+
if (this.db) {
|
|
149
|
+
this.db.close();
|
|
150
|
+
this.initialized = false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=history-db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-db.js","sourceRoot":"","sources":["../../src/database/history-db.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, SetLevelRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { ConfigParser } from './config-parser.js';
|
|
6
|
+
import { ReportGenerator } from './reporter/report-generator.js';
|
|
7
|
+
import { calculateOverallScore } from './utils/scoring.js';
|
|
8
|
+
import { Logger } from './utils/logger.js';
|
|
9
|
+
import { createContainer } from './container.js';
|
|
10
|
+
const container = createContainer();
|
|
11
|
+
const reporter = new ReportGenerator();
|
|
12
|
+
const server = new Server({ name: 'mcp-guardian', version: '0.3.0' }, { capabilities: { tools: {} } });
|
|
13
|
+
// ── Logging capability (MCP spec requirement) ─────────────────────
|
|
14
|
+
let currentLogLevel = 'info';
|
|
15
|
+
server.setRequestHandler(SetLevelRequestSchema, async (request) => {
|
|
16
|
+
const { level } = request.params;
|
|
17
|
+
currentLogLevel = level;
|
|
18
|
+
Logger.info(`Log level set to ${level}`);
|
|
19
|
+
return {};
|
|
20
|
+
});
|
|
21
|
+
// ── MCP Resources: expose latest scan report ──────────────────────
|
|
22
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
23
|
+
resources: [
|
|
24
|
+
{
|
|
25
|
+
uri: 'mcp-guardian://latest-scan',
|
|
26
|
+
name: 'Latest Scan Report',
|
|
27
|
+
description: 'Most recent security scan results across all MCP servers',
|
|
28
|
+
mimeType: 'application/json',
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
}));
|
|
32
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
33
|
+
if (request.params.uri === 'mcp-guardian://latest-scan') {
|
|
34
|
+
// Return the most recent security scan data from DB
|
|
35
|
+
const latestScan = { timestamp: new Date().toISOString(), note: 'Run scan_security or full_report to populate' };
|
|
36
|
+
return {
|
|
37
|
+
contents: [
|
|
38
|
+
{
|
|
39
|
+
uri: request.params.uri,
|
|
40
|
+
mimeType: 'application/json',
|
|
41
|
+
text: JSON.stringify(latestScan, null, 2),
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
throw new Error(`Resource not found: ${request.params.uri}`);
|
|
47
|
+
});
|
|
48
|
+
// ── MCP Prompts: pre-built template for auditing ──────────────────
|
|
49
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
50
|
+
prompts: [
|
|
51
|
+
{
|
|
52
|
+
name: 'audit-config',
|
|
53
|
+
description: 'Generate security audit instructions for an MCP server config',
|
|
54
|
+
arguments: [
|
|
55
|
+
{
|
|
56
|
+
name: 'configPath',
|
|
57
|
+
description: 'Path to an MCP config file (cline_mcp_settings.json)',
|
|
58
|
+
required: false,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
}));
|
|
64
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
65
|
+
const { name, arguments: args } = request.params;
|
|
66
|
+
if (name === 'audit-config') {
|
|
67
|
+
const configPath = args?.configPath || 'auto-discovered';
|
|
68
|
+
return {
|
|
69
|
+
messages: [
|
|
70
|
+
{
|
|
71
|
+
role: 'user',
|
|
72
|
+
content: {
|
|
73
|
+
type: 'text',
|
|
74
|
+
text: `Please audit the MCP configuration at ${configPath} for:
|
|
75
|
+
- Known CVEs in the described servers (via NVD/OSV.dev)
|
|
76
|
+
- Authentication weaknesses (missing API keys, unencrypted transports)
|
|
77
|
+
- Overloaded tool definitions (>15 tools per server)
|
|
78
|
+
- Suspected typo-squatting in server package names
|
|
79
|
+
- Hardcoded secrets in environment variables or command args
|
|
80
|
+
|
|
81
|
+
Use the \`scan_security\` tool with the config path to get started.`,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
throw new Error(`Prompt not found: ${name}`);
|
|
88
|
+
});
|
|
89
|
+
// ── Graceful shutdown ──────────────────────────────────────────────
|
|
90
|
+
const shutdown = () => {
|
|
91
|
+
Logger.info('Shutting down gracefully...');
|
|
92
|
+
container.db.close();
|
|
93
|
+
process.exit(0);
|
|
94
|
+
};
|
|
95
|
+
process.on('SIGINT', shutdown);
|
|
96
|
+
process.on('SIGTERM', shutdown);
|
|
97
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
98
|
+
tools: [
|
|
99
|
+
{
|
|
100
|
+
name: 'scan_security',
|
|
101
|
+
description: 'Scan MCP server configurations for security vulnerabilities (CVEs, auth, typo-squatting, secrets)',
|
|
102
|
+
inputSchema: {
|
|
103
|
+
type: 'object',
|
|
104
|
+
properties: {
|
|
105
|
+
configPath: { type: 'string', description: 'Path to an MCP config file. If omitted, auto-discovers configs.' },
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: 'audit_costs',
|
|
111
|
+
description: 'Audit token usage and estimate costs per MCP server',
|
|
112
|
+
inputSchema: {
|
|
113
|
+
type: 'object',
|
|
114
|
+
properties: {
|
|
115
|
+
serverName: { type: 'string', description: 'Filter to a specific server name. If omitted, audits all.' },
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'check_health',
|
|
121
|
+
description: 'Check health, latency, and reliability of MCP servers',
|
|
122
|
+
inputSchema: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
properties: {
|
|
125
|
+
serverName: { type: 'string', description: 'Filter to a specific server name. If omitted, checks all.' },
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'full_report',
|
|
131
|
+
description: 'Generate a complete security, cost, and health report for all MCP servers',
|
|
132
|
+
inputSchema: {
|
|
133
|
+
type: 'object',
|
|
134
|
+
properties: {
|
|
135
|
+
configPath: { type: 'string', description: 'Path to MCP config file (optional)' },
|
|
136
|
+
format: { type: 'string', enum: ['json', 'markdown', 'text'], description: 'Output format (default: text)' },
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
}));
|
|
142
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
143
|
+
const { name, arguments: args } = request.params;
|
|
144
|
+
// Load servers: single config path, aggregated all, or auto-discover
|
|
145
|
+
let servers;
|
|
146
|
+
let configDescription;
|
|
147
|
+
if (args?.configPath) {
|
|
148
|
+
servers = ConfigParser.parse(args.configPath);
|
|
149
|
+
configDescription = args.configPath;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
const result = ConfigParser.parseAll();
|
|
153
|
+
servers = result.servers;
|
|
154
|
+
configDescription = result.sourcePaths.length > 1
|
|
155
|
+
? `aggregated (${result.sourcePaths.length} files)`
|
|
156
|
+
: (result.sourcePaths[0] || 'auto-detected');
|
|
157
|
+
}
|
|
158
|
+
if (servers.length === 0) {
|
|
159
|
+
return {
|
|
160
|
+
content: [{ type: 'text', text: 'No MCP servers found. Please specify a configPath or ensure MCP configs exist.' }],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
switch (name) {
|
|
164
|
+
case 'scan_security': {
|
|
165
|
+
const results = await Promise.all(servers.map((s) => container.securityScanner.scanServer(s)));
|
|
166
|
+
for (const r of results) {
|
|
167
|
+
container.db.addSecurityScan(r.serverName, r.score, r.cves.length, r);
|
|
168
|
+
}
|
|
169
|
+
return { content: [{ type: 'text', text: reporter.formatSecurityReports(results) }] };
|
|
170
|
+
}
|
|
171
|
+
case 'audit_costs': {
|
|
172
|
+
const filtered = args?.serverName ? servers.filter((s) => s.name === args.serverName) : servers;
|
|
173
|
+
const results = await Promise.all(filtered.map((s) => container.costAuditor.auditServer(s)));
|
|
174
|
+
for (const r of results) {
|
|
175
|
+
container.db.addCostRecord(r.serverName, r.tokensUsed, r.estimatedCostUSD);
|
|
176
|
+
}
|
|
177
|
+
return { content: [{ type: 'text', text: reporter.formatCostReports(results) }] };
|
|
178
|
+
}
|
|
179
|
+
case 'check_health': {
|
|
180
|
+
const filtered = args?.serverName ? servers.filter((s) => s.name === args.serverName) : servers;
|
|
181
|
+
const results = await Promise.all(filtered.map((s) => container.healthMonitor.checkServer(s)));
|
|
182
|
+
for (const r of results) {
|
|
183
|
+
container.db.addHealthCheck(r.serverName, r.latencyMs, r.successRate > 0.5, r.toolCount);
|
|
184
|
+
}
|
|
185
|
+
return { content: [{ type: 'text', text: reporter.formatHealthReports(results) }] };
|
|
186
|
+
}
|
|
187
|
+
case 'full_report': {
|
|
188
|
+
const [security, costs, health] = await Promise.all([
|
|
189
|
+
Promise.all(servers.map((s) => container.securityScanner.scanServer(s))),
|
|
190
|
+
Promise.all(servers.map((s) => container.costAuditor.auditServer(s))),
|
|
191
|
+
Promise.all(servers.map((s) => container.healthMonitor.checkServer(s))),
|
|
192
|
+
]);
|
|
193
|
+
const overallScore = calculateOverallScore(security, health);
|
|
194
|
+
const fullReport = {
|
|
195
|
+
timestamp: new Date().toISOString(),
|
|
196
|
+
configPath: configDescription,
|
|
197
|
+
security,
|
|
198
|
+
costs,
|
|
199
|
+
health,
|
|
200
|
+
overallScore,
|
|
201
|
+
};
|
|
202
|
+
// Store results in DB
|
|
203
|
+
for (const r of security)
|
|
204
|
+
container.db.addSecurityScan(r.serverName, r.score, r.cves.length, r);
|
|
205
|
+
for (const r of costs)
|
|
206
|
+
container.db.addCostRecord(r.serverName, r.tokensUsed, r.estimatedCostUSD);
|
|
207
|
+
for (const r of health)
|
|
208
|
+
container.db.addHealthCheck(r.serverName, r.latencyMs, r.successRate > 0.5, r.toolCount);
|
|
209
|
+
const format = args?.format ?? 'text';
|
|
210
|
+
if (format === 'json') {
|
|
211
|
+
return {
|
|
212
|
+
content: [
|
|
213
|
+
{
|
|
214
|
+
type: 'resource',
|
|
215
|
+
resource: {
|
|
216
|
+
uri: 'report://mcp-guardian/full-report.json',
|
|
217
|
+
mimeType: 'application/json',
|
|
218
|
+
text: JSON.stringify(fullReport, null, 2),
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
{ type: 'text', text: reporter.formatFullReport(fullReport) },
|
|
222
|
+
],
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
let output;
|
|
226
|
+
if (format === 'markdown') {
|
|
227
|
+
output = reporter.toMarkdown(fullReport);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
output = reporter.formatFullReport(fullReport);
|
|
231
|
+
}
|
|
232
|
+
return { content: [{ type: 'text', text: output }] };
|
|
233
|
+
}
|
|
234
|
+
default:
|
|
235
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
async function main() {
|
|
239
|
+
const transport = new StdioServerTransport();
|
|
240
|
+
await server.connect(transport);
|
|
241
|
+
Logger.info('MCP Guardian running on stdio');
|
|
242
|
+
}
|
|
243
|
+
main().catch((err) => {
|
|
244
|
+
Logger.error(`MCP Guardian failed to start: ${err}`);
|
|
245
|
+
process.exit(1);
|
|
246
|
+
});
|
|
247
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|