framework-mcp 1.1.2 → 1.2.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 (48) hide show
  1. package/.do/app.yaml +78 -0
  2. package/CAPABILITY_TRANSFORMATION_SUMMARY.md +158 -0
  3. package/DAYS_5_6_COMPLETION_SUMMARY.md +178 -0
  4. package/DEPLOYMENT_GUIDE.md +335 -0
  5. package/DEPLOYMENT_SUMMARY_v1.1.3.md +211 -0
  6. package/README.md +34 -35
  7. package/RELEASE_NOTES_v1.1.3.md +321 -0
  8. package/RELEASE_NOTES_v1.2.0.md +396 -0
  9. package/dist/core/capability-analyzer.d.ts +29 -0
  10. package/dist/core/capability-analyzer.d.ts.map +1 -0
  11. package/dist/core/capability-analyzer.js +568 -0
  12. package/dist/core/capability-analyzer.js.map +1 -0
  13. package/dist/core/safeguard-manager.d.ts +15 -0
  14. package/dist/core/safeguard-manager.d.ts.map +1 -0
  15. package/dist/core/safeguard-manager.js +315 -0
  16. package/dist/core/safeguard-manager.js.map +1 -0
  17. package/dist/index.d.ts +29 -3
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +609 -403
  20. package/dist/index.js.map +1 -1
  21. package/dist/interfaces/http/http-server.d.ts +17 -0
  22. package/dist/interfaces/http/http-server.d.ts.map +1 -0
  23. package/dist/interfaces/http/http-server.js +285 -0
  24. package/dist/interfaces/http/http-server.js.map +1 -0
  25. package/dist/interfaces/mcp/mcp-server.d.ts +18 -0
  26. package/dist/interfaces/mcp/mcp-server.d.ts.map +1 -0
  27. package/dist/interfaces/mcp/mcp-server.js +299 -0
  28. package/dist/interfaces/mcp/mcp-server.js.map +1 -0
  29. package/dist/shared/types.d.ts +89 -0
  30. package/dist/shared/types.d.ts.map +1 -0
  31. package/dist/shared/types.js +3 -0
  32. package/dist/shared/types.js.map +1 -0
  33. package/package.json +17 -6
  34. package/src/core/capability-analyzer.ts +708 -0
  35. package/src/core/safeguard-manager.ts +339 -0
  36. package/src/index.ts +722 -461
  37. package/src/interfaces/http/http-server.ts +360 -0
  38. package/src/interfaces/mcp/mcp-server.ts +367 -0
  39. package/src/shared/types.ts +104 -0
  40. package/test_capability_integration.js +73 -0
  41. package/test_comprehensive_scenarios.js +192 -0
  42. package/test_enhanced_detection.js +74 -0
  43. package/test_integrated_validation.js +112 -0
  44. package/test_language_update.js +101 -0
  45. package/test_live_validation.json +12 -0
  46. package/test_performance_monitoring.js +124 -0
  47. package/test_runner_automated.js +156 -0
  48. package/test_suite_comprehensive.js +218 -0
package/dist/index.js CHANGED
@@ -1,4 +1,17 @@
1
1
  #!/usr/bin/env node
2
+ // Re-export the MCP server for backward compatibility
3
+ import { FrameworkMcpServer } from './interfaces/mcp/mcp-server.js';
4
+ // Start MCP server if this file is run directly
5
+ if (import.meta.url === `file://${process.argv[1]}`) {
6
+ const server = new FrameworkMcpServer();
7
+ server.run().catch(console.error);
8
+ }
9
+ export { FrameworkMcpServer } from './interfaces/mcp/mcp-server.js';
10
+ export { FrameworkHttpServer } from './interfaces/http/http-server.js';
11
+ export { CapabilityAnalyzer } from './core/capability-analyzer.js';
12
+ export { SafeguardManager } from './core/safeguard-manager.js';
13
+ // Legacy compatibility - keep the original massive implementation for reference
14
+ // This will be removed in a future version once migration is complete
2
15
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
16
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
17
  import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
@@ -7,27 +20,27 @@ const SAFEGUARD_DOMAIN_REQUIREMENTS = {
7
20
  "1.1": {
8
21
  domain: "Asset Inventory",
9
22
  required_tool_types: ["inventory", "asset_management", "cmdb", "discovery"],
10
- description: "Only asset inventory and discovery tools can provide FULL/PARTIAL coverage"
23
+ description: "Only asset inventory and discovery tools can provide FULL/PARTIAL implementation capability"
11
24
  },
12
25
  "1.2": {
13
26
  domain: "Asset Management",
14
27
  required_tool_types: ["inventory", "asset_management", "network_security", "nac"],
15
- description: "Asset management or network access control tools required for FULL/PARTIAL"
28
+ description: "Asset management or network access control tools required for FULL/PARTIAL implementation capability"
16
29
  },
17
30
  "5.1": {
18
31
  domain: "Account Management",
19
32
  required_tool_types: ["identity_management", "iam", "directory", "account_management"],
20
- description: "Identity and account management tools required for FULL/PARTIAL"
33
+ description: "Identity and account management tools required for FULL/PARTIAL implementation capability"
21
34
  },
22
35
  "6.3": {
23
36
  domain: "Authentication",
24
37
  required_tool_types: ["mfa", "authentication", "identity_management", "iam"],
25
- description: "Multi-factor authentication and identity tools required for FULL/PARTIAL"
38
+ description: "Multi-factor authentication and identity tools required for FULL/PARTIAL implementation capability"
26
39
  },
27
40
  "7.1": {
28
41
  domain: "Vulnerability Management",
29
42
  required_tool_types: ["vulnerability_management", "vulnerability_scanner", "patch_management"],
30
- description: "Vulnerability management and scanning tools required for FULL/PARTIAL"
43
+ description: "Vulnerability management and scanning tools required for FULL/PARTIAL implementation capability"
31
44
  }
32
45
  };
33
46
  // Enhanced CIS Controls Framework Data with color-coded categorization
@@ -5462,6 +5475,19 @@ const CIS_SAFEGUARDS = {
5462
5475
  };
5463
5476
  export class GRCAnalysisServer {
5464
5477
  constructor() {
5478
+ // Performance monitoring and caching
5479
+ this.performanceMetrics = {
5480
+ toolExecutionTimes: new Map(),
5481
+ startTime: Date.now(),
5482
+ totalRequests: 0,
5483
+ errorCount: 0
5484
+ };
5485
+ // Simple cache for safeguard details (most commonly requested data)
5486
+ this.cache = {
5487
+ safeguardDetails: new Map(),
5488
+ safeguardList: null,
5489
+ lastCacheCleanup: Date.now()
5490
+ };
5465
5491
  this.server = new Server({
5466
5492
  name: 'framework-mcp',
5467
5493
  version: '1.0.0',
@@ -5473,7 +5499,7 @@ export class GRCAnalysisServer {
5473
5499
  tools: [
5474
5500
  {
5475
5501
  name: 'analyze_vendor_response',
5476
- description: 'Analyze a vendor response for a specific CIS Control safeguard against the 4 GRC attributes with detailed sub-element coverage',
5502
+ description: 'Analyze a vendor response to determine their tool capability role (Full Implementation, Partial Implementation, Facilitates, Governance, or Validates) for a specific CIS Control safeguard',
5477
5503
  inputSchema: {
5478
5504
  type: 'object',
5479
5505
  properties: {
@@ -5488,7 +5514,7 @@ export class GRCAnalysisServer {
5488
5514
  },
5489
5515
  response_text: {
5490
5516
  type: 'string',
5491
- description: 'Vendor response text to analyze'
5517
+ description: 'Vendor response text describing their tool capabilities for the safeguard'
5492
5518
  }
5493
5519
  },
5494
5520
  required: ['vendor_name', 'safeguard_id', 'response_text']
@@ -5516,7 +5542,7 @@ export class GRCAnalysisServer {
5516
5542
  },
5517
5543
  {
5518
5544
  name: 'validate_coverage_claim',
5519
- description: 'Validate a vendor\'s coverage claim (FULL/PARTIAL) against specific safeguard requirements',
5545
+ description: 'Validate a vendor\'s implementation capability claim (FULL/PARTIAL) against specific safeguard requirements and evidence quality',
5520
5546
  inputSchema: {
5521
5547
  type: 'object',
5522
5548
  properties: {
@@ -5532,16 +5558,16 @@ export class GRCAnalysisServer {
5532
5558
  coverage_claim: {
5533
5559
  type: 'string',
5534
5560
  enum: ['FULL', 'PARTIAL'],
5535
- description: 'Vendor\'s coverage claim'
5561
+ description: 'Vendor\'s implementation capability claim (FULL = complete implementation, PARTIAL = limited scope implementation)'
5536
5562
  },
5537
5563
  response_text: {
5538
5564
  type: 'string',
5539
- description: 'Vendor response explaining their coverage'
5565
+ description: 'Vendor response explaining their implementation capabilities'
5540
5566
  },
5541
5567
  capabilities: {
5542
5568
  type: 'array',
5543
5569
  items: { type: 'string' },
5544
- description: 'List of vendor capabilities/attributes (Governance, Facilitates, Validates)'
5570
+ description: 'List of additional vendor capability types (Governance, Facilitates, Validates)'
5545
5571
  }
5546
5572
  },
5547
5573
  required: ['vendor_name', 'safeguard_id', 'coverage_claim', 'response_text', 'capabilities']
@@ -5568,7 +5594,7 @@ export class GRCAnalysisServer {
5568
5594
  },
5569
5595
  {
5570
5596
  name: 'validate_vendor_mapping',
5571
- description: 'Validate whether a vendor\'s stated capability mapping (Full/Partial/Facilitates/Governance/Validates) is actually supported by their explanatory text for a specific CIS safeguard',
5597
+ description: 'Validate whether a vendor\'s claimed capability role (Full Implementation/Partial Implementation/Facilitates/Governance/Validates) is actually supported by their supporting evidence for a specific CIS safeguard',
5572
5598
  inputSchema: {
5573
5599
  type: 'object',
5574
5600
  properties: {
@@ -5585,11 +5611,11 @@ export class GRCAnalysisServer {
5585
5611
  claimed_capability: {
5586
5612
  type: 'string',
5587
5613
  enum: ['full', 'partial', 'facilitates', 'governance', 'validates'],
5588
- description: 'Vendor\'s claimed capability mapping for this safeguard'
5614
+ description: 'Vendor\'s claimed capability role: full (complete implementation), partial (limited implementation), facilitates (enables/enhances), governance (policies/processes), validates (evidence/reporting)'
5589
5615
  },
5590
5616
  supporting_text: {
5591
5617
  type: 'string',
5592
- description: 'Vendor\'s supporting text blob explaining how they meet the claimed capability'
5618
+ description: 'Vendor\'s supporting evidence explaining how their tool fulfills the claimed capability role'
5593
5619
  }
5594
5620
  },
5595
5621
  required: ['safeguard_id', 'claimed_capability', 'supporting_text']
@@ -5599,28 +5625,45 @@ export class GRCAnalysisServer {
5599
5625
  }));
5600
5626
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
5601
5627
  const { name, arguments: args } = request.params;
5628
+ const startTime = Date.now();
5602
5629
  try {
5630
+ let result;
5603
5631
  switch (name) {
5604
5632
  case 'analyze_vendor_response':
5605
- return await this.analyzeVendorResponse(args);
5633
+ result = await this.analyzeVendorResponse(args);
5634
+ break;
5606
5635
  case 'get_safeguard_details':
5607
- return await this.getSafeguardDetails(args);
5636
+ result = await this.getSafeguardDetails(args);
5637
+ break;
5608
5638
  case 'validate_coverage_claim':
5609
- return await this.validateCoverageClaim(args);
5639
+ result = await this.validateCoverageClaim(args);
5640
+ break;
5610
5641
  case 'list_available_safeguards':
5611
- return await this.listAvailableSafeguards(args);
5642
+ result = await this.listAvailableSafeguards(args);
5643
+ break;
5612
5644
  case 'validate_vendor_mapping':
5613
- return await this.validateVendorMapping(args);
5645
+ result = await this.validateVendorMapping(args);
5646
+ break;
5614
5647
  default:
5615
5648
  throw new Error(`Unknown tool: ${name}`);
5616
5649
  }
5650
+ // Record successful execution time
5651
+ const executionTime = Date.now() - startTime;
5652
+ this.recordToolExecution(name, executionTime);
5653
+ return result;
5617
5654
  }
5618
5655
  catch (error) {
5656
+ // Record error and performance metrics
5657
+ this.performanceMetrics.errorCount++;
5658
+ const executionTime = Date.now() - startTime;
5659
+ this.recordToolExecution(`${name}_error`, executionTime);
5660
+ const errorMessage = this.formatErrorMessage(error, name);
5661
+ console.error(`[FrameworkMCP] Tool execution error: ${name}`, error);
5619
5662
  return {
5620
5663
  content: [
5621
5664
  {
5622
5665
  type: 'text',
5623
- text: `Error: ${error instanceof Error ? error.message : String(error)}`,
5666
+ text: errorMessage,
5624
5667
  },
5625
5668
  ],
5626
5669
  };
@@ -5629,10 +5672,14 @@ export class GRCAnalysisServer {
5629
5672
  }
5630
5673
  async getSafeguardDetails(args) {
5631
5674
  const { safeguard_id, include_examples = true } = args;
5632
- const safeguard = CIS_SAFEGUARDS[safeguard_id];
5633
- if (!safeguard) {
5634
- throw new Error(`Safeguard ${safeguard_id} not found. Use list_available_safeguards to see available safeguards.`);
5675
+ // Input validation
5676
+ this.validateSafeguardId(safeguard_id);
5677
+ // Check cache first
5678
+ const cached = this.getCachedSafeguardDetails(safeguard_id, include_examples);
5679
+ if (cached) {
5680
+ return cached;
5635
5681
  }
5682
+ const safeguard = CIS_SAFEGUARDS[safeguard_id];
5636
5683
  const result = {
5637
5684
  ...safeguard,
5638
5685
  elementBreakdown: {
@@ -5660,7 +5707,7 @@ export class GRCAnalysisServer {
5660
5707
  })
5661
5708
  }
5662
5709
  };
5663
- return {
5710
+ const response = {
5664
5711
  content: [
5665
5712
  {
5666
5713
  type: 'text',
@@ -5668,9 +5715,19 @@ export class GRCAnalysisServer {
5668
5715
  },
5669
5716
  ],
5670
5717
  };
5718
+ // Cache the result for future requests
5719
+ this.setCachedSafeguardDetails(safeguard_id, include_examples, response);
5720
+ return response;
5671
5721
  }
5672
5722
  async listAvailableSafeguards(args) {
5673
5723
  const { implementation_group, security_function } = args;
5724
+ // Check cache for complete safeguard list (only if no filters applied)
5725
+ if (!implementation_group && !security_function && this.cache.safeguardList) {
5726
+ const cacheAge = Date.now() - this.cache.safeguardList.timestamp;
5727
+ if (cacheAge < 10 * 60 * 1000) { // 10 minute cache for safeguard list
5728
+ return this.cache.safeguardList.data;
5729
+ }
5730
+ }
5674
5731
  let safeguards = Object.values(CIS_SAFEGUARDS);
5675
5732
  if (implementation_group) {
5676
5733
  safeguards = safeguards.filter(s => s.implementationGroup === implementation_group);
@@ -5693,7 +5750,7 @@ export class GRCAnalysisServer {
5693
5750
  securityFunction: s.securityFunction
5694
5751
  }))
5695
5752
  };
5696
- return {
5753
+ const response = {
5697
5754
  content: [
5698
5755
  {
5699
5756
  type: 'text',
@@ -5701,14 +5758,25 @@ export class GRCAnalysisServer {
5701
5758
  },
5702
5759
  ],
5703
5760
  };
5761
+ // Cache the complete list if no filters were applied
5762
+ if (!implementation_group && !security_function) {
5763
+ this.cache.safeguardList = {
5764
+ data: response,
5765
+ timestamp: Date.now()
5766
+ };
5767
+ }
5768
+ return response;
5704
5769
  }
5705
5770
  async analyzeVendorResponse(args) {
5706
5771
  const { vendor_name, safeguard_id, response_text } = args;
5707
- const safeguard = CIS_SAFEGUARDS[safeguard_id];
5708
- if (!safeguard) {
5709
- throw new Error(`Safeguard ${safeguard_id} not found. Available safeguards: ${Object.keys(CIS_SAFEGUARDS).join(', ')}`);
5772
+ // Input validation
5773
+ this.validateSafeguardId(safeguard_id);
5774
+ this.validateTextInput(response_text, 'Response text');
5775
+ if (!vendor_name || typeof vendor_name !== 'string' || vendor_name.trim().length === 0) {
5776
+ throw new Error('Vendor name is required');
5710
5777
  }
5711
- const analysis = this.performEnhancedSafeguardAnalysis(vendor_name, safeguard, response_text);
5778
+ const safeguard = CIS_SAFEGUARDS[safeguard_id];
5779
+ const analysis = this.performCapabilityAnalysis(vendor_name, safeguard, response_text);
5712
5780
  return {
5713
5781
  content: [
5714
5782
  {
@@ -5724,7 +5792,7 @@ export class GRCAnalysisServer {
5724
5792
  if (!safeguard) {
5725
5793
  throw new Error(`Safeguard ${safeguard_id} not found`);
5726
5794
  }
5727
- const analysis = this.performEnhancedSafeguardAnalysis(vendor_name, safeguard, response_text);
5795
+ const analysis = this.performCapabilityAnalysis(vendor_name, safeguard, response_text);
5728
5796
  // Validate the coverage claim
5729
5797
  const validation = this.validateClaim(coverage_claim, analysis, capabilities, safeguard);
5730
5798
  return {
@@ -5743,163 +5811,242 @@ export class GRCAnalysisServer {
5743
5811
  ],
5744
5812
  };
5745
5813
  }
5746
- performEnhancedSafeguardAnalysis(vendorName, safeguard, responseText) {
5814
+ performCapabilityAnalysis(vendorName, safeguard, responseText) {
5747
5815
  const text = responseText.toLowerCase();
5748
- // Capability detection keywords
5749
- const governanceKeywords = [
5816
+ // Step 1: Determine what type of capability this tool is claiming
5817
+ const claimedCapability = this.determineClaimedCapability(text, safeguard);
5818
+ // Step 2: Assess how well the tool executes that specific capability type
5819
+ const qualityAssessment = this.assessCapabilityQuality(text, safeguard, claimedCapability);
5820
+ // Step 3: Generate capability-focused analysis
5821
+ return this.generateCapabilityAnalysis(vendorName, safeguard, responseText, claimedCapability, qualityAssessment);
5822
+ }
5823
+ determineClaimedCapability(text, safeguard) {
5824
+ // Capability detection keywords - focused on what the tool DOES, not what elements it covers
5825
+ const governanceIndicators = [
5750
5826
  'policy', 'policies', 'manage', 'process', 'workflow', 'governance', 'grc',
5751
5827
  'compliance management', 'documented', 'establish', 'maintain', 'procedure',
5752
5828
  'control', 'controls', 'framework', 'standard', 'enterprise risk management',
5753
5829
  'centralized management', 'oversight'
5754
5830
  ];
5755
- const facilitatesKeywords = [
5756
- // Technical facilitation (original keywords)
5831
+ const facilitatesIndicators = [
5757
5832
  'improve', 'enhance', 'optimize', 'faster', 'better', 'stronger', 'automate',
5758
5833
  'streamline', 'efficiency', 'facilitate', 'support', 'enable', 'accelerate',
5759
5834
  'api', 'integration', 'data', 'export', 'import', 'sync', 'feed',
5760
- // Data provision and enrichment
5761
5835
  'provides data', 'data source', 'data feeds', 'enrichment', 'data enrichment',
5762
5836
  'supplemental data', 'additional data', 'contextual data', 'threat data',
5763
5837
  'intelligence feeds', 'data aggregation', 'data collection', 'data gathering',
5764
5838
  'feeds data', 'populates', 'informs', 'enriches', 'supplements',
5765
- // Governance/process facilitation (new keywords for tools like Upolicy)
5766
5839
  'enables compliance', 'facilitates implementation', 'supports compliance',
5767
5840
  'creates framework', 'enables organizations', 'infrastructure', 'foundation',
5768
- 'compliance infrastructure', 'audit infrastructure', 'policy framework',
5769
- 'enables effective', 'working together', 'comprehensive coverage',
5770
5841
  'template', 'templates', 'workflow automation', 'orchestration'
5771
5842
  ];
5772
- const validatesKeywords = [
5843
+ const validatesIndicators = [
5773
5844
  'audit', 'report', 'evidence', 'verify', 'validate', 'check', 'monitor',
5774
5845
  'compliance', 'compliance report', 'assessment', 'logging', 'tracking', 'review', 'attest',
5775
5846
  'dashboard', 'metrics', 'analytics', 'visibility', 'alert', 'attestation',
5776
5847
  'compliance tracking', 'audit trail', 'reporting capabilities', 'audit capabilities'
5777
5848
  ];
5778
- // Analyze element coverage (binary: covered or not)
5779
- const coreCoverage = this.analyzeBinaryElementCoverage(text, safeguard.coreRequirements);
5780
- const subElementCoverage = this.analyzeBinaryElementCoverage(text, safeguard.subTaxonomicalElements);
5781
- const governanceCoverage = this.analyzeBinaryElementCoverage(text, safeguard.governanceElements);
5782
- const implementationCoverage = this.analyzeBinaryElementCoverage(text, safeguard.implementationSuggestions);
5783
- // Enhanced capability detection with better scoring
5784
- const governanceScore = this.calculateKeywordScore(text, governanceKeywords);
5785
- const facilitatesScore = this.calculateKeywordScore(text, facilitatesKeywords);
5786
- const validatesScore = this.calculateKeywordScore(text, validatesKeywords);
5787
- const governanceCapability = governanceScore > 0.3;
5788
- const facilitatesCapability = facilitatesScore > 0.3;
5789
- const validatesCapability = validatesScore > 0.3;
5790
- // Check for specific facilitation patterns (tools that enable/support compliance)
5791
- const facilitationPatterns = [
5792
- 'enables compliance', 'facilitates implementation', 'creates framework',
5793
- 'policy framework', 'compliance infrastructure', 'audit infrastructure',
5794
- 'enables organizations', 'enables effective', 'working together',
5795
- 'creates the policy framework', 'enables organizations to implement',
5796
- 'facilitates implementation of', 'compliance infrastructure facilitates'
5797
- ];
5798
- const hasFacilitationPattern = facilitationPatterns.some(pattern => text.includes(pattern));
5799
- // Check for explicit non-implementation language
5800
- const nonImplementationPatterns = [
5801
- 'don\'t scan', 'don\'t catalog', 'doesn\'t scan', 'doesn\'t catalog',
5802
- 'not scan', 'not catalog', 'even though we don\'t', 'we don\'t directly',
5803
- 'rather than direct', 'instead of direct'
5804
- ];
5805
- const hasNonImplementationLanguage = nonImplementationPatterns.some(pattern => text.includes(pattern));
5806
- // Determine if full or partial coverage (based on core + sub-taxonomical elements WITHIN SCOPE)
5807
- // Full = addresses majority of core requirements + substantial sub-elements within their stated scope
5808
- // Partial = addresses some core requirements with clear scope boundaries
5809
- const corePercentage = safeguard.coreRequirements.length > 0 ?
5810
- (coreCoverage.coveredElements.length / safeguard.coreRequirements.length) * 100 : 0;
5811
- const subElementPercentage = safeguard.subTaxonomicalElements.length > 0 ?
5812
- (subElementCoverage.coveredElements.length / safeguard.subTaxonomicalElements.length) * 100 : 0;
5813
- let fullCapability = false;
5814
- let partialCapability = false;
5815
- // Full capability: High coverage of core requirements + reasonable sub-element coverage
5816
- if (corePercentage >= 70 && subElementPercentage >= 50) {
5817
- fullCapability = true;
5849
+ // Direct implementation indicators (tools that actually perform the safeguard)
5850
+ const implementationIndicators = this.getImplementationIndicators(safeguard.id);
5851
+ // Calculate keyword presence scores
5852
+ const governanceScore = this.calculateKeywordScore(text, governanceIndicators);
5853
+ const facilitatesScore = this.calculateKeywordScore(text, facilitatesIndicators);
5854
+ const validatesScore = this.calculateKeywordScore(text, validatesIndicators);
5855
+ const implementationScore = this.calculateKeywordScore(text, implementationIndicators);
5856
+ // Determine claimed capability based on strongest indicators and patterns
5857
+ if (implementationScore > 0.2 && implementationScore >= Math.max(facilitatesScore, governanceScore, validatesScore)) {
5858
+ // Tool claims to directly implement the safeguard
5859
+ return implementationScore > 0.5 ? 'full' : 'partial';
5818
5860
  }
5819
- // Partial capability: Moderate core coverage OR clear scope-limited implementation
5820
- else if (corePercentage >= 30 || (coreCoverage.coveredElements.length > 0 && subElementPercentage >= 20)) {
5821
- partialCapability = true;
5861
+ else if (governanceScore > 0.2 && governanceScore >= Math.max(facilitatesScore, validatesScore)) {
5862
+ return 'governance';
5822
5863
  }
5823
- // Enhanced primary capability logic
5824
- let primaryCapability = 'none';
5825
- if (fullCapability) {
5826
- primaryCapability = 'full';
5864
+ else if (validatesScore > 0.2 && validatesScore >= facilitatesScore) {
5865
+ return 'validates';
5827
5866
  }
5828
- else if (hasFacilitationPattern || hasNonImplementationLanguage ||
5829
- (facilitatesScore > 0.4 && facilitatesScore > governanceScore * 1.2)) {
5830
- // Prioritize facilitation when:
5831
- // 1. Clear facilitation language patterns detected, OR
5832
- // 2. Explicit non-implementation language (tool doesn't directly implement), OR
5833
- // 3. Facilitates score is substantial AND significantly higher than governance
5834
- primaryCapability = 'facilitates';
5867
+ else {
5868
+ return 'facilitates';
5835
5869
  }
5836
- else if (partialCapability) {
5837
- primaryCapability = 'partial';
5870
+ }
5871
+ getImplementationIndicators(safeguardId) {
5872
+ // Return specific indicators for what constitutes direct implementation for each safeguard
5873
+ const implementationMap = {
5874
+ "1.1": ['inventory', 'discovery', 'asset management', 'catalog', 'enumerate', 'scan devices', 'device database'],
5875
+ "1.2": ['unauthorized', 'rogue', 'detect', 'identify unauthorized', 'quarantine', 'block unauthorized'],
5876
+ "5.1": ['account inventory', 'user management', 'identity management', 'account lifecycle', 'user provisioning'],
5877
+ "6.3": ['multi-factor', 'mfa', '2fa', 'authentication', 'two-factor', 'multi-factor authentication'],
5878
+ "7.1": ['vulnerability', 'vuln', 'scanning', 'vulnerability management', 'security testing', 'penetration testing']
5879
+ };
5880
+ return implementationMap[safeguardId] || [];
5881
+ }
5882
+ assessCapabilityQuality(text, safeguard, claimedCapability) {
5883
+ // Assess how well the tool executes the claimed capability type
5884
+ const evidence = [];
5885
+ const gaps = [];
5886
+ // Quality assessment based on capability type
5887
+ let qualityScore = 0;
5888
+ switch (claimedCapability) {
5889
+ case 'full':
5890
+ case 'partial':
5891
+ qualityScore = this.assessImplementationQuality(text, safeguard, evidence, gaps);
5892
+ break;
5893
+ case 'governance':
5894
+ qualityScore = this.assessGovernanceQuality(text, safeguard, evidence, gaps);
5895
+ break;
5896
+ case 'facilitates':
5897
+ qualityScore = this.assessFacilitationQuality(text, safeguard, evidence, gaps);
5898
+ break;
5899
+ case 'validates':
5900
+ qualityScore = this.assessValidationQuality(text, safeguard, evidence, gaps);
5901
+ break;
5838
5902
  }
5839
- else if (governanceCapability && (facilitatesCapability || validatesCapability)) {
5840
- // Tools that primarily manage governance but also facilitate/validate
5841
- primaryCapability = 'governance';
5903
+ // Convert score to quality rating
5904
+ let quality;
5905
+ if (qualityScore >= 0.8)
5906
+ quality = 'excellent';
5907
+ else if (qualityScore >= 0.6)
5908
+ quality = 'good';
5909
+ else if (qualityScore >= 0.4)
5910
+ quality = 'fair';
5911
+ else
5912
+ quality = 'poor';
5913
+ return {
5914
+ quality,
5915
+ confidence: Math.round(qualityScore * 100),
5916
+ evidence: evidence.slice(0, 5), // Top 5 pieces of evidence
5917
+ gaps: gaps.slice(0, 3) // Top 3 gaps identified
5918
+ };
5919
+ }
5920
+ assessImplementationQuality(text, safeguard, evidence, gaps) {
5921
+ // Assess quality of direct implementation capability
5922
+ const implementationIndicators = this.getImplementationIndicators(safeguard.id);
5923
+ let score = 0;
5924
+ // Check for strong implementation language
5925
+ const strongIndicators = implementationIndicators.filter(indicator => text.includes(indicator.toLowerCase()));
5926
+ if (strongIndicators.length > 0) {
5927
+ score += 0.4;
5928
+ evidence.push(`Strong implementation indicators: ${strongIndicators.join(', ')}`);
5929
+ }
5930
+ // Check for comprehensive functionality description
5931
+ if (text.includes('comprehensive') || text.includes('complete') || text.includes('full')) {
5932
+ score += 0.2;
5933
+ evidence.push('Claims comprehensive functionality');
5934
+ }
5935
+ // Check for automated vs manual implementation
5936
+ if (text.includes('automat') || text.includes('real-time') || text.includes('continuous')) {
5937
+ score += 0.2;
5938
+ evidence.push('Automated implementation capability');
5842
5939
  }
5843
- else if (governanceScore > facilitatesScore && governanceCapability) {
5844
- // Pure governance tools
5845
- primaryCapability = 'governance';
5940
+ // Identify potential gaps
5941
+ if (strongIndicators.length === 0) {
5942
+ gaps.push('No clear implementation indicators found');
5846
5943
  }
5847
- else if (validatesScore > facilitatesScore && validatesCapability) {
5848
- // Validation-focused tools
5849
- primaryCapability = 'validates';
5944
+ return Math.min(score, 1.0);
5945
+ }
5946
+ assessGovernanceQuality(text, safeguard, evidence, gaps) {
5947
+ const governanceIndicators = ['policy', 'process', 'governance', 'compliance', 'documentation', 'oversight'];
5948
+ let score = 0;
5949
+ const foundIndicators = governanceIndicators.filter(indicator => text.includes(indicator));
5950
+ if (foundIndicators.length >= 3) {
5951
+ score += 0.5;
5952
+ evidence.push(`Strong governance capability: ${foundIndicators.join(', ')}`);
5953
+ }
5954
+ if (text.includes('documented') && text.includes('process')) {
5955
+ score += 0.3;
5956
+ evidence.push('Documented process management');
5957
+ }
5958
+ return Math.min(score, 1.0);
5959
+ }
5960
+ assessFacilitationQuality(text, safeguard, evidence, gaps) {
5961
+ const facilitationIndicators = ['enhance', 'enable', 'support', 'facilitate', 'improve', 'optimize'];
5962
+ let score = 0;
5963
+ const foundIndicators = facilitationIndicators.filter(indicator => text.includes(indicator));
5964
+ if (foundIndicators.length >= 2) {
5965
+ score += 0.4;
5966
+ evidence.push(`Clear facilitation capability: ${foundIndicators.join(', ')}`);
5850
5967
  }
5851
- else if (facilitatesCapability) {
5852
- // Default facilitation
5853
- primaryCapability = 'facilitates';
5968
+ return Math.min(score, 1.0);
5969
+ }
5970
+ assessValidationQuality(text, safeguard, evidence, gaps) {
5971
+ const validationIndicators = ['audit', 'report', 'monitor', 'track', 'verify', 'validate'];
5972
+ let score = 0;
5973
+ const foundIndicators = validationIndicators.filter(indicator => text.includes(indicator));
5974
+ if (foundIndicators.length >= 2) {
5975
+ score += 0.4;
5976
+ evidence.push(`Strong validation capability: ${foundIndicators.join(', ')}`);
5854
5977
  }
5855
- // Extract evidence
5856
- const evidence = this.extractEnhancedEvidence(responseText, safeguard);
5857
- // Calculate confidence based on evidence strength and keyword matches
5858
- const keywordConfidence = (governanceScore + facilitatesScore + validatesScore) / 3;
5859
- const totalCoreAndSubElements = safeguard.coreRequirements.length + safeguard.subTaxonomicalElements.length;
5860
- const coveredCoreAndSubElements = coreCoverage.coveredElements.length + subElementCoverage.coveredElements.length;
5861
- const coverageConfidence = totalCoreAndSubElements > 0 ?
5862
- coveredCoreAndSubElements / totalCoreAndSubElements : 0;
5863
- const confidence = Math.min((keywordConfidence * 0.4 + coverageConfidence * 0.6) * 100, 100);
5978
+ return Math.min(score, 1.0);
5979
+ }
5980
+ generateCapabilityAnalysis(vendorName, safeguard, responseText, claimedCapability, qualityAssessment) {
5981
+ // Generate the new capability-focused analysis result
5864
5982
  return {
5865
5983
  vendor: vendorName,
5866
5984
  safeguardId: safeguard.id,
5867
5985
  safeguardTitle: safeguard.title,
5868
- capability: primaryCapability,
5986
+ capability: claimedCapability,
5869
5987
  capabilities: {
5870
- full: fullCapability,
5871
- partial: partialCapability,
5872
- facilitates: facilitatesCapability,
5873
- governance: governanceCapability,
5874
- validates: validatesCapability
5875
- },
5876
- confidence: Math.round(confidence),
5877
- reasoning: this.generateCapabilityReasoning(primaryCapability, fullCapability, partialCapability, governanceCapability, facilitatesCapability, validatesCapability, coreCoverage, subElementCoverage, safeguard, hasFacilitationPattern, hasNonImplementationLanguage),
5878
- evidence,
5879
- elementsCovered: {
5880
- coreRequirements: coreCoverage.coveredElements,
5881
- subTaxonomicalElements: subElementCoverage.coveredElements,
5882
- governanceElements: governanceCoverage.coveredElements,
5883
- implementationMethods: implementationCoverage.coveredElements
5988
+ full: claimedCapability === 'full',
5989
+ partial: claimedCapability === 'partial',
5990
+ facilitates: claimedCapability === 'facilitates',
5991
+ governance: claimedCapability === 'governance',
5992
+ validates: claimedCapability === 'validates'
5884
5993
  },
5885
- elementsNotCovered: {
5886
- coreRequirements: coreCoverage.uncoveredElements,
5887
- subTaxonomicalElements: subElementCoverage.uncoveredElements
5888
- }
5994
+ confidence: qualityAssessment.confidence,
5995
+ reasoning: this.generateCapabilityReasoning(claimedCapability, qualityAssessment, safeguard),
5996
+ evidence: qualityAssessment.evidence,
5997
+ // Note: elementsCovered is now less relevant in capability-focused analysis
5998
+ // We focus on tool capability rather than element coverage
5999
+ toolCapabilityDescription: this.generateToolCapabilityDescription(claimedCapability, qualityAssessment),
6000
+ recommendedUse: this.generateRecommendedUse(claimedCapability, safeguard)
6001
+ };
6002
+ }
6003
+ generateCapabilityReasoning(claimedCapability, qualityAssessment, safeguard) {
6004
+ const capabilityDescriptions = {
6005
+ full: "directly implements the core functionality of this safeguard",
6006
+ partial: "implements limited aspects of this safeguard with clear scope boundaries",
6007
+ facilitates: "enhances or enables the implementation of this safeguard by others",
6008
+ governance: "provides governance, policy, and oversight capabilities for this safeguard",
6009
+ validates: "provides evidence, audit, and compliance validation for this safeguard"
6010
+ };
6011
+ const qualityDescriptor = qualityAssessment.quality;
6012
+ const description = capabilityDescriptions[claimedCapability];
6013
+ return `This tool ${description} with ${qualityDescriptor} capability quality. ${qualityAssessment.evidence.length > 0 ? 'Evidence: ' + qualityAssessment.evidence.join('; ') : ''}`;
6014
+ }
6015
+ generateToolCapabilityDescription(claimedCapability, qualityAssessment) {
6016
+ const roleDescriptions = {
6017
+ full: "Core Implementation Tool - Directly performs the safeguard functionality",
6018
+ partial: "Focused Implementation Tool - Performs specific aspects of the safeguard",
6019
+ facilitates: "Enablement Tool - Helps organizations implement the safeguard more effectively",
6020
+ governance: "Governance Tool - Manages policies, processes, and oversight for the safeguard",
6021
+ validates: "Compliance Tool - Provides audit, evidence, and validation capabilities"
6022
+ };
6023
+ return roleDescriptions[claimedCapability] || "Support Tool";
6024
+ }
6025
+ generateRecommendedUse(claimedCapability, safeguard) {
6026
+ const recommendations = {
6027
+ full: `Use as primary implementation tool for ${safeguard.title}. Ensure proper configuration and integration.`,
6028
+ partial: `Use as part of a multi-tool strategy for ${safeguard.title}. Supplement with additional capabilities as needed.`,
6029
+ facilitates: `Use to enhance existing safeguard implementation. Combine with direct implementation tools.`,
6030
+ governance: `Use for policy management and governance oversight. Pair with implementation and validation tools.`,
6031
+ validates: `Use for compliance monitoring and evidence collection. Combine with implementation tools for complete coverage.`
5889
6032
  };
6033
+ return recommendations[claimedCapability] || "Evaluate specific use case alignment.";
5890
6034
  }
5891
6035
  calculateKeywordScore(text, keywords) {
5892
- let score = 0;
5893
- let matches = 0;
6036
+ let matchedKeywords = 0;
6037
+ let totalMatches = 0;
5894
6038
  keywords.forEach(keyword => {
5895
6039
  const regex = new RegExp(keyword.replace(/\s+/g, '\\s+'), 'gi');
5896
6040
  const keywordMatches = (text.match(regex) || []).length;
5897
6041
  if (keywordMatches > 0) {
5898
- matches++;
5899
- score += keywordMatches;
6042
+ matchedKeywords++;
6043
+ totalMatches += keywordMatches;
5900
6044
  }
5901
6045
  });
5902
- return matches > 0 ? score / text.split(' ').length : 0;
6046
+ // Return percentage of keywords that were found, with bonus for multiple matches
6047
+ const baseScore = matchedKeywords / keywords.length;
6048
+ const matchBonus = Math.min(totalMatches * 0.1, 0.5); // Up to 50% bonus for multiple matches
6049
+ return Math.min(baseScore + matchBonus, 1.0);
5903
6050
  }
5904
6051
  analyzeElementCoverage(text, elements) {
5905
6052
  const coveredElements = [];
@@ -6009,63 +6156,6 @@ export class GRCAnalysisServer {
6009
6156
  }
6010
6157
  return reasons.join('. ');
6011
6158
  }
6012
- generateCapabilityReasoning(primaryCapability, full, partial, governance, facilitates, validates, coreCoverage, subElementCoverage, safeguard, hasFacilitationPattern = false, hasNonImplementationLanguage = false) {
6013
- const reasons = [];
6014
- // Primary capability explanation
6015
- switch (primaryCapability) {
6016
- case 'full':
6017
- reasons.push(`Provides FULL coverage of ${safeguard.title} - directly implements all core and sub-taxonomical elements`);
6018
- break;
6019
- case 'partial':
6020
- reasons.push(`Provides PARTIAL coverage of ${safeguard.title} - directly implements some but not all core and sub-taxonomical elements`);
6021
- break;
6022
- case 'facilitates':
6023
- if (hasFacilitationPattern || hasNonImplementationLanguage || governance) {
6024
- reasons.push(`FACILITATES ${safeguard.title} by creating governance frameworks, policy infrastructure, and compliance processes that enable organizations to implement the control effectively`);
6025
- }
6026
- else {
6027
- reasons.push(`FACILITATES ${safeguard.title} through data integration, automation, or technical capabilities that support implementation`);
6028
- }
6029
- break;
6030
- case 'governance':
6031
- reasons.push(`Provides GOVERNANCE capabilities for ${safeguard.title} through centralized policy management, process controls, and compliance oversight`);
6032
- break;
6033
- case 'validates':
6034
- reasons.push(`VALIDATES ${safeguard.title} implementation through evidence collection, compliance reporting, and audit capabilities`);
6035
- break;
6036
- default:
6037
- reasons.push(`No clear capability identified for ${safeguard.title}`);
6038
- }
6039
- // Coverage details
6040
- if (coreCoverage.coveredElements.length > 0) {
6041
- reasons.push(`Core elements addressed: ${coreCoverage.coveredElements.length}/${safeguard.coreRequirements.length}`);
6042
- }
6043
- if (subElementCoverage.coveredElements.length > 0) {
6044
- reasons.push(`Sub-taxonomical elements addressed: ${subElementCoverage.coveredElements.length}/${safeguard.subTaxonomicalElements.length}`);
6045
- }
6046
- // Additional context for facilitation tools
6047
- if (primaryCapability === 'facilitates') {
6048
- if (hasFacilitationPattern || hasNonImplementationLanguage || governance) {
6049
- reasons.push(`Note: This type of facilitation tool works alongside technical implementation solutions (asset scanners, MDM tools, etc.) to provide comprehensive control coverage`);
6050
- }
6051
- if (hasNonImplementationLanguage) {
6052
- reasons.push(`Tool explicitly enables compliance through governance/process rather than direct technical implementation`);
6053
- }
6054
- }
6055
- // Multi-capability products
6056
- const capabilityFlags = [governance, facilitates, validates].filter(Boolean);
6057
- if (capabilityFlags.length > 1) {
6058
- const capabilities = [];
6059
- if (governance)
6060
- capabilities.push('governance');
6061
- if (facilitates)
6062
- capabilities.push('facilitates');
6063
- if (validates)
6064
- capabilities.push('validates');
6065
- reasons.push(`Multi-capability product with: ${capabilities.join(', ')}`);
6066
- }
6067
- return reasons.join('. ');
6068
- }
6069
6159
  validateClaim(claim, analysis, capabilities, safeguard) {
6070
6160
  const validation = {
6071
6161
  coverageClaimValid: false,
@@ -6078,16 +6168,14 @@ export class GRCAnalysisServer {
6078
6168
  const meetsFullCriteria = analysis.capabilities.full;
6079
6169
  validation.coverageClaimValid = meetsFullCriteria;
6080
6170
  if (!meetsFullCriteria) {
6081
- const totalElements = safeguard.coreRequirements.length + safeguard.subTaxonomicalElements.length;
6082
- const coveredElements = analysis.elementsCovered.coreRequirements.length + analysis.elementsCovered.subTaxonomicalElements.length;
6083
- validation.gaps.push(`FULL coverage claim not supported: Only ${coveredElements}/${totalElements} core and sub-taxonomical elements covered`);
6171
+ validation.gaps.push(`FULL implementation capability claim not supported: Tool does not demonstrate direct implementation of core safeguard functionality`);
6084
6172
  }
6085
6173
  }
6086
6174
  else if (claim === 'PARTIAL') {
6087
6175
  const meetsPartialCriteria = analysis.capabilities.partial || analysis.capabilities.full;
6088
6176
  validation.coverageClaimValid = meetsPartialCriteria;
6089
6177
  if (!meetsPartialCriteria) {
6090
- validation.gaps.push(`PARTIAL coverage claim questionable: No core or sub-taxonomical elements clearly addressed`);
6178
+ validation.gaps.push(`PARTIAL implementation capability claim questionable: No core or sub-taxonomical elements clearly addressed`);
6091
6179
  }
6092
6180
  }
6093
6181
  // Validate capability claims
@@ -6131,12 +6219,18 @@ export class GRCAnalysisServer {
6131
6219
  }
6132
6220
  else {
6133
6221
  validation.recommendations.push(`Consider requesting additional information about: ${validation.gaps.join(', ')}`);
6134
- // Specific recommendations based on gaps
6135
- if (analysis.elementsNotCovered.coreRequirements.length > 0) {
6136
- validation.recommendations.push(`Request details on how these core elements are addressed: ${analysis.elementsNotCovered.coreRequirements.slice(0, 3).join(', ')}${analysis.elementsNotCovered.coreRequirements.length > 3 ? '...' : ''}`);
6222
+ // Capability-based recommendations
6223
+ if (analysis.capability === 'facilitates') {
6224
+ validation.recommendations.push('Consider pairing with direct implementation tools for complete safeguard coverage');
6225
+ }
6226
+ else if (analysis.capability === 'partial') {
6227
+ validation.recommendations.push('Evaluate scope limitations and identify complementary tools for full coverage');
6137
6228
  }
6138
- if (analysis.elementsNotCovered.subTaxonomicalElements.length > 0) {
6139
- validation.recommendations.push(`Ask for specifics on these sub-taxonomical elements: ${analysis.elementsNotCovered.subTaxonomicalElements.slice(0, 3).join(', ')}${analysis.elementsNotCovered.subTaxonomicalElements.length > 3 ? '...' : ''}`);
6229
+ else if (analysis.capability === 'governance') {
6230
+ validation.recommendations.push('Combine with technical implementation tools for complete safeguard execution');
6231
+ }
6232
+ else if (analysis.capability === 'validates') {
6233
+ validation.recommendations.push('Pair with implementation tools to ensure both execution and validation coverage');
6140
6234
  }
6141
6235
  if (!analysis.capabilities.validates && capabilities.includes('Validates')) {
6142
6236
  validation.recommendations.push(`Request examples of audit trails, reporting capabilities, and compliance evidence`);
@@ -6146,10 +6240,11 @@ export class GRCAnalysisServer {
6146
6240
  }
6147
6241
  async validateVendorMapping(args) {
6148
6242
  const { vendor_name = 'Unknown Vendor', safeguard_id, claimed_capability, supporting_text } = args;
6243
+ // Input validation
6244
+ this.validateSafeguardId(safeguard_id);
6245
+ this.validateTextInput(supporting_text, 'Supporting text');
6246
+ this.validateCapability(claimed_capability);
6149
6247
  const safeguard = CIS_SAFEGUARDS[safeguard_id];
6150
- if (!safeguard) {
6151
- throw new Error(`Safeguard ${safeguard_id} not found. Available safeguards: ${Object.keys(CIS_SAFEGUARDS).join(', ')}`);
6152
- }
6153
6248
  const validation = this.validateCapabilityClaim(vendor_name, safeguard, claimed_capability, supporting_text);
6154
6249
  return {
6155
6250
  content: [
@@ -6163,7 +6258,7 @@ export class GRCAnalysisServer {
6163
6258
  validateCapabilityClaim(vendorName, safeguard, claimedCapability, supportingText) {
6164
6259
  const text = supportingText.toLowerCase();
6165
6260
  // Detect tool type and validate domain match
6166
- const detectedToolType = this.detectToolType(supportingText);
6261
+ const detectedToolType = this.detectToolType(supportingText, safeguard.id);
6167
6262
  const domainValidation = this.validateDomainMatch(safeguard.id, claimedCapability, detectedToolType);
6168
6263
  // Adjust capability if domain mismatch detected
6169
6264
  let effectiveCapability = claimedCapability;
@@ -6172,20 +6267,10 @@ export class GRCAnalysisServer {
6172
6267
  originalClaim = claimedCapability;
6173
6268
  effectiveCapability = domainValidation.adjusted_capability;
6174
6269
  }
6175
- // Perform actual analysis of the supporting text
6176
- const actualAnalysis = this.performEnhancedSafeguardAnalysis(vendorName, safeguard, supportingText);
6177
- // Calculate coverage percentages
6178
- const coreCoverage = this.analyzeBinaryElementCoverage(text, safeguard.coreRequirements);
6179
- const subElementCoverage = this.analyzeBinaryElementCoverage(text, safeguard.subTaxonomicalElements);
6180
- const governanceCoverage = this.analyzeBinaryElementCoverage(text, safeguard.governanceElements);
6181
- const corePercentage = safeguard.coreRequirements.length > 0 ?
6182
- (coreCoverage.coveredElements.length / safeguard.coreRequirements.length) * 100 : 0;
6183
- const subElementPercentage = safeguard.subTaxonomicalElements.length > 0 ?
6184
- (subElementCoverage.coveredElements.length / safeguard.subTaxonomicalElements.length) * 100 : 0;
6185
- const governancePercentage = safeguard.governanceElements.length > 0 ?
6186
- (governanceCoverage.coveredElements.length / safeguard.governanceElements.length) * 100 : 0;
6187
- // Validate claim against criteria (using effective capability after domain adjustment)
6188
- const validation = this.assessClaimAlignment(effectiveCapability, actualAnalysis, corePercentage, subElementPercentage, governancePercentage, text);
6270
+ // Perform capability-focused analysis of the supporting text
6271
+ const actualAnalysis = this.performCapabilityAnalysis(vendorName, safeguard, supportingText);
6272
+ // Validate claimed capability against actual capability analysis and domain requirements
6273
+ const validation = this.assessCapabilityClaimAlignment(claimedCapability, effectiveCapability, actualAnalysis, domainValidation, text);
6189
6274
  // Add domain validation gaps if capability was adjusted
6190
6275
  if (domainValidation.should_adjust_capability) {
6191
6276
  validation.gaps.unshift(`Domain mismatch: ${domainValidation.reasoning}`);
@@ -6200,12 +6285,10 @@ export class GRCAnalysisServer {
6200
6285
  claimed_capability: claimedCapability,
6201
6286
  validation_status: validation.status,
6202
6287
  confidence_score: validation.confidence,
6203
- evidence_analysis: {
6204
- core_requirements_coverage: Math.round(corePercentage),
6205
- sub_elements_coverage: Math.round(subElementPercentage),
6206
- governance_alignment: Math.round(governancePercentage),
6207
- language_consistency: validation.languageConsistency
6208
- },
6288
+ actual_capability_detected: actualAnalysis.capability,
6289
+ capability_confidence: actualAnalysis.confidence,
6290
+ tool_capability_description: actualAnalysis.toolCapabilityDescription,
6291
+ recommended_use: actualAnalysis.recommendedUse,
6209
6292
  domain_validation: {
6210
6293
  required_tool_type: domainValidation.required_tool_types.join('/'),
6211
6294
  detected_tool_type: detectedToolType,
@@ -6219,112 +6302,42 @@ export class GRCAnalysisServer {
6219
6302
  detailed_feedback: validation.feedback
6220
6303
  };
6221
6304
  }
6222
- assessClaimAlignment(claimedCapability, actualAnalysis, corePercentage, subElementPercentage, governancePercentage, text) {
6305
+ assessCapabilityClaimAlignment(claimedCapability, effectiveCapability, actualAnalysis, domainValidation, text) {
6223
6306
  const gaps = [];
6224
6307
  const strengths = [];
6225
6308
  const recommendations = [];
6226
- let languageConsistency = 0;
6309
+ // Compare claimed capability with what we actually detected
6310
+ const claimedLower = claimedCapability.toLowerCase();
6311
+ const effectiveLower = effectiveCapability.toLowerCase();
6312
+ const actualCapability = actualAnalysis.capability;
6227
6313
  let alignmentScore = 0;
6228
- switch (claimedCapability.toLowerCase()) {
6229
- case 'full':
6230
- // Validate FULL claim
6231
- if (corePercentage >= 70 && subElementPercentage >= 40) {
6232
- alignmentScore = 85;
6233
- strengths.push('High coverage of core requirements and sub-elements');
6234
- }
6235
- else if (corePercentage >= 80 && subElementPercentage >= 30) {
6236
- // Alternative path: very high core with moderate sub-elements
6237
- alignmentScore = 80;
6238
- strengths.push('Very high core requirements coverage with adequate sub-element coverage');
6239
- }
6240
- else {
6241
- alignmentScore = Math.max(0, (corePercentage + subElementPercentage) / 2 - 15);
6242
- if (corePercentage < 70)
6243
- gaps.push(`Core requirements coverage (${Math.round(corePercentage)}%) below FULL threshold (70%)`);
6244
- if (subElementPercentage < 40)
6245
- gaps.push(`Sub-element coverage (${Math.round(subElementPercentage)}%) below FULL threshold (40%)`);
6246
- }
6247
- // Check for conflicting facilitation language
6248
- if (this.hasFacilitationLanguage(text)) {
6249
- alignmentScore -= 30;
6250
- gaps.push('Contains facilitation language inconsistent with FULL implementation claim');
6251
- }
6252
- languageConsistency = this.assessImplementationLanguage(text);
6253
- break;
6254
- case 'partial':
6255
- // Validate PARTIAL claim
6256
- if (corePercentage >= 30 || (corePercentage > 0 && subElementPercentage >= 20)) {
6257
- alignmentScore = 75;
6258
- strengths.push('Appropriate coverage level for PARTIAL implementation');
6259
- }
6260
- else {
6261
- alignmentScore = Math.max(0, corePercentage + subElementPercentage - 10);
6262
- gaps.push(`Coverage too low even for PARTIAL claim: ${Math.round(corePercentage)}% core, ${Math.round(subElementPercentage)}% sub-elements`);
6263
- }
6264
- // Check for scope boundary definition
6265
- if (this.hasScopeBoundaries(text)) {
6266
- strengths.push('Clearly defines scope boundaries and limitations');
6267
- alignmentScore += 10;
6268
- }
6269
- else {
6270
- gaps.push('Should clearly define scope boundaries for PARTIAL implementation');
6271
- recommendations.push('Specify exactly which elements are covered and which are not');
6272
- }
6273
- languageConsistency = this.assessImplementationLanguage(text);
6274
- break;
6275
- case 'facilitates':
6276
- // Validate FACILITATES claim
6277
- if (this.hasFacilitationLanguage(text) || actualAnalysis.capabilities.facilitates) {
6278
- alignmentScore = 80;
6279
- strengths.push('Contains appropriate facilitation and enablement language');
6280
- }
6281
- else {
6282
- alignmentScore = 40;
6283
- gaps.push('Lacks clear facilitation language (enables, supports, provides framework)');
6284
- }
6285
- // Check that it doesn't claim direct implementation
6286
- if (this.hasDirectImplementationLanguage(text)) {
6287
- // Special handling: If it lacks facilitation language AND claims implementation, stay QUESTIONABLE
6288
- if (alignmentScore <= 40) {
6289
- alignmentScore = 45; // Keep it in QUESTIONABLE range
6290
- }
6291
- else {
6292
- alignmentScore -= 15;
6293
- }
6294
- gaps.push('Claims direct implementation, inconsistent with FACILITATES capability');
6295
- }
6296
- languageConsistency = this.assessFacilitationLanguage(text);
6297
- break;
6298
- case 'governance':
6299
- // Validate GOVERNANCE claim
6300
- if (governancePercentage >= 60 || actualAnalysis.capabilities.governance) {
6301
- alignmentScore = 85;
6302
- strengths.push('Strong governance element coverage and policy management language');
6303
- }
6304
- else {
6305
- alignmentScore = Math.max(30, governancePercentage);
6306
- gaps.push(`Governance element coverage (${Math.round(governancePercentage)}%) below expected threshold (60%)`);
6307
- }
6308
- languageConsistency = this.assessGovernanceLanguage(text);
6309
- break;
6310
- case 'validates':
6311
- // Validate VALIDATES claim
6312
- if (actualAnalysis.capabilities.validates) {
6313
- alignmentScore = 85;
6314
- strengths.push('Contains evidence collection and reporting capabilities');
6315
- }
6316
- else {
6317
- alignmentScore = 30;
6318
- gaps.push('Lacks validation language (audit, report, evidence, verify, monitor)');
6319
- }
6320
- languageConsistency = this.assessValidationLanguage(text);
6321
- break;
6322
- default:
6323
- alignmentScore = 0;
6324
- gaps.push(`Unknown capability type: ${claimedCapability}`);
6325
- languageConsistency = 0;
6314
+ // Check if claim aligns with actual analysis
6315
+ if (claimedLower === actualCapability) {
6316
+ alignmentScore = actualAnalysis.confidence;
6317
+ strengths.push(`Claimed capability '${claimedCapability}' aligns with detected capability`);
6318
+ strengths.push(`Tool demonstrates appropriate ${actualAnalysis.toolCapabilityDescription.toLowerCase()}`);
6319
+ }
6320
+ else if (effectiveLower === actualCapability) {
6321
+ // Domain validation adjusted the capability and it matches the analysis
6322
+ alignmentScore = Math.max(actualAnalysis.confidence - 20, 30);
6323
+ gaps.push(`Original claim '${claimedCapability}' doesn't match tool type, adjusted to '${effectiveCapability}'`);
6324
+ strengths.push(`Adjusted capability '${effectiveCapability}' aligns with tool analysis`);
6325
+ }
6326
+ else {
6327
+ // Neither claimed nor effective capability matches the analysis
6328
+ alignmentScore = Math.max(actualAnalysis.confidence - 40, 10);
6329
+ gaps.push(`Claimed capability '${claimedCapability}' doesn't align with detected capability '${actualCapability}'`);
6330
+ gaps.push(`Tool appears to be: ${actualAnalysis.toolCapabilityDescription}`);
6331
+ }
6332
+ // Add evidence from the capability analysis
6333
+ if (actualAnalysis.evidence && actualAnalysis.evidence.length > 0) {
6334
+ strengths.push(`Supporting evidence: ${actualAnalysis.evidence.slice(0, 2).join('; ')}`);
6326
6335
  }
6327
- // Determine overall status
6336
+ // Domain validation feedback
6337
+ if (!domainValidation.domain_match) {
6338
+ gaps.push(`Tool type '${domainValidation.detected_tool_type}' not appropriate for this safeguard domain`);
6339
+ }
6340
+ // Determine overall status based on alignment score
6328
6341
  let status;
6329
6342
  if (alignmentScore >= 70) {
6330
6343
  status = 'SUPPORTED';
@@ -6335,18 +6348,18 @@ export class GRCAnalysisServer {
6335
6348
  else {
6336
6349
  status = 'UNSUPPORTED';
6337
6350
  }
6338
- // Generate recommendations
6339
- if (gaps.length > 0) {
6340
- recommendations.push('Address identified gaps to strengthen capability claim');
6341
- }
6351
+ // Generate capability-focused recommendations
6352
+ recommendations.push(actualAnalysis.recommendedUse);
6342
6353
  if (status === 'QUESTIONABLE') {
6343
- recommendations.push('Provide additional evidence or clarify scope to support claim');
6354
+ recommendations.push('Consider clarifying tool capabilities or adjusting capability claim');
6355
+ }
6356
+ if (!domainValidation.domain_match) {
6357
+ recommendations.push(`For ${actualCapability.toUpperCase()} capability, focus on how the tool ${actualCapability === 'facilitates' ? 'enables and enhances' : actualCapability === 'governance' ? 'manages policies and processes for' : actualCapability === 'validates' ? 'provides evidence and reporting on' : 'directly implements'} this safeguard`);
6344
6358
  }
6345
- const feedback = this.generateValidationFeedback(claimedCapability, status, gaps, strengths, alignmentScore);
6359
+ const feedback = this.generateCapabilityValidationFeedback(claimedCapability, effectiveCapability, actualCapability, status, alignmentScore, domainValidation);
6346
6360
  return {
6347
6361
  status,
6348
6362
  confidence: Math.round(alignmentScore),
6349
- languageConsistency: Math.round(languageConsistency),
6350
6363
  gaps,
6351
6364
  strengths,
6352
6365
  recommendations,
@@ -6404,70 +6417,139 @@ export class GRCAnalysisServer {
6404
6417
  ];
6405
6418
  return this.calculateKeywordScore(text, validationKeywords) * 100;
6406
6419
  }
6407
- detectToolType(text) {
6420
+ detectToolType(text, safeguardId) {
6408
6421
  const lowerText = text.toLowerCase();
6409
- // Inventory/Asset Management tools
6410
- const inventoryKeywords = [
6411
- 'asset management', 'inventory', 'cmdb', 'discovery', 'asset discovery',
6412
- 'hardware inventory', 'software inventory', 'device inventory', 'asset tracking',
6413
- 'configuration management database', 'it asset management', 'endpoint discovery'
6414
- ];
6415
- // Identity/Authentication tools
6416
- const identityKeywords = [
6417
- 'identity management', 'iam', 'active directory', 'ldap', 'sso', 'single sign-on',
6418
- 'mfa', 'multi-factor', 'authentication', 'identity provider', 'access management',
6419
- 'user management', 'account management', 'directory service'
6420
- ];
6421
- // Vulnerability Management tools
6422
- const vulnerabilityKeywords = [
6423
- 'vulnerability scanner', 'vulnerability management', 'patch management',
6424
- 'security scanner', 'vuln scan', 'penetration test', 'security assessment',
6425
- 'scanning capabilities', 'vulnerability scanning', 'network discovery'
6426
- ];
6427
- // Network Security tools
6428
- const networkSecurityKeywords = [
6429
- 'firewall', 'network access control', 'nac', 'network security', 'intrusion detection',
6430
- 'network monitoring', 'traffic analysis', 'network segmentation'
6431
- ];
6432
- // Threat Intelligence/Data Enrichment tools
6433
- const threatIntelKeywords = [
6434
- 'threat intelligence', 'threat intel', 'threat feed', 'security intelligence',
6435
- 'enrichment', 'data feed', 'contextual data', 'risk intelligence',
6436
- 'cyber threat intelligence', 'ioc feed', 'threat data'
6437
- ];
6438
- // GRC/Governance tools
6439
- const governanceKeywords = [
6440
- 'grc', 'governance', 'compliance management', 'policy management',
6441
- 'risk management', 'audit management', 'compliance platform'
6442
- ];
6443
- // Security Analytics/SIEM tools
6444
- const analyticsKeywords = [
6445
- 'siem', 'security analytics', 'log management', 'security monitoring',
6446
- 'event correlation', 'security orchestration', 'soar'
6447
- ];
6448
- // Check for tool type patterns - order by specificity (most specific first)
6449
- if (threatIntelKeywords.some(keyword => lowerText.includes(keyword))) {
6450
- return 'threat_intelligence';
6451
- }
6452
- else if (vulnerabilityKeywords.some(keyword => lowerText.includes(keyword))) {
6453
- return 'vulnerability_management';
6454
- }
6455
- else if (identityKeywords.some(keyword => lowerText.includes(keyword))) {
6456
- return 'identity_management';
6457
- }
6458
- else if (networkSecurityKeywords.some(keyword => lowerText.includes(keyword))) {
6459
- return 'network_security';
6460
- }
6461
- else if (governanceKeywords.some(keyword => lowerText.includes(keyword))) {
6462
- return 'governance';
6422
+ // Enhanced keyword definitions with scoring weights and context
6423
+ const toolTypePatterns = {
6424
+ 'inventory': {
6425
+ primary: [
6426
+ 'asset management', 'inventory management', 'cmdb', 'configuration management database',
6427
+ 'asset discovery', 'hardware inventory', 'software inventory', 'device inventory',
6428
+ 'asset tracking', 'it asset management', 'endpoint discovery', 'asset lifecycle'
6429
+ ],
6430
+ secondary: [
6431
+ 'inventory', 'discovery', 'device management', 'endpoint management',
6432
+ 'configuration management', 'asset database', 'equipment tracking'
6433
+ ],
6434
+ weight: { primary: 3, secondary: 1 }
6435
+ },
6436
+ 'identity_management': {
6437
+ primary: [
6438
+ 'identity management', 'iam', 'active directory', 'identity provider',
6439
+ 'single sign-on', 'sso', 'multi-factor authentication', 'mfa',
6440
+ 'user management', 'account management', 'directory service'
6441
+ ],
6442
+ secondary: [
6443
+ 'ldap', 'authentication', 'access management', 'identity access management',
6444
+ 'user directory', 'account lifecycle', 'privileged access'
6445
+ ],
6446
+ weight: { primary: 3, secondary: 1 }
6447
+ },
6448
+ 'vulnerability_management': {
6449
+ primary: [
6450
+ 'vulnerability management', 'vulnerability scanner', 'patch management',
6451
+ 'security scanning', 'vulnerability assessment', 'penetration testing'
6452
+ ],
6453
+ secondary: [
6454
+ 'vuln scan', 'security scanner', 'network scanner', 'scanning capabilities',
6455
+ 'security assessment', 'vulnerability scanning', 'patch deployment'
6456
+ ],
6457
+ weight: { primary: 3, secondary: 1 }
6458
+ },
6459
+ 'threat_intelligence': {
6460
+ primary: [
6461
+ 'threat intelligence', 'cyber threat intelligence', 'threat intel',
6462
+ 'threat feed', 'ioc feed', 'security intelligence', 'threat data'
6463
+ ],
6464
+ secondary: [
6465
+ 'enrichment', 'data feed', 'contextual data', 'risk intelligence',
6466
+ 'threat indicators', 'intelligence platform', 'threat correlation'
6467
+ ],
6468
+ weight: { primary: 3, secondary: 1 }
6469
+ },
6470
+ 'network_security': {
6471
+ primary: [
6472
+ 'firewall', 'network access control', 'nac', 'intrusion detection',
6473
+ 'network security', 'network segmentation'
6474
+ ],
6475
+ secondary: [
6476
+ 'network monitoring', 'traffic analysis', 'perimeter security',
6477
+ 'network protection', 'network filtering'
6478
+ ],
6479
+ weight: { primary: 3, secondary: 1 }
6480
+ },
6481
+ 'governance': {
6482
+ primary: [
6483
+ 'grc', 'governance risk compliance', 'compliance management',
6484
+ 'policy management', 'risk management', 'audit management'
6485
+ ],
6486
+ secondary: [
6487
+ 'governance', 'compliance platform', 'policy enforcement',
6488
+ 'regulatory compliance', 'framework management'
6489
+ ],
6490
+ weight: { primary: 3, secondary: 1 }
6491
+ },
6492
+ 'security_analytics': {
6493
+ primary: [
6494
+ 'siem', 'security information event management', 'security analytics',
6495
+ 'soar', 'security orchestration', 'log management'
6496
+ ],
6497
+ secondary: [
6498
+ 'security monitoring', 'event correlation', 'log analysis',
6499
+ 'security intelligence', 'incident response platform'
6500
+ ],
6501
+ weight: { primary: 3, secondary: 1 }
6502
+ }
6503
+ };
6504
+ // Calculate scores for each tool type
6505
+ const toolScores = {};
6506
+ for (const [toolType, patterns] of Object.entries(toolTypePatterns)) {
6507
+ let score = 0;
6508
+ // Check primary keywords
6509
+ for (const keyword of patterns.primary) {
6510
+ if (lowerText.includes(keyword)) {
6511
+ score += patterns.weight.primary;
6512
+ }
6513
+ }
6514
+ // Check secondary keywords
6515
+ for (const keyword of patterns.secondary) {
6516
+ if (lowerText.includes(keyword)) {
6517
+ score += patterns.weight.secondary;
6518
+ }
6519
+ }
6520
+ toolScores[toolType] = score;
6463
6521
  }
6464
- else if (analyticsKeywords.some(keyword => lowerText.includes(keyword))) {
6465
- return 'security_analytics';
6522
+ // Apply safeguard-specific context weighting if provided
6523
+ if (safeguardId && toolScores) {
6524
+ const contextBonus = 1; // Small bonus for domain alignment
6525
+ // Asset inventory safeguards (1.1, 1.2) favor inventory tools
6526
+ if (['1.1', '1.2'].includes(safeguardId) && toolScores['inventory'] > 0) {
6527
+ toolScores['inventory'] += contextBonus;
6528
+ }
6529
+ // Account inventory safeguards (5.1, 5.2, 5.3) favor identity tools
6530
+ if (['5.1', '5.2', '5.3'].includes(safeguardId) && toolScores['identity_management'] > 0) {
6531
+ toolScores['identity_management'] += contextBonus;
6532
+ }
6533
+ // Authentication safeguards (6.1, 6.2, 6.3) favor identity tools
6534
+ if (['6.1', '6.2', '6.3'].includes(safeguardId) && toolScores['identity_management'] > 0) {
6535
+ toolScores['identity_management'] += contextBonus;
6536
+ }
6537
+ // Vulnerability safeguards (7.1-7.7) favor vulnerability management tools
6538
+ if (['7.1', '7.2', '7.3', '7.4', '7.5', '7.6', '7.7'].includes(safeguardId) && toolScores['vulnerability_management'] > 0) {
6539
+ toolScores['vulnerability_management'] += contextBonus;
6540
+ }
6466
6541
  }
6467
- else if (inventoryKeywords.some(keyword => lowerText.includes(keyword))) {
6468
- return 'inventory';
6542
+ // Find the tool type with highest score
6543
+ let maxScore = 0;
6544
+ let detectedType = 'unknown';
6545
+ for (const [toolType, score] of Object.entries(toolScores)) {
6546
+ if (score > maxScore) {
6547
+ maxScore = score;
6548
+ detectedType = toolType;
6549
+ }
6469
6550
  }
6470
- return 'unknown';
6551
+ // Require minimum score threshold to avoid false positives
6552
+ return maxScore >= 2 ? detectedType : 'unknown';
6471
6553
  }
6472
6554
  validateDomainMatch(safeguardId, claimedCapability, detectedToolType) {
6473
6555
  const domainReq = SAFEGUARD_DOMAIN_REQUIREMENTS[safeguardId];
@@ -6487,7 +6569,7 @@ export class GRCAnalysisServer {
6487
6569
  required_tool_types: domainReq.required_tool_types,
6488
6570
  should_adjust_capability: true,
6489
6571
  adjusted_capability: 'facilitates',
6490
- reasoning: `${domainReq.domain} safeguard requires ${domainReq.required_tool_types.join('/')} tool types for FULL/PARTIAL coverage. Detected tool type '${detectedToolType}' can only facilitate implementation.`
6572
+ reasoning: `${domainReq.domain} safeguard requires ${domainReq.required_tool_types.join('/')} tool types for FULL/PARTIAL implementation capability. Detected tool type '${detectedToolType}' can only facilitate implementation.`
6491
6573
  };
6492
6574
  }
6493
6575
  return {
@@ -6499,8 +6581,31 @@ export class GRCAnalysisServer {
6499
6581
  'No domain validation required for this capability type'
6500
6582
  };
6501
6583
  }
6584
+ generateCapabilityValidationFeedback(claimedCapability, effectiveCapability, actualCapability, status, score, domainValidation) {
6585
+ let feedback = `Capability Validation: ${claimedCapability.toUpperCase()} claim is ${status} (${Math.round(score)}% confidence)\n\n`;
6586
+ // Analysis summary
6587
+ feedback += `ANALYSIS:\n`;
6588
+ feedback += `• Claimed: ${claimedCapability.toUpperCase()}\n`;
6589
+ if (effectiveCapability !== claimedCapability) {
6590
+ feedback += `• Domain Adjusted: ${effectiveCapability.toUpperCase()} (${domainValidation.reasoning})\n`;
6591
+ }
6592
+ feedback += `• Detected: ${actualCapability.toUpperCase()}\n`;
6593
+ feedback += `• Tool Type: ${domainValidation.detected_tool_type}\n\n`;
6594
+ // Assessment
6595
+ feedback += `ASSESSMENT: `;
6596
+ if (claimedCapability.toLowerCase() === actualCapability) {
6597
+ feedback += 'Claimed capability aligns perfectly with tool analysis.';
6598
+ }
6599
+ else if (effectiveCapability.toLowerCase() === actualCapability) {
6600
+ feedback += 'After domain validation adjustment, capability aligns with tool analysis.';
6601
+ }
6602
+ else {
6603
+ feedback += `Capability mismatch detected. Tool functions as ${actualCapability.toUpperCase()} rather than claimed ${claimedCapability.toUpperCase()}.`;
6604
+ }
6605
+ return feedback;
6606
+ }
6502
6607
  generateValidationFeedback(claimedCapability, status, gaps, strengths, score) {
6503
- let feedback = `Validation of ${claimedCapability.toUpperCase()} capability claim: ${status} (${Math.round(score)}% alignment)\n\n`;
6608
+ let feedback = `Validation of ${claimedCapability.toUpperCase()} capability role claim: ${status} (${Math.round(score)}% alignment)\n\n`;
6504
6609
  if (strengths.length > 0) {
6505
6610
  feedback += `STRENGTHS:\n${strengths.map(s => `• ${s}`).join('\n')}\n\n`;
6506
6611
  }
@@ -6510,21 +6615,122 @@ export class GRCAnalysisServer {
6510
6615
  feedback += `ASSESSMENT: `;
6511
6616
  switch (status) {
6512
6617
  case 'SUPPORTED':
6513
- feedback += 'The vendor\'s supporting evidence strongly aligns with their claimed capability.';
6618
+ feedback += 'The vendor\'s supporting evidence strongly aligns with their claimed capability role.';
6514
6619
  break;
6515
6620
  case 'QUESTIONABLE':
6516
6621
  feedback += 'The vendor\'s evidence partially supports their claim but has notable gaps or inconsistencies.';
6517
6622
  break;
6518
6623
  case 'UNSUPPORTED':
6519
- feedback += 'The vendor\'s evidence does not adequately support their claimed capability.';
6624
+ feedback += 'The vendor\'s evidence does not adequately support their claimed capability role.';
6520
6625
  break;
6521
6626
  }
6522
6627
  return feedback;
6523
6628
  }
6629
+ // Enhanced error handling and formatting
6630
+ formatErrorMessage(error, toolName) {
6631
+ if (error instanceof Error) {
6632
+ // Production-friendly error messages
6633
+ switch (error.message) {
6634
+ case /^Safeguard .+ not found/.test(error.message) ? error.message : '':
6635
+ return `❌ Invalid safeguard ID. Use 'list_available_safeguards' to see available CIS Control safeguards.`;
6636
+ case /^Unknown tool/.test(error.message) ? error.message : '':
6637
+ return `❌ Tool '${toolName}' is not available. Available tools: analyze_vendor_response, validate_vendor_mapping, validate_coverage_claim, get_safeguard_details, list_available_safeguards.`;
6638
+ default:
6639
+ return `❌ Error in ${toolName}: ${error.message}`;
6640
+ }
6641
+ }
6642
+ return `❌ Unexpected error in ${toolName}: ${String(error)}`;
6643
+ }
6644
+ getCachedSafeguardDetails(safeguardId, includeExamples) {
6645
+ const cacheKey = `${safeguardId}_${includeExamples}`;
6646
+ const cached = this.cache.safeguardDetails.get(cacheKey);
6647
+ if (cached && (Date.now() - cached.timestamp < 5 * 60 * 1000)) { // 5 minute cache
6648
+ return cached.data;
6649
+ }
6650
+ return null;
6651
+ }
6652
+ setCachedSafeguardDetails(safeguardId, includeExamples, data) {
6653
+ const cacheKey = `${safeguardId}_${includeExamples}`;
6654
+ this.cache.safeguardDetails.set(cacheKey, {
6655
+ data,
6656
+ timestamp: Date.now()
6657
+ });
6658
+ // Periodic cache cleanup to prevent memory leaks
6659
+ if (Date.now() - this.cache.lastCacheCleanup > 10 * 60 * 1000) { // 10 minutes
6660
+ this.cleanupCache();
6661
+ }
6662
+ }
6663
+ cleanupCache() {
6664
+ const now = Date.now();
6665
+ const maxAge = 10 * 60 * 1000; // 10 minutes
6666
+ // Clean up safeguard details cache
6667
+ for (const [key, value] of this.cache.safeguardDetails.entries()) {
6668
+ if (now - value.timestamp > maxAge) {
6669
+ this.cache.safeguardDetails.delete(key);
6670
+ }
6671
+ }
6672
+ this.cache.lastCacheCleanup = now;
6673
+ }
6674
+ recordToolExecution(toolName, executionTime) {
6675
+ this.performanceMetrics.totalRequests++;
6676
+ if (!this.performanceMetrics.toolExecutionTimes.has(toolName)) {
6677
+ this.performanceMetrics.toolExecutionTimes.set(toolName, []);
6678
+ }
6679
+ const times = this.performanceMetrics.toolExecutionTimes.get(toolName);
6680
+ times.push(executionTime);
6681
+ // Keep only last 100 measurements for memory efficiency
6682
+ if (times.length > 100) {
6683
+ times.shift();
6684
+ }
6685
+ }
6686
+ getPerformanceStats() {
6687
+ const uptime = Date.now() - this.performanceMetrics.startTime;
6688
+ const avgTimes = Array.from(this.performanceMetrics.toolExecutionTimes.entries())
6689
+ .map(([tool, times]) => {
6690
+ const avg = times.reduce((a, b) => a + b, 0) / times.length;
6691
+ return `${tool}: ${avg.toFixed(2)}ms`;
6692
+ });
6693
+ return `Performance Stats (Uptime: ${(uptime / 1000).toFixed(1)}s, Requests: ${this.performanceMetrics.totalRequests}, Errors: ${this.performanceMetrics.errorCount})\n${avgTimes.join(', ')}`;
6694
+ }
6695
+ // Input validation and sanitization
6696
+ validateSafeguardId(safeguardId) {
6697
+ if (!safeguardId || typeof safeguardId !== 'string') {
6698
+ throw new Error('Safeguard ID is required and must be a string');
6699
+ }
6700
+ if (!/^[0-9]+\.[0-9]+$/.test(safeguardId)) {
6701
+ throw new Error('Safeguard ID must be in format "X.Y" (e.g., "1.1", "5.1")');
6702
+ }
6703
+ if (!CIS_SAFEGUARDS[safeguardId]) {
6704
+ throw new Error(`Safeguard ${safeguardId} not found`);
6705
+ }
6706
+ }
6707
+ validateTextInput(text, fieldName) {
6708
+ if (!text || typeof text !== 'string') {
6709
+ throw new Error(`${fieldName} is required and must be a string`);
6710
+ }
6711
+ if (text.length > 10000) {
6712
+ throw new Error(`${fieldName} must be less than 10,000 characters`);
6713
+ }
6714
+ if (text.trim().length < 10) {
6715
+ throw new Error(`${fieldName} must contain at least 10 meaningful characters`);
6716
+ }
6717
+ }
6718
+ validateCapability(capability) {
6719
+ const validCapabilities = ['full', 'partial', 'facilitates', 'governance', 'validates'];
6720
+ if (!validCapabilities.includes(capability.toLowerCase())) {
6721
+ throw new Error(`Invalid capability. Must be one of: ${validCapabilities.join(', ')}`);
6722
+ }
6723
+ }
6524
6724
  async run() {
6525
6725
  const transport = new StdioServerTransport();
6526
6726
  await this.server.connect(transport);
6527
6727
  console.error('FrameworkMCP server running on stdio');
6728
+ // Log performance stats every 5 minutes in production
6729
+ if (process.env.NODE_ENV === 'production') {
6730
+ setInterval(() => {
6731
+ console.error(`[FrameworkMCP] ${this.getPerformanceStats()}`);
6732
+ }, 5 * 60 * 1000);
6733
+ }
6528
6734
  }
6529
6735
  }
6530
6736
  const server = new GRCAnalysisServer();