File size: 3,794 Bytes
42c47d4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""MCP Tools - CodeAtlas functions exposed via MCP protocol"""

import logging
from typing import Optional

from .server import mcp
from ..core.repository import RepositoryLoader
from ..core.analyzer import CodeAnalyzer
from ..core.diagram import DiagramGenerator

logger = logging.getLogger("codeatlas.mcp.tools")


@mcp.tool()
def analyze_codebase(api_key: str, github_url: Optional[str] = None, file_path: Optional[str] = None, model_name: str = "gemini-2.5-flash") -> str:
    """Analyze a codebase and generate a Graphviz DOT architecture diagram."""
    logger.info(f"analyze_codebase: url={github_url}, file={file_path}, model={model_name}")
    
    if not github_url and not file_path:
        return "Error: Please provide either a GitHub URL or a file path."
    if not api_key:
        return "Error: API key is required."
    
    loader = RepositoryLoader()
    result = loader.load_from_file(file_path) if file_path else loader.load_from_github(github_url)
    
    if result.error:
        return f"Error: {result.error}"
    
    logger.info(f"Loaded: {result.stats.files_processed} files, {result.stats.total_characters:,} chars")
    
    analyzer = CodeAnalyzer(api_key=api_key, model_name=model_name)
    analysis = analyzer.generate_diagram(result.context)
    
    if not analysis.success:
        return f"Error: {analysis.error}"
    
    DiagramGenerator()._save_diagram(analysis.content, "raw", result.repo_name)
    return analysis.content


@mcp.tool()
def get_architecture_summary(api_key: str, github_url: Optional[str] = None, file_path: Optional[str] = None, model_name: str = "gemini-2.5-flash") -> str:
    """Generate a text summary of a codebase's architecture."""
    logger.info(f"get_architecture_summary: url={github_url}, file={file_path}")
    
    if not github_url and not file_path:
        return "Error: Please provide either a GitHub URL or a file path."
    if not api_key:
        return "Error: API key is required."
    
    loader = RepositoryLoader()
    result = loader.load_from_file(file_path) if file_path else loader.load_from_github(github_url)
    
    if result.error:
        return f"Error: {result.error}"
    
    analyzer = CodeAnalyzer(api_key=api_key, model_name=model_name)
    analysis = analyzer.generate_summary(result.context)
    
    return analysis.content if analysis.success else f"Error: {analysis.error}"


@mcp.tool()
def chat_with_codebase(api_key: str, question: str, github_url: Optional[str] = None, file_path: Optional[str] = None, model_name: str = "gemini-2.5-flash") -> str:
    """Ask questions about a codebase and get AI-powered answers."""
    logger.info(f"chat_with_codebase: question={question[:50]}...")
    
    if not github_url and not file_path:
        return "Error: Please provide either a GitHub URL or a file path."
    if not api_key:
        return "Error: API key is required."
    if not question or not question.strip():
        return "Error: Please provide a question."
    
    loader = RepositoryLoader()
    result = loader.load_from_file(file_path) if file_path else loader.load_from_github(github_url)
    
    if result.error:
        return f"Error: {result.error}"
    
    analyzer = CodeAnalyzer(api_key=api_key, model_name=model_name)
    response = analyzer.chat(question, result.context)
    
    return response.content if response.success else f"Error: {response.error}"


@mcp.tool()
def list_recent_analyses() -> str:
    """List recently analyzed codebases."""
    history = DiagramGenerator().get_history(limit=10)
    
    if not history:
        return "No recent analyses found."
    
    lines = ["Recent Analyses:"]
    for i, d in enumerate(history, 1):
        lines.append(f"{i}. {d.repo_name}{d.formatted_timestamp}")
    return "\n".join(lines)