@bryan-thompson/inspector-assessment-client 1.13.0 → 1.14.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 (32) hide show
  1. package/dist/assets/{OAuthCallback-D8KW6pFf.js → OAuthCallback-DaKwjxdn.js} +1 -1
  2. package/dist/assets/{OAuthDebugCallback-D15nNAOl.js → OAuthDebugCallback-HiI2IPgB.js} +1 -1
  3. package/dist/assets/{index-cVkEgqCc.js → index-BAJG90Yd.js} +20 -8
  4. package/dist/assets/{index-Cuc9GxjD.css → index-BdXNC65t.css} +3 -0
  5. package/dist/index.html +2 -2
  6. package/lib/lib/assessmentDiffer.d.ts +79 -0
  7. package/lib/lib/assessmentDiffer.d.ts.map +1 -0
  8. package/lib/lib/assessmentDiffer.js +289 -0
  9. package/lib/lib/assessmentTypes.d.ts +69 -0
  10. package/lib/lib/assessmentTypes.d.ts.map +1 -1
  11. package/lib/lib/assessmentTypes.js +10 -0
  12. package/lib/lib/reportFormatters/DiffReportFormatter.d.ts +10 -0
  13. package/lib/lib/reportFormatters/DiffReportFormatter.d.ts.map +1 -0
  14. package/lib/lib/reportFormatters/DiffReportFormatter.js +177 -0
  15. package/lib/services/assessment/AssessmentOrchestrator.d.ts +1 -0
  16. package/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -1
  17. package/lib/services/assessment/AssessmentOrchestrator.js +22 -1
  18. package/lib/services/assessment/modules/AuthenticationAssessor.d.ts +48 -0
  19. package/lib/services/assessment/modules/AuthenticationAssessor.d.ts.map +1 -0
  20. package/lib/services/assessment/modules/AuthenticationAssessor.js +270 -0
  21. package/lib/services/assessment/modules/ExternalAPIScannerAssessor.d.ts +58 -0
  22. package/lib/services/assessment/modules/ExternalAPIScannerAssessor.d.ts.map +1 -0
  23. package/lib/services/assessment/modules/ExternalAPIScannerAssessor.js +248 -0
  24. package/lib/services/assessment/modules/FunctionalityAssessor.d.ts.map +1 -1
  25. package/lib/services/assessment/modules/FunctionalityAssessor.js +7 -0
  26. package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts +4 -0
  27. package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -1
  28. package/lib/services/assessment/modules/ManifestValidationAssessor.js +118 -4
  29. package/lib/services/assessment/modules/index.d.ts +1 -0
  30. package/lib/services/assessment/modules/index.d.ts.map +1 -1
  31. package/lib/services/assessment/modules/index.js +1 -0
  32. package/package.json +1 -1
@@ -86,9 +86,41 @@ export class ManifestValidationAssessor extends BaseAssessor {
86
86
  // Validate version format
87
87
  this.testCount++;
88
88
  validationResults.push(this.validateVersionFormat(manifest.version));
89
+ // Validate privacy policy URLs if present
90
+ let privacyPolicies;
91
+ if (manifest.privacy_policies &&
92
+ Array.isArray(manifest.privacy_policies) &&
93
+ manifest.privacy_policies.length > 0) {
94
+ this.log(`Validating ${manifest.privacy_policies.length} privacy policy URL(s)`);
95
+ const policyResults = await this.validatePrivacyPolicyUrls(manifest.privacy_policies);
96
+ privacyPolicies = {
97
+ declared: manifest.privacy_policies,
98
+ validationResults: policyResults,
99
+ allAccessible: policyResults.every((r) => r.accessible),
100
+ };
101
+ // Add validation result for privacy policies
102
+ if (!privacyPolicies.allAccessible) {
103
+ const inaccessible = policyResults.filter((r) => !r.accessible);
104
+ validationResults.push({
105
+ field: "privacy_policies",
106
+ valid: false,
107
+ value: manifest.privacy_policies,
108
+ issue: `${inaccessible.length}/${policyResults.length} privacy policy URL(s) inaccessible`,
109
+ severity: "WARNING",
110
+ });
111
+ }
112
+ else {
113
+ validationResults.push({
114
+ field: "privacy_policies",
115
+ valid: true,
116
+ value: manifest.privacy_policies,
117
+ severity: "INFO",
118
+ });
119
+ }
120
+ }
89
121
  const status = this.determineManifestStatus(validationResults, hasRequiredFields);
90
- const explanation = this.generateExplanation(validationResults, hasRequiredFields, hasIcon);
91
- const recommendations = this.generateRecommendations(validationResults);
122
+ const explanation = this.generateExplanation(validationResults, hasRequiredFields, hasIcon, privacyPolicies);
123
+ const recommendations = this.generateRecommendations(validationResults, privacyPolicies);
92
124
  this.log(`Assessment complete: ${validationResults.filter((r) => r.valid).length}/${validationResults.length} checks passed`);
93
125
  return {
94
126
  hasManifest: true,
@@ -97,6 +129,7 @@ export class ManifestValidationAssessor extends BaseAssessor {
97
129
  hasIcon,
98
130
  hasRequiredFields,
99
131
  missingFields,
132
+ privacyPolicies,
100
133
  status,
101
134
  explanation,
102
135
  recommendations,
@@ -368,6 +401,73 @@ export class ManifestValidationAssessor extends BaseAssessor {
368
401
  severity: "INFO",
369
402
  };
370
403
  }
404
+ /**
405
+ * Validate privacy policy URLs are accessible
406
+ */
407
+ async validatePrivacyPolicyUrls(privacyPolicies) {
408
+ const results = [];
409
+ for (const url of privacyPolicies) {
410
+ this.testCount++;
411
+ // Validate URL format first
412
+ try {
413
+ new URL(url);
414
+ }
415
+ catch {
416
+ results.push({
417
+ url,
418
+ accessible: false,
419
+ error: "Invalid URL format",
420
+ });
421
+ continue;
422
+ }
423
+ try {
424
+ // Use HEAD request for efficiency, fallback to GET if needed
425
+ const controller = new AbortController();
426
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
427
+ const response = await fetch(url, {
428
+ method: "HEAD",
429
+ signal: controller.signal,
430
+ redirect: "follow",
431
+ });
432
+ clearTimeout(timeoutId);
433
+ results.push({
434
+ url,
435
+ accessible: response.ok,
436
+ statusCode: response.status,
437
+ contentType: response.headers.get("content-type") || undefined,
438
+ });
439
+ }
440
+ catch (error) {
441
+ // Try GET request as fallback (some servers reject HEAD)
442
+ try {
443
+ const controller = new AbortController();
444
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
445
+ const response = await fetch(url, {
446
+ method: "GET",
447
+ signal: controller.signal,
448
+ redirect: "follow",
449
+ });
450
+ clearTimeout(timeoutId);
451
+ results.push({
452
+ url,
453
+ accessible: response.ok,
454
+ statusCode: response.status,
455
+ contentType: response.headers.get("content-type") || undefined,
456
+ });
457
+ }
458
+ catch (fetchError) {
459
+ results.push({
460
+ url,
461
+ accessible: false,
462
+ error: fetchError instanceof Error
463
+ ? fetchError.message
464
+ : "Network error",
465
+ });
466
+ }
467
+ }
468
+ }
469
+ return results;
470
+ }
371
471
  /**
372
472
  * Determine overall status
373
473
  */
@@ -385,7 +485,7 @@ export class ManifestValidationAssessor extends BaseAssessor {
385
485
  /**
386
486
  * Generate explanation
387
487
  */
388
- generateExplanation(results, hasRequiredFields, hasIcon) {
488
+ generateExplanation(results, hasRequiredFields, hasIcon, privacyPolicies) {
389
489
  const parts = [];
390
490
  const passed = results.filter((r) => r.valid).length;
391
491
  const total = results.length;
@@ -396,6 +496,10 @@ export class ManifestValidationAssessor extends BaseAssessor {
396
496
  if (!hasIcon) {
397
497
  parts.push("No icon found - recommended for MCPB bundles.");
398
498
  }
499
+ if (privacyPolicies && !privacyPolicies.allAccessible) {
500
+ const inaccessible = privacyPolicies.validationResults.filter((r) => !r.accessible);
501
+ parts.push(`${inaccessible.length} privacy policy URL(s) are inaccessible.`);
502
+ }
399
503
  const errors = results.filter((r) => !r.valid && r.severity === "ERROR");
400
504
  if (errors.length > 0) {
401
505
  parts.push(`${errors.length} error(s) require attention.`);
@@ -405,7 +509,7 @@ export class ManifestValidationAssessor extends BaseAssessor {
405
509
  /**
406
510
  * Generate recommendations
407
511
  */
408
- generateRecommendations(results) {
512
+ generateRecommendations(results, privacyPolicies) {
409
513
  const recommendations = [];
410
514
  // Group by severity
411
515
  const errors = results.filter((r) => !r.valid && r.severity === "ERROR");
@@ -422,6 +526,16 @@ export class ManifestValidationAssessor extends BaseAssessor {
422
526
  recommendations.push(`- ${warning.field}: ${warning.issue}`);
423
527
  }
424
528
  }
529
+ // Add privacy policy recommendations
530
+ if (privacyPolicies && !privacyPolicies.allAccessible) {
531
+ recommendations.push("PRIVACY POLICY - Fix inaccessible URLs:");
532
+ for (const result of privacyPolicies.validationResults) {
533
+ if (!result.accessible) {
534
+ const reason = result.error || `HTTP ${result.statusCode}`;
535
+ recommendations.push(`- ${result.url}: ${reason}`);
536
+ }
537
+ }
538
+ }
425
539
  if (recommendations.length === 0) {
426
540
  recommendations.push("Manifest validation passed. All required fields are present and valid.");
427
541
  }
@@ -30,4 +30,5 @@ export { ToolAnnotationAssessor } from "./ToolAnnotationAssessor.js";
30
30
  export { ProhibitedLibrariesAssessor } from "./ProhibitedLibrariesAssessor.js";
31
31
  export { ManifestValidationAssessor } from "./ManifestValidationAssessor.js";
32
32
  export { PortabilityAssessor } from "./PortabilityAssessor.js";
33
+ export { ExternalAPIScannerAssessor } from "./ExternalAPIScannerAssessor.js";
33
34
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAGxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAGxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC"}
@@ -33,3 +33,4 @@ export { ToolAnnotationAssessor } from "./ToolAnnotationAssessor.js";
33
33
  export { ProhibitedLibrariesAssessor } from "./ProhibitedLibrariesAssessor.js";
34
34
  export { ManifestValidationAssessor } from "./ManifestValidationAssessor.js";
35
35
  export { PortabilityAssessor } from "./PortabilityAssessor.js";
36
+ export { ExternalAPIScannerAssessor } from "./ExternalAPIScannerAssessor.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bryan-thompson/inspector-assessment-client",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "description": "Client-side application for the Enhanced MCP Inspector with assessment capabilities",
5
5
  "license": "MIT",
6
6
  "author": "Bryan Thompson <bryan@triepod.ai>",