diff --git a/mcp_codebase.py b/mcp_codebase.py index 61d64e1..cbfabdd 100644 --- a/mcp_codebase.py +++ b/mcp_codebase.py @@ -42,7 +42,7 @@ OLLAMA_BASE_URL = "http://127.0.0.1:11434" os.environ["OLLAMA_HOST"] = OLLAMA_BASE_URL os.environ["OLLAMA_API_BASE"] = OLLAMA_BASE_URL -CODEBASE_PATH = Path(os.environ.get("CODEBASE_PATH", "/home/popertots/Crussell")) # change as needed +CODEBASE_PATH = Path(os.environ.get("CODEBASE_PATH", ".")) # change as needed VECTOR_DB_PATH = Path(os.environ.get("VECTOR_DB_PATH", "./chroma_db")) BM25_INDEX_PATH = Path(os.environ.get("BM25_INDEX_PATH", "./bm25_index.json")) RAGIGNORE_PATH = CODEBASE_PATH / ".ragignore" @@ -2244,6 +2244,92 @@ Example – read_file_lines_tool("src/auth/login.py", start=45, end=60) → full Note: This tool treats / as '/home/popertots/Crussell/' so adjust paths accordingly""" return EnhancedToon.file_content_results(read_file_lines(path, start, end), path) +@mcp.tool() +def init_repo(git_url: str) -> str: + """What it does – Initialise the RAG stack with a brand‑new Git repository or update an existing one. + + The function will: + 1. Clone the repo if it does not already exist locally, + 2. Pull the latest changes if it does, + 3. Reset the global `CODEBASE_PATH` to the local clone, + 4. Remove any stale index artefacts, + 5. Re‑build the vector/BM25 indexes with the same lock‑protected flow used by `rebuild_index`, + 6. Return a human‑readable status message. + + Next steps: + • Call `health_check` to confirm that the server is ready. + • Use `search_codebase` or `find_code_references` to explore the new code. + • Use `read_file_lines_tool` to inspect any hit in detail. + """ + import shutil + from pathlib import Path + import subprocess + + # ----- 1. Determine where to clone --------------------------------- + repo_name = git_url.split('/')[-1] + if repo_name.endswith('.git'): + repo_name = repo_name[:-4] + clone_dir = Path.cwd() / repo_name + + # ----- 2. Clone / pull ----------------------------------------------- + try: + if clone_dir.exists(): + # Existing repo → pull + subprocess.run( + ["git", "-C", str(clone_dir), "pull"], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + else: + # New repo → clone + subprocess.run( + ["git", "clone", git_url], + cwd=str(Path.cwd()), + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + except subprocess.CalledProcessError as e: + return f"❌ Failed to clone/pull {git_url}: {e.stderr.strip()}" + + # ----- 3. Update the global CODEBASE_PATH -------------------------------- + global CODEBASE_PATH + CODEBASE_PATH = clone_dir + + # ----- 4. Remove stale indices ---------------------------------------- + for artefact in ("chroma_db", "bm25_index.json", "embeddings"): + artefact_path = CODEBASE_PATH / artefact + if artefact_path.exists(): + try: + if artefact_path.is_dir(): + shutil.rmtree(artefact_path) + else: + artefact_path.unlink() + except Exception as e: + logger.warning(f"Could not delete {artefact_path}: {e}") + + # ----- 5. Re‑build the index (protected by the startup lock) ------------ + try: + rebuild_index() + except Exception as e: + return f"❌ Index rebuild failed: {e}" + + # ----- 6. Report success ----------------------------------------------- + branch_name = subprocess.check_output( + ["git", "-C", str(CODEBASE_PATH), "rev-parse", "--abbrev-ref", "HEAD"], + text=True, + ).strip() + git_hash = subprocess.check_output( + ["git", "-C", str(CODEBASE_PATH), "rev-parse", "HEAD"], + text=True, + ).strip() + + return f"✅ Initialized repository at {CODEBASE_PATH} on branch {branch_name} with hash {git_hash}" + + @mcp.tool() def rebuild_index() -> str: """What it does – Re‑creates all embeddings, BM25, and metadata indexes after major code changes. @@ -2275,17 +2361,6 @@ Example – rebuild_index() → '✅ Index rebuilt (13.2 s); 11,234 chunks'""" # ----------------------------- # Startup # ----------------------------- -def startup(): - with _startup_lock: - if VECTOR_DB_PATH.exists() and BM25_INDEX_PATH.exists(): - try: - load_indexes() - except Exception as e: - logger.warning(f"Failed loading indexes: {e}; rebuilding") - build_indexes() - else: - logger.info("No existing indexes found, building from scratch...") - build_indexes() def signal_handler(sig, frame): """Handle graceful shutdown on Ctrl+C.""" @@ -2316,7 +2391,6 @@ if __name__ == "__main__": signal.signal(signal.SIGTERM, signal_handler) try: - startup() logger.info("="*60) logger.info("🚀 MCP RAG Server is ready!") logger.info("Use 'python serve_http.py' for HTTP server")