// Copyright 2025 Chris Bunting
// Brief: Main entry point for Code Complexity Analyzer MCP Server
// Scope: Advanced code complexity analysis with cyclomatic, cognitive, and Halstead metrics
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { ComplexityAnalysisService } from './services/ComplexityAnalysisService.js';
import { ASTProcessor } from './services/ASTProcessor.js';
import { MetricCalculator } from './services/MetricCalculator.js';
import { StructureAnalyzer } from './services/StructureAnalyzer.js';
import { MaintainabilityAssessor } from './services/MaintainabilityAssessor.js';
import { Logger } from './utils/Logger.js';
import {
AnalysisResult,
} from '@mcp-code-analysis/shared-types';
class ComplexityAnalyzerServer {
private server: Server;
private analysisService: ComplexityAnalysisService;
private astProcessor: ASTProcessor;
private metricCalculator: MetricCalculator;
private structureAnalyzer: StructureAnalyzer;
private maintainabilityAssessor: MaintainabilityAssessor;
private logger: Logger;
constructor() {
this.server = new Server(
{
name: 'complexity-analyzer-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
this.logger = new Logger();
this.astProcessor = new ASTProcessor();
this.metricCalculator = new MetricCalculator();
this.structureAnalyzer = new StructureAnalyzer();
this.maintainabilityAssessor = new MaintainabilityAssessor();
this.analysisService = new ComplexityAnalysisService(
this.astProcessor,
this.metricCalculator,
this.structureAnalyzer,
this.maintainabilityAssessor,
this.logger
);
this.setupHandlers();
}
private setupHandlers(): void {
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'analyze_complexity',
description: 'Analyze code complexity with comprehensive metrics including cyclomatic, cognitive, and Halstead metrics',
inputSchema: {
type: 'object',
properties: {
filePath: {
type: 'string',
description: 'Path to the file to analyze',
},
language: {
type: 'string',
description: 'Programming language (optional, auto-detected if not provided)',
enum: ['javascript', 'typescript', 'python', 'java', 'c', 'cpp', 'go', 'rust'],
},
options: {
type: 'object',
description: 'Complexity analysis options',
properties: {
thresholds: {
type: 'object',
description: 'Custom thresholds for complexity metrics',
properties: {
cyclomatic: {
type: 'number',
description: 'Cyclomatic complexity threshold',
},
cognitive: {
type: 'number',
description: 'Cognitive complexity threshold',
},
maintainability: {
type: 'number',
description: 'Maintainability index threshold',
},
},
},
includeMetrics: {
type: 'array',
items: { type: 'string' },
description: 'Specific metrics to include',
},
excludeFiles: {
type: 'array',
items: { type: 'string' },
description: 'Files to exclude from analysis',
},
},
},
},
required: ['filePath'],
},
},
{
name: 'suggest_refactorings',
description: 'Suggest refactoring opportunities based on complexity analysis',
inputSchema: {
type: 'object',
properties: {
filePath: {
type: 'string',
description: 'Path to the file to analyze for refactoring opportunities',
},
complexityThreshold: {
type: 'number',
description: 'Complexity threshold to trigger refactoring suggestions',
default: 10,
},
focusArea: {
type: 'string',
description: 'Area to focus refactoring suggestions on',
enum: ['cyclomatic', 'cognitive', 'maintainability', 'all'],
default: 'all',
},
},
required: ['filePath'],
},
},
{
name: 'calculate_metrics',
description: 'Calculate custom complexity metrics for specific code elements',
inputSchema: {
type: 'object',
properties: {
filePath: {
type: 'string',
description: 'Path to the file to analyze',
},
targetElements: {
type: 'array',
items: { type: 'string' },
description: 'Specific code elements to analyze (function names, class names, etc.)',
},
customMetrics: {
type: 'array',
items: { type: 'string' },
description: 'Custom metrics to calculate',
},
},
required: ['filePath'],
},
},
{
name: 'identify_hotspots',
description: 'Identify complexity hotspots in codebase that need immediate attention',
inputSchema: {
type: 'object',
properties: {
projectPath: {
type: 'string',
description: 'Path to the project root directory',
},
filePatterns: {
type: 'array',
items: { type: 'string' },
description: 'File patterns to include (glob patterns)',
},
hotspotThreshold: {
type: 'number',
description: 'Threshold for identifying hotspots',
default: 15,
},
maxResults: {
type: 'number',
description: 'Maximum number of hotspots to return',
default: 20,
},
},
required: ['projectPath'],
},
},
{
name: 'track_trends',
description: 'Track complexity trends over time for historical analysis',
inputSchema: {
type: 'object',
properties: {
projectPath: {
type: 'string',
description: 'Path to the project root directory',
},
timeRange: {
type: 'string',
description: 'Time range for trend analysis',
enum: ['week', 'month', 'quarter', 'year'],
default: 'month',
},
metrics: {
type: 'array',
items: { type: 'string' },
description: 'Metrics to track trends for',
default: ['cyclomaticComplexity', 'cognitiveComplexity', 'maintainabilityIndex'],
},
includeFiles: {
type: 'array',
items: { type: 'string' },
description: 'Specific files to include in trend analysis',
},
},
required: ['projectPath'],
},
},
],
};
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
let result: any;
switch (name) {
case 'analyze_complexity':
result = await this.analyzeComplexity(args);
break;
case 'suggest_refactorings':
result = await this.suggestRefactorings(args);
break;
case 'calculate_metrics':
result = await this.calculateMetrics(args);
break;
case 'identify_hotspots':
result = await this.identifyHotspots(args);
break;
case 'track_trends':
result = await this.trackTrends(args);
break;
default:
throw new Error(`Unknown tool: ${name}`);
}
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
} catch (error) {
this.logger.error(`Error executing tool ${name}:`, error);
return {
content: [
{
type: 'text',
text: JSON.stringify({
error: error instanceof Error ? error.message : 'Unknown error',
}),
},
],
isError: true,
};
}
});
}
private async analyzeComplexity(args: any): Promise<AnalysisResult> {
const { filePath, language, options = {} } = args;
this.logger.info(`Analyzing complexity for file: ${filePath}`);
return await this.analysisService.analyzeComplexity(filePath, language, options);
}
private async suggestRefactorings(args: any): Promise<any> {
const { filePath, complexityThreshold = 10, focusArea = 'all' } = args;
this.logger.info(`Suggesting refactorings for file: ${filePath}`);
return await this.analysisService.suggestRefactorings(filePath, complexityThreshold, focusArea);
}
private async calculateMetrics(args: any): Promise<any> {
const { filePath, targetElements, customMetrics } = args;
this.logger.info(`Calculating custom metrics for file: ${filePath}`);
return await this.analysisService.calculateMetrics(filePath, targetElements, customMetrics);
}
private async identifyHotspots(args: any): Promise<any> {
const { projectPath, filePatterns, hotspotThreshold = 15, maxResults = 20 } = args;
this.logger.info(`Identifying hotspots in project: ${projectPath}`);
return await this.analysisService.identifyHotspots(projectPath, filePatterns, hotspotThreshold, maxResults);
}
private async trackTrends(args: any): Promise<any> {
const { projectPath, timeRange = 'month', metrics, includeFiles } = args;
this.logger.info(`Tracking trends for project: ${projectPath}`);
return await this.analysisService.trackTrends(projectPath, timeRange, metrics, includeFiles);
}
async run(): Promise<void> {
const transport = new StdioServerTransport();
await this.server.connect(transport);
this.logger.info('Code Complexity Analyzer MCP Server started');
}
}
async function main(): Promise<void> {
const server = new ComplexityAnalyzerServer();
await server.run();
}
main().catch((error) => {
console.error('Failed to start Code Complexity Analyzer MCP Server:', error);
process.exit(1);
});