@bryan-thompson/inspector-assessment 1.6.0 → 1.7.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 (76) hide show
  1. package/cli/build/assess-full.js +528 -0
  2. package/cli/build/assess-security.js +342 -0
  3. package/client/dist/assets/{OAuthCallback-ZcXdfhZQ.js → OAuthCallback-Xo9zS7pv.js} +1 -1
  4. package/client/dist/assets/{OAuthDebugCallback-xt1SlIHS.js → OAuthDebugCallback-CaIey8K_.js} +1 -1
  5. package/client/dist/assets/{index-B3lTiDVe.js → index-nCPw6E-c.js} +4 -4
  6. package/client/dist/index.html +1 -1
  7. package/client/lib/lib/assessmentTypes.d.ts +670 -0
  8. package/client/lib/lib/assessmentTypes.d.ts.map +1 -0
  9. package/client/lib/lib/assessmentTypes.js +220 -0
  10. package/client/lib/lib/aupPatterns.d.ts +63 -0
  11. package/client/lib/lib/aupPatterns.d.ts.map +1 -0
  12. package/client/lib/lib/aupPatterns.js +344 -0
  13. package/client/lib/lib/prohibitedLibraries.d.ts +76 -0
  14. package/client/lib/lib/prohibitedLibraries.d.ts.map +1 -0
  15. package/client/lib/lib/prohibitedLibraries.js +364 -0
  16. package/client/lib/lib/securityPatterns.d.ts +64 -0
  17. package/client/lib/lib/securityPatterns.d.ts.map +1 -0
  18. package/client/lib/lib/securityPatterns.js +453 -0
  19. package/client/lib/services/assessment/AssessmentOrchestrator.d.ts +88 -0
  20. package/client/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -0
  21. package/client/lib/services/assessment/AssessmentOrchestrator.js +418 -0
  22. package/client/lib/services/assessment/ResponseValidator.d.ts +69 -0
  23. package/client/lib/services/assessment/ResponseValidator.d.ts.map +1 -0
  24. package/client/lib/services/assessment/ResponseValidator.js +1038 -0
  25. package/client/lib/services/assessment/TestDataGenerator.d.ts +86 -0
  26. package/client/lib/services/assessment/TestDataGenerator.d.ts.map +1 -0
  27. package/client/lib/services/assessment/TestDataGenerator.js +669 -0
  28. package/client/lib/services/assessment/TestScenarioEngine.d.ts +91 -0
  29. package/client/lib/services/assessment/TestScenarioEngine.d.ts.map +1 -0
  30. package/client/lib/services/assessment/TestScenarioEngine.js +505 -0
  31. package/client/lib/services/assessment/ToolClassifier.d.ts +61 -0
  32. package/client/lib/services/assessment/ToolClassifier.d.ts.map +1 -0
  33. package/client/lib/services/assessment/ToolClassifier.js +349 -0
  34. package/client/lib/services/assessment/lib/claudeCodeBridge.d.ts +160 -0
  35. package/client/lib/services/assessment/lib/claudeCodeBridge.d.ts.map +1 -0
  36. package/client/lib/services/assessment/lib/claudeCodeBridge.js +357 -0
  37. package/client/lib/services/assessment/modules/AUPComplianceAssessor.d.ts +100 -0
  38. package/client/lib/services/assessment/modules/AUPComplianceAssessor.d.ts.map +1 -0
  39. package/client/lib/services/assessment/modules/AUPComplianceAssessor.js +474 -0
  40. package/client/lib/services/assessment/modules/BaseAssessor.d.ts +71 -0
  41. package/client/lib/services/assessment/modules/BaseAssessor.d.ts.map +1 -0
  42. package/client/lib/services/assessment/modules/BaseAssessor.js +171 -0
  43. package/client/lib/services/assessment/modules/DocumentationAssessor.d.ts +45 -0
  44. package/client/lib/services/assessment/modules/DocumentationAssessor.d.ts.map +1 -0
  45. package/client/lib/services/assessment/modules/DocumentationAssessor.js +355 -0
  46. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts +25 -0
  47. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -0
  48. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.js +564 -0
  49. package/client/lib/services/assessment/modules/FunctionalityAssessor.d.ts +20 -0
  50. package/client/lib/services/assessment/modules/FunctionalityAssessor.d.ts.map +1 -0
  51. package/client/lib/services/assessment/modules/FunctionalityAssessor.js +253 -0
  52. package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts +70 -0
  53. package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts.map +1 -0
  54. package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.js +508 -0
  55. package/client/lib/services/assessment/modules/ManifestValidationAssessor.d.ts +70 -0
  56. package/client/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -0
  57. package/client/lib/services/assessment/modules/ManifestValidationAssessor.js +430 -0
  58. package/client/lib/services/assessment/modules/PortabilityAssessor.d.ts +43 -0
  59. package/client/lib/services/assessment/modules/PortabilityAssessor.d.ts.map +1 -0
  60. package/client/lib/services/assessment/modules/PortabilityAssessor.js +347 -0
  61. package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts +41 -0
  62. package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts.map +1 -0
  63. package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.js +256 -0
  64. package/client/lib/services/assessment/modules/SecurityAssessor.d.ts +176 -0
  65. package/client/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -0
  66. package/client/lib/services/assessment/modules/SecurityAssessor.js +1333 -0
  67. package/client/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts +96 -0
  68. package/client/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -0
  69. package/client/lib/services/assessment/modules/ToolAnnotationAssessor.js +593 -0
  70. package/client/lib/services/assessment/modules/UsabilityAssessor.d.ts +21 -0
  71. package/client/lib/services/assessment/modules/UsabilityAssessor.d.ts.map +1 -0
  72. package/client/lib/services/assessment/modules/UsabilityAssessor.js +241 -0
  73. package/client/lib/services/assessment/modules/index.d.ts +33 -0
  74. package/client/lib/services/assessment/modules/index.d.ts.map +1 -0
  75. package/client/lib/services/assessment/modules/index.js +35 -0
  76. package/package.json +5 -2
@@ -0,0 +1,528 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Full Assessment Runner CLI
4
+ *
5
+ * Runs comprehensive MCP server assessment using AssessmentOrchestrator
6
+ * with all 11 assessor modules and optional Claude Code integration.
7
+ *
8
+ * Usage:
9
+ * mcp-assess-full --server <server-name> [--claude-enabled] [--full]
10
+ * mcp-assess-full my-server --source ./my-server --output ./results.json
11
+ */
12
+ import * as fs from "fs";
13
+ import * as path from "path";
14
+ import * as os from "os";
15
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
16
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
17
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
18
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
19
+ // Import from local client lib (will use package exports when published)
20
+ import { AssessmentOrchestrator, } from "../../client/lib/services/assessment/AssessmentOrchestrator.js";
21
+ import { DEFAULT_ASSESSMENT_CONFIG, } from "../../client/lib/lib/assessmentTypes.js";
22
+ import { FULL_CLAUDE_CODE_CONFIG } from "../../client/lib/services/assessment/lib/claudeCodeBridge.js";
23
+ /**
24
+ * Load server configuration from Claude Code's MCP settings
25
+ */
26
+ function loadServerConfig(serverName, configPath) {
27
+ const possiblePaths = [
28
+ configPath,
29
+ path.join(os.homedir(), ".config", "mcp", "servers", `${serverName}.json`),
30
+ path.join(os.homedir(), ".config", "claude", "claude_desktop_config.json"),
31
+ ].filter(Boolean);
32
+ for (const tryPath of possiblePaths) {
33
+ if (!fs.existsSync(tryPath))
34
+ continue;
35
+ const config = JSON.parse(fs.readFileSync(tryPath, "utf-8"));
36
+ if (config.mcpServers && config.mcpServers[serverName]) {
37
+ const serverConfig = config.mcpServers[serverName];
38
+ return {
39
+ transport: "stdio",
40
+ command: serverConfig.command,
41
+ args: serverConfig.args || [],
42
+ env: serverConfig.env || {},
43
+ };
44
+ }
45
+ if (config.url ||
46
+ config.transport === "http" ||
47
+ config.transport === "sse") {
48
+ if (!config.url) {
49
+ throw new Error(`Invalid server config: transport is '${config.transport}' but 'url' is missing`);
50
+ }
51
+ return {
52
+ transport: config.transport || "http",
53
+ url: config.url,
54
+ };
55
+ }
56
+ if (config.command) {
57
+ return {
58
+ transport: "stdio",
59
+ command: config.command,
60
+ args: config.args || [],
61
+ env: config.env || {},
62
+ };
63
+ }
64
+ }
65
+ throw new Error(`Server config not found for: ${serverName}\nTried: ${possiblePaths.join(", ")}`);
66
+ }
67
+ /**
68
+ * Load optional files from source code path
69
+ */
70
+ function loadSourceFiles(sourcePath) {
71
+ const result = {};
72
+ const readmePaths = ["README.md", "readme.md", "Readme.md"];
73
+ for (const readmePath of readmePaths) {
74
+ const fullPath = path.join(sourcePath, readmePath);
75
+ if (fs.existsSync(fullPath)) {
76
+ result.readmeContent = fs.readFileSync(fullPath, "utf-8");
77
+ break;
78
+ }
79
+ }
80
+ const packagePath = path.join(sourcePath, "package.json");
81
+ if (fs.existsSync(packagePath)) {
82
+ result.packageJson = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
83
+ }
84
+ const manifestPath = path.join(sourcePath, "manifest.json");
85
+ if (fs.existsSync(manifestPath)) {
86
+ result.manifestRaw = fs.readFileSync(manifestPath, "utf-8");
87
+ try {
88
+ result.manifestJson = JSON.parse(result.manifestRaw);
89
+ }
90
+ catch {
91
+ console.warn("[Assessment] Failed to parse manifest.json");
92
+ }
93
+ }
94
+ result.sourceCodeFiles = new Map();
95
+ const sourceExtensions = [".ts", ".js", ".py", ".go", ".rs"];
96
+ const loadSourceDir = (dir, prefix = "") => {
97
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
98
+ for (const entry of entries) {
99
+ if (entry.name.startsWith(".") || entry.name === "node_modules")
100
+ continue;
101
+ const fullPath = path.join(dir, entry.name);
102
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
103
+ if (entry.isDirectory()) {
104
+ loadSourceDir(fullPath, relativePath);
105
+ }
106
+ else if (sourceExtensions.some((ext) => entry.name.endsWith(ext))) {
107
+ try {
108
+ const content = fs.readFileSync(fullPath, "utf-8");
109
+ if (content.length < 100000) {
110
+ result.sourceCodeFiles.set(relativePath, content);
111
+ }
112
+ }
113
+ catch {
114
+ // Skip unreadable files
115
+ }
116
+ }
117
+ }
118
+ };
119
+ try {
120
+ loadSourceDir(sourcePath);
121
+ }
122
+ catch (e) {
123
+ console.warn("[Assessment] Could not load source files:", e);
124
+ }
125
+ return result;
126
+ }
127
+ /**
128
+ * Connect to MCP server via configured transport
129
+ */
130
+ async function connectToServer(config) {
131
+ let transport;
132
+ switch (config.transport) {
133
+ case "http":
134
+ if (!config.url)
135
+ throw new Error("URL required for HTTP transport");
136
+ transport = new StreamableHTTPClientTransport(new URL(config.url));
137
+ break;
138
+ case "sse":
139
+ if (!config.url)
140
+ throw new Error("URL required for SSE transport");
141
+ transport = new SSEClientTransport(new URL(config.url));
142
+ break;
143
+ case "stdio":
144
+ default:
145
+ if (!config.command)
146
+ throw new Error("Command required for stdio transport");
147
+ transport = new StdioClientTransport({
148
+ command: config.command,
149
+ args: config.args,
150
+ env: {
151
+ ...Object.fromEntries(Object.entries(process.env).filter(([, v]) => v !== undefined)),
152
+ ...config.env,
153
+ },
154
+ stderr: "pipe",
155
+ });
156
+ break;
157
+ }
158
+ const client = new Client({
159
+ name: "mcp-assess-full",
160
+ version: "1.0.0",
161
+ }, {
162
+ capabilities: {},
163
+ });
164
+ await client.connect(transport);
165
+ return client;
166
+ }
167
+ /**
168
+ * Create callTool wrapper for assessment context
169
+ */
170
+ function createCallToolWrapper(client) {
171
+ return async (name, params) => {
172
+ try {
173
+ const response = await client.callTool({
174
+ name,
175
+ arguments: params,
176
+ });
177
+ return {
178
+ content: response.content,
179
+ isError: response.isError || false,
180
+ structuredContent: response
181
+ .structuredContent,
182
+ };
183
+ }
184
+ catch (error) {
185
+ return {
186
+ content: [
187
+ {
188
+ type: "text",
189
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
190
+ },
191
+ ],
192
+ isError: true,
193
+ };
194
+ }
195
+ };
196
+ }
197
+ /**
198
+ * Build assessment configuration
199
+ */
200
+ function buildConfig(options) {
201
+ const config = {
202
+ ...DEFAULT_ASSESSMENT_CONFIG,
203
+ enableExtendedAssessment: options.fullAssessment !== false,
204
+ parallelTesting: true,
205
+ testTimeout: 30000,
206
+ };
207
+ if (options.fullAssessment !== false) {
208
+ config.assessmentCategories = {
209
+ functionality: true,
210
+ security: true,
211
+ documentation: true,
212
+ errorHandling: true,
213
+ usability: true,
214
+ mcpSpecCompliance: true,
215
+ aupCompliance: true,
216
+ toolAnnotations: true,
217
+ prohibitedLibraries: true,
218
+ manifestValidation: true,
219
+ portability: true,
220
+ };
221
+ }
222
+ if (options.claudeEnabled) {
223
+ config.claudeCode = {
224
+ enabled: true,
225
+ timeout: FULL_CLAUDE_CODE_CONFIG.timeout || 60000,
226
+ maxRetries: FULL_CLAUDE_CODE_CONFIG.maxRetries || 2,
227
+ features: {
228
+ intelligentTestGeneration: true,
229
+ aupSemanticAnalysis: true,
230
+ annotationInference: true,
231
+ documentationQuality: true,
232
+ },
233
+ };
234
+ }
235
+ return config;
236
+ }
237
+ /**
238
+ * Run full assessment
239
+ */
240
+ async function runFullAssessment(options) {
241
+ if (!options.jsonOnly) {
242
+ console.log(`\n🔍 Starting full assessment for: ${options.serverName}`);
243
+ }
244
+ const serverConfig = loadServerConfig(options.serverName, options.serverConfigPath);
245
+ if (!options.jsonOnly) {
246
+ console.log("✅ Server config loaded");
247
+ }
248
+ const client = await connectToServer(serverConfig);
249
+ if (!options.jsonOnly) {
250
+ console.log("✅ Connected to MCP server");
251
+ }
252
+ const response = await client.listTools();
253
+ const tools = response.tools || [];
254
+ if (!options.jsonOnly) {
255
+ console.log(`🔧 Found ${tools.length} tool${tools.length !== 1 ? "s" : ""}`);
256
+ }
257
+ const config = buildConfig(options);
258
+ const orchestrator = new AssessmentOrchestrator(config);
259
+ if (!options.jsonOnly) {
260
+ if (orchestrator.isClaudeEnabled()) {
261
+ console.log("🤖 Claude Code integration enabled");
262
+ }
263
+ else if (options.claudeEnabled) {
264
+ console.log("⚠️ Claude Code requested but not available");
265
+ }
266
+ }
267
+ let sourceFiles = {};
268
+ if (options.sourceCodePath && fs.existsSync(options.sourceCodePath)) {
269
+ sourceFiles = loadSourceFiles(options.sourceCodePath);
270
+ if (!options.jsonOnly) {
271
+ console.log(`📁 Loaded source files from: ${options.sourceCodePath}`);
272
+ }
273
+ }
274
+ const context = {
275
+ serverName: options.serverName,
276
+ tools,
277
+ callTool: createCallToolWrapper(client),
278
+ config,
279
+ sourceCodePath: options.sourceCodePath,
280
+ ...sourceFiles,
281
+ };
282
+ if (!options.jsonOnly) {
283
+ console.log(`\n🏃 Running assessment with ${Object.keys(config.assessmentCategories || {}).length} modules...`);
284
+ console.log("");
285
+ }
286
+ const results = await orchestrator.runFullAssessment(context);
287
+ await client.close();
288
+ return results;
289
+ }
290
+ /**
291
+ * Save results to JSON file
292
+ */
293
+ function saveResults(serverName, results, outputPath) {
294
+ const defaultPath = `/tmp/inspector-full-assessment-${serverName}.json`;
295
+ const finalPath = outputPath || defaultPath;
296
+ const output = {
297
+ timestamp: new Date().toISOString(),
298
+ assessmentType: "full",
299
+ ...results,
300
+ };
301
+ fs.writeFileSync(finalPath, JSON.stringify(output, null, 2));
302
+ return finalPath;
303
+ }
304
+ /**
305
+ * Display summary
306
+ */
307
+ function displaySummary(results) {
308
+ const { overallStatus, summary, totalTestsRun, executionTime, functionality, security, aupCompliance, toolAnnotations, portability, documentation, errorHandling, mcpSpecCompliance, prohibitedLibraries, manifestValidation, } = results;
309
+ console.log("\n" + "=".repeat(70));
310
+ console.log("FULL ASSESSMENT RESULTS");
311
+ console.log("=".repeat(70));
312
+ console.log(`Server: ${results.serverName}`);
313
+ console.log(`Overall Status: ${overallStatus}`);
314
+ console.log(`Total Tests Run: ${totalTestsRun}`);
315
+ console.log(`Execution Time: ${executionTime}ms`);
316
+ console.log("-".repeat(70));
317
+ console.log("\n📊 MODULE STATUS:");
318
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
319
+ const modules = [
320
+ ["Functionality", functionality],
321
+ ["Security", security],
322
+ ["Documentation", documentation],
323
+ ["Error Handling", errorHandling],
324
+ ["MCP Spec Compliance", mcpSpecCompliance],
325
+ ["AUP Compliance", aupCompliance],
326
+ ["Tool Annotations", toolAnnotations],
327
+ ["Prohibited Libraries", prohibitedLibraries],
328
+ ["Manifest Validation", manifestValidation],
329
+ ["Portability", portability],
330
+ ];
331
+ for (const [name, module] of modules) {
332
+ if (module) {
333
+ const icon = module.status === "PASS"
334
+ ? "✅"
335
+ : module.status === "FAIL"
336
+ ? "❌"
337
+ : "⚠️";
338
+ console.log(` ${icon} ${name}: ${module.status}`);
339
+ }
340
+ }
341
+ console.log("\n📋 KEY FINDINGS:");
342
+ console.log(` ${summary}`);
343
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
344
+ const securityModule = security;
345
+ if (securityModule?.vulnerabilities?.length > 0) {
346
+ const vulns = securityModule.vulnerabilities;
347
+ console.log(`\n🔒 SECURITY VULNERABILITIES (${vulns.length}):`);
348
+ for (const vuln of vulns.slice(0, 5)) {
349
+ console.log(` • ${vuln}`);
350
+ }
351
+ if (vulns.length > 5) {
352
+ console.log(` ... and ${vulns.length - 5} more`);
353
+ }
354
+ }
355
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
356
+ const aupModule = aupCompliance;
357
+ if (aupModule?.violations?.length > 0) {
358
+ const violations = aupModule.violations;
359
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
360
+ const critical = violations.filter((v) => v.severity === "CRITICAL");
361
+ console.log(`\n⚖️ AUP FINDINGS:`);
362
+ console.log(` Total flagged: ${violations.length}`);
363
+ if (critical.length > 0) {
364
+ console.log(` 🚨 CRITICAL violations: ${critical.length}`);
365
+ }
366
+ }
367
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
368
+ const annotationsModule = toolAnnotations;
369
+ if (annotationsModule) {
370
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
371
+ const funcModule = functionality;
372
+ console.log(`\n🏷️ TOOL ANNOTATIONS:`);
373
+ console.log(` Annotated: ${annotationsModule.annotatedCount || 0}/${funcModule?.workingTools || 0}`);
374
+ if (annotationsModule.missingAnnotationsCount > 0) {
375
+ console.log(` Missing: ${annotationsModule.missingAnnotationsCount}`);
376
+ }
377
+ if (annotationsModule.misalignedAnnotationsCount > 0) {
378
+ console.log(` ⚠️ Misalignments: ${annotationsModule.misalignedAnnotationsCount}`);
379
+ }
380
+ }
381
+ if (results.recommendations?.length > 0) {
382
+ console.log("\n💡 RECOMMENDATIONS:");
383
+ for (const rec of results.recommendations.slice(0, 5)) {
384
+ console.log(` • ${rec}`);
385
+ }
386
+ }
387
+ console.log("\n" + "=".repeat(70));
388
+ }
389
+ /**
390
+ * Parse command-line arguments
391
+ */
392
+ function parseArgs() {
393
+ const args = process.argv.slice(2);
394
+ const options = {};
395
+ for (let i = 0; i < args.length; i++) {
396
+ const arg = args[i];
397
+ if (!arg)
398
+ continue;
399
+ switch (arg) {
400
+ case "--server":
401
+ case "-s":
402
+ options.serverName = args[++i];
403
+ break;
404
+ case "--config":
405
+ case "-c":
406
+ options.serverConfigPath = args[++i];
407
+ break;
408
+ case "--output":
409
+ case "-o":
410
+ options.outputPath = args[++i];
411
+ break;
412
+ case "--source":
413
+ options.sourceCodePath = args[++i];
414
+ break;
415
+ case "--claude-enabled":
416
+ options.claudeEnabled = true;
417
+ break;
418
+ case "--full":
419
+ options.fullAssessment = true;
420
+ break;
421
+ case "--verbose":
422
+ case "-v":
423
+ options.verbose = true;
424
+ break;
425
+ case "--json":
426
+ options.jsonOnly = true;
427
+ break;
428
+ case "--help":
429
+ case "-h":
430
+ printHelp();
431
+ options.helpRequested = true;
432
+ return options;
433
+ default:
434
+ if (!arg.startsWith("-")) {
435
+ if (!options.serverName) {
436
+ options.serverName = arg;
437
+ }
438
+ }
439
+ else {
440
+ console.error(`Unknown argument: ${arg}`);
441
+ printHelp();
442
+ setTimeout(() => process.exit(1), 10);
443
+ options.helpRequested = true;
444
+ return options;
445
+ }
446
+ }
447
+ }
448
+ if (!options.serverName) {
449
+ console.error("Error: --server is required");
450
+ printHelp();
451
+ setTimeout(() => process.exit(1), 10);
452
+ options.helpRequested = true;
453
+ return options;
454
+ }
455
+ return options;
456
+ }
457
+ /**
458
+ * Print help message
459
+ */
460
+ function printHelp() {
461
+ console.log(`
462
+ Usage: mcp-assess-full [options] [server-name]
463
+
464
+ Run comprehensive MCP server assessment with all 11 assessor modules.
465
+
466
+ Options:
467
+ --server, -s <name> Server name (required, or pass as first positional arg)
468
+ --config, -c <path> Path to server config JSON
469
+ --output, -o <path> Output JSON path (default: /tmp/inspector-full-assessment-<server>.json)
470
+ --source <path> Source code path for deep analysis (AUP, portability, etc.)
471
+ --claude-enabled Enable Claude Code integration for intelligent analysis
472
+ --full Enable all assessment modules (default)
473
+ --json Output only JSON (no console summary)
474
+ --verbose, -v Enable verbose logging
475
+ --help, -h Show this help message
476
+
477
+ Assessment Modules (11 total):
478
+ • Functionality - Tests all tools work correctly
479
+ • Security - Prompt injection & vulnerability testing
480
+ • Documentation - README completeness checks
481
+ • Error Handling - Validates error responses
482
+ • Usability - Input validation & UX
483
+ • MCP Spec - Protocol compliance
484
+ • AUP Compliance - Acceptable Use Policy checks
485
+ • Tool Annotations - readOnlyHint/destructiveHint validation
486
+ • Prohibited Libs - Dependency security checks
487
+ • Manifest - MCPB manifest.json validation
488
+ • Portability - Cross-platform compatibility
489
+
490
+ Examples:
491
+ mcp-assess-full my-server
492
+ mcp-assess-full --server broken-mcp --claude-enabled
493
+ mcp-assess-full --server my-server --source ./my-server --output ./results.json
494
+ `);
495
+ }
496
+ /**
497
+ * Main execution
498
+ */
499
+ async function main() {
500
+ try {
501
+ const options = parseArgs();
502
+ if (options.helpRequested) {
503
+ return;
504
+ }
505
+ const results = await runFullAssessment(options);
506
+ if (!options.jsonOnly) {
507
+ displaySummary(results);
508
+ }
509
+ const outputPath = saveResults(options.serverName, results, options.outputPath);
510
+ if (options.jsonOnly) {
511
+ console.log(outputPath);
512
+ }
513
+ else {
514
+ console.log(`📄 Results saved to: ${outputPath}\n`);
515
+ }
516
+ const exitCode = results.overallStatus === "FAIL" ? 1 : 0;
517
+ setTimeout(() => process.exit(exitCode), 10);
518
+ }
519
+ catch (error) {
520
+ console.error("\n❌ Error:", error instanceof Error ? error.message : String(error));
521
+ if (error instanceof Error && error.stack && process.env.DEBUG) {
522
+ console.error("\nStack trace:");
523
+ console.error(error.stack);
524
+ }
525
+ setTimeout(() => process.exit(1), 10);
526
+ }
527
+ }
528
+ main();