"""๐Ÿ† 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("""

๐ŸŽจ CodeLint Premium - MCP Edition

Professional Code Analysis with AI-Powered Insights

Connected to FastMCP Server with 10 tools and 9 AI models

""") with gr.Tabs(): # TAB 1: Code Analysis with gr.Tab("๐Ÿ“ Code Analysis"): with gr.Row(): with gr.Column(scale=2): code_input = gr.Textbox( label="Source Code", placeholder="Paste your code here...", lines=15 ) with gr.Column(scale=1): language = gr.Dropdown( choices=["auto", "python", "javascript", "typescript"], value="auto", label="Language" ) model = gr.Dropdown( choices=model_options, value="๐Ÿ†“ Grok 4.1 Fast (OpenRouter)", label="AI Model" ) analyze_btn = gr.Button("๐Ÿš€ Analyze Code", variant="primary") results_md = gr.Markdown(label="Results") results_json = gr.JSON(label="Raw Results") async def analyze_ui(code: str, lang: str, model_name: str): if not code.strip(): return "โŒ Please enter code", None try: # Call analyzer directly, not the FastMCP tool original_lang = lang if lang == "auto": lang = detect_language(code) # Log for debugging import sys print(f"DEBUG: Original lang: {original_lang}, Detected lang: {lang}", file=sys.stderr) print(f"DEBUG: Code preview: {code[:100]}...", file=sys.stderr) if lang == "python": analyzer = PythonAnalyzer() result = await analyzer.analyze(code) elif lang in ["javascript", "typescript"]: analyzer = JavaScriptAnalyzer() result = await analyzer.analyze(code, language=lang) else: return f"โŒ Unsupported language: {lang}", None # Extract data from result issues = result.get("issues", []) summary = result.get("summary", {}) # Log for debugging import sys print(f"DEBUG: Found {len(issues)} issues", file=sys.stderr) print(f"DEBUG: Summary: {summary}", file=sys.stderr) if issues: print(f"DEBUG: First issue: {issues[0]}", file=sys.stderr) output = f""" # ๐Ÿ“Š Analysis Results ## ๐ŸŽฏ Summary - **Total Issues**: {len(issues)} - **Errors**: {summary.get('errors', 0)} ๐Ÿ”ด - **Warnings**: {summary.get('warnings', 0)} ๐ŸŸก - **Security**: {summary.get('security_issues', 0)} ๐Ÿ›ก๏ธ ## ๐Ÿ› Issues Found """ if not issues: output += "\nโœ… **No issues found! Code looks clean.**\n" else: for i, issue in enumerate(issues[:20], 1): emoji = "๐Ÿ”ด" if issue.get("severity") == "error" else "๐ŸŸก" line = issue.get('line', 'N/A') col = issue.get('column', '') location = f"Line {line}" + (f":{col}" if col else "") message = issue.get('message', 'No message') rule_id = issue.get('rule_id', '') output += f"\n{emoji} **Issue {i}** ({location})\n" output += f" {message}\n" if rule_id: output += f" *Rule: {rule_id}*\n" if len(issues) > 20: output += f"\n\n*... and {len(issues) - 20} more issues*" return output, result except Exception as e: import traceback print(f"ERROR: {traceback.format_exc()}", file=sys.stderr) return f"โŒ Error: {str(e)}", None analyze_btn.click( fn=analyze_ui, inputs=[code_input, language, model], outputs=[results_md, results_json] ) # Helper function for running analyzer async def _run_analyzer(code: str, lang: str): """Helper to run code analysis""" if lang == "python": analyzer = PythonAnalyzer() return await analyzer.analyze(code) elif lang in ["javascript", "typescript"]: analyzer = JavaScriptAnalyzer() return await analyzer.analyze(code, language=lang) else: return {"issues": [], "summary": {}} # Helper function for model mapping (used by all AI features) def _get_model_map(): """Map UI model names to actual model IDs""" return { "โญ OpenAI GPT-5 Preview": "gpt-5", "โญ Google Gemini 3 Pro": "gemini-3", "โญ Claude Sonnet 4.5": "claude-sonnet", "๐Ÿ†“ Grok 4.1 Fast (OpenRouter)": "grok-4.1", "๐Ÿ†“ KAT-Coder-Pro V1": "kat-coder", "๐Ÿ†“ Qwen3-Coder-32B": "qwen-coder", "๐Ÿ†“ LongCat 7B (OpenRouter)": "longcat", "๐Ÿ†“ GPT-OSS 4o (OpenRouter)": "gpt-oss", "๐Ÿ†“ Kimi K2 128k": "kimi" } # TAB 2: Project Analysis with gr.Tab("๐Ÿ“ฆ Project Analysis"): project_path = gr.Textbox(label="Project Path", placeholder="C:\\path\\to\\project") max_files = gr.Slider(10, 500, 100, step=10, label="Max Files") project_btn = gr.Button("๐Ÿ“Š Analyze Project", variant="primary") project_results = gr.Markdown() project_json = gr.JSON() async def project_ui(path: str, max_f: int): if not path.strip(): return "โŒ Enter project path", None try: # Call analyzer function directly from src.analyzers.project_analyzer import analyze_project as analyze_proj result = await analyze_proj(project_path=path, max_files=max_f) summary = result.get("summary", {}) metadata = result.get("metadata", {}) output = f""" # ๐Ÿ“ฆ Project Analysis ## ๐Ÿ“Š Summary - **Files**: {summary.get('files_analyzed', 0)} - **Errors**: {summary.get('total_errors', 0)} ๐Ÿ”ด - **Warnings**: {summary.get('total_warnings', 0)} ๐ŸŸก - **Security**: {summary.get('total_security_issues', 0)} ๐Ÿ›ก๏ธ - **Lines**: {metadata.get('total_lines_of_code', 0):,} ## ๐Ÿ“ Languages {', '.join(metadata.get('languages', []))} """ return output, result except Exception as e: return f"โŒ Error: {str(e)}", None project_btn.click( fn=project_ui, inputs=[project_path, max_files], outputs=[project_results, project_json] ) # TAB 3: Git Diff with gr.Tab("๐Ÿ”„ Git Diff"): repo_path = gr.Textbox(label="Repo Path", placeholder="C:\\path\\to\\repo") base_ref = gr.Textbox(label="Base Ref", value="HEAD") git_btn = gr.Button("๐Ÿ” Analyze Changes", variant="primary") git_results = gr.Markdown() git_json = gr.JSON() async def git_ui(repo: str, base: str): if not repo.strip(): return "โŒ Enter repo path", None try: # Call analyzer function directly from src.analyzers.git_analyzer import analyze_git_diff as analyze_git result = await analyze_git(repo_path=repo, base_ref=base) summary = result.get("summary", {}) output = f""" # ๐Ÿ”„ Git Diff Analysis ## ๐Ÿ“Š Summary - **Files Changed**: {summary.get('files_changed', 0)} - **Errors**: {summary.get('total_errors', 0)} ๐Ÿ”ด - **Warnings**: {summary.get('total_warnings', 0)} ๐ŸŸก - **Security**: {summary.get('total_security_issues', 0)} ๐Ÿ›ก๏ธ """ return output, result except Exception as e: return f"โŒ Error: {str(e)}", None git_btn.click( fn=git_ui, inputs=[repo_path, base_ref], outputs=[git_results, git_json] ) # TAB 4: AI Assistant with gr.Tab("๐Ÿค– AI Assistant"): ai_code = gr.Textbox(label="Code", lines=10) ai_lang = gr.Dropdown(["auto", "python", "javascript", "typescript"], value="auto", label="Language") ai_model = gr.Dropdown(model_options, value="๐Ÿ†“ Grok 4.1 Fast (OpenRouter)", label="Model") with gr.Tabs(): with gr.Tab("Explain"): explain_btn = gr.Button("๐Ÿ’ก Explain") explain_out = gr.Markdown() async def explain_ui(code: str, lang: str, model_name: str): if not code.strip(): return "โŒ Enter code" try: # Map display name to actual model ID actual_model = _get_model_map().get(model_name, "grok-4.1") # Use AI client directly if lang == "auto": lang = detect_language(code) prompt = f"""Explain this {lang} code in detail: ```{lang} {code} ``` Provide a clear, educational explanation covering: 1. What the code does 2. How it works 3. Potential issues or improvements """ explanation = await generate_ai_response(prompt=prompt, model_name=actual_model) return f"# ๐Ÿค– Explanation\n\n{explanation}" except Exception as e: return f"โŒ Error: {str(e)}" explain_btn.click(fn=explain_ui, inputs=[ai_code, ai_lang, ai_model], outputs=[explain_out]) with gr.Tab("Generate Tests"): tests_btn = gr.Button("๐Ÿงช Generate Tests") tests_out = gr.Markdown() async def tests_ui(code: str, lang: str, model_name: str): if not code.strip(): return "โŒ Enter code" try: # Map display name to actual model ID actual_model = _get_model_map().get(model_name, "grok-4.1") # Use AI client directly if lang == "auto": lang = detect_language(code) test_framework = {"python": "pytest", "javascript": "jest", "typescript": "jest"}.get(lang, "unittest") prompt = f"""Generate comprehensive tests for this {lang} code using {test_framework}: ```{lang} {code} ``` Include: - Happy path tests - Edge cases - Error conditions - Clear test names """ tests = await generate_ai_response(prompt=prompt, model_name=actual_model) return f"# ๐Ÿงช Tests\n\n```\n{tests}\n```" except Exception as e: return f"โŒ Error: {str(e)}" tests_btn.click(fn=tests_ui, inputs=[ai_code, ai_lang, ai_model], outputs=[tests_out]) # TAB 5: Smart Prioritization with gr.Tab("๐ŸŽฏ Smart Prioritization"): prio_code = gr.Textbox(label="Code to Analyze", lines=15, placeholder="Paste your code here...") prio_lang = gr.Dropdown(["auto", "python", "javascript", "typescript"], value="auto", label="Language") prio_btn = gr.Button("๐Ÿ“Š Prioritize Issues", variant="primary") prio_stats = gr.Markdown() prio_json = gr.JSON() async def prioritize_ui(code: str, lang: str): if not code.strip(): return "โŒ Enter code", None try: if lang == "auto": lang = detect_language(code) # Analyze code first result = await _run_analyzer(code, lang) issues = result.get("issues", []) if not issues: return "โœ… No issues found!", result # Prioritize issues from src.utils.prioritization import IssuePrioritizer prioritizer = IssuePrioritizer() prioritized_issues = prioritizer.prioritize_issues(issues) stats = prioritizer.get_statistics(prioritized_issues) top_issue = prioritized_issues[0] if prioritized_issues else None output = f""" # ๐ŸŽฏ Issue Prioritization Report ## ๐Ÿ“Š Statistics - **Total Issues**: {stats['total']} - **By Severity**: Critical: {stats['by_severity'].get('critical', 0)}, High: {stats['by_severity'].get('high', 0)}, Medium: {stats['by_severity'].get('medium', 0)}, Low: {stats['by_severity'].get('low', 0)} - **Estimated Fix Time**: {stats['total_fix_time_minutes']} minutes - **Quick Wins**: {stats['quick_wins']} issues ## ๐Ÿ”ฅ Top Priority Issue """ if top_issue: metadata = top_issue.get('metadata', {}) output += f""" - **Line {top_issue['line']}**: {top_issue['message']} - **Priority Score**: {top_issue.get('priority_score', 0)} - **Severity**: {top_issue.get('priority_severity', 'unknown')} - **Fix Effort**: {metadata.get('fix_effort', 'unknown')} (~{metadata.get('fix_time_minutes', 0)} min) """ output += "\n## ๐Ÿ“‹ All Issues (Prioritized)\n\n" for i, issue in enumerate(prioritized_issues[:10], 1): severity = issue.get('priority_severity', 'unknown') output += f"{i}. **[{severity.upper()}]** Line {issue['line']}: {issue['message']} (Score: {issue.get('priority_score', 0)})\n" if len(prioritized_issues) > 10: output += f"\n... and {len(prioritized_issues) - 10} more issues" return output, {"issues": prioritized_issues, "statistics": stats} except Exception as e: import traceback return f"โŒ Error: {str(e)}\n\n{traceback.format_exc()}", None prio_btn.click(fn=prioritize_ui, inputs=[prio_code, prio_lang], outputs=[prio_stats, prio_json]) # TAB 6: Auto-Fix with gr.Tab("๐Ÿ”ง Auto-Fix"): fix_code = gr.Textbox(label="Code with Issues", lines=15, placeholder="Paste your code here...") fix_lang = gr.Dropdown(["auto", "python", "javascript", "typescript"], value="auto", label="Language") fix_btn = gr.Button("โšก Auto-Fix Issues", variant="primary") fix_results = gr.Markdown() with gr.Row(): fix_code_before = gr.Code(label="โŒ Before (Original)", lines=10, language="python", interactive=False) fix_code_after = gr.Code(label="โœ… After (Fixed)", lines=10, language="python", interactive=False) async def autofix_ui(code: str, lang: str): if not code.strip(): return "โŒ Enter code", code, code try: if lang == "auto": lang = detect_language(code) # Analyze code result = await _run_analyzer(code, lang) issues = result.get("issues", []) if not issues: return "โœ… No issues found to fix!", code, code # Apply auto-fixes using AutoFixer class from src.utils.auto_fix import AutoFixer fixer = AutoFixer() fixed_code, applied_fixes = fixer.batch_fix(code, issues) # Get manual review issues manual_review = [issue for issue in issues if not any(fix['line'] == issue.get('line') for fix in applied_fixes)] output = f""" # ๐Ÿ”ง Auto-Fix Report ## ๐Ÿ“Š Summary - **Total Issues**: {len(issues)} - **Fixed**: {len(applied_fixes)} ({len(applied_fixes)/len(issues)*100:.1f}%) - **Manual Review Needed**: {len(manual_review)} ## โœ… Fixes Applied """ for fix in applied_fixes[:10]: output += f"- Line {fix['line']}: {fix['fix_description']}\n" if len(applied_fixes) > 10: output += f"\n... and {len(applied_fixes) - 10} more fixes" if manual_review: output += "\n\n## โš ๏ธ Manual Review Required\n" for issue in manual_review[:5]: output += f"- Line {issue.get('line', 'N/A')}: {issue.get('message', 'Unknown issue')}\n" return output, code, fixed_code except Exception as e: import traceback return f"โŒ Error: {str(e)}\n\n{traceback.format_exc()}", code, code fix_btn.click(fn=autofix_ui, inputs=[fix_code, fix_lang], outputs=[fix_results, fix_code_before, fix_code_after]) # TAB 7: Duplication Detector with gr.Tab("๐Ÿ” Duplication Detection"): dup_code = gr.Textbox(label="Code to Analyze", lines=15, placeholder="Paste your code here...") dup_threshold = gr.Slider(50, 100, 85, step=5, label="Similarity Threshold (%)") dup_btn = gr.Button("๐Ÿ”Ž Detect Duplicates", variant="primary") dup_results = gr.Markdown() dup_json = gr.JSON() async def duplication_ui(code: str, threshold: int): if not code.strip(): return "โŒ Enter code", None try: from src.utils.duplication_detector import DuplicationDetector detector = DuplicationDetector(similarity_threshold=threshold / 100.0) result = detector.analyze_duplication(code) stats = result["statistics"] dup_count = result["duplicates_found"] severity = result["severity"] output = f""" # ๐Ÿ” Code Duplication Report ## ๐Ÿ“Š Statistics - **Total Lines**: {stats['total_lines']} - **Duplicated Lines**: {stats['duplicated_lines']} - **Duplication Rate**: {stats['duplication_percentage']} - **Duplicate Blocks**: {dup_count} - **Severity**: {severity.upper()} ## ๐Ÿ”„ Duplicate Blocks Found """ for i, dup in enumerate(result["duplicates"][:10], 1): output += f""" ### Block {i} (Similarity: {dup['similarity']:.1f}%) - **Location 1**: Lines {dup['block1']['start']}-{dup['block1']['end']} - **Location 2**: Lines {dup['block2']['start']}-{dup['block2']['end']} - **Suggestion**: {dup['suggestion']} """ if len(result["duplicates"]) > 10: output += f"\n... and {len(result['duplicates']) - 10} more duplicates" return output, result except Exception as e: import traceback return f"โŒ Error: {str(e)}\n\n{traceback.format_exc()}", None dup_btn.click(fn=duplication_ui, inputs=[dup_code, dup_threshold], outputs=[dup_results, dup_json]) # TAB 8: Server Info with gr.Tab("โ„น๏ธ About"): gr.Markdown(""" # ๐ŸŽจ CodeLint Premium - MCP Edition ## โœจ Features - **10 MCP Tools**: Complete analysis suite - **9 AI Models**: 3 premium โญ + 6 free ๐Ÿ†“ - **Multi-Language**: Python, JavaScript, TypeScript - **MCP Protocol**: Fully integrated FastMCP server ## ๐Ÿ”ง Tools - analyze_code, check_security, complexity_score - suggest_fixes, analyze_project, analyze_git_diff - explain_code, generate_tests, generate_docs - get_server_info ## ๐Ÿ“š Resources - Best practices guide - Security guidelines - Complexity guide --- ๐Ÿ’Ž **Premium Edition** | ๐Ÿ† **MCP Integrated** | ๐Ÿš€ **Production Ready** """) gr.Markdown("""
Powered by FastMCP Server with 9 AI models
""") return demo # ============================================================================ # RUN SERVER # ============================================================================ def main(): """Start the FastMCP server with Gradio UI""" logger.info("๐Ÿš€ Starting CodeLint Premium MCP Server...") logger.info(f"๐Ÿ“ฆ 10 tools available") logger.info(f"๐Ÿ“š 3 resources available") logger.info("๐ŸŽจ Launching Gradio UI...") # Create and mount Gradio UI demo = create_gradio_ui() # Launch Gradio demo.launch( server_name="0.0.0.0", server_port=7861, share=False, inbrowser=True ) if __name__ == "__main__": main()