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
JavaScript
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