analyze-metrics
Analyze code repository metrics to measure complexity, identify patterns, and track code quality across files and functions.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| repositoryPath | Yes | Path to the repository to analyze | |
| includeFiles | No | Include file-level metrics in the output | |
| includeFunctions | No | Include function-level metrics in the output |
Implementation Reference
- src/features/code-metrics/index.ts:13-46 (handler)Executes the tool logic: logs the analysis start, calls analyzeCodeMetrics helper, filters output based on includeFiles/includeFunctions options, returns JSON metrics or error response.async ({ repositoryPath, includeFiles, includeFunctions }) => { try { console.log(`Analyzing code metrics in: ${repositoryPath}`); // Perform the analysis const metrics = await analyzeCodeMetrics(repositoryPath); // Filter the output based on options if (!includeFiles) { delete metrics.files; } else if (!includeFunctions) { // Remove function details from file metrics for (const file of metrics?.files ?? []) { delete file.functions; } } return { content: [{ type: "text", text: JSON.stringify(metrics, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error analyzing code metrics: ${(error as Error).message}` }], isError: true }; } } );
- Input validation schema using Zod for the analyze-metrics tool parameters.{ repositoryPath: z.string().describe("Path to the repository to analyze"), includeFiles: z.boolean().optional().default(true).describe("Include file-level metrics in the output"), includeFunctions: z.boolean().optional().default(false).describe("Include function-level metrics in the output") },
- src/features/code-metrics/index.ts:5-47 (registration)Function that registers the analyze-metrics tool on the MCP server, providing name, input schema, and handler.export function registerCodeMetricsTools(server: McpServer) { server.tool( "analyze-metrics", { repositoryPath: z.string().describe("Path to the repository to analyze"), includeFiles: z.boolean().optional().default(true).describe("Include file-level metrics in the output"), includeFunctions: z.boolean().optional().default(false).describe("Include function-level metrics in the output") }, async ({ repositoryPath, includeFiles, includeFunctions }) => { try { console.log(`Analyzing code metrics in: ${repositoryPath}`); // Perform the analysis const metrics = await analyzeCodeMetrics(repositoryPath); // Filter the output based on options if (!includeFiles) { delete metrics.files; } else if (!includeFunctions) { // Remove function details from file metrics for (const file of metrics?.files ?? []) { delete file.functions; } } return { content: [{ type: "text", text: JSON.stringify(metrics, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error analyzing code metrics: ${(error as Error).message}` }], isError: true }; } } ); }
- Core helper implementing repository scanning, per-file analysis (metrics, complexity, functions), and project aggregation.export async function analyzeCodeMetrics(repositoryPath: string): Promise<ProjectMetrics> { // Find all code files const files = await findCodeFiles(repositoryPath); // Analyze each file const fileMetrics: FileMetrics[] = []; let totalComplexity = 0; for (const file of files) { const filePath = path.join(repositoryPath, file); const language = detectLanguage(file); try { const content = await fs.readFile(filePath, 'utf8'); const metrics = analyzeFileMetrics(content, language); fileMetrics.push({ filePath: file, language, ...metrics }); totalComplexity += metrics.cyclomaticComplexity; } catch (error) { console.error(`Error analyzing file ${file}:`, error); } } // Compile project-level metrics const totalLines = fileMetrics.reduce((sum, file) => sum + file.lineCount, 0); const totalCodeLines = fileMetrics.reduce((sum, file) => sum + file.codeLines, 0); const totalCommentLines = fileMetrics.reduce((sum, file) => sum + file.commentLines, 0); // Count files by language const filesByLanguage: Record<string, number> = {}; for (const file of fileMetrics) { filesByLanguage[file.language] = (filesByLanguage[file.language] || 0) + 1; } return { totalFiles: fileMetrics.length, totalLines, totalCodeLines, totalCommentLines, averageComplexity: fileMetrics.length > 0 ? totalComplexity / fileMetrics.length : 0, filesByLanguage, files: fileMetrics }; }
- TypeScript interfaces defining FileMetrics and ProjectMetrics for input/output structures used in the analysis.interface FileMetrics { filePath: string; language: string; lineCount: number; emptyLines: number; commentLines: number; codeLines: number; cyclomaticComplexity: number; functions?: { name: string; lineCount: number; complexity: number; params: number; }[]; } interface ProjectMetrics { totalFiles: number; totalLines: number; totalCodeLines: number; totalCommentLines: number; averageComplexity: number; filesByLanguage: Record<string, number>; files?: FileMetrics[]; }