@bryan-thompson/inspector-assessment 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.
- package/cli/build/assess-full.js +528 -0
- package/cli/build/assess-security.js +342 -0
- package/client/dist/assets/{OAuthCallback-ZcXdfhZQ.js → OAuthCallback-cGhwkoyY.js} +1 -1
- package/client/dist/assets/{OAuthDebugCallback-xt1SlIHS.js → OAuthDebugCallback-2rmUqser.js} +1 -1
- package/client/dist/assets/{index-B3lTiDVe.js → index-BnFixpvH.js} +4 -4
- package/client/dist/index.html +1 -1
- package/client/lib/lib/assessmentTypes.d.ts +670 -0
- package/client/lib/lib/assessmentTypes.d.ts.map +1 -0
- package/client/lib/lib/assessmentTypes.js +220 -0
- package/client/lib/lib/aupPatterns.d.ts +63 -0
- package/client/lib/lib/aupPatterns.d.ts.map +1 -0
- package/client/lib/lib/aupPatterns.js +344 -0
- package/client/lib/lib/prohibitedLibraries.d.ts +76 -0
- package/client/lib/lib/prohibitedLibraries.d.ts.map +1 -0
- package/client/lib/lib/prohibitedLibraries.js +364 -0
- package/client/lib/lib/securityPatterns.d.ts +64 -0
- package/client/lib/lib/securityPatterns.d.ts.map +1 -0
- package/client/lib/lib/securityPatterns.js +453 -0
- package/client/lib/services/assessment/AssessmentOrchestrator.d.ts +88 -0
- package/client/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -0
- package/client/lib/services/assessment/AssessmentOrchestrator.js +418 -0
- package/client/lib/services/assessment/ResponseValidator.d.ts +69 -0
- package/client/lib/services/assessment/ResponseValidator.d.ts.map +1 -0
- package/client/lib/services/assessment/ResponseValidator.js +1038 -0
- package/client/lib/services/assessment/TestDataGenerator.d.ts +86 -0
- package/client/lib/services/assessment/TestDataGenerator.d.ts.map +1 -0
- package/client/lib/services/assessment/TestDataGenerator.js +669 -0
- package/client/lib/services/assessment/TestScenarioEngine.d.ts +91 -0
- package/client/lib/services/assessment/TestScenarioEngine.d.ts.map +1 -0
- package/client/lib/services/assessment/TestScenarioEngine.js +505 -0
- package/client/lib/services/assessment/ToolClassifier.d.ts +61 -0
- package/client/lib/services/assessment/ToolClassifier.d.ts.map +1 -0
- package/client/lib/services/assessment/ToolClassifier.js +349 -0
- package/client/lib/services/assessment/lib/claudeCodeBridge.d.ts +160 -0
- package/client/lib/services/assessment/lib/claudeCodeBridge.d.ts.map +1 -0
- package/client/lib/services/assessment/lib/claudeCodeBridge.js +357 -0
- package/client/lib/services/assessment/modules/AUPComplianceAssessor.d.ts +100 -0
- package/client/lib/services/assessment/modules/AUPComplianceAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/AUPComplianceAssessor.js +474 -0
- package/client/lib/services/assessment/modules/BaseAssessor.d.ts +71 -0
- package/client/lib/services/assessment/modules/BaseAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/BaseAssessor.js +171 -0
- package/client/lib/services/assessment/modules/DocumentationAssessor.d.ts +45 -0
- package/client/lib/services/assessment/modules/DocumentationAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/DocumentationAssessor.js +355 -0
- package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts +25 -0
- package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/ErrorHandlingAssessor.js +564 -0
- package/client/lib/services/assessment/modules/FunctionalityAssessor.d.ts +20 -0
- package/client/lib/services/assessment/modules/FunctionalityAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/FunctionalityAssessor.js +253 -0
- package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts +70 -0
- package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/MCPSpecComplianceAssessor.js +508 -0
- package/client/lib/services/assessment/modules/ManifestValidationAssessor.d.ts +70 -0
- package/client/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/ManifestValidationAssessor.js +430 -0
- package/client/lib/services/assessment/modules/PortabilityAssessor.d.ts +43 -0
- package/client/lib/services/assessment/modules/PortabilityAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/PortabilityAssessor.js +347 -0
- package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts +41 -0
- package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/ProhibitedLibrariesAssessor.js +256 -0
- package/client/lib/services/assessment/modules/SecurityAssessor.d.ts +176 -0
- package/client/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/SecurityAssessor.js +1333 -0
- package/client/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts +96 -0
- package/client/lib/services/assessment/modules/ToolAnnotationAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/ToolAnnotationAssessor.js +593 -0
- package/client/lib/services/assessment/modules/UsabilityAssessor.d.ts +21 -0
- package/client/lib/services/assessment/modules/UsabilityAssessor.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/UsabilityAssessor.js +241 -0
- package/client/lib/services/assessment/modules/index.d.ts +33 -0
- package/client/lib/services/assessment/modules/index.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/index.js +35 -0
- 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();
|