analyzeConnections.ts•5.09 kB
/**
* Analyze connections tool for forensic evidence
*/
import { Tool } from '@modelcontextprotocol/sdk/types.js';
import { EvidenceParser } from '../evidenceParser.js';
import { PythonCodeGenerator } from '../pythonGenerator.js';
import { OpenAIClient } from '../client.js';
import { NetworkAnalysis, AnalysisRequest } from '../types.js';
import { Config } from '../config.js';
export class AnalyzeConnectionsTool {
private evidenceParser: EvidenceParser;
private pythonGenerator: PythonCodeGenerator;
private openaiClient: OpenAIClient;
constructor(config: Config) {
this.openaiClient = new OpenAIClient(
config.openaiApiKey,
config.openaiModel,
config.openaiOrgId
);
this.evidenceParser = new EvidenceParser(this.openaiClient);
this.pythonGenerator = new PythonCodeGenerator();
}
/**
* Get tool definition for MCP
*/
getDefinition(): Tool {
return {
name: 'analyze_connections',
description: 'Analyze evidence text to identify people and their connections, then generate Python code for network visualization',
inputSchema: {
type: 'object',
properties: {
evidence: {
type: 'string',
description: 'The evidence text to analyze for connections between people',
},
options: {
type: 'object',
properties: {
includeVisualization: {
type: 'boolean',
description: 'Whether to include Python visualization code (default: true)',
default: true,
},
minimumConnectionStrength: {
type: 'number',
description: 'Minimum connection strength to include (1-10, default: 3)',
default: 3,
},
groupByOrganization: {
type: 'boolean',
description: 'Whether to group people by organization in visualization (default: true)',
default: true,
},
},
},
},
required: ['evidence'],
},
};
}
/**
* Execute the analyze connections tool
*/
async execute(request: AnalysisRequest) {
try {
const { evidence, options = {} } = request;
// Parse evidence to extract people and connections
const { people, connections, evidenceItems } = await this.evidenceParser.parseEvidence(evidence);
// Filter connections by minimum strength
const minStrength = options.minimumConnectionStrength || 3;
const filteredConnections = connections.filter(conn => conn.strength >= minStrength);
// Generate clusters and identify central figures
const clusters = this.pythonGenerator.generateClusterAnalysis(people, filteredConnections);
const centralFigures = this.pythonGenerator.identifyCentralFigures(people, filteredConnections);
// Generate Python visualization code
let pythonCode = '';
if (options.includeVisualization !== false) {
pythonCode = this.pythonGenerator.generateNetworkVisualization(people, filteredConnections);
}
const analysis: NetworkAnalysis = {
people,
connections: filteredConnections,
clusters,
centralFigures,
pythonCode,
};
return {
content: [
{
type: 'text',
text: this.formatAnalysisResults(analysis, evidenceItems),
},
...(pythonCode ? [{
type: 'text' as const,
text: `\`\`\`python\n${pythonCode}\n\`\`\``
}] : [])
],
};
} catch (error) {
console.error('Error in analyze_connections:', error);
return {
content: [
{
type: 'text',
text: `Error analyzing connections: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
}
/**
* Format analysis results for display
*/
private formatAnalysisResults(analysis: NetworkAnalysis, evidenceItems: any[]): string {
const { people, connections, clusters, centralFigures } = analysis;
return `## Network Analysis Results
### People Identified (${people.length}):
${people.map(p => {
const org = p.organization ? ` [${p.organization}]` : '';
const role = p.role ? ` (${p.role})` : '';
return `- **${p.name}**${role}${org}`;
}).join('\n')}
### Connections Found (${connections.length}):
${connections
.sort((a, b) => b.strength - a.strength)
.map(c => `- **${c.from}** → **${c.to}**: ${c.relationship} (strength: ${c.strength}/10)\n *Evidence: ${c.evidence}*`)
.join('\n')}
### Central Figures:
${centralFigures.map(name => `- **${name}**`).join('\n')}
### Clusters/Groups:
${clusters.map((cluster, i) => `**Group ${i + 1}:** ${Array.isArray(cluster) ? cluster.join(', ') : cluster}`).join('\n')}
### Evidence Items Analyzed:
${evidenceItems.map(item => `- **${item.type}**: ${item.source}`).join('\n')}
${analysis.pythonCode ? '### Python Visualization Code:' : ''}`;
}
}