@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,508 @@
1
+ /**
2
+ * MCP Spec Compliance Assessment Module
3
+ * Simple, focused MCP protocol validation for directory approval
4
+ */
5
+ import Ajv from "ajv";
6
+ import { BaseAssessor } from "./BaseAssessor.js";
7
+ export class MCPSpecComplianceAssessor extends BaseAssessor {
8
+ ajv;
9
+ constructor(config) {
10
+ super(config);
11
+ this.ajv = new Ajv({ allErrors: true });
12
+ }
13
+ /**
14
+ * Assess MCP Specification Compliance - Hybrid Approach
15
+ * Separates protocol-verified checks from metadata-based hints
16
+ */
17
+ async assess(context) {
18
+ const protocolVersion = this.extractProtocolVersion(context);
19
+ const tools = context.tools;
20
+ const callTool = context.callTool;
21
+ // SECTION 1: Protocol Checks (HIGH CONFIDENCE - actually tested)
22
+ const schemaCheck = this.checkSchemaCompliance(tools);
23
+ const jsonRpcCheck = await this.checkJsonRpcCompliance(callTool);
24
+ const errorCheck = await this.checkErrorResponses(tools, callTool);
25
+ const protocolChecks = {
26
+ jsonRpcCompliance: {
27
+ passed: jsonRpcCheck.passed,
28
+ confidence: "high",
29
+ evidence: "Verified via actual tool call",
30
+ rawResponse: jsonRpcCheck.rawResponse,
31
+ },
32
+ serverInfoValidity: {
33
+ passed: this.checkServerInfoValidity(context.serverInfo),
34
+ confidence: "high",
35
+ evidence: "Validated server info structure",
36
+ rawResponse: context.serverInfo,
37
+ },
38
+ schemaCompliance: {
39
+ passed: schemaCheck.passed,
40
+ confidence: schemaCheck.confidence,
41
+ warnings: schemaCheck.details ? [schemaCheck.details] : undefined,
42
+ rawResponse: tools.map((t) => ({
43
+ name: t.name,
44
+ inputSchema: t.inputSchema,
45
+ })),
46
+ },
47
+ errorResponseCompliance: {
48
+ passed: errorCheck.passed,
49
+ confidence: "high",
50
+ evidence: "Tested error handling with invalid parameters",
51
+ rawResponse: errorCheck.rawResponse,
52
+ },
53
+ structuredOutputSupport: {
54
+ passed: this.checkStructuredOutputSupport(tools),
55
+ confidence: "high",
56
+ evidence: `${tools.filter((t) => t.outputSchema).length}/${tools.length} tools have outputSchema`,
57
+ rawResponse: tools.map((t) => ({
58
+ name: t.name,
59
+ hasOutputSchema: !!t.outputSchema,
60
+ outputSchema: t.outputSchema,
61
+ })),
62
+ },
63
+ };
64
+ // SECTION 2: Metadata Hints (LOW CONFIDENCE - not tested, just parsed)
65
+ const metadataHints = this.extractMetadataHints(context);
66
+ // Calculate score based ONLY on protocol checks (reliable)
67
+ const checksArray = Object.values(protocolChecks);
68
+ const passedCount = checksArray.filter((c) => c.passed).length;
69
+ const complianceScore = (passedCount / checksArray.length) * 100;
70
+ // Determine status based on protocol checks only
71
+ let status;
72
+ if (!protocolChecks.serverInfoValidity.passed) {
73
+ status = "FAIL";
74
+ }
75
+ else if (complianceScore >= 90) {
76
+ status = "PASS";
77
+ }
78
+ else if (complianceScore >= 70) {
79
+ status = "NEED_MORE_INFO";
80
+ }
81
+ else {
82
+ status = "FAIL";
83
+ }
84
+ const explanation = this.generateExplanationHybrid(complianceScore, protocolChecks);
85
+ const recommendations = this.generateRecommendationsHybrid(protocolChecks, metadataHints);
86
+ // Legacy fields for backward compatibility
87
+ const transportCompliance = this.assessTransportCompliance(context);
88
+ const oauthImplementation = this.assessOAuthCompliance(context);
89
+ const annotationSupport = this.assessAnnotationSupport(context);
90
+ const streamingSupport = this.assessStreamingSupport(context);
91
+ return {
92
+ protocolVersion,
93
+ protocolChecks,
94
+ metadataHints,
95
+ status,
96
+ complianceScore,
97
+ explanation,
98
+ recommendations,
99
+ // Legacy fields (deprecated but maintained for backward compatibility)
100
+ transportCompliance,
101
+ oauthImplementation,
102
+ annotationSupport,
103
+ streamingSupport,
104
+ };
105
+ }
106
+ /**
107
+ * Extract protocol version from context
108
+ */
109
+ extractProtocolVersion(context) {
110
+ // Try metadata.protocolVersion first
111
+ const metadata = context.serverInfo?.metadata;
112
+ const protocolVersion = metadata?.protocolVersion;
113
+ if (protocolVersion) {
114
+ this.log(`Using protocol version from metadata: ${protocolVersion}`);
115
+ return protocolVersion;
116
+ }
117
+ // Fall back to server version
118
+ if (context.serverInfo?.version) {
119
+ this.log(`Using server version as protocol version: ${context.serverInfo.version}`);
120
+ return context.serverInfo.version;
121
+ }
122
+ // Default if no version information available
123
+ this.log("No protocol version information available, using default");
124
+ return "2025-06-18"; // Current MCP spec version as fallback
125
+ }
126
+ /**
127
+ * Check JSON-RPC 2.0 compliance
128
+ */
129
+ async checkJsonRpcCompliance(callTool) {
130
+ try {
131
+ // Test basic JSON-RPC structure by making a simple call
132
+ // If we can call any tool, JSON-RPC is working
133
+ const result = await callTool("list", {});
134
+ return { passed: result !== null, rawResponse: result };
135
+ }
136
+ catch (error) {
137
+ // If call fails, that's actually expected for many tools
138
+ // The fact that we got a structured response means JSON-RPC works
139
+ return { passed: true, rawResponse: error };
140
+ }
141
+ }
142
+ /**
143
+ * Check if server info is valid and properly formatted
144
+ */
145
+ checkServerInfoValidity(serverInfo) {
146
+ if (!serverInfo) {
147
+ // No server info is acceptable (optional)
148
+ return true;
149
+ }
150
+ // Check if name is properly set (should be a string, not null/undefined)
151
+ if (serverInfo.name !== undefined && serverInfo.name !== null) {
152
+ if (typeof serverInfo.name !== "string") {
153
+ this.log("Server info name is not a string");
154
+ return false;
155
+ }
156
+ }
157
+ // Check if metadata is properly formatted (should be an object if present)
158
+ if (serverInfo.metadata !== undefined && serverInfo.metadata !== null) {
159
+ if (typeof serverInfo.metadata !== "object") {
160
+ this.log("Server info metadata is not an object");
161
+ return false;
162
+ }
163
+ }
164
+ return true;
165
+ }
166
+ /**
167
+ * Check schema compliance for all tools
168
+ */
169
+ checkSchemaCompliance(tools) {
170
+ try {
171
+ let hasErrors = false;
172
+ const errors = [];
173
+ for (const tool of tools) {
174
+ if (tool.inputSchema) {
175
+ // Validate that the schema is valid JSON Schema
176
+ const isValid = this.ajv.validateSchema(tool.inputSchema);
177
+ if (!isValid) {
178
+ hasErrors = true;
179
+ const errorMsg = `${tool.name}: ${JSON.stringify(this.ajv.errors)}`;
180
+ errors.push(errorMsg);
181
+ console.warn(`Invalid schema for tool ${tool.name}:`, this.ajv.errors);
182
+ }
183
+ }
184
+ }
185
+ // If errors found, mark as low confidence (likely Zod conversion issues)
186
+ return {
187
+ passed: !hasErrors,
188
+ confidence: hasErrors ? "low" : "high",
189
+ details: hasErrors ? errors.join("; ") : undefined,
190
+ };
191
+ }
192
+ catch (error) {
193
+ console.error("Schema compliance check failed:", error);
194
+ return {
195
+ passed: false,
196
+ confidence: "low",
197
+ details: String(error),
198
+ };
199
+ }
200
+ }
201
+ /**
202
+ * Check error response compliance
203
+ */
204
+ async checkErrorResponses(tools, callTool) {
205
+ try {
206
+ if (tools.length === 0)
207
+ return { passed: true, rawResponse: "No tools to test" };
208
+ // Test error handling with invalid parameters
209
+ const testTool = tools[0];
210
+ try {
211
+ const result = await callTool(testTool.name, { invalid_param: "test" });
212
+ return { passed: true, rawResponse: result }; // Server handled gracefully
213
+ }
214
+ catch (error) {
215
+ return { passed: true, rawResponse: error }; // Server provided error response
216
+ }
217
+ }
218
+ catch (error) {
219
+ return { passed: false, rawResponse: error };
220
+ }
221
+ }
222
+ /**
223
+ * Check if tools have structured output support (2025-06-18 feature)
224
+ */
225
+ checkStructuredOutputSupport(tools) {
226
+ // Check if any tools define outputSchema
227
+ const toolsWithOutputSchema = tools.filter((tool) => tool.outputSchema).length;
228
+ const percentage = tools.length > 0 ? (toolsWithOutputSchema / tools.length) * 100 : 0;
229
+ // Log for debugging
230
+ this.log(`Structured output support: ${toolsWithOutputSchema}/${tools.length} tools (${percentage.toFixed(1)}%)`);
231
+ // Consider it supported if at least some tools use it
232
+ return toolsWithOutputSchema > 0;
233
+ }
234
+ /**
235
+ * Assess transport compliance (basic check)
236
+ */
237
+ assessTransportCompliance(context) {
238
+ // If no server info at all, assume failure
239
+ if (!context.serverInfo) {
240
+ return {
241
+ supportsStreamableHTTP: false,
242
+ deprecatedSSE: false,
243
+ transportValidation: "failed",
244
+ supportsStdio: false,
245
+ supportsSSE: false,
246
+ confidence: "low",
247
+ detectionMethod: "manual-required",
248
+ requiresManualCheck: true,
249
+ manualVerificationSteps: [
250
+ "Test STDIO: Run `npm start`, send JSON-RPC initialize request",
251
+ "Test HTTP: Set HTTP_STREAMABLE_SERVER=true, run `npm start`, test /health endpoint",
252
+ "Check if framework handles transports internally",
253
+ ],
254
+ };
255
+ }
256
+ // Check transport from metadata
257
+ const metadata = context.serverInfo?.metadata;
258
+ const transport = metadata?.transport;
259
+ const hasTransportMetadata = !!transport;
260
+ const supportsStreamableHTTP = transport === "streamable-http" ||
261
+ transport === "http" ||
262
+ (!transport && !!context.serverInfo);
263
+ const deprecatedSSE = transport === "sse";
264
+ // Determine validation status
265
+ let transportValidation = "passed";
266
+ // Check for MCP-Protocol-Version header requirement (2025-06-18)
267
+ // Note: We can't directly check headers through the SDK, but we can verify protocol version
268
+ const protocolVersion = this.extractProtocolVersion(context);
269
+ const isNewProtocol = protocolVersion >= "2025-06-18";
270
+ if (deprecatedSSE) {
271
+ transportValidation = "partial"; // SSE is deprecated
272
+ }
273
+ else if (transport &&
274
+ transport !== "streamable-http" &&
275
+ transport !== "http" &&
276
+ transport !== "stdio") {
277
+ transportValidation = "failed"; // Unknown transport
278
+ }
279
+ else if (isNewProtocol &&
280
+ (transport === "http" || transport === "streamable-http")) {
281
+ // For HTTP transport on 2025-06-18+, headers are required
282
+ // We assume compliance if using the new protocol version
283
+ this.log(`HTTP transport detected with protocol ${protocolVersion} - header compliance assumed`);
284
+ }
285
+ // Determine confidence based on detection method
286
+ const confidence = hasTransportMetadata ? "medium" : "low";
287
+ const requiresManualCheck = !hasTransportMetadata;
288
+ return {
289
+ supportsStreamableHTTP: supportsStreamableHTTP,
290
+ deprecatedSSE: deprecatedSSE,
291
+ transportValidation: transportValidation,
292
+ // Added missing properties that UI expects
293
+ supportsStdio: transport === "stdio" || !transport,
294
+ supportsSSE: deprecatedSSE,
295
+ // Detection metadata
296
+ confidence,
297
+ detectionMethod: hasTransportMetadata ? "automated" : "manual-required",
298
+ requiresManualCheck,
299
+ manualVerificationSteps: requiresManualCheck
300
+ ? [
301
+ "Test STDIO: Run `npm start`, send JSON-RPC initialize request via stdin",
302
+ "Test HTTP: Set HTTP_STREAMABLE_SERVER=true, run `npm start`, curl http://localhost:3000/health",
303
+ "Check if framework (e.g., FastMCP, firecrawl-fastmcp) handles transports internally",
304
+ "Review server startup logs for transport initialization messages",
305
+ ]
306
+ : undefined,
307
+ };
308
+ }
309
+ /**
310
+ * Assess annotation support
311
+ */
312
+ assessAnnotationSupport(context) {
313
+ // Check if server metadata indicates annotation support
314
+ const metadata = context.serverInfo?.metadata;
315
+ const annotations = metadata?.annotations;
316
+ const supportsAnnotations = annotations?.supported || false;
317
+ const customAnnotations = annotations?.types || [];
318
+ return {
319
+ supportsReadOnlyHint: supportsAnnotations,
320
+ supportsDestructiveHint: supportsAnnotations,
321
+ supportsTitleAnnotation: supportsAnnotations,
322
+ customAnnotations: customAnnotations.length > 0 ? customAnnotations : undefined,
323
+ };
324
+ }
325
+ /**
326
+ * Assess streaming support
327
+ */
328
+ assessStreamingSupport(context) {
329
+ // Check if server metadata indicates streaming support
330
+ const metadata = context.serverInfo?.metadata;
331
+ const streaming = metadata?.streaming;
332
+ const supportsStreaming = streaming?.supported || false;
333
+ const protocol = streaming?.protocol;
334
+ // Validate protocol is one of the allowed types
335
+ const validProtocols = ["http-streaming", "sse", "websocket"];
336
+ const streamingProtocol = protocol && validProtocols.includes(protocol)
337
+ ? protocol
338
+ : supportsStreaming
339
+ ? "http-streaming"
340
+ : undefined;
341
+ return {
342
+ supportsStreaming: supportsStreaming,
343
+ streamingProtocol,
344
+ };
345
+ }
346
+ /**
347
+ * Assess OAuth implementation (optional)
348
+ */
349
+ assessOAuthCompliance(context) {
350
+ // Check if OAuth is configured
351
+ const metadata = context.serverInfo?.metadata;
352
+ const oauthConfig = metadata?.oauth;
353
+ if (!oauthConfig || !oauthConfig.enabled) {
354
+ // OAuth is optional for MCP servers
355
+ return undefined;
356
+ }
357
+ // Extract OAuth configuration with type assertions
358
+ const resourceIndicators = [];
359
+ if (oauthConfig.resourceIndicators) {
360
+ const indicators = oauthConfig.resourceIndicators;
361
+ resourceIndicators.push(...indicators);
362
+ }
363
+ if (oauthConfig.resourceServer) {
364
+ resourceIndicators.push(oauthConfig.resourceServer);
365
+ }
366
+ if (oauthConfig.authorizationEndpoint &&
367
+ !resourceIndicators.includes(oauthConfig.authorizationEndpoint)) {
368
+ resourceIndicators.push(oauthConfig.authorizationEndpoint);
369
+ }
370
+ return {
371
+ implementsResourceServer: oauthConfig.enabled === true,
372
+ supportsRFC8707: oauthConfig.supportsRFC8707 || false,
373
+ resourceIndicators: resourceIndicators,
374
+ tokenValidation: oauthConfig.tokenValidation !== false, // Default to true if not specified
375
+ scopeEnforcement: oauthConfig.scopeEnforcement !== false, // Default to true if not specified
376
+ // Added missing properties that UI expects
377
+ supportsOAuth: oauthConfig.enabled === true,
378
+ supportsPKCE: oauthConfig.supportsPKCE || false,
379
+ };
380
+ }
381
+ /**
382
+ * Extract metadata hints from server context
383
+ * LOW CONFIDENCE - these are just parsed from metadata, not tested
384
+ */
385
+ extractMetadataHints(context) {
386
+ const metadata = context.serverInfo?.metadata;
387
+ if (!metadata && !context.serverInfo) {
388
+ return undefined;
389
+ }
390
+ // Parse transport hints
391
+ const transport = metadata?.transport;
392
+ const transportHints = {
393
+ detectedTransport: transport,
394
+ supportsStdio: transport === "stdio" || !transport,
395
+ supportsHTTP: transport === "http" ||
396
+ transport === "streamable-http" ||
397
+ (!transport && !!context.serverInfo),
398
+ supportsSSE: transport === "sse",
399
+ detectionMethod: (transport ? "metadata" : "assumed"),
400
+ };
401
+ // Parse OAuth hints
402
+ const oauthConfig = metadata?.oauth;
403
+ const oauthHints = oauthConfig
404
+ ? {
405
+ hasOAuthConfig: true,
406
+ supportsOAuth: oauthConfig.enabled === true,
407
+ supportsPKCE: oauthConfig.supportsPKCE || false,
408
+ resourceIndicators: oauthConfig.resourceIndicators
409
+ ? oauthConfig.resourceIndicators
410
+ : undefined,
411
+ }
412
+ : undefined;
413
+ // Parse annotation hints
414
+ const annotations = metadata?.annotations;
415
+ const annotationHints = {
416
+ supportsReadOnlyHint: annotations?.supported || false,
417
+ supportsDestructiveHint: annotations?.supported || false,
418
+ supportsTitleAnnotation: annotations?.supported || false,
419
+ customAnnotations: annotations?.types
420
+ ? annotations.types
421
+ : undefined,
422
+ };
423
+ // Parse streaming hints
424
+ const streaming = metadata?.streaming;
425
+ const streamingHints = {
426
+ supportsStreaming: streaming?.supported || false,
427
+ streamingProtocol: streaming?.protocol &&
428
+ ["http-streaming", "sse", "websocket"].includes(streaming.protocol)
429
+ ? streaming.protocol
430
+ : undefined,
431
+ };
432
+ return {
433
+ confidence: "low",
434
+ requiresManualVerification: true,
435
+ transportHints,
436
+ oauthHints,
437
+ annotationHints,
438
+ streamingHints,
439
+ manualVerificationSteps: [
440
+ "Test STDIO transport: Run `npm start`, send JSON-RPC initialize request via stdin",
441
+ "Test HTTP transport: Set HTTP_STREAMABLE_SERVER=true, run `npm start`, curl http://localhost:3000/health",
442
+ "Verify OAuth endpoints if configured",
443
+ "Check if framework (FastMCP, firecrawl-fastmcp) handles transports/features internally",
444
+ "Review server startup logs for transport initialization messages",
445
+ ],
446
+ };
447
+ }
448
+ /**
449
+ * Generate explanation based on protocol checks
450
+ */
451
+ generateExplanationHybrid(complianceScore, checks) {
452
+ const failedChecks = [];
453
+ if (!checks.jsonRpcCompliance.passed)
454
+ failedChecks.push("JSON-RPC compliance");
455
+ if (!checks.serverInfoValidity.passed)
456
+ failedChecks.push("server info validity");
457
+ if (!checks.schemaCompliance.passed)
458
+ failedChecks.push("schema compliance");
459
+ if (!checks.errorResponseCompliance.passed)
460
+ failedChecks.push("error response compliance");
461
+ if (!checks.structuredOutputSupport.passed)
462
+ failedChecks.push("structured output support");
463
+ if (complianceScore >= 90) {
464
+ return "Excellent MCP protocol compliance. Server meets all critical requirements verified through protocol testing.";
465
+ }
466
+ else if (complianceScore >= 70) {
467
+ return `Good MCP compliance with minor issues in protocol testing: ${failedChecks.join(", ")}. Review recommended before directory submission.`;
468
+ }
469
+ else {
470
+ return `Poor MCP compliance detected in protocol testing. Critical issues: ${failedChecks.join(", ")}. Must fix before directory approval.`;
471
+ }
472
+ }
473
+ /**
474
+ * Generate simplified recommendations based on protocol checks and metadata hints
475
+ */
476
+ generateRecommendationsHybrid(checks, metadataHints) {
477
+ const recommendations = [];
478
+ // Protocol check failures (high confidence)
479
+ if (!checks.jsonRpcCompliance.passed) {
480
+ recommendations.push("⚠️ JSON-RPC 2.0 compliance failed: Ensure all requests/responses follow JSON-RPC 2.0 format with proper jsonrpc, id, method/result fields.");
481
+ }
482
+ if (!checks.serverInfoValidity.passed) {
483
+ recommendations.push("❌ Server info is malformed: Fix serverInfo structure to include valid name and metadata fields.");
484
+ }
485
+ if (!checks.schemaCompliance.passed) {
486
+ if (checks.schemaCompliance.confidence === "low") {
487
+ recommendations.push("⚠️ Schema validation warnings detected (LOW CONFIDENCE): May be false positives from Zod/TypeBox conversion. Test if tools execute successfully - if they do, this is likely a conversion artifact and not a real problem.");
488
+ }
489
+ else {
490
+ recommendations.push("⚠️ JSON Schema validation errors: Review tool schemas and ensure they follow JSON Schema specification.");
491
+ }
492
+ }
493
+ if (!checks.errorResponseCompliance.passed) {
494
+ recommendations.push("⚠️ Error response format issues: Return proper MCP error objects with error codes and messages following JSON-RPC 2.0 format.");
495
+ }
496
+ if (!checks.structuredOutputSupport.passed) {
497
+ recommendations.push("💡 Enhancement: Add outputSchema to tools for type-safe responses (optional MCP 2025-06-18 feature).");
498
+ }
499
+ // Metadata hints reminder
500
+ if (metadataHints?.requiresManualVerification) {
501
+ recommendations.push("ℹ️ Transport/OAuth/Streaming features require manual verification (metadata-based detection only).");
502
+ }
503
+ if (recommendations.length === 0) {
504
+ recommendations.push("✅ Excellent MCP compliance! All protocol checks passed. Server is ready for directory submission.");
505
+ }
506
+ return recommendations;
507
+ }
508
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Manifest Validation Assessor
3
+ * Validates MCPB manifest.json against spec requirements
4
+ *
5
+ * Checks:
6
+ * - manifest_version (must be 0.3)
7
+ * - Required fields: name, version, description, author
8
+ * - mcp_config structure
9
+ * - icon.png presence
10
+ *
11
+ * Reference: MCPB Specification
12
+ */
13
+ import { BaseAssessor } from "./BaseAssessor.js";
14
+ import { AssessmentContext } from "../AssessmentOrchestrator.js";
15
+ import type { ManifestValidationAssessment } from "../../../lib/assessmentTypes.js";
16
+ export declare class ManifestValidationAssessor extends BaseAssessor {
17
+ /**
18
+ * Run manifest validation assessment
19
+ */
20
+ assess(context: AssessmentContext): Promise<ManifestValidationAssessment>;
21
+ /**
22
+ * Create result when no manifest is available
23
+ */
24
+ private createNoManifestResult;
25
+ /**
26
+ * Create result when manifest JSON is invalid
27
+ */
28
+ private createInvalidJsonResult;
29
+ /**
30
+ * Validate manifest_version field
31
+ */
32
+ private validateManifestVersion;
33
+ /**
34
+ * Validate required field presence
35
+ */
36
+ private validateRequiredField;
37
+ /**
38
+ * Validate recommended field presence
39
+ */
40
+ private validateRecommendedField;
41
+ /**
42
+ * Validate mcp_config structure
43
+ */
44
+ private validateMcpConfig;
45
+ /**
46
+ * Validate icon presence
47
+ */
48
+ private validateIcon;
49
+ /**
50
+ * Validate name format
51
+ */
52
+ private validateNameFormat;
53
+ /**
54
+ * Validate version format (semver)
55
+ */
56
+ private validateVersionFormat;
57
+ /**
58
+ * Determine overall status
59
+ */
60
+ private determineManifestStatus;
61
+ /**
62
+ * Generate explanation
63
+ */
64
+ private generateExplanation;
65
+ /**
66
+ * Generate recommendations
67
+ */
68
+ private generateRecommendations;
69
+ }
70
+ //# sourceMappingURL=ManifestValidationAssessor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ManifestValidationAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ManifestValidationAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EACV,4BAA4B,EAI7B,MAAM,uBAAuB,CAAC;AAM/B,qBAAa,0BAA2B,SAAQ,YAAY;IAC1D;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,4BAA4B,CAAC;IA0GxC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAyB9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAmB/B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAgC/B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiC7B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAiChC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA+CzB;;OAEG;IACH,OAAO,CAAC,YAAY;IAqCpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA+B1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA8B7B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CA+BhC"}