@bryan-thompson/inspector-assessment-client 1.6.0 → 1.7.1

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 (74) hide show
  1. package/dist/assets/{OAuthCallback-ZcXdfhZQ.js → OAuthCallback-cGhwkoyY.js} +1 -1
  2. package/dist/assets/{OAuthDebugCallback-xt1SlIHS.js → OAuthDebugCallback-2rmUqser.js} +1 -1
  3. package/dist/assets/{index-B3lTiDVe.js → index-BnFixpvH.js} +4 -4
  4. package/dist/index.html +1 -1
  5. package/lib/lib/assessmentTypes.d.ts +670 -0
  6. package/lib/lib/assessmentTypes.d.ts.map +1 -0
  7. package/lib/lib/assessmentTypes.js +220 -0
  8. package/lib/lib/aupPatterns.d.ts +63 -0
  9. package/lib/lib/aupPatterns.d.ts.map +1 -0
  10. package/lib/lib/aupPatterns.js +344 -0
  11. package/lib/lib/prohibitedLibraries.d.ts +76 -0
  12. package/lib/lib/prohibitedLibraries.d.ts.map +1 -0
  13. package/lib/lib/prohibitedLibraries.js +364 -0
  14. package/lib/lib/securityPatterns.d.ts +64 -0
  15. package/lib/lib/securityPatterns.d.ts.map +1 -0
  16. package/lib/lib/securityPatterns.js +453 -0
  17. package/lib/services/assessment/AssessmentOrchestrator.d.ts +88 -0
  18. package/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -0
  19. package/lib/services/assessment/AssessmentOrchestrator.js +418 -0
  20. package/lib/services/assessment/ResponseValidator.d.ts +69 -0
  21. package/lib/services/assessment/ResponseValidator.d.ts.map +1 -0
  22. package/lib/services/assessment/ResponseValidator.js +1038 -0
  23. package/lib/services/assessment/TestDataGenerator.d.ts +86 -0
  24. package/lib/services/assessment/TestDataGenerator.d.ts.map +1 -0
  25. package/lib/services/assessment/TestDataGenerator.js +669 -0
  26. package/lib/services/assessment/TestScenarioEngine.d.ts +91 -0
  27. package/lib/services/assessment/TestScenarioEngine.d.ts.map +1 -0
  28. package/lib/services/assessment/TestScenarioEngine.js +505 -0
  29. package/lib/services/assessment/ToolClassifier.d.ts +61 -0
  30. package/lib/services/assessment/ToolClassifier.d.ts.map +1 -0
  31. package/lib/services/assessment/ToolClassifier.js +349 -0
  32. package/lib/services/assessment/lib/claudeCodeBridge.d.ts +160 -0
  33. package/lib/services/assessment/lib/claudeCodeBridge.d.ts.map +1 -0
  34. package/lib/services/assessment/lib/claudeCodeBridge.js +357 -0
  35. package/lib/services/assessment/modules/AUPComplianceAssessor.d.ts +100 -0
  36. package/lib/services/assessment/modules/AUPComplianceAssessor.d.ts.map +1 -0
  37. package/lib/services/assessment/modules/AUPComplianceAssessor.js +474 -0
  38. package/lib/services/assessment/modules/BaseAssessor.d.ts +71 -0
  39. package/lib/services/assessment/modules/BaseAssessor.d.ts.map +1 -0
  40. package/lib/services/assessment/modules/BaseAssessor.js +171 -0
  41. package/lib/services/assessment/modules/DocumentationAssessor.d.ts +45 -0
  42. package/lib/services/assessment/modules/DocumentationAssessor.d.ts.map +1 -0
  43. package/lib/services/assessment/modules/DocumentationAssessor.js +355 -0
  44. package/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts +25 -0
  45. package/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -0
  46. package/lib/services/assessment/modules/ErrorHandlingAssessor.js +564 -0
  47. package/lib/services/assessment/modules/FunctionalityAssessor.d.ts +20 -0
  48. package/lib/services/assessment/modules/FunctionalityAssessor.d.ts.map +1 -0
  49. package/lib/services/assessment/modules/FunctionalityAssessor.js +253 -0
  50. package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts +70 -0
  51. package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts.map +1 -0
  52. package/lib/services/assessment/modules/MCPSpecComplianceAssessor.js +508 -0
  53. package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts +70 -0
  54. package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -0
  55. package/lib/services/assessment/modules/ManifestValidationAssessor.js +430 -0
  56. package/lib/services/assessment/modules/PortabilityAssessor.d.ts +43 -0
  57. package/lib/services/assessment/modules/PortabilityAssessor.d.ts.map +1 -0
  58. package/lib/services/assessment/modules/PortabilityAssessor.js +347 -0
  59. package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts +41 -0
  60. package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts.map +1 -0
  61. package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.js +256 -0
  62. package/lib/services/assessment/modules/SecurityAssessor.d.ts +176 -0
  63. package/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -0
  64. package/lib/services/assessment/modules/SecurityAssessor.js +1333 -0
  65. package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts +96 -0
  66. package/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -0
  67. package/lib/services/assessment/modules/ToolAnnotationAssessor.js +593 -0
  68. package/lib/services/assessment/modules/UsabilityAssessor.d.ts +21 -0
  69. package/lib/services/assessment/modules/UsabilityAssessor.d.ts.map +1 -0
  70. package/lib/services/assessment/modules/UsabilityAssessor.js +241 -0
  71. package/lib/services/assessment/modules/index.d.ts +33 -0
  72. package/lib/services/assessment/modules/index.d.ts.map +1 -0
  73. package/lib/services/assessment/modules/index.js +35 -0
  74. package/package.json +15 -3
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Portability Assessor
3
+ * Detects hardcoded paths and platform-specific code
4
+ *
5
+ * Checks:
6
+ * - Hardcoded absolute paths
7
+ * - User home directory references
8
+ * - ${BUNDLE_ROOT} anti-pattern (should use ${__dirname})
9
+ * - Platform-specific code without fallbacks
10
+ * - ${__dirname} usage (correct pattern)
11
+ *
12
+ * Reference: MCPB Bundle Portability Requirements
13
+ */
14
+ import { BaseAssessor } from "./BaseAssessor.js";
15
+ /**
16
+ * Patterns for detecting portability issues
17
+ */
18
+ const ISSUE_PATTERNS = {
19
+ // Absolute Unix paths (not ${__dirname})
20
+ absoluteUnixPath: /(?<!\$\{__dirname\}|['"])\/(?:usr|home|var|etc|opt|tmp|Users|Applications)\/[^\s'"]+/g,
21
+ // Absolute Windows paths
22
+ absoluteWindowsPath: /[A-Z]:\\[^\s'"]+/gi,
23
+ // User home directory references
24
+ userHomePath: /(?:~\/|\/Users\/|\/home\/)[^\s'"]+/g,
25
+ // ${BUNDLE_ROOT} anti-pattern
26
+ bundleRootAntipattern: /\$\{BUNDLE_ROOT\}/g,
27
+ // Platform-specific checks without fallbacks
28
+ platformSpecificDarwin: /process\.platform\s*===?\s*['"]darwin['"]/g,
29
+ platformSpecificWin32: /process\.platform\s*===?\s*['"]win32['"]/g,
30
+ platformSpecificLinux: /process\.platform\s*===?\s*['"]linux['"]/g,
31
+ // Hardcoded config paths
32
+ hardcodedConfigPaths: /['"](?:\/etc\/|~\/\.|\.config\/)[^'"]+['"]/g,
33
+ };
34
+ /**
35
+ * Patterns for correct usage (positive signals)
36
+ */
37
+ const GOOD_PATTERNS = {
38
+ // Correct ${__dirname} usage
39
+ dirname: /\$\{__dirname\}/g,
40
+ // process.cwd() (usually acceptable)
41
+ processCwd: /process\.cwd\(\)/g,
42
+ // Cross-platform path handling
43
+ pathJoin: /path\.join\(/g,
44
+ pathResolve: /path\.resolve\(/g,
45
+ };
46
+ export class PortabilityAssessor extends BaseAssessor {
47
+ /**
48
+ * Run portability assessment
49
+ */
50
+ async assess(context) {
51
+ this.log("Starting portability assessment");
52
+ this.testCount = 0;
53
+ const issues = [];
54
+ let scannedFiles = 0;
55
+ let platformSpecificCount = 0;
56
+ let hardcodedPathCount = 0;
57
+ let usesDirname = false;
58
+ let usesBundleRoot = false;
59
+ // Check manifest if available
60
+ if (context.manifestRaw) {
61
+ this.testCount++;
62
+ scannedFiles++;
63
+ const manifestIssues = this.scanFile("manifest.json", context.manifestRaw);
64
+ issues.push(...manifestIssues);
65
+ // Check for ${__dirname} and ${BUNDLE_ROOT} in manifest
66
+ if (GOOD_PATTERNS.dirname.test(context.manifestRaw)) {
67
+ usesDirname = true;
68
+ }
69
+ if (ISSUE_PATTERNS.bundleRootAntipattern.test(context.manifestRaw)) {
70
+ usesBundleRoot = true;
71
+ }
72
+ }
73
+ // Check package.json scripts
74
+ if (context.packageJson) {
75
+ this.testCount++;
76
+ scannedFiles++;
77
+ const packageJson = context.packageJson;
78
+ if (packageJson.scripts) {
79
+ const scriptsStr = JSON.stringify(packageJson.scripts);
80
+ const scriptIssues = this.scanFile("package.json (scripts)", scriptsStr);
81
+ issues.push(...scriptIssues);
82
+ }
83
+ }
84
+ // Check source code files if available
85
+ if (context.sourceCodeFiles && context.config.enableSourceCodeAnalysis) {
86
+ this.log("Scanning source code files for portability issues...");
87
+ for (const [filePath, content] of context.sourceCodeFiles) {
88
+ // Skip irrelevant files
89
+ if (this.shouldSkipFile(filePath))
90
+ continue;
91
+ this.testCount++;
92
+ scannedFiles++;
93
+ const fileIssues = this.scanFile(filePath, content);
94
+ issues.push(...fileIssues);
95
+ // Check for good patterns
96
+ if (GOOD_PATTERNS.dirname.test(content)) {
97
+ usesDirname = true;
98
+ }
99
+ if (ISSUE_PATTERNS.bundleRootAntipattern.test(content)) {
100
+ usesBundleRoot = true;
101
+ }
102
+ }
103
+ }
104
+ // Count issue types
105
+ hardcodedPathCount = issues.filter((i) => i.type === "hardcoded_path" ||
106
+ i.type === "absolute_path" ||
107
+ i.type === "user_home_path").length;
108
+ platformSpecificCount = issues.filter((i) => i.type === "platform_specific").length;
109
+ const status = this.determinePortabilityStatus(issues, usesDirname, usesBundleRoot);
110
+ const explanation = this.generateExplanation(issues, usesDirname, usesBundleRoot, scannedFiles);
111
+ const recommendations = this.generateRecommendations(issues, usesDirname, usesBundleRoot);
112
+ this.log(`Assessment complete: ${issues.length} portability issues found`);
113
+ return {
114
+ issues,
115
+ scannedFiles,
116
+ platformSpecificCount,
117
+ hardcodedPathCount,
118
+ usesDirname,
119
+ usesBundleRoot,
120
+ status,
121
+ explanation,
122
+ recommendations,
123
+ };
124
+ }
125
+ /**
126
+ * Scan a file for portability issues
127
+ */
128
+ scanFile(filePath, content) {
129
+ const issues = [];
130
+ const lines = content.split("\n");
131
+ for (let i = 0; i < lines.length; i++) {
132
+ const line = lines[i];
133
+ const lineNumber = i + 1;
134
+ // Check for ${BUNDLE_ROOT} anti-pattern
135
+ const bundleRootMatches = line.match(ISSUE_PATTERNS.bundleRootAntipattern);
136
+ if (bundleRootMatches) {
137
+ for (const match of bundleRootMatches) {
138
+ issues.push({
139
+ type: "bundle_root_antipattern",
140
+ filePath,
141
+ lineNumber,
142
+ matchedText: match,
143
+ severity: "HIGH",
144
+ recommendation: "Replace ${BUNDLE_ROOT} with ${__dirname} - BUNDLE_ROOT is not supported",
145
+ });
146
+ }
147
+ }
148
+ // Check for absolute Unix paths (excluding __dirname prefixed)
149
+ const cleanLine = line.replace(/\$\{__dirname\}/g, ""); // Remove __dirname to avoid false positives
150
+ const unixPathMatches = cleanLine.match(ISSUE_PATTERNS.absoluteUnixPath);
151
+ if (unixPathMatches) {
152
+ for (const match of unixPathMatches) {
153
+ // Skip if it looks like a URL or comment
154
+ if (match.includes("://") ||
155
+ line.trim().startsWith("//") ||
156
+ line.trim().startsWith("*")) {
157
+ continue;
158
+ }
159
+ issues.push({
160
+ type: "absolute_path",
161
+ filePath,
162
+ lineNumber,
163
+ matchedText: match,
164
+ severity: "HIGH",
165
+ recommendation: "Use relative paths or ${__dirname} for bundle portability",
166
+ });
167
+ }
168
+ }
169
+ // Check for absolute Windows paths
170
+ const windowsPathMatches = line.match(ISSUE_PATTERNS.absoluteWindowsPath);
171
+ if (windowsPathMatches) {
172
+ for (const match of windowsPathMatches) {
173
+ issues.push({
174
+ type: "absolute_path",
175
+ filePath,
176
+ lineNumber,
177
+ matchedText: match,
178
+ severity: "HIGH",
179
+ recommendation: "Use relative paths or path.join() for cross-platform support",
180
+ });
181
+ }
182
+ }
183
+ // Check for user home paths
184
+ const homePathMatches = line.match(ISSUE_PATTERNS.userHomePath);
185
+ if (homePathMatches) {
186
+ for (const match of homePathMatches) {
187
+ // Skip if in a comment
188
+ if (line.trim().startsWith("//") ||
189
+ line.trim().startsWith("*") ||
190
+ line.trim().startsWith("#")) {
191
+ continue;
192
+ }
193
+ issues.push({
194
+ type: "user_home_path",
195
+ filePath,
196
+ lineNumber,
197
+ matchedText: match,
198
+ severity: "MEDIUM",
199
+ recommendation: "Use os.homedir() or environment variable for user home paths",
200
+ });
201
+ }
202
+ }
203
+ // Check for platform-specific code without apparent fallback
204
+ const platformChecks = [
205
+ ISSUE_PATTERNS.platformSpecificDarwin,
206
+ ISSUE_PATTERNS.platformSpecificWin32,
207
+ ISSUE_PATTERNS.platformSpecificLinux,
208
+ ];
209
+ for (const pattern of platformChecks) {
210
+ const matches = line.match(pattern);
211
+ if (matches) {
212
+ // Check if there's a fallback (else clause or default case)
213
+ const hasElse = content
214
+ .substring(content.indexOf(line))
215
+ .includes("else");
216
+ const hasDefault = content
217
+ .substring(content.indexOf(line))
218
+ .includes("default:");
219
+ if (!hasElse && !hasDefault) {
220
+ for (const match of matches) {
221
+ issues.push({
222
+ type: "platform_specific",
223
+ filePath,
224
+ lineNumber,
225
+ matchedText: match,
226
+ severity: "LOW",
227
+ recommendation: "Consider adding fallback for other platforms",
228
+ });
229
+ }
230
+ }
231
+ }
232
+ }
233
+ }
234
+ return issues;
235
+ }
236
+ /**
237
+ * Check if file should be skipped
238
+ */
239
+ shouldSkipFile(filePath) {
240
+ const skipPatterns = [
241
+ /node_modules/,
242
+ /\.test\.(ts|js|tsx|jsx)$/,
243
+ /\.spec\.(ts|js|tsx|jsx)$/,
244
+ /\.d\.ts$/,
245
+ /package-lock\.json$/,
246
+ /yarn\.lock$/,
247
+ /\.map$/,
248
+ /\.min\.(js|css)$/,
249
+ /README\.md$/i,
250
+ /CHANGELOG\.md$/i,
251
+ /LICENSE/i,
252
+ ];
253
+ return skipPatterns.some((pattern) => pattern.test(filePath));
254
+ }
255
+ /**
256
+ * Determine overall status
257
+ */
258
+ determinePortabilityStatus(issues, usesDirname, usesBundleRoot) {
259
+ // ${BUNDLE_ROOT} usage = automatic FAIL
260
+ if (usesBundleRoot) {
261
+ return "FAIL";
262
+ }
263
+ // HIGH severity issues = FAIL
264
+ const highIssues = issues.filter((i) => i.severity === "HIGH");
265
+ if (highIssues.length > 0) {
266
+ return "FAIL";
267
+ }
268
+ // MEDIUM severity issues = NEED_MORE_INFO
269
+ const mediumIssues = issues.filter((i) => i.severity === "MEDIUM");
270
+ if (mediumIssues.length > 0) {
271
+ return "NEED_MORE_INFO";
272
+ }
273
+ // Uses ${__dirname} is a positive signal
274
+ if (usesDirname && issues.length === 0) {
275
+ return "PASS";
276
+ }
277
+ // LOW severity issues only
278
+ if (issues.length > 0) {
279
+ return "NEED_MORE_INFO";
280
+ }
281
+ return "PASS";
282
+ }
283
+ /**
284
+ * Generate explanation
285
+ */
286
+ generateExplanation(issues, usesDirname, usesBundleRoot, scannedFiles) {
287
+ const parts = [];
288
+ if (usesBundleRoot) {
289
+ parts.push("CRITICAL: Uses ${BUNDLE_ROOT} which is not supported in MCPB bundles.");
290
+ }
291
+ if (issues.length === 0) {
292
+ parts.push("No portability issues detected.");
293
+ }
294
+ else {
295
+ const highCount = issues.filter((i) => i.severity === "HIGH").length;
296
+ const mediumCount = issues.filter((i) => i.severity === "MEDIUM").length;
297
+ if (highCount > 0) {
298
+ parts.push(`${highCount} high-severity portability issue(s) found.`);
299
+ }
300
+ if (mediumCount > 0) {
301
+ parts.push(`${mediumCount} medium-severity issue(s) found.`);
302
+ }
303
+ }
304
+ if (usesDirname) {
305
+ parts.push("Uses ${__dirname} correctly for relative paths.");
306
+ }
307
+ parts.push(`Scanned ${scannedFiles} file(s).`);
308
+ return parts.join(" ");
309
+ }
310
+ /**
311
+ * Generate recommendations
312
+ */
313
+ generateRecommendations(issues, usesDirname, usesBundleRoot) {
314
+ const recommendations = [];
315
+ if (usesBundleRoot) {
316
+ recommendations.push("CRITICAL: Replace all ${BUNDLE_ROOT} with ${__dirname} - BUNDLE_ROOT variable is not supported in MCPB bundles.");
317
+ }
318
+ // Group issues by type
319
+ const byType = new Map();
320
+ for (const issue of issues) {
321
+ const existing = byType.get(issue.type) || [];
322
+ existing.push(issue);
323
+ byType.set(issue.type, existing);
324
+ }
325
+ // Add recommendations by type
326
+ for (const [type, typeIssues] of byType) {
327
+ if (type === "bundle_root_antipattern")
328
+ continue; // Already handled
329
+ const first = typeIssues[0];
330
+ if (typeIssues.length === 1) {
331
+ recommendations.push(`${first.filePath}:${first.lineNumber}: ${first.recommendation}`);
332
+ }
333
+ else {
334
+ recommendations.push(`${typeIssues.length} ${type.replace(/_/g, " ")} issues: ${first.recommendation}`);
335
+ }
336
+ }
337
+ if (recommendations.length === 0) {
338
+ if (usesDirname) {
339
+ recommendations.push("Server uses proper relative paths with ${__dirname}. Good portability.");
340
+ }
341
+ else {
342
+ recommendations.push("Consider using ${__dirname} for paths in manifest.json for better portability.");
343
+ }
344
+ }
345
+ return recommendations;
346
+ }
347
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Prohibited Libraries Assessor
3
+ * Detects financial and media processing libraries per Policy #28-30
4
+ *
5
+ * Checks:
6
+ * - package.json dependencies
7
+ * - requirements.txt (Python)
8
+ * - Source code imports (if sourceCodePath provided)
9
+ *
10
+ * Reference: Anthropic MCP Directory Policy #28-30
11
+ */
12
+ import { BaseAssessor } from "./BaseAssessor.js";
13
+ import { AssessmentContext } from "../AssessmentOrchestrator.js";
14
+ import type { ProhibitedLibrariesAssessment } from "../../../lib/assessmentTypes.js";
15
+ export declare class ProhibitedLibrariesAssessor extends BaseAssessor {
16
+ /**
17
+ * Run prohibited libraries assessment
18
+ */
19
+ assess(context: AssessmentContext): Promise<ProhibitedLibrariesAssessment>;
20
+ /**
21
+ * Check if file is a source file worth scanning
22
+ */
23
+ private isSourceFile;
24
+ /**
25
+ * De-duplicate matches, keeping the most severe
26
+ */
27
+ private deduplicateMatches;
28
+ /**
29
+ * Calculate overall status from matches
30
+ */
31
+ private calculateStatusFromMatches;
32
+ /**
33
+ * Generate explanation
34
+ */
35
+ private generateExplanation;
36
+ /**
37
+ * Generate recommendations
38
+ */
39
+ private generateRecommendations;
40
+ }
41
+ //# sourceMappingURL=ProhibitedLibrariesAssessor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProhibitedLibrariesAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ProhibitedLibrariesAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EACV,6BAA6B,EAG9B,MAAM,uBAAuB,CAAC;AAO/B,qBAAa,2BAA4B,SAAQ,YAAY;IAC3D;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,6BAA6B,CAAC;IA4IzC;;OAEG;IACH,OAAO,CAAC,YAAY;IA0BpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAqB1B;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAuBlC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAoD3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CAqDhC"}
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Prohibited Libraries Assessor
3
+ * Detects financial and media processing libraries per Policy #28-30
4
+ *
5
+ * Checks:
6
+ * - package.json dependencies
7
+ * - requirements.txt (Python)
8
+ * - Source code imports (if sourceCodePath provided)
9
+ *
10
+ * Reference: Anthropic MCP Directory Policy #28-30
11
+ */
12
+ import { BaseAssessor } from "./BaseAssessor.js";
13
+ import { checkPackageJsonDependencies, checkRequirementsTxt, checkSourceImports, } from "../../../lib/prohibitedLibraries.js";
14
+ export class ProhibitedLibrariesAssessor extends BaseAssessor {
15
+ /**
16
+ * Run prohibited libraries assessment
17
+ */
18
+ async assess(context) {
19
+ this.log("Starting prohibited libraries assessment");
20
+ this.testCount = 0;
21
+ const matches = [];
22
+ const scannedFiles = [];
23
+ let hasFinancialLibraries = false;
24
+ let hasMediaLibraries = false;
25
+ // Check package.json dependencies
26
+ if (context.packageJson) {
27
+ this.log("Scanning package.json dependencies...");
28
+ this.testCount++;
29
+ scannedFiles.push("package.json");
30
+ const packageJson = context.packageJson;
31
+ const depMatches = checkPackageJsonDependencies(packageJson);
32
+ for (const match of depMatches) {
33
+ matches.push({
34
+ name: match.library.name,
35
+ category: match.library.category,
36
+ location: "package.json",
37
+ severity: match.library.severity,
38
+ reason: match.library.reason,
39
+ policyReference: match.library.policyReference,
40
+ });
41
+ if (match.library.category === "financial" ||
42
+ match.library.category === "payments" ||
43
+ match.library.category === "banking") {
44
+ hasFinancialLibraries = true;
45
+ }
46
+ if (match.library.category === "media") {
47
+ hasMediaLibraries = true;
48
+ }
49
+ }
50
+ }
51
+ // Check source code files if available
52
+ if (context.sourceCodeFiles && context.config.enableSourceCodeAnalysis) {
53
+ this.log("Scanning source code files...");
54
+ for (const [filePath, content] of context.sourceCodeFiles) {
55
+ // Check Python requirements files
56
+ if (filePath.endsWith("requirements.txt") ||
57
+ filePath.endsWith("requirements-dev.txt")) {
58
+ this.testCount++;
59
+ scannedFiles.push(filePath);
60
+ const reqMatches = checkRequirementsTxt(content);
61
+ for (const match of reqMatches) {
62
+ matches.push({
63
+ name: match.library.name,
64
+ category: match.library.category,
65
+ location: "requirements.txt",
66
+ filePath,
67
+ lineNumber: match.lineNumber,
68
+ severity: match.library.severity,
69
+ reason: match.library.reason,
70
+ policyReference: match.library.policyReference,
71
+ });
72
+ if (match.library.category === "financial" ||
73
+ match.library.category === "payments" ||
74
+ match.library.category === "banking") {
75
+ hasFinancialLibraries = true;
76
+ }
77
+ if (match.library.category === "media") {
78
+ hasMediaLibraries = true;
79
+ }
80
+ }
81
+ }
82
+ // Check source code imports
83
+ if (this.isSourceFile(filePath)) {
84
+ this.testCount++;
85
+ scannedFiles.push(filePath);
86
+ const importMatches = checkSourceImports(content);
87
+ for (const match of importMatches) {
88
+ matches.push({
89
+ name: match.library.name,
90
+ category: match.library.category,
91
+ location: "source_import",
92
+ filePath,
93
+ lineNumber: match.lineNumber,
94
+ severity: match.library.severity,
95
+ reason: match.library.reason,
96
+ policyReference: match.library.policyReference,
97
+ });
98
+ if (match.library.category === "financial" ||
99
+ match.library.category === "payments" ||
100
+ match.library.category === "banking") {
101
+ hasFinancialLibraries = true;
102
+ }
103
+ if (match.library.category === "media") {
104
+ hasMediaLibraries = true;
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+ // De-duplicate matches by library name
111
+ const uniqueMatches = this.deduplicateMatches(matches);
112
+ const status = this.calculateStatusFromMatches(uniqueMatches);
113
+ const explanation = this.generateExplanation(uniqueMatches, hasFinancialLibraries, hasMediaLibraries, scannedFiles);
114
+ const recommendations = this.generateRecommendations(uniqueMatches);
115
+ this.log(`Assessment complete: ${uniqueMatches.length} prohibited libraries found`);
116
+ return {
117
+ matches: uniqueMatches,
118
+ scannedFiles,
119
+ hasFinancialLibraries,
120
+ hasMediaLibraries,
121
+ status,
122
+ explanation,
123
+ recommendations,
124
+ };
125
+ }
126
+ /**
127
+ * Check if file is a source file worth scanning
128
+ */
129
+ isSourceFile(filePath) {
130
+ const sourceExtensions = [
131
+ ".ts",
132
+ ".tsx",
133
+ ".js",
134
+ ".jsx",
135
+ ".mjs",
136
+ ".cjs",
137
+ ".py",
138
+ ".rs",
139
+ ".go",
140
+ ];
141
+ // Skip test files and node_modules
142
+ if (filePath.includes("node_modules") ||
143
+ filePath.includes(".test.") ||
144
+ filePath.includes(".spec.") ||
145
+ filePath.includes("__tests__")) {
146
+ return false;
147
+ }
148
+ return sourceExtensions.some((ext) => filePath.endsWith(ext));
149
+ }
150
+ /**
151
+ * De-duplicate matches, keeping the most severe
152
+ */
153
+ deduplicateMatches(matches) {
154
+ const byName = new Map();
155
+ for (const match of matches) {
156
+ const existing = byName.get(match.name);
157
+ if (!existing) {
158
+ byName.set(match.name, match);
159
+ }
160
+ else {
161
+ // Keep the more severe match
162
+ const severityOrder = { BLOCKING: 3, HIGH: 2, MEDIUM: 1 };
163
+ if (severityOrder[match.severity] > severityOrder[existing.severity]) {
164
+ byName.set(match.name, match);
165
+ }
166
+ }
167
+ }
168
+ return Array.from(byName.values());
169
+ }
170
+ /**
171
+ * Calculate overall status from matches
172
+ */
173
+ calculateStatusFromMatches(matches) {
174
+ // Any BLOCKING library = FAIL
175
+ const blockingMatches = matches.filter((m) => m.severity === "BLOCKING");
176
+ if (blockingMatches.length > 0) {
177
+ return "FAIL";
178
+ }
179
+ // HIGH severity = NEED_MORE_INFO (requires justification)
180
+ const highMatches = matches.filter((m) => m.severity === "HIGH");
181
+ if (highMatches.length > 0) {
182
+ return "NEED_MORE_INFO";
183
+ }
184
+ // MEDIUM severity = PASS with notes
185
+ if (matches.length > 0) {
186
+ return "NEED_MORE_INFO";
187
+ }
188
+ return "PASS";
189
+ }
190
+ /**
191
+ * Generate explanation
192
+ */
193
+ generateExplanation(matches, hasFinancial, hasMedia, scannedFiles) {
194
+ const parts = [];
195
+ if (matches.length === 0) {
196
+ parts.push("No prohibited libraries detected. Server appears compliant with Policy #28-30.");
197
+ }
198
+ else {
199
+ const blockingCount = matches.filter((m) => m.severity === "BLOCKING").length;
200
+ const highCount = matches.filter((m) => m.severity === "HIGH").length;
201
+ const mediumCount = matches.filter((m) => m.severity === "MEDIUM").length;
202
+ if (blockingCount > 0) {
203
+ parts.push(`BLOCKING: ${blockingCount} prohibited library/libraries detected that violate MCP Directory policy.`);
204
+ }
205
+ if (highCount > 0) {
206
+ parts.push(`HIGH: ${highCount} library/libraries detected that require justification for MCP server use.`);
207
+ }
208
+ if (mediumCount > 0) {
209
+ parts.push(`MEDIUM: ${mediumCount} library/libraries flagged for review.`);
210
+ }
211
+ if (hasFinancial) {
212
+ parts.push("Financial/payment processing libraries detected - violates Policy #28-29.");
213
+ }
214
+ if (hasMedia) {
215
+ parts.push("Media processing libraries detected - may require justification per Policy #30.");
216
+ }
217
+ }
218
+ parts.push(`Scanned ${scannedFiles.length} file(s).`);
219
+ return parts.join(" ");
220
+ }
221
+ /**
222
+ * Generate recommendations
223
+ */
224
+ generateRecommendations(matches) {
225
+ const recommendations = [];
226
+ // Group by severity
227
+ const blocking = matches.filter((m) => m.severity === "BLOCKING");
228
+ const high = matches.filter((m) => m.severity === "HIGH");
229
+ const medium = matches.filter((m) => m.severity === "MEDIUM");
230
+ if (blocking.length > 0) {
231
+ recommendations.push("BLOCKING - The following libraries must be removed for MCP Directory approval:");
232
+ for (const match of blocking) {
233
+ recommendations.push(`- ${match.name} (${match.policyReference}): ${match.reason}`);
234
+ }
235
+ }
236
+ if (high.length > 0) {
237
+ recommendations.push("HIGH - The following libraries require strong justification:");
238
+ for (const match of high) {
239
+ recommendations.push(`- ${match.name} (${match.policyReference}): ${match.reason}`);
240
+ }
241
+ }
242
+ if (medium.length > 0) {
243
+ recommendations.push("MEDIUM - Review the following libraries for necessity:");
244
+ for (const match of medium.slice(0, 3)) {
245
+ recommendations.push(`- ${match.name} (${match.policyReference}): ${match.reason}`);
246
+ }
247
+ }
248
+ if (matches.length === 0) {
249
+ recommendations.push("No prohibited libraries detected. Server is compliant with library restrictions.");
250
+ }
251
+ else {
252
+ recommendations.push("Reference: MCP Directory Policy #28-30 restricts financial transaction and media processing libraries.");
253
+ }
254
+ return recommendations;
255
+ }
256
+ }