@bryan-thompson/inspector-assessment-client 1.35.2 → 1.35.3

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 (29) hide show
  1. package/lib/lib/assessment/coreTypes.d.ts +23 -0
  2. package/lib/lib/assessment/coreTypes.d.ts.map +1 -1
  3. package/lib/lib/assessment/extendedTypes.d.ts +45 -2
  4. package/lib/lib/assessment/extendedTypes.d.ts.map +1 -1
  5. package/lib/lib/assessment/jsonlEventSchemas.d.ts +4 -4
  6. package/lib/lib/assessment/resultTypes.d.ts +12 -1
  7. package/lib/lib/assessment/resultTypes.d.ts.map +1 -1
  8. package/lib/lib/aupPatterns.d.ts +50 -0
  9. package/lib/lib/aupPatterns.d.ts.map +1 -1
  10. package/lib/lib/aupPatterns.js +140 -0
  11. package/lib/lib/securityPatterns.d.ts.map +1 -1
  12. package/lib/lib/securityPatterns.js +92 -0
  13. package/lib/services/assessment/modules/DeveloperExperienceAssessor.d.ts +26 -1
  14. package/lib/services/assessment/modules/DeveloperExperienceAssessor.d.ts.map +1 -1
  15. package/lib/services/assessment/modules/DeveloperExperienceAssessor.js +160 -1
  16. package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts +32 -0
  17. package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -1
  18. package/lib/services/assessment/modules/ManifestValidationAssessor.js +218 -20
  19. package/lib/services/assessment/modules/securityTests/ConfidenceScorer.d.ts.map +1 -1
  20. package/lib/services/assessment/modules/securityTests/ConfidenceScorer.js +28 -0
  21. package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts +95 -0
  22. package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts.map +1 -1
  23. package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.js +174 -0
  24. package/lib/services/assessment/modules/securityTests/SecurityPayloadTester.d.ts.map +1 -1
  25. package/lib/services/assessment/modules/securityTests/SecurityPayloadTester.js +15 -0
  26. package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts +40 -0
  27. package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts.map +1 -1
  28. package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.js +143 -131
  29. package/package.json +1 -1
@@ -1809,6 +1809,98 @@ export const SECURITY_ATTACK_PATTERNS = [
1809
1809
  },
1810
1810
  ],
1811
1811
  },
1812
+ // ==========================================
1813
+ // EXCESSIVE PERMISSIONS SCOPE TESTS (Issue #144, Challenge #22)
1814
+ // ==========================================
1815
+ // 32. EXCESSIVE PERMISSIONS SCOPE
1816
+ {
1817
+ attackName: "Excessive Permissions Scope",
1818
+ description: "Test if tools with restrictive annotations (readOnlyHint=True) allow privileged operations via specific inputs (CWE-250, CWE-269)",
1819
+ payloads: [
1820
+ // Privileged action payloads for tools that claim readOnlyHint=True
1821
+ {
1822
+ payload: "write_file",
1823
+ evidence: /"scope_violation"\s*:\s*true|"actual_scope"\s*:\s*"write"/i,
1824
+ riskLevel: "HIGH",
1825
+ description: "Write operation bypassing readOnlyHint=True annotation (CWE-250)",
1826
+ payloadType: "scope_violation",
1827
+ parameterTypes: ["action", "operation", "command", "cmd"],
1828
+ },
1829
+ {
1830
+ payload: "delete_data",
1831
+ evidence: /"scope_violation"\s*:\s*true|"actual_scope"\s*:\s*"delete"/i,
1832
+ riskLevel: "HIGH",
1833
+ description: "Delete operation bypassing destructiveHint=False annotation (CWE-250)",
1834
+ payloadType: "scope_violation",
1835
+ parameterTypes: ["action", "operation", "command", "cmd"],
1836
+ },
1837
+ {
1838
+ payload: "execute_command",
1839
+ evidence: /"scope_violation"\s*:\s*true|"actual_scope"\s*:\s*"execute"/i,
1840
+ riskLevel: "HIGH",
1841
+ description: "Execute operation bypassing readOnlyHint=True annotation (CWE-250)",
1842
+ payloadType: "scope_violation",
1843
+ parameterTypes: ["action", "operation", "command", "cmd"],
1844
+ },
1845
+ {
1846
+ payload: "network_request",
1847
+ evidence: /"scope_violation"\s*:\s*true|"actual_scope"\s*:\s*"network"/i,
1848
+ riskLevel: "HIGH",
1849
+ description: "Network operation bypassing openWorldHint=False annotation (CWE-250)",
1850
+ payloadType: "scope_violation",
1851
+ parameterTypes: ["action", "operation", "command", "cmd"],
1852
+ },
1853
+ {
1854
+ payload: "modify_config",
1855
+ evidence: /"scope_violation"\s*:\s*true|"actual_scope"\s*:\s*"modify"/i,
1856
+ riskLevel: "HIGH",
1857
+ description: "Config modification bypassing readOnlyHint=True annotation (CWE-250)",
1858
+ payloadType: "scope_violation",
1859
+ parameterTypes: ["action", "operation", "command", "cmd"],
1860
+ },
1861
+ {
1862
+ payload: "environment_access",
1863
+ evidence: /"scope_violation"\s*:\s*true|"actual_scope"\s*:\s*"environment"/i,
1864
+ riskLevel: "HIGH",
1865
+ description: "Environment access bypassing annotation restrictions (CWE-250)",
1866
+ payloadType: "scope_violation",
1867
+ parameterTypes: ["action", "operation", "command", "cmd"],
1868
+ },
1869
+ // Escalation keyword payloads for tools that claim readOnlyHint=True
1870
+ {
1871
+ payload: "show admin users",
1872
+ evidence: /"scope_escalation"\s*:\s*true|"privileged_data"\s*:|admin[_-]?mode[_-]?activated/i,
1873
+ riskLevel: "HIGH",
1874
+ description: "Keyword-triggered privilege escalation via 'admin' (CWE-269)",
1875
+ payloadType: "scope_escalation",
1876
+ parameterTypes: ["request", "query", "input", "text", "message"],
1877
+ },
1878
+ {
1879
+ payload: "sudo access logs",
1880
+ evidence: /"scope_escalation"\s*:\s*true|"system_secrets"\s*:|"trigger_keyword"\s*:\s*"sudo"/i,
1881
+ riskLevel: "HIGH",
1882
+ description: "Keyword-triggered privilege escalation via 'sudo' (CWE-269)",
1883
+ payloadType: "scope_escalation",
1884
+ parameterTypes: ["request", "query", "input", "text", "message"],
1885
+ },
1886
+ {
1887
+ payload: "elevate to root",
1888
+ evidence: /"scope_escalation"\s*:\s*true|"trigger_keyword"\s*:\s*"(elevate|root)"/i,
1889
+ riskLevel: "HIGH",
1890
+ description: "Keyword-triggered privilege escalation via 'elevate' or 'root' (CWE-269)",
1891
+ payloadType: "scope_escalation",
1892
+ parameterTypes: ["request", "query", "input", "text", "message"],
1893
+ },
1894
+ {
1895
+ payload: "get superuser privileges",
1896
+ evidence: /"scope_escalation"\s*:\s*true|"trigger_keyword"\s*:\s*"(superuser|privilege)"/i,
1897
+ riskLevel: "HIGH",
1898
+ description: "Keyword-triggered privilege escalation via 'superuser' or 'privilege' (CWE-269)",
1899
+ payloadType: "scope_escalation",
1900
+ parameterTypes: ["request", "query", "input", "text", "message"],
1901
+ },
1902
+ ],
1903
+ },
1812
1904
  ];
1813
1905
  /**
1814
1906
  * Get all payloads for an attack type
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * @module assessment/modules/DeveloperExperienceAssessor
14
14
  */
15
- import { DocumentationMetrics, UsabilityMetrics, AssessmentStatus } from "../../../lib/assessmentTypes.js";
15
+ import { DocumentationMetrics, UsabilityMetrics, AssessmentStatus, NamespaceDetectionResult } from "../../../lib/assessmentTypes.js";
16
16
  import { BaseAssessor } from "./BaseAssessor.js";
17
17
  import { AssessmentContext } from "../AssessmentOrchestrator.js";
18
18
  /**
@@ -35,6 +35,8 @@ export interface DeveloperExperienceAssessment {
35
35
  usability: number;
36
36
  overall: number;
37
37
  };
38
+ /** Namespace detection results (Issue #142) */
39
+ namespaceDetection?: NamespaceDetectionResult;
38
40
  }
39
41
  export declare class DeveloperExperienceAssessor extends BaseAssessor<DeveloperExperienceAssessment> {
40
42
  assess(context: AssessmentContext): Promise<DeveloperExperienceAssessment>;
@@ -97,6 +99,29 @@ export declare class DeveloperExperienceAssessor extends BaseAssessor<DeveloperE
97
99
  private isDescriptiveName;
98
100
  private getToolSchema;
99
101
  private calculateUsabilityScore;
102
+ /**
103
+ * Detect namespace/prefix patterns in tool names.
104
+ * This helps identify intentional naming conventions like:
105
+ * - calc_add, calc_subtract -> namespace "calc"
106
+ * - fileRead, fileWrite -> namespace "file"
107
+ * - myserver_tool1, myserver_tool2 -> matches server name
108
+ */
109
+ private detectNamespace;
110
+ /**
111
+ * Find common prefix among tool names.
112
+ * Handles both snake_case (calc_add) and camelCase (calcAdd) conventions.
113
+ */
114
+ private findCommonPrefix;
115
+ /**
116
+ * Check if tool names use the server name as a prefix.
117
+ * Normalizes server name to match common patterns.
118
+ */
119
+ private checkServerNamePrefix;
120
+ /**
121
+ * Normalize server name for prefix matching.
122
+ * Converts "My-Server" -> "myserver", "my_server" -> "myserver"
123
+ */
124
+ private normalizeServerName;
100
125
  private determineOverallStatus;
101
126
  private generateExplanation;
102
127
  private generateRecommendations;
@@ -1 +1 @@
1
- {"version":3,"file":"DeveloperExperienceAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/DeveloperExperienceAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAEhB,gBAAgB,EAKjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,yCAAyC;IACzC,aAAa,EAAE,oBAAoB,CAAC;IACpC,qCAAqC;IACrC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,gDAAgD;IAChD,MAAM,EAAE,gBAAgB,CAAC;IACzB,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,iDAAiD;IACjD,MAAM,EAAE;QACN,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,qBAAa,2BAA4B,SAAQ,YAAY,CAAC,6BAA6B,CAAC;IACpF,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,6BAA6B,CAAC;IAsEzC,OAAO,CAAC,oBAAoB;IAmH5B,OAAO,CAAC,yBAAyB;IA4CjC,OAAO,CAAC,wBAAwB;IAiBhC,OAAO,CAAC,sBAAsB;IA8B9B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,mBAAmB;IAwC3B,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,mBAAmB;IA6B3B;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAkBlC;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAW9B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,qBAAqB;IAgC7B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAgBjC;;;OAGG;IACH,OAAO,CAAC,aAAa;IAoBrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsEzB,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,uBAAuB;IAsC/B,OAAO,CAAC,uBAAuB;IAwC/B,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,iBAAiB;IAiCzB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,sBAAsB;IAM9B,OAAO,CAAC,mBAAmB;IAyC3B,OAAO,CAAC,uBAAuB;CAmDhC"}
1
+ {"version":3,"file":"DeveloperExperienceAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/DeveloperExperienceAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAEhB,gBAAgB,EAKhB,wBAAwB,EACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,yCAAyC;IACzC,aAAa,EAAE,oBAAoB,CAAC;IACpC,qCAAqC;IACrC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,gDAAgD;IAChD,MAAM,EAAE,gBAAgB,CAAC;IACzB,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,iDAAiD;IACjD,MAAM,EAAE;QACN,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,+CAA+C;IAC/C,kBAAkB,CAAC,EAAE,wBAAwB,CAAC;CAC/C;AAED,qBAAa,2BAA4B,SAAQ,YAAY,CAAC,6BAA6B,CAAC;IACpF,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,6BAA6B,CAAC;IA6EzC,OAAO,CAAC,oBAAoB;IAmH5B,OAAO,CAAC,yBAAyB;IA4CjC,OAAO,CAAC,wBAAwB;IAiBhC,OAAO,CAAC,sBAAsB;IA8B9B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,mBAAmB;IAwC3B,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,mBAAmB;IA6B3B;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAkBlC;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAW9B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,qBAAqB;IAgC7B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAgBjC;;;OAGG;IACH,OAAO,CAAC,aAAa;IAoBrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsEzB,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,uBAAuB;IAsC/B,OAAO,CAAC,uBAAuB;IAwC/B,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,iBAAiB;IAiCzB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,uBAAuB;IAgB/B;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAsEvB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA0DxB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAsC7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,sBAAsB;IAM9B,OAAO,CAAC,mBAAmB;IAyC3B,OAAO,CAAC,uBAAuB;CAmDhC"}
@@ -30,6 +30,8 @@ export class DeveloperExperienceAssessor extends BaseAssessor {
30
30
  // Assess usability
31
31
  const usabilityMetrics = this.analyzeUsability(context.tools);
32
32
  const usabilityScore = this.calculateUsabilityScore(usabilityMetrics);
33
+ // Issue #142: Detect namespace/prefix patterns in tool names
34
+ const namespaceDetection = this.detectNamespace(context.tools, context.serverInfo?.name);
33
35
  // Calculate overall score (weighted average: 60% docs, 40% usability)
34
36
  const overallScore = Math.round(documentationScore * 0.6 + usabilityScore * 0.4);
35
37
  // Determine status using Issue #55 thresholds
@@ -37,7 +39,7 @@ export class DeveloperExperienceAssessor extends BaseAssessor {
37
39
  // Generate explanation and recommendations
38
40
  const explanation = this.generateExplanation(documentationMetrics, usabilityMetrics, context.tools);
39
41
  const recommendations = this.generateRecommendations(documentationMetrics, usabilityMetrics);
40
- this.testCount = 15; // Documentation (5) + Quality (6) + Usability (4) checks
42
+ this.testCount = 16; // Documentation (5) + Quality (6) + Usability (4) + Namespace (1) checks
41
43
  return {
42
44
  documentation: documentationMetrics,
43
45
  usability: usabilityMetrics,
@@ -49,6 +51,7 @@ export class DeveloperExperienceAssessor extends BaseAssessor {
49
51
  usability: usabilityScore,
50
52
  overall: overallScore,
51
53
  },
54
+ namespaceDetection,
52
55
  };
53
56
  }
54
57
  // ============================================================================
@@ -673,6 +676,162 @@ export class DeveloperExperienceAssessor extends BaseAssessor {
673
676
  return Math.round((score / maxScore) * 100);
674
677
  }
675
678
  // ============================================================================
679
+ // Namespace Detection (Issue #142)
680
+ // ============================================================================
681
+ /**
682
+ * Detect namespace/prefix patterns in tool names.
683
+ * This helps identify intentional naming conventions like:
684
+ * - calc_add, calc_subtract -> namespace "calc"
685
+ * - fileRead, fileWrite -> namespace "file"
686
+ * - myserver_tool1, myserver_tool2 -> matches server name
687
+ */
688
+ detectNamespace(tools, serverName) {
689
+ const toolNames = tools.map((t) => t.name);
690
+ const totalTools = toolNames.length;
691
+ // Need at least 2 tools to detect a namespace
692
+ if (totalTools < 2) {
693
+ return {
694
+ detected: false,
695
+ confidence: "low",
696
+ toolsCovered: 0,
697
+ totalTools,
698
+ matchPattern: "none",
699
+ };
700
+ }
701
+ // Try server name prefix first (highest priority)
702
+ if (serverName) {
703
+ const serverNameResult = this.checkServerNamePrefix(toolNames, serverName);
704
+ if (serverNameResult.matches >= 2 &&
705
+ serverNameResult.matches / totalTools >= 0.5) {
706
+ return {
707
+ detected: true,
708
+ namespace: this.normalizeServerName(serverName),
709
+ confidence: "high",
710
+ toolsCovered: serverNameResult.matches,
711
+ totalTools,
712
+ matchPattern: "serverName",
713
+ evidence: serverNameResult.matchedTools.slice(0, 5),
714
+ };
715
+ }
716
+ }
717
+ // Try common prefix detection
718
+ const prefixResult = this.findCommonPrefix(toolNames);
719
+ if (prefixResult) {
720
+ const coverageRatio = prefixResult.count / totalTools;
721
+ const confidence = coverageRatio >= 0.5 ? "high" : coverageRatio >= 0.3 ? "medium" : "low";
722
+ if (prefixResult.count >= 2 && coverageRatio >= 0.3) {
723
+ return {
724
+ detected: true,
725
+ namespace: prefixResult.prefix,
726
+ confidence,
727
+ toolsCovered: prefixResult.count,
728
+ totalTools,
729
+ matchPattern: "prefix",
730
+ evidence: prefixResult.matchedTools.slice(0, 5),
731
+ };
732
+ }
733
+ }
734
+ // No namespace detected
735
+ return {
736
+ detected: false,
737
+ confidence: "low",
738
+ toolsCovered: 0,
739
+ totalTools,
740
+ matchPattern: "none",
741
+ };
742
+ }
743
+ /**
744
+ * Find common prefix among tool names.
745
+ * Handles both snake_case (calc_add) and camelCase (calcAdd) conventions.
746
+ */
747
+ findCommonPrefix(toolNames) {
748
+ if (toolNames.length < 2)
749
+ return null;
750
+ // Build prefix frequency map
751
+ const prefixCounts = new Map();
752
+ for (const name of toolNames) {
753
+ // Extract prefix using snake_case separator
754
+ const snakeMatch = name.match(/^([a-z]+)_/);
755
+ if (snakeMatch && snakeMatch[1].length >= 3) {
756
+ const prefix = snakeMatch[1];
757
+ if (!prefixCounts.has(prefix)) {
758
+ prefixCounts.set(prefix, []);
759
+ }
760
+ prefixCounts.get(prefix).push(name);
761
+ }
762
+ // Extract prefix using camelCase pattern
763
+ const camelMatch = name.match(/^([a-z]+)[A-Z]/);
764
+ if (camelMatch && camelMatch[1].length >= 3) {
765
+ const prefix = camelMatch[1];
766
+ if (!prefixCounts.has(prefix)) {
767
+ prefixCounts.set(prefix, []);
768
+ }
769
+ // Avoid double-counting if snake_case already found this name
770
+ const existing = prefixCounts.get(prefix);
771
+ if (!existing.includes(name)) {
772
+ existing.push(name);
773
+ }
774
+ }
775
+ }
776
+ // Find the prefix with the most matches
777
+ let bestPrefix = null;
778
+ let bestCount = 0;
779
+ let bestTools = [];
780
+ for (const [prefix, tools] of prefixCounts) {
781
+ if (tools.length > bestCount) {
782
+ bestPrefix = prefix;
783
+ bestCount = tools.length;
784
+ bestTools = tools;
785
+ }
786
+ }
787
+ if (bestPrefix && bestCount >= 2) {
788
+ return {
789
+ prefix: bestPrefix,
790
+ count: bestCount,
791
+ matchedTools: bestTools,
792
+ };
793
+ }
794
+ return null;
795
+ }
796
+ /**
797
+ * Check if tool names use the server name as a prefix.
798
+ * Normalizes server name to match common patterns.
799
+ */
800
+ checkServerNamePrefix(toolNames, serverName) {
801
+ const normalizedServerName = this.normalizeServerName(serverName);
802
+ const matchedTools = [];
803
+ for (const name of toolNames) {
804
+ const nameLower = name.toLowerCase();
805
+ // Check snake_case prefix (e.g., myserver_tool)
806
+ if (nameLower.startsWith(normalizedServerName + "_")) {
807
+ matchedTools.push(name);
808
+ continue;
809
+ }
810
+ // Check camelCase prefix (e.g., myserverTool)
811
+ if (nameLower.startsWith(normalizedServerName) &&
812
+ name.length > normalizedServerName.length &&
813
+ /[A-Z]/.test(name[normalizedServerName.length])) {
814
+ matchedTools.push(name);
815
+ continue;
816
+ }
817
+ // Check kebab-case prefix (e.g., myserver-tool)
818
+ if (nameLower.startsWith(normalizedServerName + "-")) {
819
+ matchedTools.push(name);
820
+ }
821
+ }
822
+ return {
823
+ matches: matchedTools.length,
824
+ matchedTools,
825
+ };
826
+ }
827
+ /**
828
+ * Normalize server name for prefix matching.
829
+ * Converts "My-Server" -> "myserver", "my_server" -> "myserver"
830
+ */
831
+ normalizeServerName(serverName) {
832
+ return serverName.toLowerCase().replace(/[-_\s]/g, "");
833
+ }
834
+ // ============================================================================
676
835
  // Combined Status, Explanation, and Recommendations
677
836
  // ============================================================================
678
837
  determineOverallStatus(overallScore) {
@@ -13,6 +13,13 @@
13
13
  import { BaseAssessor } from "./BaseAssessor.js";
14
14
  import { AssessmentContext } from "../AssessmentOrchestrator.js";
15
15
  import type { ManifestValidationAssessment } from "../../../lib/assessmentTypes.js";
16
+ /**
17
+ * Calculate Levenshtein distance between two strings
18
+ * Uses space-optimized two-row algorithm for O(min(n,m)) memory
19
+ * Used for "did you mean?" suggestions on mismatched tool names (Issue #140)
20
+ * Exported for testing (Issue #141 - ISSUE-002)
21
+ */
22
+ export declare function levenshteinDistance(a: string, b: string, maxDist?: number): number;
16
23
  export declare class ManifestValidationAssessor extends BaseAssessor {
17
24
  /**
18
25
  * Get mcp_config from manifest (supports both root and nested v0.3 format)
@@ -22,6 +29,21 @@ export declare class ManifestValidationAssessor extends BaseAssessor {
22
29
  * @returns The mcp_config object or undefined if not found in either location
23
30
  */
24
31
  private getMcpConfig;
32
+ /**
33
+ * Extract contact information from manifest (Issue #141 - D4 check)
34
+ * Supports: author object, author string (email parsing), repository fallback
35
+ *
36
+ * @param manifest - The parsed manifest JSON
37
+ * @returns Extracted contact info or undefined if no contact info found
38
+ */
39
+ private extractContactInfo;
40
+ /**
41
+ * Extract version information from manifest (Issue #141 - D5 check)
42
+ *
43
+ * @param manifest - The parsed manifest JSON
44
+ * @returns Extracted version info or undefined if no version found
45
+ */
46
+ private extractVersionInfo;
25
47
  /**
26
48
  * Run manifest validation assessment
27
49
  */
@@ -62,6 +84,16 @@ export declare class ManifestValidationAssessor extends BaseAssessor {
62
84
  * Validate version format (semver)
63
85
  */
64
86
  private validateVersionFormat;
87
+ /**
88
+ * Validate manifest tool declarations against actual server tools (Issue #140)
89
+ * Compares tool names in manifest.tools against context.tools from tools/list
90
+ * Uses Levenshtein distance for "did you mean?" suggestions
91
+ */
92
+ private validateToolNamesMatch;
93
+ /**
94
+ * Fetch with retry logic for transient network failures
95
+ */
96
+ private fetchWithRetry;
65
97
  /**
66
98
  * Validate privacy policy URLs are accessible
67
99
  */
@@ -1 +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,EAM7B,MAAM,uBAAuB,CAAC;AAM/B,qBAAa,0BAA2B,SAAQ,YAAY;IAC1D;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IAcpB;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,4BAA4B,CAAC;IAqLxC;;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;YACW,yBAAyB;IAqFvC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0C3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CA+ChC"}
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;AAE9D,OAAO,KAAK,EACV,4BAA4B,EAS7B,MAAM,uBAAuB,CAAC;AAO/B;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAwCR;AA+BD,qBAAa,0BAA2B,SAAQ,YAAY;IAC1D;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IAcpB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAqC1B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,4BAA4B,CAAC;IAiMxC;;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;IA4B7B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAyE9B;;OAEG;YACW,cAAc;IAuC5B;;OAEG;YACW,yBAAyB;IAmEvC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0C3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CA+ChC"}