Skip to main content
Glama

CTS MCP Server

by EricA1019
metrics.jsโ€ข4.34 kB
/** * Audit Metrics Collection * * Collects project-wide metrics: * - Lines of Code (LOC) * - Cyclomatic Complexity * - File counts * - Test coverage (placeholder) */ import { readFileSync } from 'fs'; import { join } from 'path'; /** * Collect comprehensive project metrics */ export async function collectMetrics(projectPath, files) { const metrics = { loc: { total: 0, byFile: {}, average: 0 }, complexity: { total: 0, byFile: {}, average: 0, max: 0, maxFile: '' }, files: { total: files.length, gdscript: 0, scenes: 0, resources: 0 }, testCoverage: 0, }; // Filter by file type const gdFiles = files.filter((f) => f.endsWith('.gd')); const sceneFiles = files.filter((f) => f.endsWith('.tscn')); const resourceFiles = files.filter((f) => f.endsWith('.tres')); metrics.files.gdscript = gdFiles.length; metrics.files.scenes = sceneFiles.length; metrics.files.resources = resourceFiles.length; // Analyze GDScript files for (const file of gdFiles) { const filePath = join(projectPath, file); try { const source = readFileSync(filePath, 'utf-8'); // Count lines of code const lines = source.split('\n').length; metrics.loc.total += lines; metrics.loc.byFile[file] = lines; // Calculate cyclomatic complexity (simplified) const complexityScore = calculateComplexity(source); metrics.complexity.total += complexityScore; metrics.complexity.byFile[file] = complexityScore; if (complexityScore > metrics.complexity.max) { metrics.complexity.max = complexityScore; metrics.complexity.maxFile = file; } } catch { // Skip unreadable files } } // Calculate averages if (gdFiles.length > 0) { metrics.loc.average = Math.round(metrics.loc.total / gdFiles.length); metrics.complexity.average = Math.round(metrics.complexity.total / gdFiles.length); } // Estimate test coverage (count test files vs. source files) const testFiles = files.filter((f) => f.includes('/test/') || f.includes('_test.gd')); const sourceFiles = gdFiles.filter((f) => !f.includes('/test/') && !f.includes('_test.gd')); if (sourceFiles.length > 0) { metrics.testCoverage = Math.round((testFiles.length / sourceFiles.length) * 100); metrics.testCoverage = Math.min(100, metrics.testCoverage); // Cap at 100% } return metrics; } /** * Calculate cyclomatic complexity for source code * * Simplified metric: count control flow statements * - Base complexity: 1 * - +1 for each: if, elif, for, while, match, and, or */ function calculateComplexity(source) { let complexity = 1; // Base complexity // Count control flow keywords const controlFlowPatterns = [ /\bif\b/g, /\belif\b/g, /\bfor\b/g, /\bwhile\b/g, /\bmatch\b/g, /\band\b/g, /\bor\b/g, ]; for (const pattern of controlFlowPatterns) { const matches = source.match(pattern); if (matches) { complexity += matches.length; } } return complexity; } /** * Calculate file-level complexity breakdown */ export function getComplexityBreakdown(metrics) { const breakdown = { low: 0, medium: 0, high: 0 }; for (const complexity of Object.values(metrics.complexity.byFile)) { if (complexity <= 10) { breakdown.low++; } else if (complexity <= 20) { breakdown.medium++; } else { breakdown.high++; } } return breakdown; } /** * Get top N most complex files */ export function getTopComplexFiles(metrics, n = 10) { const entries = Object.entries(metrics.complexity.byFile); entries.sort((a, b) => b[1] - a[1]); return entries.slice(0, n).map(([file, complexity]) => ({ file, complexity, })); } /** * Get top N largest files */ export function getTopLargestFiles(metrics, n = 10) { const entries = Object.entries(metrics.loc.byFile); entries.sort((a, b) => b[1] - a[1]); return entries.slice(0, n).map(([file, loc]) => ({ file, loc, })); } //# sourceMappingURL=metrics.js.map

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/EricA1019/CTS_MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server