stellar-cyber-mcp-agents
Version:
Model Context Protocol (MCP) server for Stellar Cyber security operations with specialized multi-agent analysis capabilities
1,116 lines • 61 kB
JavaScript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
// Set environment flag to disable background timers FIRST
process.env.MCP_MODE = 'true';
// Keep console.error for debugging, suppress others
const originalConsole = global.console;
global.console = {
...originalConsole,
log: () => { },
info: () => { },
warn: () => { },
error: originalConsole.error, // Keep error logging for debugging
debug: () => { },
};
// Global orchestrator instance - initialize once and reuse
let globalOrchestrator = null;
let orchestratorInitialized = false;
async function getOrchestrator() {
// Only try to initialize once
if (orchestratorInitialized && !globalOrchestrator) {
throw new Error('Orchestrator initialization failed previously');
}
if (!globalOrchestrator && !orchestratorInitialized) {
orchestratorInitialized = true;
try {
console.error('Lazy loading orchestrator for first tool call...');
// Check if we have required environment variables
if (!process.env.STELLAR_API_URL || !process.env.STELLAR_API_TOKEN) {
throw new Error('Missing required environment variables: STELLAR_API_URL or STELLAR_API_TOKEN');
}
console.error('Importing orchestrator module...');
const orchestratorModule = await import('./orchestrator.js');
console.error('Orchestrator module imported successfully');
const { MultiAgentOrchestrator, createDefaultConfig } = orchestratorModule;
const config = createDefaultConfig();
config.stellar.apiUrl = process.env.STELLAR_API_URL;
config.stellar.apiToken = process.env.STELLAR_API_TOKEN;
// Disable all logging to prevent EPIPE errors
config.logging.enableConsole = false;
config.logging.enableFile = false;
// Disable background timers/intervals to prevent EPIPE errors
config.agents.correlation.config.enableCampaignDetection = false;
console.error('Creating orchestrator instance...');
globalOrchestrator = new MultiAgentOrchestrator(config);
// Add error handlers to prevent crashes
if (globalOrchestrator.on) {
globalOrchestrator.on('error', (error) => {
console.error('Orchestrator runtime error:', error);
// Don't crash the server on orchestrator errors
});
}
console.error('Starting orchestrator...');
await globalOrchestrator.start();
console.error('Orchestrator initialized and started successfully');
}
catch (error) {
console.error('Failed to initialize orchestrator:', error);
orchestratorInitialized = false;
globalOrchestrator = null;
// Don't throw - let the tool call handle the error gracefully
throw new Error(`Orchestrator initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
if (!globalOrchestrator) {
throw new Error('Orchestrator not available');
}
return globalOrchestrator;
}
// Helper function to wrap orchestrator calls
async function executeOrchestratorMethod(methodName, ...args) {
try {
const orchestrator = await getOrchestrator();
// Add timeout to prevent hanging operations
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Operation timed out after 60 seconds')), 60000);
});
const operationPromise = orchestrator[methodName](...args);
const result = await Promise.race([operationPromise, timeoutPromise]);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
// Log error to stderr for debugging
console.error(`Orchestrator method ${methodName} failed:`, error);
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: error instanceof Error ? error.message : 'Unknown error',
tool: methodName,
status: 'error'
}, null, 2),
},
],
};
}
}
// Create the MCP server
const server = new Server({
name: 'stellar-cyber-agents',
version: '1.0.0',
}, {
capabilities: {
tools: {},
},
});
// Add server event handlers for debugging
server.onerror = (error) => {
console.error('MCP Server error:', error);
};
// Log when server receives messages
const originalSetRequestHandler = server.setRequestHandler;
server.setRequestHandler = function (schema, handler) {
return originalSetRequestHandler.call(this, schema, async (request, extra) => {
console.error(`Received request: ${request.method || 'unknown'}`);
try {
const result = await handler(request, extra);
console.error(`Request ${request.method || 'unknown'} completed successfully`);
return result;
}
catch (error) {
console.error(`Request ${request.method || 'unknown'} failed:`, error);
throw error;
}
});
};
// Define available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'test_connection',
description: 'Test connection to Stellar Cyber API',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'investigate_case',
description: 'Investigate a Stellar Cyber case by case ID',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to investigate',
},
options: {
type: 'object',
description: 'Investigation options',
properties: {},
},
},
required: ['caseId'],
},
},
{
name: 'correlate_case',
description: 'Find cases related to a given case ID',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to correlate',
},
method: {
type: 'string',
description: 'Correlation method (e.g., observables, timeline)',
default: 'observables',
},
},
required: ['caseId'],
},
},
{
name: 'analyze_network',
description: 'Analyze network activity for a case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to analyze',
},
timeRange: {
type: 'object',
properties: {
start: {
type: 'string',
description: 'Start time (ISO format)',
},
end: {
type: 'string',
description: 'End time (ISO format)',
},
},
required: ['start', 'end'],
},
options: {
type: 'object',
description: 'Analysis options',
properties: {},
},
},
required: ['caseId', 'timeRange'],
},
},
{
name: 'execute_workflow',
description: 'Execute a security workflow',
inputSchema: {
type: 'object',
properties: {
workflowId: {
type: 'string',
description: 'The workflow ID to execute',
},
input: {
type: 'object',
description: 'Input data for the workflow',
properties: {},
},
},
required: ['workflowId', 'input'],
},
},
{
name: 'get_system_status',
description: 'Get the status of the multi-agent system',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'get_agent_metrics',
description: 'Get performance metrics for all agents',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'search_cases',
description: 'List and filter Stellar Cyber cases. Returns cases sorted by creation date with optional client-side filtering.',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Optional search text to filter cases by name, description, severity, or status. Applied as client-side filter.',
},
filters: {
type: 'object',
description: 'Optional filters to narrow results',
properties: {
severity: {
type: 'string',
description: 'Filter by case severity (e.g., high, medium, low)',
},
status: {
type: 'string',
description: 'Filter by case status (e.g., open, closed, in_progress)',
},
assignee: {
type: 'string',
description: 'Filter by assigned user name or email',
},
limit: {
type: 'number',
description: 'Maximum number of cases to retrieve from API (default: 20, max: 20)',
},
sort: {
type: 'string',
description: 'Sort order: -created_at (newest first) or created_at (oldest first). Default: -created_at',
},
},
},
},
required: [],
},
},
{
name: 'get_case_activities',
description: 'Get activities/actions performed on a specific case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to get activities for',
},
},
required: ['caseId'],
},
},
{
name: 'get_case_observables',
description: 'Get observables/IOCs associated with a specific case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to get observables for',
},
},
required: ['caseId'],
},
},
{
name: 'get_case_alerts',
description: 'Get security alerts associated with a specific case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to get alerts for',
},
},
required: ['caseId'],
},
},
{
name: 'get_case_comments',
description: 'Get comments/notes for a specific case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to get comments for',
},
},
required: ['caseId'],
},
},
{
name: 'get_case_detailed_summary',
description: 'Get detailed summary and metadata for a specific case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to get detailed summary for',
},
},
required: ['caseId'],
},
},
{
name: 'get_case_scores',
description: 'Get risk scores and assessments for a specific case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to get scores for',
},
},
required: ['caseId'],
},
},
{
name: 'analyze_case_observables',
description: 'Analyze case observables/IOCs and get recommendations',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to analyze observables for',
},
},
required: ['caseId'],
},
},
{
name: 'get_case_timeline',
description: 'Get chronological timeline of case events',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to get timeline for',
},
},
required: ['caseId'],
},
},
{
name: 'get_case_artifacts',
description: 'Get artifacts/files associated with a case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to get artifacts for',
},
},
required: ['caseId'],
},
},
{
name: 'suggest_workflow',
description: 'Get workflow recommendations based on case characteristics',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to suggest workflow for',
},
},
required: ['caseId'],
},
},
{
name: 'update_case_status',
description: 'Update the status of a case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to update',
},
status: {
type: 'string',
description: 'New case status (e.g., open, closed, in_progress)',
},
comment: {
type: 'string',
description: 'Optional comment explaining the status change',
},
},
required: ['caseId', 'status'],
},
},
{
name: 'add_case_comment',
description: 'Add a comment/note to a case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to add comment to',
},
comment: {
type: 'string',
description: 'Comment text to add',
},
},
required: ['caseId', 'comment'],
},
},
{
name: 'get_related_cases',
description: 'Find cases related to a given case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to find related cases for',
},
method: {
type: 'string',
description: 'Correlation method to use (observables, temporal, behavioral)',
default: 'observables',
},
},
required: ['caseId'],
},
},
{
name: 'get_threat_intelligence',
description: 'Get threat intelligence information for a case',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to get threat intel for',
},
},
required: ['caseId'],
},
},
{
name: 'detect_campaigns',
description: 'Detect threat campaigns across multiple cases',
inputSchema: {
type: 'object',
properties: {
criteria: {
type: 'object',
description: 'Criteria for campaign detection',
properties: {
timeRange: {
type: 'object',
properties: {
start: {
type: 'string',
description: 'Start time (ISO format)',
},
end: {
type: 'string',
description: 'End time (ISO format)',
},
},
},
minCases: {
type: 'number',
description: 'Minimum number of cases for a campaign',
default: 3,
},
similarity: {
type: 'number',
description: 'Minimum similarity score (0-1)',
default: 0.7,
},
},
},
},
required: [],
},
},
{
name: 'analyze_case_similarity',
description: 'Analyze similarity between two cases',
inputSchema: {
type: 'object',
properties: {
caseId1: {
type: 'string',
description: 'First case ID to compare',
},
caseId2: {
type: 'string',
description: 'Second case ID to compare',
},
},
required: ['caseId1', 'caseId2'],
},
},
{
name: 'detect_lateral_movement',
description: 'Detect lateral movement patterns in network activity',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to analyze',
},
timeRange: {
type: 'object',
properties: {
start: {
type: 'string',
description: 'Start time (ISO format)',
},
end: {
type: 'string',
description: 'End time (ISO format)',
},
},
required: ['start', 'end'],
},
},
required: ['caseId', 'timeRange'],
},
},
{
name: 'detect_c2_communication',
description: 'Detect command and control communication patterns',
inputSchema: {
type: 'object',
properties: {
caseId: {
type: 'string',
description: 'The case ID to analyze',
},
timeRange: {
type: 'object',
properties: {
start: {
type: 'string',
description: 'Start time (ISO format)',
},
end: {
type: 'string',
description: 'End time (ISO format)',
},
},
required: ['start', 'end'],
},
},
required: ['caseId', 'timeRange'],
},
},
{
name: 'hunt_network_threats',
description: 'Hunt for network threats based on query criteria',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'object',
description: 'Threat hunting query parameters',
properties: {
indicators: {
type: 'array',
items: {
type: 'string',
},
description: 'IOCs or indicators to hunt for',
},
patterns: {
type: 'array',
items: {
type: 'string',
},
description: 'Network patterns to detect',
},
protocols: {
type: 'array',
items: {
type: 'string',
},
description: 'Network protocols to analyze',
},
},
},
timeRange: {
type: 'object',
properties: {
start: {
type: 'string',
description: 'Start time (ISO format)',
},
end: {
type: 'string',
description: 'End time (ISO format)',
},
},
required: ['start', 'end'],
},
},
required: ['query', 'timeRange'],
},
},
{
name: 'get_workflow_status',
description: 'Get the status of a running workflow',
inputSchema: {
type: 'object',
properties: {
workflowId: {
type: 'string',
description: 'The workflow execution ID',
},
},
required: ['workflowId'],
},
},
{
name: 'cancel_workflow',
description: 'Cancel a running workflow',
inputSchema: {
type: 'object',
properties: {
workflowId: {
type: 'string',
description: 'The workflow execution ID to cancel',
},
},
required: ['workflowId'],
},
},
],
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'test_connection': {
const apiUrl = process.env.STELLAR_API_URL;
const apiToken = process.env.STELLAR_API_TOKEN;
if (!apiUrl || !apiToken) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
status: 'error',
message: 'Missing environment variables',
details: {
STELLAR_API_URL: apiUrl ? 'Set' : 'Missing',
STELLAR_API_TOKEN: apiToken ? 'Set' : 'Missing'
}
}, null, 2),
},
],
};
}
// Test Stellar Cyber token refresh flow
try {
// Step 1: Try to get an access token using the provided token (which should be a refresh token)
const tokenResponse = await fetch(`${apiUrl}/connect/api/v1/access_token`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiToken}`,
'Content-Type': 'application/json'
}
});
const tokenResult = {
status: tokenResponse.status,
statusText: tokenResponse.statusText,
ok: tokenResponse.ok
};
if (!tokenResponse.ok) {
const errorText = await tokenResponse.text();
return {
content: [
{
type: 'text',
text: JSON.stringify({
status: 'error',
message: 'Token refresh failed',
details: {
url: `${apiUrl}/connect/api/v1/access_token`,
response: tokenResult,
errorBody: errorText,
tokenLength: apiToken.length,
suggestion: 'Check if the STELLAR_API_TOKEN is a valid refresh token, not an access token'
}
}, null, 2),
},
],
};
}
const tokenData = await tokenResponse.json();
// Step 2: Test using the new access token
let apiTestResult = null;
if (tokenData.access_token) {
try {
const apiResponse = await fetch(`${apiUrl}/connect/api/v1/cases?limit=1`, {
headers: {
'Authorization': `Bearer ${tokenData.access_token}`,
'Content-Type': 'application/json'
}
});
apiTestResult = {
status: apiResponse.status,
statusText: apiResponse.statusText,
ok: apiResponse.ok
};
}
catch (error) {
apiTestResult = {
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
return {
content: [
{
type: 'text',
text: JSON.stringify({
status: 'success',
message: 'Token refresh test completed',
details: {
tokenRefresh: {
url: `${apiUrl}/connect/api/v1/access_token`,
response: tokenResult,
hasAccessToken: !!tokenData.access_token,
accessTokenLength: tokenData.access_token?.length || 0,
expiresIn: tokenData.exp || tokenData.expires_in,
tokenType: tokenData.token_type
},
apiTest: apiTestResult
}
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
status: 'error',
message: 'Connection test failed',
error: error instanceof Error ? error.message : 'Unknown error',
details: {
url: apiUrl,
tokenLength: apiToken.length
}
}, null, 2),
},
],
};
}
}
case 'investigate_case':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('investigateCase', args.caseId);
case 'correlate_case':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('correlateCase', args.caseId);
case 'get_system_status':
return await executeOrchestratorMethod('getStatus');
case 'analyze_network':
if (!args || !args.caseId || !args.timeRange) {
throw new Error('caseId and timeRange arguments are required');
}
return await executeOrchestratorMethod('analyzeNetwork', args.caseId, args.timeRange);
case 'execute_workflow':
if (!args || !args.workflowId || !args.input) {
throw new Error('workflowId and input arguments are required');
}
return await executeOrchestratorMethod('executeWorkflow', args.workflowId, args.input);
case 'get_agent_metrics':
return await executeOrchestratorMethod('getAgentMetrics');
case 'search_cases':
return await executeOrchestratorMethod('searchCases', args?.query || '', args?.filters);
case 'get_case_activities':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('getCaseActivities', args.caseId);
case 'get_case_observables':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('getCaseObservables', args.caseId);
case 'get_case_alerts':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('getCaseAlerts', args.caseId);
case 'get_case_comments':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('getCaseComments', args.caseId);
case 'get_case_detailed_summary':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('getCaseDetailedSummary', args.caseId);
case 'get_case_scores':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('getCaseScores', args.caseId);
case 'analyze_case_observables':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('analyzeCaseObservables', args.caseId);
case 'get_case_timeline':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('getCaseTimeline', args.caseId);
case 'get_case_artifacts':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('getCaseArtifacts', args.caseId);
case 'suggest_workflow': {
try {
const { MultiAgentOrchestrator, createDefaultConfig } = await import('./orchestrator.js');
const config = createDefaultConfig();
if (process.env.STELLAR_API_URL)
config.stellar.apiUrl = process.env.STELLAR_API_URL;
if (process.env.STELLAR_API_TOKEN)
config.stellar.apiToken = process.env.STELLAR_API_TOKEN;
// Disable all logging to prevent EPIPE errors
config.logging.enableConsole = false;
config.logging.enableFile = false;
// Disable background timers/intervals to prevent EPIPE errors
config.agents.correlation.config.enableCampaignDetection = false;
const orchestrator = new MultiAgentOrchestrator(config);
orchestrator.removeAllListeners(); // Prevent console output
await orchestrator.start();
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
const result = await orchestrator.suggestWorkflow(args.caseId);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: error instanceof Error ? error.message : 'Unknown error',
tool: name,
status: 'error'
}, null, 2),
},
],
};
}
}
case 'update_case_status':
if (!args || !args.caseId || !args.status) {
throw new Error('caseId and status arguments are required');
}
return await executeOrchestratorMethod('updateCaseStatus', args.caseId, args.status, args.comment);
case 'add_case_comment':
if (!args || !args.caseId || !args.comment) {
throw new Error('caseId and comment arguments are required');
}
return await executeOrchestratorMethod('addCaseComment', args.caseId, args.comment);
case 'get_related_cases':
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
return await executeOrchestratorMethod('getRelatedCases', args.caseId);
case 'get_threat_intelligence': {
try {
const { MultiAgentOrchestrator, createDefaultConfig } = await import('./orchestrator.js');
const config = createDefaultConfig();
if (process.env.STELLAR_API_URL)
config.stellar.apiUrl = process.env.STELLAR_API_URL;
if (process.env.STELLAR_API_TOKEN)
config.stellar.apiToken = process.env.STELLAR_API_TOKEN;
// Disable all logging to prevent EPIPE errors
config.logging.enableConsole = false;
config.logging.enableFile = false;
// Disable background timers/intervals to prevent EPIPE errors
config.agents.correlation.config.enableCampaignDetection = false;
const orchestrator = new MultiAgentOrchestrator(config);
orchestrator.removeAllListeners(); // Prevent console output
await orchestrator.start();
if (!args || !args.caseId) {
throw new Error('caseId argument is required');
}
const result = await orchestrator.getThreatIntelligence(args.caseId);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: error instanceof Error ? error.message : 'Unknown error',
tool: name,
status: 'error'
}, null, 2),
},
],
};
}
}
case 'detect_campaigns': {
try {
const { MultiAgentOrchestrator, createDefaultConfig } = await import('./orchestrator.js');
const config = createDefaultConfig();
if (process.env.STELLAR_API_URL)
config.stellar.apiUrl = process.env.STELLAR_API_URL;
if (process.env.STELLAR_API_TOKEN)
config.stellar.apiToken = process.env.STELLAR_API_TOKEN;
// Disable all logging to prevent EPIPE errors
config.logging.enableConsole = false;
config.logging.enableFile = false;
// Disable background timers/intervals to prevent EPIPE errors
config.agents.correlation.config.enableCampaignDetection = false;
const orchestrator = new MultiAgentOrchestrator(config);
orchestrator.removeAllListeners(); // Prevent console output
await orchestrator.start();
const result = await orchestrator.detectCampaigns(args?.criteria || {});
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: error instanceof Error ? error.message : 'Unknown error',
tool: name,
status: 'error'
}, null, 2),
},
],
};
}
}
case 'analyze_case_similarity':
if (!args || !args.caseId1 || !args.caseId2) {
throw new Error('caseId1 and caseId2 arguments are required');
}
return await executeOrchestratorMethod('analyzeCaseSimilarity', args.caseId1, args.caseId2);
case 'detect_lateral_movement': {
try {
const { MultiAgentOrchestrator, createDefaultConfig } = await import('./orchestrator.js');
const config = createDefaultConfig();
if (process.env.STELLAR_API_URL)
config.stellar.apiUrl = process.env.STELLAR_API_URL;
if (process.env.STELLAR_API_TOKEN)
config.stellar.apiToken = process.env.STELLAR_API_TOKEN;
// Disable all logging to prevent EPIPE errors
config.logging.enableConsole = false;
config.logging.enableFile = false;
// Disable background timers/intervals to prevent EPIPE errors
config.agents.correlation.config.enableCampaignDetection = false;
const orchestrator = new MultiAgentOrchestrator(config);
orchestrator.removeAllListeners(); // Prevent console output
await orchestrator.start();
if (!args || !args.caseId || !args.timeRange) {
throw new Error('caseId and timeRange arguments are required');
}
const result = await orchestrator.detectLateralMovement(args.caseId, args.timeRange);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: error instanceof Error ? error.message : 'Unknown error',
tool: name,
status: 'error'
}, null, 2),
},
],
};
}
}
case 'detect_c2_communication': {
try {
const { MultiAgentOrchestrator, createDefaultConfig } = await import('./orchestrator.js');
const config = createDefaultConfig();
if (process.env.STELLAR_API_URL)
config.stellar.apiUrl = process.env.STELLAR_API_URL;
if (process.env.STELLAR_API_TOKEN)
config.stellar.apiToken = process.env.STELLAR_API_TOKEN;
// Disable all logging to prevent EPIPE errors
config.logging.enableConsole = false;
config.logging.enableFile = false;
// Disable background timers/intervals to prevent EPIPE errors
config.agents.correlation.config.enableCampaignDetection = false;
const orchestrator = new MultiAgentOrchestrator(config);
orchestrator.removeAllListeners(); // Prevent console output
await orchestrator.start();
if (!args || !args.caseId || !args.timeRange) {
throw new Error('caseId and timeRange arguments are required');
}
const result = await orchestrator.detectC2Communication(args.caseId, args.timeRange);
return {
content: [
{
type: 'text',
text: JSON.stringify(re