"""๐ CodeLint MCP Server - Premium Edition FastMCP server with 10 tools, mature analyzers, and premium AI integration. Built for top-tier performance with comprehensive error handling. """ import logging import sys from pathlib import Path from typing import Any # Add src to path sys.path.insert(0, str(Path(__file__).parent.parent)) # Configure logging to stderr only logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', stream=sys.stderr ) logger = logging.getLogger(__name__) # FastMCP imports from fastmcp import FastMCP from fastmcp.resources import FunctionResource # Our premium analyzers from src.analyzers.python_analyzer import PythonAnalyzer, analyze_python from src.analyzers.javascript_analyzer import JavaScriptAnalyzer, analyze_javascript from src.analyzers.project_analyzer import ProjectAnalyzer, analyze_project from src.analyzers.git_analyzer import GitAnalyzer, analyze_git_diff # Utilities from src.utils.language_detector import detect_language from src.utils.ai_client import generate_ai_response from src.config import Config # Create FastMCP server mcp = FastMCP("codelint-premium") logger.info("๐ CodeLint MCP Server - Premium Edition") logger.info("โ All analyzers loaded and ready") # ============================================================================ # CORE TOOLS (5 Essential) # ============================================================================ @mcp.tool() async def analyze_code(code: str, language: str = "auto") -> dict[str, Any]: """ Comprehensive code analysis with linting, security, and complexity. Analyzes source code using multiple specialized tools: - Python: Ruff (linting), Bandit (security), Radon (complexity) - JavaScript/TypeScript: ESLint (linting), complexity analysis Args: code: Source code to analyze language: Programming language (python, javascript, typescript, or auto) Returns: Analysis results with issues, summary, and metadata """ try: if not code or not code.strip(): return {"error": "Code cannot be empty", "issues": []} # Auto-detect language if needed if language == "auto": language = detect_language(code) logger.info(f"Auto-detected language: {language}") # Run appropriate analyzer if language == "python": analyzer = PythonAnalyzer() result = await analyzer.analyze(code) elif language in ["javascript", "typescript"]: analyzer = JavaScriptAnalyzer() result = await analyzer.analyze(code, language=language) else: return { "error": f"Unsupported language: {language}", "supported": ["python", "javascript", "typescript"], "issues": [] } logger.info(f"Analysis complete: {len(result.get('issues', []))} issues found") return result except Exception as e: logger.error(f"analyze_code failed: {e}", exc_info=True) return {"error": str(e), "issues": []} @mcp.tool() async def check_security(code: str, language: str = "auto") -> dict[str, Any]: """ Security vulnerability scanning with severity classification. Focuses specifically on security issues: - Python: Bandit security scanner - JavaScript/TypeScript: Security-focused ESLint rules Args: code: Source code to scan for vulnerabilities language: Programming language (python, javascript, typescript, or auto) Returns: Security scan results with vulnerability details """ try: if not code or not code.strip(): return {"error": "Code cannot be empty", "vulnerabilities": []} if language == "auto": language = detect_language(code) # Python security scanning if language == "python": from src.analyzers.python_analyzer import scan_security_python result = await scan_security_python(code) return result # JavaScript security would use ESLint security rules elif language in ["javascript", "typescript"]: analyzer = JavaScriptAnalyzer() result = await analyzer.analyze(code, language=language) # Filter for security issues only security_issues = [ issue for issue in result.get("issues", []) if "security" in issue.get("message", "").lower() ] return { "vulnerabilities": security_issues, "summary": { "total": len(security_issues), "high": sum(1 for i in security_issues if i.get("severity") == "error"), "medium": sum(1 for i in security_issues if i.get("severity") == "warning") } } else: return {"error": f"Security scanning not supported for: {language}", "vulnerabilities": []} except Exception as e: logger.error(f"check_security failed: {e}", exc_info=True) return {"error": str(e), "vulnerabilities": []} @mcp.tool() async def complexity_score(code: str, language: str = "auto") -> dict[str, Any]: """ Calculate code complexity metrics and maintainability index. Metrics include: - Cyclomatic complexity - Maintainability index - Function count - Lines of code Args: code: Source code to analyze language: Programming language (python, javascript, typescript, or auto) Returns: Complexity metrics dictionary """ try: if not code or not code.strip(): return {"error": "Code cannot be empty", "complexity": {}} if language == "auto": language = detect_language(code) if language == "python": from src.analyzers.python_analyzer import calculate_complexity_python result = await calculate_complexity_python(code) return result elif language in ["javascript", "typescript"]: from src.analyzers.javascript_analyzer import calculate_complexity_javascript result = await calculate_complexity_javascript(code) return result else: return {"error": f"Complexity analysis not supported for: {language}", "complexity": {}} except Exception as e: logger.error(f"complexity_score failed: {e}", exc_info=True) return {"error": str(e), "complexity": {}} @mcp.tool() async def suggest_fixes(code: str, language: str = "auto", model: str = "grok-4.1") -> dict[str, Any]: """ AI-powered fix suggestions for code issues. Uses premium AI models to: - Identify problems in code - Generate fix suggestions with explanations - Provide complete corrected code Args: code: Source code with issues language: Programming language (auto-detected if not specified) model: AI model to use (default: grok-4.1 free) Returns: Fix suggestions with explanations and corrected code """ try: if not code or not code.strip(): return {"error": "Code cannot be empty", "suggestions": []} if language == "auto": language = detect_language(code) # First analyze to find issues analyzer_result = await analyze_code(code=code, language=language) issues = analyzer_result.get("issues", []) if not issues: return { "message": "No issues found - code looks good!", "suggestions": [] } # Prepare prompt for AI issues_summary = "\\n".join([ f"- Line {issue.get('line')}: {issue.get('message')}" for issue in issues[:10] # Limit to first 10 issues ]) prompt = f"""Analyze this {language} code and suggest fixes for the following issues: ```{language} {code} ``` Issues found: {issues_summary} Please provide: 1. Explanation of each issue 2. How to fix it 3. Complete corrected code Be concise but comprehensive.""" # Get AI response ai_response = await generate_ai_response( prompt=prompt, model_name=model ) return { "issues_found": len(issues), "ai_suggestions": ai_response, "model_used": model } except Exception as e: logger.error(f"suggest_fixes failed: {e}", exc_info=True) return {"error": str(e), "suggestions": []} @mcp.tool() async def get_server_info() -> dict[str, Any]: """ Get server capabilities, supported languages, and available AI models. Returns: Server information including tools, resources, and models """ config = Config() return { "server": "CodeLint MCP Premium", "version": "2.0.0", "tools": [ "analyze_code", "check_security", "complexity_score", "suggest_fixes", "analyze_project", "analyze_git_diff", "explain_code", "generate_tests", "generate_docs", "get_server_info" ], "supported_languages": [ "python", "javascript", "typescript" ], "analyzers": { "python": ["ruff", "bandit", "radon"], "javascript": ["eslint", "complexity"], "typescript": ["eslint", "complexity"] }, "ai_models": config.get_dropdown_options(), "features": [ "Multi-file project analysis", "Git diff analysis", "AI-powered explanations", "Test generation", "Documentation generation", "9 AI model options (3 premium, 6 free)" ] } # ============================================================================ # COMPETITIVE TOOLS (5 Advanced) # ============================================================================ @mcp.tool() async def analyze_project(project_path: str, max_files: int = 100) -> dict[str, Any]: """ Analyze an entire project with multiple files. Features: - Parallel file processing - Multi-language support - Aggregated results across all files - Automatic exclusion of common directories (node_modules, __pycache__, etc.) Args: project_path: Root directory of the project max_files: Maximum number of files to analyze (default: 100) Returns: Aggregated analysis results for the entire project """ try: result = await analyze_project(project_path=project_path, max_files=max_files) return result except Exception as e: logger.error(f"analyze_project failed: {e}", exc_info=True) return {"error": str(e), "files_analyzed": 0} @mcp.tool() async def analyze_git_diff(repo_path: str, base_ref: str = "HEAD") -> dict[str, Any]: """ Analyze only changed files in a Git diff. Perfect for CI/CD integration and pull request reviews. Args: repo_path: Path to Git repository base_ref: Base reference for comparison (default: HEAD) Returns: Analysis results for changed files only """ try: result = await analyze_git_diff(repo_path=repo_path, base_ref=base_ref) return result except Exception as e: logger.error(f"analyze_git_diff failed: {e}", exc_info=True) return {"error": str(e), "files_changed": 0} @mcp.tool() async def explain_code(code: str, language: str = "auto", model: str = "grok-4.1") -> dict[str, Any]: """ AI-powered code explanation. Get clear explanations of what code does, how it works, and potential issues. Args: code: Source code to explain language: Programming language (auto-detected if not specified) model: AI model to use (default: grok-4.1 free) Returns: Detailed code explanation """ try: if not code or not code.strip(): return {"error": "Code cannot be empty"} if language == "auto": language = detect_language(code) prompt = f"""Explain this {language} code in detail: ```{language} {code} ``` Please provide: 1. What the code does (high-level overview) 2. How it works (step-by-step breakdown) 3. Any potential issues or improvements 4. Best practices that are or aren't being followed Be clear and educational.""" explanation = await generate_ai_response(prompt=prompt, model_name=model) return { "language": language, "explanation": explanation, "model_used": model } except Exception as e: logger.error(f"explain_code failed: {e}", exc_info=True) return {"error": str(e)} @mcp.tool() async def generate_tests(code: str, language: str = "auto", model: str = "grok-4.1") -> dict[str, Any]: """ AI-powered test generation. Generate comprehensive unit tests for your code. Args: code: Source code to generate tests for language: Programming language (auto-detected if not specified) model: AI model to use (default: grok-4.1 free) Returns: Generated test code with test cases """ try: if not code or not code.strip(): return {"error": "Code cannot be empty"} if language == "auto": language = detect_language(code) # Determine test framework test_framework = { "python": "pytest", "javascript": "jest", "typescript": "jest" }.get(language, "unittest") prompt = f"""Generate comprehensive unit tests for this {language} code using {test_framework}: ```{language} {code} ``` Please provide: 1. Complete test file with all necessary imports 2. Test cases covering: - Normal/happy path scenarios - Edge cases - Error conditions - Boundary conditions 3. Clear test names and docstrings 4. Setup/teardown if needed Make tests production-ready and well-documented.""" tests = await generate_ai_response(prompt=prompt, model_name=model) return { "language": language, "test_framework": test_framework, "tests": tests, "model_used": model } except Exception as e: logger.error(f"generate_tests failed: {e}", exc_info=True) return {"error": str(e)} @mcp.tool() async def generate_docs(code: str, language: str = "auto", model: str = "grok-4.1") -> dict[str, Any]: """ AI-powered documentation generation. Generate comprehensive documentation including docstrings, comments, and README. Args: code: Source code to document language: Programming language (auto-detected if not specified) model: AI model to use (default: grok-4.1 free) Returns: Generated documentation in appropriate format """ try: if not code or not code.strip(): return {"error": "Code cannot be empty"} if language == "auto": language = detect_language(code) prompt = f"""Generate comprehensive documentation for this {language} code: ```{language} {code} ``` Please provide: 1. Module/file-level docstring 2. Function/class docstrings following best practices: - Python: Google/NumPy style - JavaScript/TypeScript: JSDoc 3. Inline comments for complex logic 4. Usage examples 5. Parameter descriptions and return types Make documentation clear, complete, and professional.""" docs = await generate_ai_response(prompt=prompt, model_name=model) return { "language": language, "documentation": docs, "model_used": model } except Exception as e: logger.error(f"generate_docs failed: {e}", exc_info=True) return {"error": str(e)} @mcp.tool() async def prioritize_issues(code: str, language: str = "auto") -> dict[str, Any]: """ Smart issue prioritization with severity, impact, and fix effort analysis. Enriches analysis results with: - Priority scoring (Critical/High/Medium/Low) - Impact categories (Security/Reliability/Performance/Style) - Fix effort estimation (Quick/Medium/Major) - Time to fix estimates - Statistics and quick wins identification Args: code: Source code to analyze and prioritize language: Programming language (auto-detected if not specified) Returns: Prioritized issues with rich metadata and statistics """ try: # First run analysis result = await analyze_code(code, language) issues = result.get("issues", []) if not issues: return { "prioritized_issues": [], "statistics": {}, "message": "No issues found!" } # Import prioritization system from src.utils.prioritization import IssuePrioritizer, format_priority_report # Prioritize and enrich issues prioritized = IssuePrioritizer.prioritize_issues(issues) stats = IssuePrioritizer.get_statistics(prioritized) report = format_priority_report(prioritized) return { "prioritized_issues": prioritized, "statistics": stats, "report": report, "language": result.get("language"), "total_issues": len(prioritized) } except Exception as e: logger.error(f"prioritize_issues failed: {e}", exc_info=True) return {"error": str(e)} @mcp.tool() async def auto_fix_code(code: str, language: str = "auto", preview_only: bool = False) -> dict[str, Any]: """ Auto-fix common code issues with preview and batch capabilities. Automatically fixes: - Missing semicolons - console.log/debugger statements - Trailing whitespace - var to const/let - == to === - Unused variables (prefix with _) Args: code: Source code to fix language: Programming language (auto-detected if not specified) preview_only: If True, only show previews without applying fixes Returns: Fixed code with list of applied fixes """ try: # First run analysis result = await analyze_code(code, language) issues = result.get("issues", []) if not issues: return { "fixed_code": code, "applied_fixes": [], "message": "No issues to fix!" } # Import auto-fix engine from src.utils.auto_fix import AutoFixer, format_fix_report if preview_only: # Generate fix summary with previews fix_summary = AutoFixer.get_fix_summary(code, issues) report = format_fix_report(fix_summary) return { "preview_mode": True, "fix_summary": fix_summary, "report": report, "original_code": code } else: # Apply all fixes fixed_code, applied_fixes = AutoFixer.batch_fix(code, issues) return { "fixed_code": fixed_code, "applied_fixes": applied_fixes, "fixes_count": len(applied_fixes), "original_code": code, "language": result.get("language") } except Exception as e: logger.error(f"auto_fix_code failed: {e}", exc_info=True) return {"error": str(e)} @mcp.tool() async def analyze_dependencies(project_path: str) -> dict[str, Any]: """ Analyze project dependencies for vulnerabilities and outdated packages. Checks for: - Known CVEs in dependencies - Outdated packages - Security vulnerabilities - License compatibility issues Supports: - Node.js (package.json) - Python (requirements.txt) Args: project_path: Path to project directory Returns: Dependency analysis with vulnerabilities and recommendations """ try: from src.utils.dependency_analyzer import DependencyAnalyzer, format_dependency_report analysis = DependencyAnalyzer.analyze_dependencies(project_path) report = format_dependency_report(analysis) return { "analysis": analysis, "report": report, "project_path": project_path } except Exception as e: logger.error(f"analyze_dependencies failed: {e}", exc_info=True) return {"error": str(e)} @mcp.tool() async def detect_duplication(code: str, language: str = "auto", min_lines: int = 5) -> dict[str, Any]: """ Detect code duplication and suggest DRY refactoring. Finds: - Copy-pasted code blocks - Similar code patterns - Refactoring opportunities Args: code: Source code to analyze language: Programming language (auto-detected if not specified) min_lines: Minimum lines to consider as duplication (default: 5) Returns: Duplication analysis with refactoring suggestions """ try: from src.utils.duplication_detector import DuplicationDetector, format_duplication_report detector = DuplicationDetector(min_lines=min_lines) analysis = detector.analyze_duplication(code) report = format_duplication_report(analysis) return { "analysis": analysis, "report": report, "language": language if language != "auto" else detect_language(code) } except Exception as e: logger.error(f"detect_duplication failed: {e}", exc_info=True) return {"error": str(e)} # ============================================================================ # RESOURCES (Static Information) # ============================================================================ @mcp.resource("guide://best-practices") async def best_practices_guide() -> str: """Code quality and best practices guide""" return """ # Code Quality Best Practices ## Python - Use type hints for better code clarity - Follow PEP 8 style guide - Keep functions small and focused - Use descriptive variable names - Handle exceptions properly - Write docstrings for all public functions - Avoid mutable default arguments - Use context managers for resources ## JavaScript/TypeScript - Use const/let instead of var - Enable strict mode - Handle promises properly - Use async/await for async code - Validate inputs - Use === instead of == - Keep functions pure when possible - Use TypeScript for large projects ## Security - Never use eval() or exec() - Validate and sanitize all inputs - Use parameterized queries for databases - Keep dependencies updated - Never commit secrets or credentials - Use HTTPS for all external communications """ @mcp.resource("guide://security") async def security_guidelines() -> str: """Security scanning and vulnerability prevention guide""" return """ # Security Guidelines ## Common Vulnerabilities ### Python - **Code Injection**: Avoid eval(), exec(), compile() with user input - **Deserialization**: Never use pickle.loads() on untrusted data - **Path Traversal**: Validate file paths, don't allow ../ - **SQL Injection**: Use parameterized queries - **Command Injection**: Avoid shell=True in subprocess ### JavaScript/TypeScript - **XSS**: Sanitize all user inputs before rendering - **Prototype Pollution**: Avoid Object.assign with user data - **ReDoS**: Be careful with complex regular expressions - **Path Traversal**: Validate file paths - **SQL Injection**: Use parameterized queries ## Best Practices - Principle of least privilege - Defense in depth - Input validation and sanitization - Secure defaults - Regular security updates - Security testing in CI/CD """ @mcp.resource("guide://complexity") async def complexity_guide() -> str: """Complexity metrics and maintainability guide""" return """ # Complexity and Maintainability ## Cyclomatic Complexity - **1-10**: Simple, easy to test - **11-20**: Moderate, needs attention - **21-50**: Complex, hard to maintain - **50+**: Very complex, refactor recommended ## Maintainability Index - **85-100**: Highly maintainable (Green) - **65-84**: Moderately maintainable (Yellow) - **0-64**: Hard to maintain (Red) ## Tips to Reduce Complexity - Extract methods/functions - Use early returns - Replace nested conditions with guard clauses - Apply design patterns - Break large functions into smaller ones - Use polymorphism instead of conditionals """ # ============================================================================ # GRADIO UI INTEGRATION # ============================================================================ def create_gradio_ui(): """Create premium Gradio UI integrated with MCP""" import gradio as gr # Get config instance cfg = Config() # Custom CSS for premium look CUSTOM_CSS = """ .gradio-container { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; } .contain { background: rgba(17, 24, 39, 0.95) !important; backdrop-filter: blur(20px) !important; border-radius: 24px !important; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5) !important; } .gr-button { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; border-radius: 12px !important; transition: all 0.3s !important; } .gr-button:hover { transform: translateY(-2px) !important; } """ # Get model options model_options = cfg.get_dropdown_options() with gr.Blocks(theme=gr.themes.Soft(primary_hue="purple"), css=CUSTOM_CSS) as demo: gr.Markdown("""
Connected to FastMCP Server with 10 tools and 9 AI models