stellar-cyber-mcp-agents
Version:
Model Context Protocol (MCP) server for Stellar Cyber security operations with specialized multi-agent analysis capabilities
479 lines • 18.8 kB
JavaScript
import { EventEmitter } from 'events';
import { AgentType } from '../types/agent.js';
export class IntelligenceSharingService extends EventEmitter {
intelligenceStore = new Map();
subscriptions = new Map();
collaborationRequests = new Map();
agentCapabilities = new Map();
cleanupInterval;
constructor() {
super();
// Initialize agent capabilities
this.initializeCapabilities();
// Start cleanup interval for expired intelligence
this.cleanupInterval = setInterval(() => {
this.cleanupExpiredIntelligence();
}, 60000); // Check every minute
}
initializeCapabilities() {
this.agentCapabilities.set(AgentType.INVESTIGATION, [
'case-analysis', 'evidence-collection', 'timeline-reconstruction'
]);
this.agentCapabilities.set(AgentType.CORRELATION, [
'pattern-matching', 'cross-case-analysis', 'similarity-scoring'
]);
this.agentCapabilities.set(AgentType.NETWORK_ANALYSIS, [
'traffic-analysis', 'connection-mapping', 'protocol-analysis'
]);
this.agentCapabilities.set(AgentType.MALWARE_ANALYSIS, [
'static-analysis', 'dynamic-analysis', 'signature-generation'
]);
this.agentCapabilities.set(AgentType.CREDENTIAL_ANALYSIS, [
'credential-validation', 'breach-checking', 'password-analysis'
]);
this.agentCapabilities.set(AgentType.CAMPAIGN_DETECTION, [
'clustering', 'ttp-analysis', 'infrastructure-mapping'
]);
this.agentCapabilities.set(AgentType.WORKFLOW, [
'orchestration', 'task-coordination', 'dependency-management'
]);
}
shareIntelligence(item) {
// Validate intelligence item
this.validateIntelligenceItem(item);
// Store intelligence
this.intelligenceStore.set(item.id, item);
// Notify subscribers
this.notifySubscribers(item);
// Emit intelligence shared event
this.emit('intelligence:shared', {
itemId: item.id,
source: item.source,
type: item.type,
confidence: item.confidence
});
}
validateIntelligenceItem(item) {
if (!item.id || !item.type || !item.source || !item.data) {
throw new Error('Invalid intelligence item: missing required fields');
}
if (item.confidence < 0 || item.confidence > 1) {
throw new Error('Invalid confidence value: must be between 0 and 1');
}
}
queryIntelligence(query) {
const results = [];
const now = Date.now();
for (const item of this.intelligenceStore.values()) {
// Check if item is expired
if (!query.includeExpired && item.ttl &&
(new Date(item.timestamp).getTime() + item.ttl) < now) {
continue;
}
// Apply filters
if (query.types && !query.types.includes(item.type))
continue;
if (query.minConfidence && item.confidence < query.minConfidence)
continue;
if (query.sources && !query.sources.some(s => this.agentIdsEqual(s, item.source)))
continue;
if (query.tags && query.tags.length > 0) {
const hasMatchingTag = query.tags.some(tag => item.tags.includes(tag));
if (!hasMatchingTag)
continue;
}
if (query.timeRange) {
const itemTime = new Date(item.timestamp).getTime();
const startTime = new Date(query.timeRange.start).getTime();
const endTime = new Date(query.timeRange.end).getTime();
if (itemTime < startTime || itemTime > endTime)
continue;
}
results.push(item);
}
// Sort by timestamp (newest first) and confidence
results.sort((a, b) => {
const timeA = new Date(a.timestamp).getTime();
const timeB = new Date(b.timestamp).getTime();
if (timeB !== timeA)
return timeB - timeA;
return b.confidence - a.confidence;
});
// Apply limit
if (query.limit) {
return results.slice(0, query.limit);
}
return results;
}
subscribe(agentId, query, callback) {
const subscriptionId = crypto.randomUUID();
const subscription = {
id: subscriptionId,
agentId,
query,
callback,
active: true,
created: new Date().toISOString()
};
this.subscriptions.set(subscriptionId, subscription);
// Send initial results
const initialResults = this.queryIntelligence(query);
if (initialResults.length > 0) {
callback(initialResults);
}
this.emit('subscription:created', {
subscriptionId,
agentId,
query
});
return subscriptionId;
}
unsubscribe(subscriptionId) {
const subscription = this.subscriptions.get(subscriptionId);
if (!subscription)
return false;
subscription.active = false;
this.subscriptions.delete(subscriptionId);
this.emit('subscription:cancelled', {
subscriptionId,
agentId: subscription.agentId
});
return true;
}
notifySubscribers(item) {
for (const subscription of this.subscriptions.values()) {
if (!subscription.active)
continue;
// Check if item matches subscription query
const matchingItems = this.queryIntelligence({
...subscription.query,
limit: 1
}).filter(i => i.id === item.id);
if (matchingItems.length > 0) {
try {
subscription.callback([item]);
}
catch (error) {
console.error(`Subscription callback failed for ${subscription.id}:`, error);
}
}
}
}
async requestCollaboration(request) {
request.id = request.id || crypto.randomUUID();
this.collaborationRequests.set(request.id, request);
// Find agents capable of handling this request
const capableAgents = this.findCapableAgents(request);
// Emit collaboration request to capable agents
this.emit('collaboration:request', {
requestId: request.id,
type: request.type,
targetAgents: capableAgents,
parameters: request.parameters,
priority: request.priority
});
// Set timeout for the request
setTimeout(() => {
const activeRequest = this.collaborationRequests.get(request.id);
if (activeRequest) {
this.emit('collaboration:timeout', {
requestId: request.id,
requestingAgent: request.requestingAgent
});
this.collaborationRequests.delete(request.id);
}
}, request.timeout);
return request.id;
}
findCapableAgents(request) {
const capableAgents = [];
for (const agentType of request.targetAgents) {
const capabilities = this.agentCapabilities.get(agentType);
if (capabilities && this.hasRequiredCapability(request, capabilities)) {
capableAgents.push(agentType);
}
}
return capableAgents;
}
hasRequiredCapability(request, capabilities) {
// Simple capability matching - in a real system this would be more sophisticated
switch (request.type) {
case 'analysis':
return capabilities.some(cap => cap.includes('analysis'));
case 'correlation':
return capabilities.includes('pattern-matching') || capabilities.includes('cross-case-analysis');
case 'validation':
return capabilities.includes('validation') || capabilities.includes('verification');
case 'enhancement':
return true; // Most agents can enhance data
default:
return false;
}
}
submitCollaborationResult(result) {
const request = this.collaborationRequests.get(result.requestId);
if (!request) {
console.warn(`Collaboration result submitted for unknown request: ${result.requestId}`);
return;
}
// Emit result
this.emit('collaboration:result', result);
// Call callback if provided
if (request.callback) {
try {
request.callback([result]);
}
catch (error) {
console.error(`Collaboration callback failed for ${result.requestId}:`, error);
}
}
// Store result as intelligence if appropriate
if (result.status === 'COMPLETED' && result.confidence > 0.5) {
const intelligenceItem = {
id: crypto.randomUUID(),
type: 'correlation',
source: result.respondingAgent,
timestamp: result.timestamp,
confidence: result.confidence,
data: result.data,
tags: ['collaboration', request.type],
priority: request.priority,
metadata: {
analysisId: result.requestId,
version: '1.0',
format: 'collaboration-result'
}
};
this.shareIntelligence(intelligenceItem);
}
}
enhanceIntelligence(itemId, enhancement) {
const item = this.intelligenceStore.get(itemId);
if (!item)
return false;
// Create enhanced version
const enhancedItem = {
...item,
...enhancement,
id: crypto.randomUUID(), // New ID for enhanced version
timestamp: new Date().toISOString(),
metadata: {
...item.metadata,
version: this.incrementVersion(item.metadata.version)
}
};
this.shareIntelligence(enhancedItem);
this.emit('intelligence:enhanced', {
originalId: itemId,
enhancedId: enhancedItem.id,
enhancementSource: enhancement.source
});
return true;
}
incrementVersion(version) {
const parts = version.split('.');
const major = parseInt(parts[0]) || 1;
const minor = parseInt(parts[1]) || 0;
const patch = parseInt(parts[2]) || 0;
return `${major}.${minor}.${patch + 1}`;
}
correlateIntelligence(items) {
const correlations = [];
// Group items by type and analyze patterns
const groupedItems = this.groupItemsByType(items);
for (const [type, typeItems] of groupedItems.entries()) {
if (typeItems.length < 2)
continue;
// Find correlations within the same type
const typeCorrelations = this.findTypeCorrelations(type, typeItems);
correlations.push(...typeCorrelations);
}
// Cross-type correlations
const crossTypeCorrelations = this.findCrossTypeCorrelations(groupedItems);
correlations.push(...crossTypeCorrelations);
return correlations;
}
groupItemsByType(items) {
const groups = new Map();
for (const item of items) {
const group = groups.get(item.type) || [];
group.push(item);
groups.set(item.type, group);
}
return groups;
}
findTypeCorrelations(type, items) {
const correlations = [];
// Simple pattern detection - look for similar data values
const valueMap = new Map();
for (const item of items) {
const key = this.extractCorrelationKey(item);
if (key) {
const group = valueMap.get(key) || [];
group.push(item);
valueMap.set(key, group);
}
}
// Create correlation items for groups with multiple items
for (const [key, groupItems] of valueMap.entries()) {
if (groupItems.length > 1) {
const correlation = {
id: crypto.randomUUID(),
type: 'correlation',
source: { type: AgentType.HUB, instance: 'intelligence-service', uuid: crypto.randomUUID() },
timestamp: new Date().toISOString(),
confidence: Math.min(...groupItems.map(i => i.confidence)),
data: {
correlationType: 'value-match',
correlationKey: key,
relatedItems: groupItems.map(i => i.id),
pattern: `Multiple ${type} items with matching ${key}`
},
tags: ['auto-correlation', type],
priority: this.determineCorrelationPriority(groupItems),
metadata: {
version: '1.0',
format: 'auto-correlation'
}
};
correlations.push(correlation);
}
}
return correlations;
}
extractCorrelationKey(item) {
// Extract a key that can be used for correlation
if (typeof item.data === 'object' && item.data !== null) {
return JSON.stringify(item.data).substring(0, 100); // First 100 chars as key
}
if (typeof item.data === 'string') {
return item.data;
}
return null;
}
findCrossTypeCorrelations(groups) {
const correlations = [];
// Look for temporal correlations
const allItems = Array.from(groups.values()).flat();
const temporalCorrelations = this.findTemporalCorrelations(allItems);
correlations.push(...temporalCorrelations);
return correlations;
}
findTemporalCorrelations(items) {
const correlations = [];
const timeWindow = 300000; // 5 minutes
// Sort items by timestamp
const sortedItems = items.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
// Find items within time windows
for (let i = 0; i < sortedItems.length - 1; i++) {
const currentTime = new Date(sortedItems[i].timestamp).getTime();
const cluster = [sortedItems[i]];
for (let j = i + 1; j < sortedItems.length; j++) {
const nextTime = new Date(sortedItems[j].timestamp).getTime();
if (nextTime - currentTime <= timeWindow) {
cluster.push(sortedItems[j]);
}
else {
break;
}
}
if (cluster.length > 1) {
const correlation = {
id: crypto.randomUUID(),
type: 'correlation',
source: { type: AgentType.HUB, instance: 'intelligence-service', uuid: crypto.randomUUID() },
timestamp: new Date().toISOString(),
confidence: 0.6,
data: {
correlationType: 'temporal',
timeWindow: timeWindow,
relatedItems: cluster.map(i => i.id),
pattern: `${cluster.length} intelligence items within ${timeWindow}ms`
},
tags: ['temporal-correlation'],
priority: 'MEDIUM',
metadata: {
version: '1.0',
format: 'temporal-correlation'
}
};
correlations.push(correlation);
}
}
return correlations;
}
determineCorrelationPriority(items) {
const maxPriority = Math.max(...items.map(i => this.priorityToNumber(i.priority)));
return this.numberToPriority(maxPriority);
}
priorityToNumber(priority) {
switch (priority) {
case 'LOW': return 1;
case 'MEDIUM': return 2;
case 'HIGH': return 3;
case 'CRITICAL': return 4;
default: return 1;
}
}
numberToPriority(num) {
switch (num) {
case 4: return 'CRITICAL';
case 3: return 'HIGH';
case 2: return 'MEDIUM';
default: return 'LOW';
}
}
cleanupExpiredIntelligence() {
const now = Date.now();
const expired = [];
for (const [id, item] of this.intelligenceStore.entries()) {
if (item.ttl && (new Date(item.timestamp).getTime() + item.ttl) < now) {
expired.push(id);
}
}
for (const id of expired) {
this.intelligenceStore.delete(id);
}
if (expired.length > 0) {
this.emit('intelligence:cleanup', {
expiredCount: expired.length,
remainingCount: this.intelligenceStore.size
});
}
}
agentIdsEqual(a, b) {
return a.type === b.type && a.instance === b.instance && a.uuid === b.uuid;
}
getStatistics() {
const stats = {
totalIntelligence: this.intelligenceStore.size,
activeSubscriptions: this.subscriptions.size,
activeCollaborations: this.collaborationRequests.size,
intelligenceByType: new Map(),
intelligenceByPriority: new Map(),
averageConfidence: 0
};
let totalConfidence = 0;
for (const item of this.intelligenceStore.values()) {
// Count by type
const typeCount = stats.intelligenceByType.get(item.type) || 0;
stats.intelligenceByType.set(item.type, typeCount + 1);
// Count by priority
const priorityCount = stats.intelligenceByPriority.get(item.priority) || 0;
stats.intelligenceByPriority.set(item.priority, priorityCount + 1);
totalConfidence += item.confidence;
}
if (this.intelligenceStore.size > 0) {
stats.averageConfidence = totalConfidence / this.intelligenceStore.size;
}
return stats;
}
destroy() {
clearInterval(this.cleanupInterval);
this.intelligenceStore.clear();
this.subscriptions.clear();
this.collaborationRequests.clear();
this.removeAllListeners();
}
}
//# sourceMappingURL=intelligence-sharing.js.map