UNPKG

mcp-cve-intelligence-server-lite-test

Version:

Lite Model Context Protocol server for comprehensive CVE intelligence gathering with multi-source exploit discovery, designed for security professionals and cybersecurity researchers - Alpha Release

431 lines (419 loc) 19.6 kB
#!/usr/bin/env node import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import process from 'node:process'; import { fileURLToPath } from 'node:url'; import { CVEService } from './services/cve-service.js'; import { SourceManager } from './services/source-manager.js'; import { HealthService } from './services/health-service.js'; import { TransportManager } from './transport/transport-manager.js'; import { getAppConfiguration } from './config/index.js'; import { createContextLogger, createPerformanceTimer } from './utils/logger.js'; import { SimpleCVESearchSchema, mapToFullSearchFilters, CVEReportSchema, CVEDetailSchema, TrendingCVEsSchema, CPESearchSchema, EPSSRequestSchema, AssessTechnologyStackSchema, ThreatHuntingCVEsSchema, BugBountyHuntingSchema, } from './types/cve.js'; import { transformCVESearchResultForDisplay, transformCVEForDisplay } from './utils/cve-utils.js'; const logger = createContextLogger('CVEIntelligenceServer'); export class CVEIntelligenceServer { cveService; sourceManager; healthService; transportManager; config; constructor() { // Load initial config - will be reloaded in initialize() to pick up CLI changes this.config = getAppConfiguration(); } /** * Compresses JSON response to minimize size while maintaining readability * @param data Data to stringify * @param compress Whether to compress (remove whitespace) or keep readable * @returns JSON string */ compressJsonResponse(data, compress) { // Use config value or environment variable fallback const shouldCompress = compress ?? this.config.transport.http.compressJson; if (shouldCompress) { // Remove all unnecessary whitespace return JSON.stringify(data); } // Keep readable format for debugging return JSON.stringify(data, null, 2); } async initialize() { if (this.isInitialized()) { logger.warn('Server already initialized'); return; } try { // Reload configuration to pick up any environment variables set by CLI this.config = getAppConfiguration(); // Create performance timer const timer = createPerformanceTimer('server_initialization'); // Initialize source manager this.sourceManager = new SourceManager(); // Initialize CVE service this.cveService = new CVEService(this.sourceManager); // Initialize health service this.healthService = new HealthService(this.sourceManager, this.config.server.version, process.env.NODE_ENV || 'development'); // Initialize transport manager with health service this.transportManager = new TransportManager(this.config, this.createMcpServer.bind(this), this.healthService); timer.end(); logger.info('Server initialization completed successfully'); } catch (error) { logger.error('Failed to initialize server:', error instanceof Error ? error : new Error(String(error))); throw error; } } getConfig() { return this.config; } isInitialized() { return !!(this.cveService && this.sourceManager && this.healthService && this.transportManager); } createMcpServer() { const server = new McpServer({ name: this.config.server.name, version: this.config.server.version, }, { capabilities: { tools: {}, prompts: {}, sampling: {}, }, }); // Define all CVE intelligence tools using modern registerTool API with simplified schemas server.registerTool('searchCves', { description: 'Search for CVEs using filters like keywords, vendors, severity levels, and date ranges. Returns results sorted by relevance. IMPORTANT: For recent/relevant results, always specify date ranges (e.g., last 2-3 years) when searching by keywords, vendors, or products - without date filters you may get very old CVEs that are less actionable. Use severity filters (CRITICAL, HIGH) to prioritize important vulnerabilities.', inputSchema: SimpleCVESearchSchema.shape, }, async ({ ...args }) => { const timer = createPerformanceTimer('search_cves'); try { // Map simplified API to full internal filters const fullFilters = mapToFullSearchFilters(args); const result = await this.cveService?.searchCVEs(fullFilters); // Transform the result to replace descriptions arrays with description strings const transformedResult = transformCVESearchResultForDisplay(result); timer.end({ resultCount: result?.totalResults }); return { content: [ { type: 'text', text: this.compressJsonResponse(transformedResult || {}), }, ], }; } catch (error) { timer.end({ error: true }); throw error; } }); server.registerTool('getCveDetails', { description: 'Get detailed information about a specific CVE including CVSS metrics, affected products, and references.', inputSchema: CVEDetailSchema.shape, }, async ({ ...args }) => { const timer = createPerformanceTimer('get_cve_details'); try { const { cveId } = args; const result = await this.cveService?.getCVEDetails(cveId); // Transform the result to replace descriptions array with description string const transformedResult = transformCVEForDisplay(result); timer.end(); return { content: [ { type: 'text', text: this.compressJsonResponse(transformedResult || {}), }, ], }; } catch (error) { timer.end({ error: true }); throw error; } }); server.registerTool('getTrendingCves', { description: 'Get currently trending CVEs based on severity, exploit availability, and recent activity.', inputSchema: TrendingCVEsSchema.shape, }, async ({ ...args }) => { const timer = createPerformanceTimer('get_trending_cves'); try { const { limit = 20 } = args; const result = await this.cveService?.getTrendingCVEs(limit); timer.end(); return { content: [ { type: 'text', text: this.compressJsonResponse(result || []), }, ], }; } catch (error) { timer.end({ error: true }); throw error; } }); server.registerTool('calculateEpssScores', { description: 'Calculate EPSS (Exploit Prediction Scoring System) scores for vulnerability prioritization with environmental context.', inputSchema: EPSSRequestSchema.shape, }, async ({ ...args }) => { const timer = createPerformanceTimer('calculate_epss_scores'); try { const result = await this.cveService?.calculateEPSSScores(args); timer.end(); return { content: [ { type: 'text', text: this.compressJsonResponse(result || {}), }, ], }; } catch (error) { timer.end({ error: true }); throw error; } }); server.registerTool('generateCveReport', { description: 'Generate a comprehensive penetration testing report for one or more CVEs.', inputSchema: CVEReportSchema.shape, }, async ({ ...args }) => { const timer = createPerformanceTimer('generate_cve_report'); try { const result = await this.cveService?.generateReport(args); timer.end(); return { content: [ { type: 'text', text: result || '', }, ], }; } catch (error) { timer.end({ error: true }); throw error; } }); server.registerTool('searchByCpe', { description: 'Search for CVEs affecting specific products using CPE (Common Platform Enumeration) identifiers.', inputSchema: CPESearchSchema.shape, }, async ({ ...args }) => { const timer = createPerformanceTimer('search_by_cpe'); try { const { cpe, ...filters } = args; const searchFilters = { cvssV3Severity: filters.severity, pubStartDate: filters.dateStart, pubEndDate: filters.dateEnd, resultsPerPage: filters.resultsPerPage, }; const result = await this.cveService?.searchByCPE(cpe, searchFilters); // Transform the result to replace descriptions arrays with description strings const transformedResult = transformCVESearchResultForDisplay(result); timer.end(); return { content: [ { type: 'text', text: this.compressJsonResponse(transformedResult || {}), }, ], }; } catch (error) { timer.end({ error: true }); throw error; } }); server.registerTool('getSourceHealth', { description: 'Check the health and status of all configured CVE data sources.', inputSchema: {}, }, async () => { const timer = createPerformanceTimer('get_source_health'); try { const result = await this.sourceManager?.getSourceHealth(); timer.end(); return { content: [ { type: 'text', text: this.compressJsonResponse(result || {}), }, ], }; } catch (error) { timer.end({ error: true }); throw error; } }); // Register CVE intelligence prompts for common security workflows server.registerPrompt('assess-technology-stack', { description: 'Assess vulnerabilities in a technology stack with prioritization', argsSchema: AssessTechnologyStackSchema.shape, }, async (args) => { const technologies = args.technologies; const environment = args.environment || 'production'; return { description: `Security assessment for ${technologies} in ${environment}`, messages: [ { role: 'user', content: { type: 'text', text: `Perform a comprehensive vulnerability assessment for the following technology stack: ${technologies} Please: 1. Search for recent CRITICAL and HIGH severity CVEs affecting these technologies 2. Prioritize vulnerabilities with available exploits 3. Calculate EPSS scores with environmental context for ${environment} environment 4. Generate a summary report with actionable recommendations Focus on vulnerabilities from the last 2 years that pose the highest risk.`, }, }, ], }; }); server.registerPrompt('threat-hunting-cves', { description: 'Hunt for specific CVE threats with exploit intelligence', argsSchema: ThreatHuntingCVEsSchema.shape, }, async (args) => { const cveId = args.cve_id; const threatType = args.threat_type || 'remote code execution'; const searchTarget = cveId || `recent ${threatType} vulnerabilities`; return { description: `Threat hunting analysis for ${searchTarget}`, messages: [ { role: 'user', content: { type: 'text', text: cveId ? `Conduct a detailed threat hunting analysis for ${cveId}: 1. Get comprehensive CVE details including CVSS metrics and affected products 2. Search for available exploits and proof-of-concept code 3. Calculate EPSS score with critical infrastructure context 4. Provide threat actor attribution and attack patterns if available 5. Generate actionable threat hunting indicators and detection strategies` : `Hunt for ${threatType} threats in the current threat landscape: 1. Search for recent ${threatType} CVEs (last 12 months) with CRITICAL/HIGH severity 2. Focus on vulnerabilities with public exploits or proof-of-concept code 3. Prioritize based on EPSS scores and exploit availability 4. Identify trending vulnerabilities that threat actors are actively exploiting 5. Provide threat hunting queries and detection recommendations`, }, }, ], }; }); server.registerPrompt('bug-bounty-hunting', { description: 'Hunt for exploitable vulnerabilities suitable for bug bounty programs', argsSchema: BugBountyHuntingSchema.shape, }, async (args) => { const targetTechnologies = args.target_technologies; const impactFocus = args.impact_focus || 'high impact vulnerabilities'; const disclosureWindow = args.disclosure_window || '180d'; const exploitPreference = args.exploit_preference || 'any'; // Convert disclosure window to readable format const windowMapping = { '90d': '90 days', '180d': '6 months', '1y': '1 year', '2y': '2 years' }; const readableWindow = windowMapping[disclosureWindow] || disclosureWindow; return { description: `Bug bounty hunting analysis for ${targetTechnologies}`, messages: [ { role: 'user', content: { type: 'text', text: `Conduct a comprehensive bug bounty hunting analysis for: ${targetTechnologies} **Target Focus:** ${impactFocus} **Disclosure Window:** Recent vulnerabilities from the last ${readableWindow} **Exploit Preference:** ${exploitPreference} Please perform the following analysis: 1. **Vulnerability Discovery:** - Search for recent CVEs affecting ${targetTechnologies} within the last ${readableWindow} - Focus on ${impactFocus} vulnerabilities with CVSS scores of 7.0+ - Prioritize vulnerabilities suitable for web applications and external-facing services 2. **Exploitability Assessment:** ${exploitPreference === 'with-exploits' ? '- Only include CVEs with available proof-of-concept or working exploits' : exploitPreference === 'no-exploits' ? '- Focus on CVEs without public exploits (higher chance of being unpatched)' : '- Include both exploited and unexploited vulnerabilities'} - Calculate EPSS scores to prioritize exploitation likelihood - Identify authentication bypass, privilege escalation, and RCE vulnerabilities 3. **Bug Bounty Intelligence:** - Assess impact potential and likely bounty value tier - Identify CVEs affecting popular software likely to be in scope - Look for vulnerabilities in components commonly found in bug bounty targets - Focus on web application frameworks, content management systems, and API technologies 4. **Research Strategy:** - Provide specific search patterns for finding affected targets - Suggest methodology for confirming vulnerability presence - Recommend responsible disclosure timeline and approach - Identify potential variant hunting opportunities 5. **Actionable Deliverables:** - Generate a prioritized target list with impact assessment - Provide reconnaissance suggestions for finding vulnerable instances - Include references to technical analysis and exploitation resources **Note:** Ensure all research follows responsible disclosure practices and bug bounty program guidelines.`, }, }, ], }; }); return server; } async run(transportType) { const type = transportType || this.config.transport.type; try { // Use the full transport config from our centralized configuration const transportConfig = this.config.transport; await this.transportManager?.startTransport(transportConfig); if (type === 'stdio') { logger.info('CVE Intelligence MCP Server running via stdio'); } else { const host = this.config.transport.http?.host; const port = this.config.transport.http?.port; logger.info(`CVE Intelligence MCP Server running on HTTP at http://${host}:${port}`); logger.info(` POST http://${host}:${port}/mcp - MCP requests`); logger.info(` GET http://${host}:${port}/health - Health check`); } } catch (error) { logger.error('Failed to start transport:', error instanceof Error ? error : new Error(String(error))); throw error; } } async shutdown() { try { await this.transportManager?.stopTransports(); logger.info('Server shutdown completed'); } catch (error) { logger.error('Error during shutdown:', error instanceof Error ? error : new Error(String(error))); throw error; } } } // Main execution when run directly or via NPX // More robust detection that handles symlinks (global npm installs) and NPX const __filename = fileURLToPath(import.meta.url); const isMainModule = process.argv[1] === __filename || process.argv[1].endsWith('mcp-cve-intelligence-server-lite') || import.meta.url === `file://${process.argv[1]}`; if (isMainModule) { const { CLIService } = await import('./services/cli-service.js'); const cliService = new CLIService(); cliService.parse(); } //# sourceMappingURL=index.js.map