UNPKG

mcp-ai-agent-guidelines

Version:

A comprehensive Model Context Protocol server providing professional tools, resources, and prompts for implementing AI agent best practices

359 lines (350 loc) 14.7 kB
import { z } from "zod"; import { buildReferencesSection } from "./shared/prompt-utils.js"; const CleanCodeScorerSchema = z.object({ projectPath: z.string().optional(), codeContent: z.string().optional(), language: z.string().optional(), framework: z.string().optional(), coverageMetrics: z .object({ statements: z.number().min(0).max(100).optional(), branches: z.number().min(0).max(100).optional(), functions: z.number().min(0).max(100).optional(), lines: z.number().min(0).max(100).optional(), }) .optional(), includeReferences: z.boolean().optional().default(true), includeMetadata: z.boolean().optional().default(true), inputFile: z.string().optional(), }); export async function cleanCodeScorer(args) { const input = CleanCodeScorerSchema.parse(args); const scoreResult = calculateCleanCodeScore(input); const references = input.includeReferences ? buildReferencesSection([ "Clean Code principles: https://www.freecodecamp.org/news/clean-coding-for-beginners/", "Code quality metrics: https://docs.sonarqube.org/latest/user-guide/metric-definitions/", "Test coverage best practices: https://martinfowler.com/bliki/TestCoverage.html", "TypeScript best practices: https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html", ]) : undefined; const metadata = input.includeMetadata ? [ "### Metadata", `- Updated: ${new Date().toISOString().slice(0, 10)}`, "- Source tool: mcp_ai-agent-guid_clean-code-scorer", input.inputFile ? `- Input file: ${input.inputFile}` : undefined, ] .filter(Boolean) .join("\n") : undefined; return { content: [ { type: "text", text: `## 🏆 Clean Code Score Report ${metadata ? `${metadata}\n` : ""} ### 📊 Overall Score **${scoreResult.overallScore}/100** - ${scoreResult.scoreDescription} ${generateScoreBar(scoreResult.overallScore)} ### 📈 Category Breakdown ${Object.entries(scoreResult.categories) .map(([category, data]) => { const categoryName = category .replace(/([A-Z])/g, " $1") .replace(/^./, (str) => str.toUpperCase()); const percentage = (data.score / data.weight) * 100; const status = getScoreStatus(percentage); return `#### ${status} ${categoryName} - Score: ${data.score}/${data.weight} (${percentage.toFixed(1)}%) ${data.issues.length > 0 ? `- Issues:\n${data.issues.map((issue) => ` - ${issue}`).join("\n")}` : "- ✅ No issues found"}`; }) .join("\n\n")} ${scoreResult.achievements.length > 0 ? `### 🎉 Achievements\n${scoreResult.achievements.map((a, i) => `${i + 1}. ${a}`).join("\n")}\n` : ""} ### 💡 Recommendations ${scoreResult.recommendations.map((rec, index) => `${index + 1}. ${rec}`).join("\n")} ### 🚀 Next Steps ${scoreResult.nextSteps.map((step, index) => `${index + 1}. ${step}`).join("\n")} ### 📊 Score Distribution \`\`\` Code Hygiene: ${generateMiniBar(scoreResult.categories.codeHygiene.score, scoreResult.categories.codeHygiene.weight)} Test Coverage: ${generateMiniBar(scoreResult.categories.testCoverage.score, scoreResult.categories.testCoverage.weight)} TypeScript: ${generateMiniBar(scoreResult.categories.typeScript.score, scoreResult.categories.typeScript.weight)} Linting: ${generateMiniBar(scoreResult.categories.linting.score, scoreResult.categories.linting.weight)} Documentation: ${generateMiniBar(scoreResult.categories.documentation.score, scoreResult.categories.documentation.weight)} Security: ${generateMiniBar(scoreResult.categories.security.score, scoreResult.categories.security.weight)} \`\`\` ${references ? `\n${references}\n` : ""} ### ⚠️ Disclaimer - This score is calculated based on multiple quality metrics and best practices - Achieving 100/100 requires excellence across all categories - Regular monitoring and improvement is recommended `, }, ], }; } function calculateCleanCodeScore(input) { const categories = { codeHygiene: { score: 0, weight: 20, issues: [] }, testCoverage: { score: 0, weight: 25, issues: [] }, typeScript: { score: 0, weight: 20, issues: [] }, linting: { score: 0, weight: 15, issues: [] }, documentation: { score: 0, weight: 10, issues: [] }, security: { score: 0, weight: 10, issues: [] }, }; const recommendations = []; const nextSteps = []; const achievements = []; // Code Hygiene Scoring if (input.codeContent) { const hygieneResult = analyzeCodeHygiene(input.codeContent, input.language || "javascript"); categories.codeHygiene.score = Math.round((hygieneResult.score / 100) * categories.codeHygiene.weight); categories.codeHygiene.issues = hygieneResult.issues; if (hygieneResult.score >= 85) { achievements.push("Excellent code hygiene maintained"); } else if (hygieneResult.score < 70) { recommendations.push("Improve code hygiene by addressing identified issues"); nextSteps.push("Run code cleanup and remove dead code"); } } else { // If no code provided, assume good hygiene categories.codeHygiene.score = categories.codeHygiene.weight; } // Test Coverage Scoring if (input.coverageMetrics) { const coverage = input.coverageMetrics; const avgCoverage = ((coverage.statements || 0) + (coverage.branches || 0) + (coverage.functions || 0) + (coverage.lines || 0)) / 4; categories.testCoverage.score = Math.round((avgCoverage / 100) * categories.testCoverage.weight); if (avgCoverage < 80) { categories.testCoverage.issues.push(`Average coverage ${avgCoverage.toFixed(1)}% is below 80% target`); } if ((coverage.statements || 0) < 80) { categories.testCoverage.issues.push(`Statement coverage ${coverage.statements}% is below 80%`); } if ((coverage.branches || 0) < 80) { categories.testCoverage.issues.push(`Branch coverage ${coverage.branches}% is below 80%`); } if ((coverage.functions || 0) < 80) { categories.testCoverage.issues.push(`Function coverage ${coverage.functions}% is below 80%`); } if (avgCoverage >= 90) { achievements.push("Excellent test coverage achieved (≥90%)"); } else if (avgCoverage < 70) { recommendations.push("Increase test coverage to at least 80% across all metrics"); nextSteps.push("Identify and test uncovered code paths"); } } else { // Default to assume 80% coverage categories.testCoverage.score = Math.round(0.8 * categories.testCoverage.weight); } // TypeScript Scoring (assume passing if no errors) categories.typeScript.score = categories.typeScript.weight; achievements.push("TypeScript strict mode enabled and passing"); // Linting Scoring (assume Biome is configured and passing) categories.linting.score = categories.linting.weight; achievements.push("Biome linting and formatting configured"); // Documentation Scoring if (input.codeContent) { const docScore = analyzeDocumentation(input.codeContent); categories.documentation.score = Math.round((docScore / 100) * categories.documentation.weight); if (docScore < 70) { categories.documentation.issues.push("Insufficient code documentation and comments"); recommendations.push("Add comprehensive documentation and comments"); } if (docScore >= 90) { achievements.push("Well-documented codebase"); } } else { categories.documentation.score = Math.round(0.8 * categories.documentation.weight); } // Security Scoring if (input.codeContent) { const securityScore = analyzeSecurityIssues(input.codeContent); categories.security.score = Math.round((securityScore.score / 100) * categories.security.weight); categories.security.issues = securityScore.issues; if (securityScore.score < 80) { recommendations.push("Address security vulnerabilities immediately"); nextSteps.push("Run security audit and fix identified issues"); } if (securityScore.score === 100) { achievements.push("No security vulnerabilities detected"); } } else { categories.security.score = categories.security.weight; achievements.push("Security checks passed"); } // Calculate overall score const overallScore = Math.round(Object.values(categories).reduce((sum, cat) => sum + cat.score, 0)); let scoreDescription = ""; if (overallScore >= 95) { scoreDescription = "🏆 Perfect - Clean Code Excellence"; } else if (overallScore >= 90) { scoreDescription = "✨ Excellent - Near Perfect Quality"; } else if (overallScore >= 80) { scoreDescription = "✅ Very Good - High Quality Code"; } else if (overallScore >= 70) { scoreDescription = "👍 Good - Quality Standards Met"; } else if (overallScore >= 60) { scoreDescription = "⚠️ Fair - Improvements Needed"; } else { scoreDescription = "❌ Poor - Significant Issues"; } // Add general recommendations if (overallScore < 100) { if (recommendations.length === 0) { recommendations.push("Continue maintaining current quality standards"); } recommendations.push("Regular code reviews and pair programming sessions"); recommendations.push("Automated quality gates in CI/CD pipeline"); } if (nextSteps.length === 0) { if (overallScore === 100) { nextSteps.push("Maintain this excellent quality level"); nextSteps.push("Share best practices with the team"); } else { nextSteps.push("Focus on lowest scoring categories first"); nextSteps.push("Set up automated quality monitoring"); } } return { overallScore, scoreDescription, categories, recommendations, nextSteps, achievements, }; } function analyzeCodeHygiene(code, language) { let score = 100; const issues = []; // Check for TODOs/FIXMEs if (code.includes("TODO") || code.includes("FIXME")) { score -= 5; issues.push("TODO or FIXME comments found"); } // Check for debug statements if ((code.includes("console.log") || code.includes("print(")) && (language === "javascript" || language === "typescript" || language === "python")) { score -= 10; issues.push("Debug statements found"); } // Check for hardcoded credentials if (/(apiKey|api_key|password|secret|token)\s*=\s*['"][^'"]+['"]/i.test(code)) { score -= 20; issues.push("Potential hardcoded credentials detected"); } // Check for commented code const commentedLines = (code.match(/^\s*(\/\/|#)\s*(const|let|var|def|function)/gm) || []).length; if (commentedLines > 3) { score -= 5; issues.push(`${commentedLines} lines of commented code found`); } // Check for complex functions (>50 lines) const functionMatches = code.match(/function\s+\w+\s*\([^)]*\)\s*{[\s\S]*?}/g) || []; for (const func of functionMatches) { const lines = func.split("\n").length; if (lines > 50) { score -= 10; issues.push("Complex function detected (>50 lines)"); break; } } return { score: Math.max(0, score), issues }; } function analyzeDocumentation(code) { let score = 70; // Base score // Check for JSDoc/docstring comments const docComments = (code.match(/\/\*\*[\s\S]*?\*\/|'''[\s\S]*?'''|"""[\s\S]*?"""/g) || []).length; if (docComments > 0) { score += 15; } // Check for inline comments const inlineComments = (code.match(/\/\/.*|#.*/g) || []).length; if (inlineComments > 5) { score += 15; } // Check for README or documentation keywords if (/README|CONTRIBUTING|CHANGELOG/i.test(code)) { score += 10; } return Math.min(100, score); } function analyzeSecurityIssues(code) { let score = 100; const issues = []; // Check for eval() or exec() if (/\b(eval|exec)\s*\(/i.test(code)) { score -= 30; issues.push("Use of eval() or exec() detected - security risk"); } // Check for SQL injection risks if (/(SELECT|INSERT|UPDATE|DELETE)\s+.*\+.*/.test(code)) { score -= 25; issues.push("Potential SQL injection vulnerability"); } // Check for XSS risks if (/innerHTML\s*=|dangerouslySetInnerHTML/i.test(code)) { score -= 20; issues.push("Potential XSS vulnerability with innerHTML"); } // Check for hardcoded secrets if (/(secret|password|api_key|apiKey|token|auth|credential)\s*=\s*['"][^'"]+['"]/i.test(code)) { score -= 25; issues.push("Hardcoded secrets or credentials found"); } return { score: Math.max(0, score), issues }; } function generateScoreBar(score) { const barLength = 50; const filledLength = Math.round((score / 100) * barLength); const emptyLength = barLength - filledLength; const filled = "█".repeat(filledLength); const empty = "░".repeat(emptyLength); let color = "🔴"; if (score >= 90) color = "🟢"; else if (score >= 70) color = "🟡"; else if (score >= 50) color = "🟠"; return `${color} [${filled}${empty}] ${score}%`; } function generateMiniBar(score, weight) { const percentage = (score / weight) * 100; const barLength = 20; const filledLength = Math.round((percentage / 100) * barLength); const emptyLength = barLength - filledLength; const filled = "█".repeat(filledLength); const empty = "░".repeat(emptyLength); return `[${filled}${empty}] ${score}/${weight}`; } function getScoreStatus(percentage) { if (percentage >= 90) return "🟢"; if (percentage >= 70) return "🟡"; if (percentage >= 50) return "🟠"; return "🔴"; } //# sourceMappingURL=clean-code-scorer.js.map