@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.
Files changed (106) hide show
  1. package/README.md +505 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +216 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/clients/nvd-client.d.ts +17 -0
  7. package/dist/clients/nvd-client.d.ts.map +1 -0
  8. package/dist/clients/nvd-client.js +64 -0
  9. package/dist/clients/nvd-client.js.map +1 -0
  10. package/dist/clients/osv-client.d.ts +19 -0
  11. package/dist/clients/osv-client.d.ts.map +1 -0
  12. package/dist/clients/osv-client.js +60 -0
  13. package/dist/clients/osv-client.js.map +1 -0
  14. package/dist/clients/pricing-client.d.ts +16 -0
  15. package/dist/clients/pricing-client.d.ts.map +1 -0
  16. package/dist/clients/pricing-client.js +171 -0
  17. package/dist/clients/pricing-client.js.map +1 -0
  18. package/dist/config-parser.d.ts +24 -0
  19. package/dist/config-parser.d.ts.map +1 -0
  20. package/dist/config-parser.js +96 -0
  21. package/dist/config-parser.js.map +1 -0
  22. package/dist/container.d.ts +12 -0
  23. package/dist/container.d.ts.map +1 -0
  24. package/dist/container.js +22 -0
  25. package/dist/container.js.map +1 -0
  26. package/dist/database/history-db.d.ts +28 -0
  27. package/dist/database/history-db.d.ts.map +1 -0
  28. package/dist/database/history-db.js +154 -0
  29. package/dist/database/history-db.js.map +1 -0
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +247 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/proxy/proxy-manager.d.ts +12 -0
  35. package/dist/proxy/proxy-manager.d.ts.map +1 -0
  36. package/dist/proxy/proxy-manager.js +37 -0
  37. package/dist/proxy/proxy-manager.js.map +1 -0
  38. package/dist/proxy/proxy-server.d.ts +26 -0
  39. package/dist/proxy/proxy-server.d.ts.map +1 -0
  40. package/dist/proxy/proxy-server.js +99 -0
  41. package/dist/proxy/proxy-server.js.map +1 -0
  42. package/dist/reporter/report-generator.d.ts +9 -0
  43. package/dist/reporter/report-generator.d.ts.map +1 -0
  44. package/dist/reporter/report-generator.js +145 -0
  45. package/dist/reporter/report-generator.js.map +1 -0
  46. package/dist/scanners/auth-prober.d.ts +13 -0
  47. package/dist/scanners/auth-prober.d.ts.map +1 -0
  48. package/dist/scanners/auth-prober.js +59 -0
  49. package/dist/scanners/auth-prober.js.map +1 -0
  50. package/dist/scanners/command-validator.d.ts +15 -0
  51. package/dist/scanners/command-validator.d.ts.map +1 -0
  52. package/dist/scanners/command-validator.js +50 -0
  53. package/dist/scanners/command-validator.js.map +1 -0
  54. package/dist/scanners/cve-checker.d.ts +15 -0
  55. package/dist/scanners/cve-checker.d.ts.map +1 -0
  56. package/dist/scanners/cve-checker.js +28 -0
  57. package/dist/scanners/cve-checker.js.map +1 -0
  58. package/dist/scanners/secret-scanner.d.ts +12 -0
  59. package/dist/scanners/secret-scanner.d.ts.map +1 -0
  60. package/dist/scanners/secret-scanner.js +72 -0
  61. package/dist/scanners/secret-scanner.js.map +1 -0
  62. package/dist/scanners/typo-squat-detector.d.ts +14 -0
  63. package/dist/scanners/typo-squat-detector.d.ts.map +1 -0
  64. package/dist/scanners/typo-squat-detector.js +82 -0
  65. package/dist/scanners/typo-squat-detector.js.map +1 -0
  66. package/dist/services/cost-auditor.d.ts +14 -0
  67. package/dist/services/cost-auditor.d.ts.map +1 -0
  68. package/dist/services/cost-auditor.js +90 -0
  69. package/dist/services/cost-auditor.js.map +1 -0
  70. package/dist/services/health-monitor.d.ts +8 -0
  71. package/dist/services/health-monitor.d.ts.map +1 -0
  72. package/dist/services/health-monitor.js +51 -0
  73. package/dist/services/health-monitor.js.map +1 -0
  74. package/dist/services/security-scanner.d.ts +20 -0
  75. package/dist/services/security-scanner.d.ts.map +1 -0
  76. package/dist/services/security-scanner.js +92 -0
  77. package/dist/services/security-scanner.js.map +1 -0
  78. package/dist/types.d.ts +86 -0
  79. package/dist/types.d.ts.map +1 -0
  80. package/dist/types.js +2 -0
  81. package/dist/types.js.map +1 -0
  82. package/dist/utils/logger.d.ts +13 -0
  83. package/dist/utils/logger.d.ts.map +1 -0
  84. package/dist/utils/logger.js +35 -0
  85. package/dist/utils/logger.js.map +1 -0
  86. package/dist/utils/mcp-client.d.ts +33 -0
  87. package/dist/utils/mcp-client.d.ts.map +1 -0
  88. package/dist/utils/mcp-client.js +182 -0
  89. package/dist/utils/mcp-client.js.map +1 -0
  90. package/dist/utils/rate-limiter.d.ts +31 -0
  91. package/dist/utils/rate-limiter.d.ts.map +1 -0
  92. package/dist/utils/rate-limiter.js +74 -0
  93. package/dist/utils/rate-limiter.js.map +1 -0
  94. package/dist/utils/scoring.d.ts +9 -0
  95. package/dist/utils/scoring.d.ts.map +1 -0
  96. package/dist/utils/scoring.js +19 -0
  97. package/dist/utils/scoring.js.map +1 -0
  98. package/dist/utils/tls-checker.d.ts +13 -0
  99. package/dist/utils/tls-checker.d.ts.map +1 -0
  100. package/dist/utils/tls-checker.js +62 -0
  101. package/dist/utils/tls-checker.js.map +1 -0
  102. package/dist/utils/token-counter.d.ts +7 -0
  103. package/dist/utils/token-counter.d.ts.map +1 -0
  104. package/dist/utils/token-counter.js +16 -0
  105. package/dist/utils/token-counter.js.map +1 -0
  106. package/package.json +52 -0
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Regex patterns for detecting hardcoded secrets in config values.
3
+ */
4
+ const SECRET_PATTERNS = [
5
+ {
6
+ type: 'api_key',
7
+ regex: /(?:api[_-]?key|apikey)\s*[:=]\s*['"]?([A-Za-z0-9_\-]{20,})['"]?/i,
8
+ },
9
+ {
10
+ type: 'token',
11
+ regex: /(?:token|auth|bearer)\s*[:=]\s*['"]?([A-Za-z0-9_\-.]{20,})['"]?/i,
12
+ },
13
+ {
14
+ type: 'private_key',
15
+ regex: /-----BEGIN (?:RSA |EC )?PRIVATE KEY-----/,
16
+ },
17
+ {
18
+ type: 'password',
19
+ regex: /(?:password|passwd|pwd)\s*[:=]\s*['"]?([^'"\s]{8,})['"]?/i,
20
+ },
21
+ {
22
+ type: 'github_token',
23
+ regex: /gh[pousr]_[A-Za-z0-9_]{36,}/,
24
+ },
25
+ {
26
+ type: 'openai_key',
27
+ regex: /sk-[A-Za-z0-9]{32,}/,
28
+ },
29
+ ];
30
+ /**
31
+ * Scans MCP server configs for hardcoded secrets in environment variables
32
+ * and command-line arguments.
33
+ */
34
+ export class SecretScanner {
35
+ /**
36
+ * Scan a server config for hardcoded secrets.
37
+ */
38
+ scan(server) {
39
+ const findings = [];
40
+ // Scan environment variable values
41
+ if (server.env) {
42
+ for (const [key, value] of Object.entries(server.env)) {
43
+ if (typeof value !== 'string')
44
+ continue;
45
+ for (const pattern of SECRET_PATTERNS) {
46
+ if (pattern.regex.test(value)) {
47
+ findings.push({
48
+ type: pattern.type,
49
+ location: `env:${key}`,
50
+ severity: pattern.type === 'private_key' ? 'HIGH' : 'MEDIUM',
51
+ });
52
+ }
53
+ }
54
+ }
55
+ }
56
+ // Scan command-line arguments (might contain inline keys)
57
+ if (server.args && server.args.length > 0) {
58
+ const cmdline = server.args.join(' ');
59
+ for (const pattern of SECRET_PATTERNS) {
60
+ if (pattern.regex.test(cmdline)) {
61
+ findings.push({
62
+ type: pattern.type,
63
+ location: 'command_args',
64
+ severity: 'HIGH',
65
+ });
66
+ }
67
+ }
68
+ }
69
+ return findings;
70
+ }
71
+ }
72
+ //# sourceMappingURL=secret-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-scanner.js","sourceRoot":"","sources":["../../src/scanners/secret-scanner.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,eAAe,GAAsC;IACzD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,kEAAkE;KAC1E;IACD;QACE,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,kEAAkE;KAC1E;IACD;QACE,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,0CAA0C;KAClD;IACD;QACE,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,2DAA2D;KACnE;IACD;QACE,IAAI,EAAE,cAAc;QACpB,KAAK,EAAE,6BAA6B;KACrC;IACD;QACE,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,qBAAqB;KAC7B;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,OAAO,aAAa;IACxB;;OAEG;IACH,IAAI,CAAC,MAAuB;QAC1B,MAAM,QAAQ,GAAoB,EAAE,CAAC;QAErC,mCAAmC;QACnC,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YACf,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtD,IAAI,OAAO,KAAK,KAAK,QAAQ;oBAAE,SAAS;gBACxC,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;oBACtC,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;wBAC9B,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,OAAO,CAAC,IAAI;4BAClB,QAAQ,EAAE,OAAO,GAAG,EAAE;4BACtB,QAAQ,EAAE,OAAO,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;yBAC7D,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,0DAA0D;QAC1D,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACtC,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;gBACtC,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBAChC,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,OAAO,CAAC,IAAI;wBAClB,QAAQ,EAAE,cAAc;wBACxB,QAAQ,EAAE,MAAM;qBACjB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import { TypoSquatResult } from '../types.js';
2
+ /**
3
+ * Detects typo-squatting by comparing package names against known
4
+ * official packages using Levenshtein distance.
5
+ */
6
+ export declare class TypoSquatDetector {
7
+ /**
8
+ * Check a server name against known official packages.
9
+ * Returns suspicious matches (Levenshtein distance 1-2).
10
+ */
11
+ detect(serverName: string): TypoSquatResult[];
12
+ private levenshteinDistance;
13
+ }
14
+ //# sourceMappingURL=typo-squat-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typo-squat-detector.d.ts","sourceRoot":"","sources":["../../src/scanners/typo-squat-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAiC9C;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B;;;OAGG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,EAAE;IAuB7C,OAAO,CAAC,mBAAmB;CA2B5B"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Known official MCP server packages (subset of awesome-mcp-servers).
3
+ * In production, this could be fetched from a registry.
4
+ */
5
+ const OFFICIAL_PACKAGES = [
6
+ '@modelcontextprotocol/server-filesystem',
7
+ '@modelcontextprotocol/server-github',
8
+ '@modelcontextprotocol/server-gitlab',
9
+ '@modelcontextprotocol/server-postgres',
10
+ '@modelcontextprotocol/server-sqlite',
11
+ '@modelcontextprotocol/server-memory',
12
+ '@modelcontextprotocol/server-puppeteer',
13
+ '@modelcontextprotocol/server-brave-search',
14
+ '@modelcontextprotocol/server-fetch',
15
+ '@modelcontextprotocol/server-everything',
16
+ '@modelcontextprotocol/server-sequential-thinking',
17
+ '@modelcontextprotocol/server-time',
18
+ 'mcp-server-brave-search',
19
+ 'mcp-server-puppeteer',
20
+ 'mcp-server-filesystem',
21
+ 'server-filesystem',
22
+ 'server-github',
23
+ 'server-postgres',
24
+ 'server-sqlite',
25
+ 'server-memory',
26
+ 'server-puppeteer',
27
+ 'server-brave-search',
28
+ 'server-fetch',
29
+ 'server-sequential-thinking',
30
+ ];
31
+ /**
32
+ * Detects typo-squatting by comparing package names against known
33
+ * official packages using Levenshtein distance.
34
+ */
35
+ export class TypoSquatDetector {
36
+ /**
37
+ * Check a server name against known official packages.
38
+ * Returns suspicious matches (Levenshtein distance 1-2).
39
+ */
40
+ detect(serverName) {
41
+ if (!serverName)
42
+ return [];
43
+ const results = [];
44
+ const normalized = serverName.toLowerCase().trim();
45
+ for (const official of OFFICIAL_PACKAGES) {
46
+ const officialNorm = official.toLowerCase().trim();
47
+ const distance = this.levenshteinDistance(normalized, officialNorm);
48
+ // Flag very close matches (distance 1-2) that aren't exact matches
49
+ if (distance > 0 && distance <= 2) {
50
+ results.push({
51
+ suspiciousName: serverName,
52
+ similarityTo: official,
53
+ distance,
54
+ });
55
+ }
56
+ }
57
+ return results;
58
+ }
59
+ levenshteinDistance(a, b) {
60
+ const m = a.length;
61
+ const n = b.length;
62
+ // Create two rows for memory efficiency
63
+ let prev = new Array(n + 1);
64
+ let curr = new Array(n + 1);
65
+ for (let j = 0; j <= n; j++) {
66
+ prev[j] = j;
67
+ }
68
+ for (let i = 1; i <= m; i++) {
69
+ curr[0] = i;
70
+ for (let j = 1; j <= n; j++) {
71
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
72
+ curr[j] = Math.min(prev[j] + 1, // deletion
73
+ curr[j - 1] + 1, // insertion
74
+ prev[j - 1] + cost // substitution
75
+ );
76
+ }
77
+ [prev, curr] = [curr, prev];
78
+ }
79
+ return prev[n];
80
+ }
81
+ }
82
+ //# sourceMappingURL=typo-squat-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typo-squat-detector.js","sourceRoot":"","sources":["../../src/scanners/typo-squat-detector.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,iBAAiB,GAAa;IAClC,yCAAyC;IACzC,qCAAqC;IACrC,qCAAqC;IACrC,uCAAuC;IACvC,qCAAqC;IACrC,qCAAqC;IACrC,wCAAwC;IACxC,2CAA2C;IAC3C,oCAAoC;IACpC,yCAAyC;IACzC,kDAAkD;IAClD,mCAAmC;IACnC,yBAAyB;IACzB,sBAAsB;IACtB,uBAAuB;IACvB,mBAAmB;IACnB,eAAe;IACf,iBAAiB;IACjB,eAAe;IACf,eAAe;IACf,kBAAkB;IAClB,qBAAqB;IACrB,cAAc;IACd,4BAA4B;CAC7B,CAAC;AAEF;;;GAGG;AACH,MAAM,OAAO,iBAAiB;IAC5B;;;OAGG;IACH,MAAM,CAAC,UAAkB;QACvB,IAAI,CAAC,UAAU;YAAE,OAAO,EAAE,CAAC;QAE3B,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,MAAM,UAAU,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAEnD,KAAK,MAAM,QAAQ,IAAI,iBAAiB,EAAE,CAAC;YACzC,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;YACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;YAEpE,mEAAmE;YACnE,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;gBAClC,OAAO,CAAC,IAAI,CAAC;oBACX,cAAc,EAAE,UAAU;oBAC1B,YAAY,EAAE,QAAQ;oBACtB,QAAQ;iBACT,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,mBAAmB,CAAC,CAAS,EAAE,CAAS;QAC9C,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QACnB,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QAEnB,wCAAwC;QACxC,IAAI,IAAI,GAAG,IAAI,KAAK,CAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACpC,IAAI,IAAI,GAAG,IAAI,KAAK,CAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QAEpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACd,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5B,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC3C,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAChB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAQ,WAAW;gBAC9B,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAI,YAAY;gBAC/B,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,eAAe;iBACnC,CAAC;YACJ,CAAC;YACD,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC9B,CAAC;QAED,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import { CostReport, McpServerConfig } from '../types.js';
2
+ import { PricingClient } from '../clients/pricing-client.js';
3
+ import { HistoryDatabase } from '../database/history-db.js';
4
+ export declare class CostAuditor {
5
+ private tokenCounter;
6
+ private pricing;
7
+ private db;
8
+ constructor(pricingClient?: PricingClient, db?: HistoryDatabase);
9
+ auditServer(server: McpServerConfig): Promise<CostReport>;
10
+ private buildReportFromRecords;
11
+ countTokens(text: string): number;
12
+ dispose(): void;
13
+ }
14
+ //# sourceMappingURL=cost-auditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-auditor.d.ts","sourceRoot":"","sources":["../../src/services/cost-auditor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAY,eAAe,EAAmB,MAAM,aAAa,CAAC;AAErF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D,qBAAa,WAAW;IACtB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,EAAE,CAA8B;gBAE5B,aAAa,CAAC,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,eAAe;IAMzD,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;IAmC/D,OAAO,CAAC,sBAAsB;IA4C9B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIjC,OAAO,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,90 @@
1
+ import { TokenCounter } from '../utils/token-counter.js';
2
+ import { PricingClient } from '../clients/pricing-client.js';
3
+ import { Logger } from '../utils/logger.js';
4
+ export class CostAuditor {
5
+ tokenCounter;
6
+ pricing;
7
+ db;
8
+ constructor(pricingClient, db) {
9
+ this.tokenCounter = new TokenCounter();
10
+ this.pricing = pricingClient || new PricingClient();
11
+ this.db = db;
12
+ }
13
+ async auditServer(server) {
14
+ if (!this.db) {
15
+ return {
16
+ serverName: server.name,
17
+ tokensUsed: 0,
18
+ inputTokens: 0,
19
+ outputTokens: 0,
20
+ estimatedCostUSD: 0,
21
+ pricingModel: 'unknown',
22
+ toolBreakdown: [],
23
+ note: 'Database not available. Ensure the proxy has been configured.',
24
+ };
25
+ }
26
+ try {
27
+ const records = await this.db.getCallRecordsForServer(server.name);
28
+ if (records.length > 0) {
29
+ return this.buildReportFromRecords(server.name, records);
30
+ }
31
+ }
32
+ catch (err) {
33
+ Logger.debug(`Cost audit: DB read failed for ${server.name}: ${err?.message}`);
34
+ }
35
+ return {
36
+ serverName: server.name,
37
+ tokensUsed: 0,
38
+ inputTokens: 0,
39
+ outputTokens: 0,
40
+ estimatedCostUSD: 0,
41
+ pricingModel: 'unknown',
42
+ toolBreakdown: [],
43
+ note: 'No recorded call data. Use `mcp-guardian proxy` to capture real token usage.',
44
+ };
45
+ }
46
+ buildReportFromRecords(serverName, records) {
47
+ const pricingModel = 'gpt-4o';
48
+ const toolMap = new Map();
49
+ for (const r of records) {
50
+ const existing = toolMap.get(r.toolName) || { inputTokens: 0, outputTokens: 0, calls: 0 };
51
+ existing.inputTokens += r.requestTokens;
52
+ existing.outputTokens += r.responseTokens;
53
+ existing.calls += 1;
54
+ toolMap.set(r.toolName, existing);
55
+ }
56
+ const breakdown = [];
57
+ let totalInput = 0;
58
+ let totalOutput = 0;
59
+ for (const [toolName, data] of toolMap) {
60
+ const totalTokens = data.inputTokens + data.outputTokens;
61
+ const cost = this.pricing.calculateCost(data.inputTokens, pricingModel, false) +
62
+ this.pricing.calculateCost(data.outputTokens, pricingModel, true);
63
+ breakdown.push({
64
+ toolName,
65
+ tokens: totalTokens,
66
+ calls: data.calls,
67
+ cost: Math.round(cost * 10000) / 10000,
68
+ });
69
+ totalInput += data.inputTokens;
70
+ totalOutput += data.outputTokens;
71
+ }
72
+ const totalCost = breakdown.reduce((sum, t) => sum + t.cost, 0);
73
+ return {
74
+ serverName,
75
+ tokensUsed: totalInput + totalOutput,
76
+ inputTokens: totalInput,
77
+ outputTokens: totalOutput,
78
+ estimatedCostUSD: Math.round(totalCost * 10000) / 10000,
79
+ pricingModel,
80
+ toolBreakdown: breakdown,
81
+ };
82
+ }
83
+ countTokens(text) {
84
+ return this.tokenCounter.count(text);
85
+ }
86
+ dispose() {
87
+ this.tokenCounter.free();
88
+ }
89
+ }
90
+ //# sourceMappingURL=cost-auditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-auditor.js","sourceRoot":"","sources":["../../src/services/cost-auditor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,OAAO,WAAW;IACd,YAAY,CAAe;IAC3B,OAAO,CAAgB;IACvB,EAAE,CAA8B;IAExC,YAAY,aAA6B,EAAE,EAAoB;QAC7D,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,aAAa,IAAI,IAAI,aAAa,EAAE,CAAC;QACpD,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAAuB;QACvC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,OAAO;gBACL,UAAU,EAAE,MAAM,CAAC,IAAI;gBACvB,UAAU,EAAE,CAAC;gBACb,WAAW,EAAE,CAAC;gBACd,YAAY,EAAE,CAAC;gBACf,gBAAgB,EAAE,CAAC;gBACnB,YAAY,EAAE,SAAS;gBACvB,aAAa,EAAE,EAAE;gBACjB,IAAI,EAAE,+DAA+D;aACtE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,uBAAuB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACnE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,OAAO,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,MAAM,CAAC,KAAK,CAAC,kCAAkC,MAAM,CAAC,IAAI,KAAK,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;QACjF,CAAC;QAED,OAAO;YACL,UAAU,EAAE,MAAM,CAAC,IAAI;YACvB,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,CAAC;YACf,gBAAgB,EAAE,CAAC;YACnB,YAAY,EAAE,SAAS;YACvB,aAAa,EAAE,EAAE;YACjB,IAAI,EAAE,8EAA8E;SACrF,CAAC;IACJ,CAAC;IAEO,sBAAsB,CAAC,UAAkB,EAAE,OAA0B;QAC3E,MAAM,YAAY,GAAG,QAAQ,CAAC;QAC9B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAwE,CAAC;QAEhG,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YAC1F,QAAQ,CAAC,WAAW,IAAI,CAAC,CAAC,aAAa,CAAC;YACxC,QAAQ,CAAC,YAAY,IAAI,CAAC,CAAC,cAAc,CAAC;YAC1C,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,SAAS,GAAe,EAAE,CAAC;QACjC,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC;YACvC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC;YACzD,MAAM,IAAI,GACR,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,EAAE,KAAK,CAAC;gBACjE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;YAEpE,SAAS,CAAC,IAAI,CAAC;gBACb,QAAQ;gBACR,MAAM,EAAE,WAAW;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,KAAK;aACvC,CAAC,CAAC;YACH,UAAU,IAAI,IAAI,CAAC,WAAW,CAAC;YAC/B,WAAW,IAAI,IAAI,CAAC,YAAY,CAAC;QACnC,CAAC;QAED,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAChE,OAAO;YACL,UAAU;YACV,UAAU,EAAE,UAAU,GAAG,WAAW;YACpC,WAAW,EAAE,UAAU;YACvB,YAAY,EAAE,WAAW;YACzB,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,KAAK;YACvD,YAAY;YACZ,aAAa,EAAE,SAAS;SACzB,CAAC;IACJ,CAAC;IAED,WAAW,CAAC,IAAY;QACtB,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IAED,OAAO;QACL,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import { McpServerConfig, HealthReport } from '../types.js';
2
+ import { HistoryDatabase } from '../database/history-db.js';
3
+ export declare class HealthMonitor {
4
+ private db;
5
+ constructor(db: HistoryDatabase);
6
+ checkServer(server: McpServerConfig): Promise<HealthReport>;
7
+ }
8
+ //# sourceMappingURL=health-monitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-monitor.d.ts","sourceRoot":"","sources":["../../src/services/health-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAkB;gBAEhB,EAAE,EAAE,eAAe;IAIzB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;CA+ClE"}
@@ -0,0 +1,51 @@
1
+ import { McpClient } from '../utils/mcp-client.js';
2
+ export class HealthMonitor {
3
+ db;
4
+ constructor(db) {
5
+ this.db = db;
6
+ }
7
+ async checkServer(server) {
8
+ const start = Date.now();
9
+ const probe = await McpClient.probe(server);
10
+ const latency = probe.latencyMs || (Date.now() - start);
11
+ const historicalRate = await this.db.getRecentSuccessRate(server.name);
12
+ const successRate = probe.success
13
+ ? Math.max(historicalRate, 0.5)
14
+ : Math.min(historicalRate, 0.3);
15
+ const toolCount = probe.toolCount ?? 0;
16
+ const overloadWarning = toolCount > 15;
17
+ const contextPressure = toolCount > 10 ? 0.7 : toolCount > 5 ? 0.4 : 0.2;
18
+ const recs = [];
19
+ if (overloadWarning) {
20
+ recs.push(`Reduce number of tools (currently ${toolCount}) to avoid agent confusion — consider grouping into named subtools`);
21
+ }
22
+ if (toolCount > 20) {
23
+ recs.push('Consider splitting into multiple smaller servers for better reliability');
24
+ }
25
+ if (!probe.success && probe.authRequired) {
26
+ recs.push('Server requires authentication — ensure credentials are configured');
27
+ }
28
+ if (!probe.success && probe.error) {
29
+ recs.push(`Probe failed: ${probe.error}`);
30
+ }
31
+ if (latency > 2000) {
32
+ recs.push(`Server response is slow (${latency}ms) — check network connectivity or server implementation`);
33
+ }
34
+ if (latency > 5000) {
35
+ recs.push(`Server response is extremely slow (${latency}ms) — consider optimizing startup or using a faster transport`);
36
+ }
37
+ if (recs.length === 0) {
38
+ recs.push('Server appears healthy');
39
+ }
40
+ return {
41
+ serverName: server.name,
42
+ latencyMs: latency,
43
+ successRate: Math.round(successRate * 100) / 100,
44
+ contextPressure: Math.round(contextPressure * 100) / 100,
45
+ toolCount,
46
+ overloadWarning,
47
+ recommendations: recs,
48
+ };
49
+ }
50
+ }
51
+ //# sourceMappingURL=health-monitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-monitor.js","sourceRoot":"","sources":["../../src/services/health-monitor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAkB,MAAM,wBAAwB,CAAC;AAEnE,MAAM,OAAO,aAAa;IAChB,EAAE,CAAkB;IAE5B,YAAY,EAAmB;QAC7B,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAAuB;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,KAAK,GAAmB,MAAM,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC;QAExD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACvE,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO;YAC/B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC;YAC/B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QAElC,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC;QACvC,MAAM,eAAe,GAAG,SAAS,GAAG,EAAE,CAAC;QACvC,MAAM,eAAe,GAAG,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAEzE,MAAM,IAAI,GAAa,EAAE,CAAC;QAC1B,IAAI,eAAe,EAAE,CAAC;YACpB,IAAI,CAAC,IAAI,CAAC,qCAAqC,SAAS,oEAAoE,CAAC,CAAC;QAChI,CAAC;QACD,IAAI,SAAS,GAAG,EAAE,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,yEAAyE,CAAC,CAAC;QACvF,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YACzC,IAAI,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5C,CAAC;QACD,IAAI,OAAO,GAAG,IAAI,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,4BAA4B,OAAO,2DAA2D,CAAC,CAAC;QAC5G,CAAC;QACD,IAAI,OAAO,GAAG,IAAI,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,sCAAsC,OAAO,+DAA+D,CAAC,CAAC;QAC1H,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QACtC,CAAC;QAED,OAAO;YACL,UAAU,EAAE,MAAM,CAAC,IAAI;YACvB,SAAS,EAAE,OAAO;YAClB,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC,GAAG,GAAG;YAChD,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,GAAG,CAAC,GAAG,GAAG;YACxD,SAAS;YACT,eAAe;YACf,eAAe,EAAE,IAAI;SACtB,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ import { SecurityReport, McpServerConfig } from '../types.js';
2
+ import { CveChecker } from '../scanners/cve-checker.js';
3
+ import { AuthProber } from '../scanners/auth-prober.js';
4
+ import { TypoSquatDetector } from '../scanners/typo-squat-detector.js';
5
+ import { SecretScanner } from '../scanners/secret-scanner.js';
6
+ import { CommandValidator } from '../scanners/command-validator.js';
7
+ /**
8
+ * Orchestrates all security scanning for a single MCP server.
9
+ * Runs CVE checks, auth probing, typo-squat detection, and secret scanning in parallel.
10
+ */
11
+ export declare class SecurityScanner {
12
+ private cveChecker;
13
+ private authProber;
14
+ private typoDetector;
15
+ private secretScanner;
16
+ private cmdValidator;
17
+ constructor(cveChecker?: CveChecker, authProber?: AuthProber, typoDetector?: TypoSquatDetector, secretScanner?: SecretScanner, cmdValidator?: CommandValidator);
18
+ scanServer(server: McpServerConfig): Promise<SecurityReport>;
19
+ }
20
+ //# sourceMappingURL=security-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-scanner.d.ts","sourceRoot":"","sources":["../../src/services/security-scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAA0D,MAAM,aAAa,CAAC;AACtH,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEpE;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,YAAY,CAAmB;gBAGrC,UAAU,CAAC,EAAE,UAAU,EACvB,UAAU,CAAC,EAAE,UAAU,EACvB,YAAY,CAAC,EAAE,iBAAiB,EAChC,aAAa,CAAC,EAAE,aAAa,EAC7B,YAAY,CAAC,EAAE,gBAAgB;IAS3B,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;CAqBnE"}
@@ -0,0 +1,92 @@
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 { CommandValidator } from '../scanners/command-validator.js';
6
+ /**
7
+ * Orchestrates all security scanning for a single MCP server.
8
+ * Runs CVE checks, auth probing, typo-squat detection, and secret scanning in parallel.
9
+ */
10
+ export class SecurityScanner {
11
+ cveChecker;
12
+ authProber;
13
+ typoDetector;
14
+ secretScanner;
15
+ cmdValidator;
16
+ constructor(cveChecker, authProber, typoDetector, secretScanner, cmdValidator) {
17
+ this.cveChecker = cveChecker || new CveChecker();
18
+ this.authProber = authProber || new AuthProber();
19
+ this.typoDetector = typoDetector || new TypoSquatDetector();
20
+ this.secretScanner = secretScanner || new SecretScanner();
21
+ this.cmdValidator = cmdValidator || new CommandValidator();
22
+ }
23
+ async scanServer(server) {
24
+ const [cves, auth, typos, secrets, cmdWarnings] = await Promise.all([
25
+ this.cveChecker.check(server.packageName || server.name, server.version),
26
+ Promise.resolve(this.authProber.probe(server)),
27
+ Promise.resolve(this.typoDetector.detect(server.name)),
28
+ Promise.resolve(this.secretScanner.scan(server)),
29
+ Promise.resolve(this.cmdValidator.validate(server)),
30
+ ]);
31
+ const score = calculateSecurityScore(cves, auth, typos, secrets, cmdWarnings);
32
+ const recommendations = generateRecommendations(cves, auth, typos, secrets, cmdWarnings);
33
+ return {
34
+ serverName: server.name,
35
+ cves,
36
+ authStatus: auth,
37
+ typoSquatRisk: typos,
38
+ secretsFound: secrets,
39
+ score,
40
+ recommendations,
41
+ };
42
+ }
43
+ }
44
+ function calculateSecurityScore(cves, auth, typos, secrets, cmdWarnings) {
45
+ let score = 100;
46
+ if (cves.some((c) => c.severity === 'CRITICAL'))
47
+ score -= 40;
48
+ if (cves.some((c) => c.severity === 'HIGH'))
49
+ score -= 20;
50
+ if (cves.some((c) => c.severity === 'MEDIUM'))
51
+ score -= 10;
52
+ if (!auth.hasAuthentication)
53
+ score -= 20;
54
+ if (!auth.isTransportEncrypted)
55
+ score -= 10;
56
+ if (typos.length > 0)
57
+ score -= 30;
58
+ if (secrets.length > 0)
59
+ score -= 15;
60
+ if (cmdWarnings.some((w) => w.severity === 'HIGH'))
61
+ score -= 25;
62
+ if (cmdWarnings.some((w) => w.severity === 'MEDIUM'))
63
+ score -= 10;
64
+ return Math.max(0, score);
65
+ }
66
+ function generateRecommendations(cves, auth, typos, secrets, cmdWarnings) {
67
+ const recs = [];
68
+ if (cves.length > 0) {
69
+ const criticalCount = cves.filter((c) => c.severity === 'CRITICAL').length;
70
+ const highCount = cves.filter((c) => c.severity === 'HIGH').length;
71
+ recs.push(`Update to fix ${cves.length} known vulnerabilities${criticalCount > 0 ? ` (${criticalCount} critical)` : ''}${highCount > 0 ? `, ${highCount} high` : ''}`);
72
+ const fixedCves = cves.filter((c) => c.fixedVersion);
73
+ if (fixedCves.length > 0) {
74
+ recs.push(`CVE(s) with available fixes: ${fixedCves.map((c) => `${c.id} → v${c.fixedVersion}`).join(', ')}`);
75
+ }
76
+ }
77
+ if (!auth.hasAuthentication)
78
+ recs.push('Add authentication headers or API keys to prevent unauthorized access');
79
+ if (!auth.isTransportEncrypted)
80
+ recs.push('Use HTTPS or secure transport for remote servers');
81
+ if (typos.length > 0)
82
+ recs.push(`Verify package name against official registry — possible typo-squatting: ${typos.map((t) => t.similarityTo).join(', ')}`);
83
+ if (secrets.length > 0)
84
+ recs.push(`Remove ${secrets.length} hardcoded secret(s) from tool definitions — use environment variable references instead`);
85
+ for (const w of cmdWarnings) {
86
+ recs.push(`[${w.severity}] ${w.field}: ${w.issue}`);
87
+ }
88
+ if (recs.length === 0)
89
+ recs.push('No security issues found');
90
+ return recs;
91
+ }
92
+ //# sourceMappingURL=security-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-scanner.js","sourceRoot":"","sources":["../../src/services/security-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ export interface McpServerConfig {
2
+ name: string;
3
+ command?: string;
4
+ args?: string[];
5
+ env?: Record<string, string>;
6
+ url?: string;
7
+ transport: 'stdio' | 'sse';
8
+ packageName?: string;
9
+ version?: string;
10
+ }
11
+ export interface SecurityReport {
12
+ serverName: string;
13
+ cves: CveFinding[];
14
+ authStatus: AuthStatus;
15
+ typoSquatRisk: TypoSquatResult[];
16
+ secretsFound: SecretFinding[];
17
+ score: number;
18
+ recommendations: string[];
19
+ }
20
+ export interface CveFinding {
21
+ id: string;
22
+ severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
23
+ summary: string;
24
+ fixedVersion?: string;
25
+ }
26
+ export interface AuthStatus {
27
+ hasAuthentication: boolean;
28
+ method?: string;
29
+ isTransportEncrypted: boolean;
30
+ }
31
+ export interface TypoSquatResult {
32
+ suspiciousName: string;
33
+ similarityTo: string;
34
+ distance: number;
35
+ }
36
+ export interface SecretFinding {
37
+ type: string;
38
+ location: string;
39
+ severity: 'HIGH' | 'MEDIUM';
40
+ }
41
+ export interface CostReport {
42
+ serverName: string;
43
+ tokensUsed: number;
44
+ inputTokens: number;
45
+ outputTokens: number;
46
+ estimatedCostUSD: number;
47
+ pricingModel: string;
48
+ toolBreakdown: ToolCost[];
49
+ note?: string;
50
+ }
51
+ export interface ToolCost {
52
+ toolName: string;
53
+ tokens: number;
54
+ calls: number;
55
+ cost: number;
56
+ }
57
+ export interface HealthReport {
58
+ serverName: string;
59
+ latencyMs: number;
60
+ successRate: number;
61
+ contextPressure: number;
62
+ toolCount: number;
63
+ overloadWarning: boolean;
64
+ recommendations: string[];
65
+ }
66
+ export interface FullReport {
67
+ timestamp: string;
68
+ configPath: string;
69
+ security: SecurityReport[];
70
+ costs: CostReport[];
71
+ health: HealthReport[];
72
+ overallScore: number;
73
+ }
74
+ /**
75
+ * Recorded by the MCP proxy interceptor for real cost tracking.
76
+ */
77
+ export interface ProxyCallRecord {
78
+ serverName: string;
79
+ toolName: string;
80
+ requestTokens: number;
81
+ responseTokens: number;
82
+ totalTokens: number;
83
+ durationMs: number;
84
+ timestamp: string;
85
+ }
86
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ export declare enum LogLevel {
2
+ DEBUG = 0,
3
+ INFO = 1,
4
+ WARN = 2,
5
+ ERROR = 3
6
+ }
7
+ export declare class Logger {
8
+ static debug(msg: string): void;
9
+ static info(msg: string): void;
10
+ static warn(msg: string): void;
11
+ static error(msg: string): void;
12
+ }
13
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,oBAAY,QAAQ;IAClB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACV;AAOD,qBAAa,MAAM;IACjB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAM/B,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAM9B,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAM9B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAKhC"}