{"slug": "repo-rag-mcp-rag-over-any-git-repository-not-just-this-one", "title": "🔍 repo-rag MCP — RAG over ANY Git Repository, Not Just This One", "summary": "MachuraHarry released repo-rag MCP, a Pipe-based server that turns any Git repository into a RAG server for AI IDEs, featuring 11 tools including keyword search without API keys, cited AI answers, code symbol lookup across five languages, and file outlines, backed by persistent SQLite indexes and a read-only sandbox. The server, run via `pipe examples/repo_rag_server.pipe`, clones the repo, builds three indexes, and serves MCP over stdio, with optional OpenRouter API key for semantic search.", "body_md": "[← All posts← Alle Beiträge](../blog.html)\n\n# 🔍 repo-rag MCP — RAG over ANY Git Repository, Not Just This One\n\n**One command turns any Git repository into a full RAG server for your AI IDE: keyword search that works with zero API keys, cited AI answers, code symbol lookup across five languages, and file outlines — all backed by persistent SQLite indexes and a locked-down sandbox.**\n\n> **Related reading:** [pipe-docs MCP](pipe-docs-mcp.html) — the same architecture, but hard-wired to the Pipe language docs · [RAG in ~10 Lines](tutorial-local-rag.html) — the minimal pattern this server generalizes\n\nOur [ pipe_docs_server](pipe-docs-mcp.html) answers questions about *Pipe itself*. But the moment you work on a different project, you want the same experience there: point an AI agent at\n\n**any** repository and let it search, read, and reason about the code without dumping files into context windows. That is exactly what\n\n`examples/repo_rag_server.pipe`\n\ndoes — one Pipe file, no dependencies beyond the `docs-pipe`\n\nmodule (auto-fetched from the registry), published indexes, and a hardened sandbox.## 🚀 Quickstart: 60 seconds to your own repo RAG\n\n```\n# 1. Install Pipe (Linux/macOS/Windows)\ncurl -fsSL https://raw.githubusercontent.com/MachuraHarry/pipe/master/install.sh | sh\n\n# 2. Point it at any repository and start the MCP server (stdio)\nexport REPO_RAG_URL=\"https://github.com/your-user/your-repo\"\npipe examples/repo_rag_server.pipe\n```\n\nThe first run clones the repository shallowly, prunes junk directories, builds three persistent SQLite indexes, then locks itself into a read-only sandbox and serves MCP over stdio. Register it in your MCP client:\n\n```\n{\n  \"mcpServers\": {\n    \"repo-rag\": {\n      \"command\": \"pipe\",\n      \"args\": [\"examples/repo_rag_server.pipe\"],\n      \"env\": {\n        \"REPO_RAG_URL\": \"https://github.com/your-user/your-repo\",\n        \"OPENROUTER_API_KEY\": \"sk-or-...\"\n      }\n    }\n  }\n}\n# 1. Pipe installieren (Linux/macOS/Windows)\ncurl -fsSL https://raw.githubusercontent.com/MachuraHarry/pipe/master/install.sh | sh\n\n# 2. Auf ein beliebiges Repo zeigen und den MCP-Server starten (stdio)\nexport REPO_RAG_URL=\"https://github.com/dein-user/dein-repo\"\npipe examples/repo_rag_server.pipe\n```\n\nDer erste Lauf klont das Repository flach, entfernt Junk-Verzeichnisse, baut drei persistente SQLite-Indexe, verriegelt sich dann in eine Read-only-Sandbox und serviert MCP über stdio. Registriere den Server in deinem MCP-Client:\n\n```\n{\n  \"mcpServers\": {\n    \"repo-rag\": {\n      \"command\": \"pipe\",\n      \"args\": [\"examples/repo_rag_server.pipe\"],\n      \"env\": {\n        \"REPO_RAG_URL\": \"https://github.com/dein-user/dein-repo\",\n        \"OPENROUTER_API_KEY\": \"sk-or-...\"\n      }\n    }\n  }\n}\n```\n\n## 🧰 The tools: 11 ways into your codebase\n\n| Tool | Needs key | What it does |\n|---|---|---|\n`search_docs(query)` | optional* | Markdown search across README, docs/, wikis — semantic hybrid with a key, keyword-only without |\n`ask_docs(question)` | yes | Cited RAG answer grounded in the documentation |\n`read_doc(path)` | no | Read any Markdown file |\n`list_docs()` | no | List all discovered `.md` /`.mdx` files |\n`search_code(query)` | no | Find functions, types, classes, structs, enums, tests in Go, Pipe, Python, JS/TS, Rust + generic fallback |\n`file_symbols(path)` | no | New: outline of ONE file — every indexed declaration with kind, name, line and declaration text |\n`read_source(path, offset)` | no | Source view with line numbers, paginated at 500 lines |\n`list_sources()` | no | All recognized source files |\n`repo_info()` | no | URL, ref, detected languages, readiness |\n`index_status()` | no | Index statistics + last sync counts |\n`refresh_index()` | no | Incremental re-sync from the cached checkout |\n\n\\* keyword mode needs no key at all — the documentation of any public repo is searchable out of the box.\n\nThe typical agent loop looks like: `list_sources`\n\n→ `file_symbols(\"pkg/server/handler.go\")`\n\nto understand a file's structure → `read_source`\n\nfor the interesting region → `search_code`\n\nwhen hunting for a name. Every answer stays small and targeted instead of flooding the context window.\n\n| Tool | Key nötig | Was es tut |\n|---|---|---|\n`search_docs(query)` | optional* | Markdown-Suche über README, docs/, Wikis — semantisch-hybrid mit Key, sonst rein per Keyword |\n`ask_docs(question)` | ja | Zitierte RAG-Antwort auf Basis der Doku |\n`read_doc(path)` | nein | Beliebige Markdown-Datei lesen |\n`list_docs()` | nein | Alle gefundenen `.md` /`.mdx` -Dateien |\n`search_code(query)` | nein | Functions, Types, Classes, Structs, Enums, Tests in Go, Pipe, Python, JS/TS, Rust + generischem Fallback |\n`file_symbols(path)` | nein | Neu: Outline einer Datei — jede indizierte Deklaration mit Art, Name, Zeile und Deklarationstext |\n`read_source(path, offset)` | nein | Quellcode-Ansicht mit Zeilennummern, paginiert à 500 Zeilen |\n`list_sources()` | nein | Alle erkannten Quelldateien |\n`repo_info()` | nein | URL, Ref, erkannte Sprachen, Bereitschaft |\n`index_status()` | nein | Index-Statistiken + letzte Sync-Counts |\n`refresh_index()` | nein | Inkrementeller Re-Sync aus dem gecachten Checkout |\n\n\\* Der Keyword-Modus braucht gar keinen Key — die Doku jedes öffentlichen Repos ist damit out-of-the-box durchsuchbar.\n\nDie typische Agent-Schleife: `list_sources`\n\n→ `file_symbols(\"pkg/server/handler.go\")`\n\nzum Verstehen der Dateistruktur → `read_source`\n\nfür die interessante Region → `search_code`\n\nbei der Jagd nach einem Namen. Jede Antwort bleibt klein und gezielt, statt das Kontextfenster zu fluten.\n\n## ⚙️ Under the hood: three SQLite indexes, zero re-indexing pain\n\nOn startup the server builds up to three persistent databases in its cache directory:\n\n— every declaration (function, class, struct, enum, test) with file, line range, language and source text. Synced incrementally: each file's SHA-256 decides whether it gets rescanned, so a warm start costs a few hash checks.`code.db`\n\n— heading-aware Markdown chunks for keyword retrieval. Works with`docs-kw.db`\n\n**no API key whatsoever**; scores weight heading hits 3× and normalize by query token count so single-hit chunks don't truncate to zero.— semantic embedding index via`docs.db`\n\n`docs-pipe`\n\n, only built when a provider with an embeddings endpoint is configured.\n\nPersistence has one subtlety: the pure-Pipe sqlite module flushes on `db_close`\n\n, while serve handles stay open for the process lifetime. The server therefore runs each index through a throwaway build handle whose close persists, then reopens a serving handle — and if the filesystem is already read-only at that point, a `try/catch`\n\nfalls back to in-memory resync. A killed process loses nothing; a restart reports `unchanged: N`\n\ninstead of re-indexing.\n\nBeim Start baut der Server bis zu drei persistente Datenbanken in seinem Cache-Verzeichnis:\n\n— jede Deklaration (Funktion, Klasse, Struct, Enum, Test) mit Datei, Zeilenbereich, Sprache und Quelltext. Inkrementell synchronisiert: Der SHA-256 jeder Datei entscheidet über einen Rescan — ein Warm Start kostet nur wenige Hash-Prüfungen.`code.db`\n\n— Heading-bewusste Markdown-Chunks für Keyword-Retrieval. Funktioniert`docs-kw.db`\n\n**ganz ohne API-Key**; Scores gewichten Heading-Treffer 3× und normalisieren über die Query-Token, sodass Ein-Treffer-Chunks nicht auf Score 0 abschneiden.— semantischer Embedding-Index via`docs.db`\n\n`docs-pipe`\n\n, nur gebaut wenn ein Provider mit Embeddings-Endpunkt konfiguriert ist.\n\nBei der Persistenz gibt es einen Kniff: Das Pure-Pipe-sqlite-Modul flushed bei `db_close`\n\n, während Serve-Handles prozesslang offen bleiben. Deshalb läuft jeder Index durch einen Wegwerf-Build-Handle, dessen `close`\n\npersistiert, danach wird ein frisches Serve-Handle geöffnet — und wenn das Filesystem zu dem Zeitpunkt schon read-only ist, fängt ein `try/catch`\n\ndas mit In-Memory-Resync ab. Ein gekillter Prozess verliert nichts; ein Neustart meldet `unchanged: N`\n\nstatt neu zu indizieren.\n\n## 🔒 Security: least privilege by construction\n\nAn MCP server that clones arbitrary repositories must be paranoid. The server declares two sandbox profiles and locks the harder one before serving:\n\n(startup): filesystem full, exec restricted to`rag-build`\n\n`git`\n\nand`rm`\n\n, network limited to Git hosts and AI provider APIs. The repository URL is validated against a strict character allowlist *before* it ever touches a shell command.(locked): filesystem read-only, exec completely disabled, network narrowed to the configured AI providers. Even a prompt-injected model cannot write files, run commands, or phone home elsewhere.`rag-serve`\n\nPath arguments pass through a resolver gate that rejects absolute paths and `..`\n\ntraversal, so `read_source(\"/etc/passwd\")`\n\nfails cleanly.\n\nEin MCP-Server, der beliebige Repositories klont, muss paranoid sein. Der Server deklariert zwei Sandbox-Profile und verriegelt das härtere, bevor er serviert:\n\n(Startup): Filesystem voll, exec auf`rag-build`\n\n`git`\n\nund`rm`\n\nbeschränkt, Netz auf Git-Hosts und AI-Provider-APIs begrenzt. Die Repository-URL wird *vor* jedem Shell-Kontakt gegen eine strikte Zeichen-Allowlist validiert.(verriegelt): Filesystem read-only, exec komplett deaktiviert, Netz auf die konfigurierten AI-Provider eingedampft. Selbst ein prompt-injiziertes Modell kann keine Dateien schreiben, keine Kommandos ausführen und nirgendwohin telefonieren.`rag-serve`\n\nPfad-Argumente laufen durch ein Resolver-Gate, das absolute Pfade und `..`\n\n-Traversal ablehnt — `read_source(\"/etc/passwd\")`\n\nscheitert sauber.\n\n## 🤖 AI providers: including OpenRouter free models\n\nAny of three keys enables the AI tier:\n\n/`DEEPSEEK_API_KEY`\n\n— full experience: semantic hybrid`OPENAI_API_KEY`\n\n`search_docs`\n\nplus grounded`ask_docs`\n\n.— chat completions through OpenRouter, ideal with the free tier. Set`OPENROUTER_API_KEY`\n\n`REPO_RAG_MODEL`\n\nto pick a model (default`nvidia/nemotron-3-super-120b-a12b:free`\n\n; browse others with the`:free`\n\nsuffix).\n\nOne honest caveat: OpenRouter exposes **no embeddings endpoint**, so the semantic layer stays dormant there. Instead of letting answers degrade to general knowledge, `ask_docs`\n\ndetects empty semantic retrieval and falls back to the keyword chunk index — answers remain grounded in the actual repository with numbered citations:\n\n```\n{\n  \"answer\": \"Widgets are components or concepts described as great in the Alpha Doc [1] and explored in detail—including their lifecycle and tips—in the Beta Doc [2].\",\n  \"sources\": [\n    { \"path\": \"a.md\", \"score\": 0.4, \"line_start\": 1 },\n    { \"path\": \"b.md\", \"score\": 0.2, \"line_start\": 1 }\n  ]\n}\n```\n\nReal output from a live test against a two-file fixture repository, produced by a free-tier model. Free models share an upstream rate-limit pool, so expect occasional 429s — pick another `:free`\n\nslug via `REPO_RAG_MODEL`\n\nor retry shortly.\n\nDrei Keys schalten die KI-Ebene frei:\n\n/`DEEPSEEK_API_KEY`\n\n— das volle Erlebnis: semantisch-hybrides`OPENAI_API_KEY`\n\n`search_docs`\n\nplus grounded`ask_docs`\n\n.— Chat-Completions über OpenRouter, ideal für den Free-Tier. Mit`OPENROUTER_API_KEY`\n\n`REPO_RAG_MODEL`\n\nwählst du das Modell (Default`nvidia/nemotron-3-super-120b-a12b:free`\n\n; weitere mit`:free`\n\n-Suffix).\n\nEin ehrlicher Hinweis: OpenRouter bietet **keinen Embeddings-Endpunkt**, dort bleibt also die semantische Ebene außen vor. Statt Antworten aufs Allgemeinwissen abrutschen zu lassen, erkennt `ask_docs`\n\ndie leere semantische Treffermenge und fällt auf den Keyword-Chunks-Index zurück — Antworten bleiben im echten Repository verankert, mit nummerierten Zitationen (siehe JSON-Beispiel oben).\n\nEchte Ausgabe eines Live-Tests gegen ein Zwei-Dateien-Fixture-Repo, produziert von einem Free-Tier-Model. Free-Models teilen sich einen Upstream-Rate-Limit-Pool — gelegentliche 429s sind normal: entweder kurz warten oder über `REPO_RAG_MODEL`\n\neinen anderen `:free`\n\n-Slug wählen.\n\n## ✅ Quality: parity-tested, not vibes-tested\n\nThe server ships with a 41-test suite (`scripts/repo-rag-code-index-test.pipe`\n\n) covering chunking, syncing, searching and persistence. The suite runs byte-identically under the tree-walker **and** the bytecode VM — which is not a given: getting there surfaced and fixed four real engine bugs (module symbol isolation, a while-body terminator defect, builtin masking in module scope, and double-emitted index operands). The server itself was smoke-tested end-to-end over stdio JSON-RPC: cold start, warm start, cited AI answers against a live OpenRouter key, sandbox-locked refreshes.\n\nDer Server kommt mit einer 41-Test-Suite (`scripts/repo-rag-code-index-test.pipe`\n\n): Chunking, Sync, Suche und Persistenz. Sie läuft byte-identisch unter dem Tree-Walker **und** der Bytecode-VM — was nicht selbstverständlich ist: Auf dem Weg dorthin kamen vier echte Engine-Bugs ans Licht (Modul-Symbol-Isolation, ein While-Body-Terminator-Defekt, Builtin-Masking im Modul-Scope und doppelt emittierte Index-Operanden). Der Server selbst wurde End-to-End per stdio-JSON-RPC gesmoket: Cold Start, Warm Start, zitierte KI-Antworten gegen einen echten OpenRouter-Key, Sandbox-verriegelte Refreshes.\n\n## 🗺️ Try it\n\nEverything lives in the repository:\n\n- Server:\n`examples/repo_rag_server.pipe`\n\n- Library:\n`examples/lib/repo_rag_lib.pipe`\n\n- Test suite:\n`scripts/repo-rag-code-index-test.pipe`\n\n- Docs: MCP chapter §25.8 in\n`docs/en/25-mcp.md`\n\nClone Pipe, export `REPO_RAG_URL`\n\n, run the server, and give your AI IDE eyes into any codebase. If you build something with it — or want more tools (reference search? git-log integration?) — issues and PRs are welcome.\n\nAlles liegt im Repository:\n\n- Server:\n`examples/repo_rag_server.pipe`\n\n- Bibliothek:\n`examples/lib/repo_rag_lib.pipe`\n\n- Test-Suite:\n`scripts/repo-rag-code-index-test.pipe`\n\n- Doku: MCP-Kapitel §25.8 in\n`docs/de/25-mcp.md`\n\nPipe klonen, `REPO_RAG_URL`\n\nexportieren, Server starten — und deiner KI-IDE Augen in jede Codebase geben. Wenn du etwas damit baust — oder mehr Tools willst (Referenzsuche? git-log-Integration?) — Issues und PRs sind willkommen.\n\n# 🔍 repo-rag MCP — RAG über ein BELIEBIGES Git-Repository, nicht nur über dieses\n\n**Ein Befehl verwandelt ein beliebiges Git-Repository in einen vollwertigen RAG-Server für deine KI-IDE: Keyword-Suche ganz ohne API-Key, zitierte KI-Antworten, Code-Symbol-Lookup in fünf Sprachen und File-Outlines — alles auf persistenten SQLite-Indexen und in einer verriegelten Sandbox.**\n\n> **Weiterlesen:** [pipe-docs MCP](pipe-docs-mcp.html) — dieselbe Architektur, aber fest auf die Pipe-Doku verdrahtet · [RAG in ~10 Zeilen](tutorial-local-rag.html) — das minimale Muster, das dieser Server verallgemeinert\n\nUnser [ pipe_docs_server](pipe-docs-mcp.html) beantwortet Fragen zu *Pipe selbst*. Aber sobald du an einem anderen Projekt arbeitest, willst du dort dasselbe Erlebnis: einen KI-Agenten auf\n\n**ein beliebiges** Repository zeigen lassen und ihn suchen, lesen und über den Code nachdenken lassen — ohne Dateien in Kontextfenster zu kippen. Genau das macht\n\n`examples/repo_rag_server.pipe`\n\n: eine Pipe-Datei, keine Abhängigkeiten außer dem `docs-pipe`\n\n-Modul (holt sich der Registry automatisch), publizierte Indexe und eine gehärtete Sandbox.\n\n```\n# 1. Install Pipe (Linux/macOS/Windows)\ncurl -fsSL https://raw.githubusercontent.com/MachuraHarry/pipe/master/install.sh | sh\n\n# 2. Point it at any repository and start the MCP server (stdio)\nexport REPO_RAG_URL=\"https://github.com/your-user/your-repo\"\npipe examples/repo_rag_server.pipe\n```\n\nThe first run clones the repository shallowly, prunes junk directories, builds three persistent SQLite indexes, then locks itself into a read-only sandbox and serves MCP over stdio. Register it in your MCP client:\n\n```\n{\n  \"mcpServers\": {\n    \"repo-rag\": {\n      \"command\": \"pipe\",\n      \"args\": [\"examples/repo_rag_server.pipe\"],\n      \"env\": {\n        \"REPO_RAG_URL\": \"https://github.com/your-user/your-repo\",\n        \"OPENROUTER_API_KEY\": \"sk-or-...\"\n      }\n    }\n  }\n}\n```\n\n## 🚀 Quickstart: In 60 Sekunden zum eigenen Repo-RAG\n\n```\n# 1. Pipe installieren (Linux/macOS/Windows)\ncurl -fsSL https://raw.githubusercontent.com/MachuraHarry/pipe/master/install.sh | sh\n\n# 2. Auf ein beliebiges Repo zeigen und den MCP-Server starten (stdio)\nexport REPO_RAG_URL=\"https://github.com/dein-user/dein-repo\"\npipe examples/repo_rag_server.pipe\n```\n\nDer erste Lauf klont das Repository flach, entfernt Junk-Verzeichnisse, baut drei persistente SQLite-Indexe, verriegelt sich dann in eine Read-only-Sandbox und serviert MCP über stdio. Registriere den Server in deinem MCP-Client:\n\n```\n{\n  \"mcpServers\": {\n    \"repo-rag\": {\n      \"command\": \"pipe\",\n      \"args\": [\"examples/repo_rag_server.pipe\"],\n      \"env\": {\n        \"REPO_RAG_URL\": \"https://github.com/dein-user/dein-repo\",\n        \"OPENROUTER_API_KEY\": \"sk-or-...\"\n      }\n    }\n  }\n}\n```\n\n| Tool | Needs key | What it does |\n|---|---|---|\n`search_docs(query)` | optional* | Markdown search across README, docs/, wikis — semantic hybrid with a key, keyword-only without |\n`ask_docs(question)` | yes | Cited RAG answer grounded in the documentation |\n`read_doc(path)` | no | Read any Markdown file |\n`list_docs()` | no | List all discovered `.md` /`.mdx` files |\n`search_code(query)` | no | Find functions, types, classes, structs, enums, tests in Go, Pipe, Python, JS/TS, Rust + generic fallback |\n`file_symbols(path)` | no | New: outline of ONE file — every indexed declaration with kind, name, line and declaration text |\n`read_source(path, offset)` | no | Source view with line numbers, paginated at 500 lines |\n`list_sources()` | no | All recognized source files |\n`repo_info()` | no | URL, ref, detected languages, readiness |\n`index_status()` | no | Index statistics + last sync counts |\n`refresh_index()` | no | Incremental re-sync from the cached checkout |\n\n\\* keyword mode needs no key at all — the documentation of any public repo is searchable out of the box.\n\nThe typical agent loop looks like: `list_sources`\n\n→ `file_symbols(\"pkg/server/handler.go\")`\n\nto understand a file's structure → `read_source`\n\nfor the interesting region → `search_code`\n\nwhen hunting for a name. Every answer stays small and targeted instead of flooding the context window.\n\n## 🧰 Die Tools: 11 Wege in deine Codebase\n\n| Tool | Key nötig | Was es tut |\n|---|---|---|\n`search_docs(query)` | optional* | Markdown-Suche über README, docs/, Wikis — semantisch-hybrid mit Key, sonst rein per Keyword |\n`ask_docs(question)` | ja | Zitierte RAG-Antwort auf Basis der Doku |\n`read_doc(path)` | nein | Beliebige Markdown-Datei lesen |\n`list_docs()` | nein | Alle gefundenen `.md` /`.mdx` -Dateien |\n`search_code(query)` | nein | Functions, Types, Classes, Structs, Enums, Tests in Go, Pipe, Python, JS/TS, Rust + generischem Fallback |\n`file_symbols(path)` | nein | Neu: Outline einer Datei — jede indizierte Deklaration mit Art, Name, Zeile und Deklarationstext |\n`read_source(path, offset)` | nein | Quellcode-Ansicht mit Zeilennummern, paginiert à 500 Zeilen |\n`list_sources()` | nein | Alle erkannten Quelldateien |\n`repo_info()` | nein | URL, Ref, erkannte Sprachen, Bereitschaft |\n`index_status()` | nein | Index-Statistiken + letzte Sync-Counts |\n`refresh_index()` | nein | Inkrementeller Re-Sync aus dem gecachten Checkout |\n\n\\* Der Keyword-Modus braucht gar keinen Key — die Doku jedes öffentlichen Repos ist damit out-of-the-box durchsuchbar.\n\nDie typische Agent-Schleife: `list_sources`\n\n→ `file_symbols(\"pkg/server/handler.go\")`\n\nzum Verstehen der Dateistruktur → `read_source`\n\nfür die interessante Region → `search_code`\n\nbei der Jagd nach einem Namen. Jede Antwort bleibt klein und gezielt, statt das Kontextfenster zu fluten.\n\nOn startup the server builds up to three persistent databases in its cache directory:\n\n— every declaration (function, class, struct, enum, test) with file, line range, language and source text. Synced incrementally: each file's SHA-256 decides whether it gets rescanned, so a warm start costs a few hash checks.`code.db`\n\n— heading-aware Markdown chunks for keyword retrieval. Works with`docs-kw.db`\n\n**no API key whatsoever**; scores weight heading hits 3× and normalize by query token count so single-hit chunks don't truncate to zero.— semantic embedding index via`docs.db`\n\n`docs-pipe`\n\n, only built when a provider with an embeddings endpoint is configured.\n\nPersistence has one subtlety: the pure-Pipe sqlite module flushes on `db_close`\n\n, while serve handles stay open for the process lifetime. The server therefore runs each index through a throwaway build handle whose close persists, then reopens a serving handle — and if the filesystem is already read-only at that point, a `try/catch`\n\nfalls back to in-memory resync. A killed process loses nothing; a restart reports `unchanged: N`\n\ninstead of re-indexing.\n\n## ⚙️ Unter der Haube: drei SQLite-Indexe, kein Re-Indexierungs-Stress\n\nBeim Start baut der Server bis zu drei persistente Datenbanken in seinem Cache-Verzeichnis:\n\n— jede Deklaration (Funktion, Klasse, Struct, Enum, Test) mit Datei, Zeilenbereich, Sprache und Quelltext. Inkrementell synchronisiert: Der SHA-256 jeder Datei entscheidet über einen Rescan — ein Warm Start kostet nur wenige Hash-Prüfungen.`code.db`\n\n— Heading-bewusste Markdown-Chunks für Keyword-Retrieval. Funktioniert`docs-kw.db`\n\n**ganz ohne API-Key**; Scores gewichten Heading-Treffer 3× und normalisieren über die Query-Token, sodass Ein-Treffer-Chunks nicht auf Score 0 abschneiden.— semantischer Embedding-Index via`docs.db`\n\n`docs-pipe`\n\n, nur gebaut wenn ein Provider mit Embeddings-Endpunkt konfiguriert ist.\n\nBei der Persistenz gibt es einen Kniff: Das Pure-Pipe-sqlite-Modul flushed bei `db_close`\n\n, während Serve-Handles prozesslang offen bleiben. Deshalb läuft jeder Index durch einen Wegwerf-Build-Handle, dessen `close`\n\npersistiert, danach wird ein frisches Serve-Handle geöffnet — und wenn das Filesystem zu dem Zeitpunkt schon read-only ist, fängt ein `try/catch`\n\ndas mit In-Memory-Resync ab. Ein gekillter Prozess verliert nichts; ein Neustart meldet `unchanged: N`\n\nstatt neu zu indizieren.\n\nAn MCP server that clones arbitrary repositories must be paranoid. The server declares two sandbox profiles and locks the harder one before serving:\n\n(startup): filesystem full, exec restricted to`rag-build`\n\n`git`\n\nand`rm`\n\n, network limited to Git hosts and AI provider APIs. The repository URL is validated against a strict character allowlist *before* it ever touches a shell command.(locked): filesystem read-only, exec completely disabled, network narrowed to the configured AI providers. Even a prompt-injected model cannot write files, run commands, or phone home elsewhere.`rag-serve`\n\nPath arguments pass through a resolver gate that rejects absolute paths and `..`\n\ntraversal, so `read_source(\"/etc/passwd\")`\n\nfails cleanly.\n\n## 🔒 Sicherheit: Least Privilege by Construction\n\nEin MCP-Server, der beliebige Repositories klont, muss paranoid sein. Der Server deklariert zwei Sandbox-Profile und verriegelt das härtere, bevor er serviert:\n\n(Startup): Filesystem voll, exec auf`rag-build`\n\n`git`\n\nund`rm`\n\nbeschränkt, Netz auf Git-Hosts und AI-Provider-APIs begrenzt. Die Repository-URL wird *vor* jedem Shell-Kontakt gegen eine strikte Zeichen-Allowlist validiert.(verriegelt): Filesystem read-only, exec komplett deaktiviert, Netz auf die konfigurierten AI-Provider eingedampft. Selbst ein prompt-injiziertes Modell kann keine Dateien schreiben, keine Kommandos ausführen und nirgendwohin telefonieren.`rag-serve`\n\nPfad-Argumente laufen durch ein Resolver-Gate, das absolute Pfade und `..`\n\n-Traversal ablehnt — `read_source(\"/etc/passwd\")`\n\nscheitert sauber.\n\nAny of three keys enables the AI tier:\n\n/`DEEPSEEK_API_KEY`\n\n— full experience: semantic hybrid`OPENAI_API_KEY`\n\n`search_docs`\n\nplus grounded`ask_docs`\n\n.— chat completions through OpenRouter, ideal with the free tier. Set`OPENROUTER_API_KEY`\n\n`REPO_RAG_MODEL`\n\nto pick a model (default`nvidia/nemotron-3-super-120b-a12b:free`\n\n; browse others with the`:free`\n\nsuffix).\n\nOne honest caveat: OpenRouter exposes **no embeddings endpoint**, so the semantic layer stays dormant there. Instead of letting answers degrade to general knowledge, `ask_docs`\n\ndetects empty semantic retrieval and falls back to the keyword chunk index — answers remain grounded in the actual repository with numbered citations:\n\n```\n{\n  \"answer\": \"Widgets are components or concepts described as great in the Alpha Doc [1] and explored in detail—including their lifecycle and tips—in the Beta Doc [2].\",\n  \"sources\": [\n    { \"path\": \"a.md\", \"score\": 0.4, \"line_start\": 1 },\n    { \"path\": \"b.md\", \"score\": 0.2, \"line_start\": 1 }\n  ]\n}\n```\n\nReal output from a live test against a two-file fixture repository, produced by a free-tier model. Free models share an upstream rate-limit pool, so expect occasional 429s — pick another `:free`\n\nslug via `REPO_RAG_MODEL`\n\nor retry shortly.\n\n## 🤖 AI-Provider: inklusive OpenRouter-Free-Models\n\nDrei Keys schalten die KI-Ebene frei:\n\n/`DEEPSEEK_API_KEY`\n\n— das volle Erlebnis: semantisch-hybrides`OPENAI_API_KEY`\n\n`search_docs`\n\nplus grounded`ask_docs`\n\n.— Chat-Completions über OpenRouter, ideal für den Free-Tier. Mit`OPENROUTER_API_KEY`\n\n`REPO_RAG_MODEL`\n\nwählst du das Modell (Default`nvidia/nemotron-3-super-120b-a12b:free`\n\n; weitere mit`:free`\n\n-Suffix).\n\nEin ehrlicher Hinweis: OpenRouter bietet **keinen Embeddings-Endpunkt**, dort bleibt also die semantische Ebene außen vor. Statt Antworten aufs Allgemeinwissen abrutschen zu lassen, erkennt `ask_docs`\n\ndie leere semantische Treffermenge und fällt auf den Keyword-Chunks-Index zurück — Antworten bleiben im echten Repository verankert, mit nummerierten Zitationen (siehe JSON-Beispiel oben).\n\nEchte Ausgabe eines Live-Tests gegen ein Zwei-Dateien-Fixture-Repo, produziert von einem Free-Tier-Model. Free-Models teilen sich einen Upstream-Rate-Limit-Pool — gelegentliche 429s sind normal: entweder kurz warten oder über `REPO_RAG_MODEL`\n\neinen anderen `:free`\n\n-Slug wählen.\n\nThe server ships with a 41-test suite (`scripts/repo-rag-code-index-test.pipe`\n\n) covering chunking, syncing, searching and persistence. The suite runs byte-identically under the tree-walker **and** the bytecode VM — which is not a given: getting there surfaced and fixed four real engine bugs (module symbol isolation, a while-body terminator defect, builtin masking in module scope, and double-emitted index operands). The server itself was smoke-tested end-to-end over stdio JSON-RPC: cold start, warm start, cited AI answers against a live OpenRouter key, sandbox-locked refreshes.\n\n## ✅ Qualität: Parität statt Vibes\n\nDer Server kommt mit einer 41-Test-Suite (`scripts/repo-rag-code-index-test.pipe`\n\n): Chunking, Sync, Suche und Persistenz. Sie läuft byte-identisch unter dem Tree-Walker **und** der Bytecode-VM — was nicht selbstverständlich ist: Auf dem Weg dorthin kamen vier echte Engine-Bugs ans Licht (Modul-Symbol-Isolation, ein While-Body-Terminator-Defekt, Builtin-Masking im Modul-Scope und doppelt emittierte Index-Operanden). Der Server selbst wurde End-to-End per stdio-JSON-RPC gesmoket: Cold Start, Warm Start, zitierte KI-Antworten gegen einen echten OpenRouter-Key, Sandbox-verriegelte Refreshes.\n\nEverything lives in the repository:\n\n- Server:\n`examples/repo_rag_server.pipe`\n\n- Library:\n`examples/lib/repo_rag_lib.pipe`\n\n- Test suite:\n`scripts/repo-rag-code-index-test.pipe`\n\n- Docs: MCP chapter §25.8 in\n`docs/en/25-mcp.md`\n\nClone Pipe, export `REPO_RAG_URL`\n\n, run the server, and give your AI IDE eyes into any codebase. If you build something with it — or want more tools (reference search? git-log integration?) — issues and PRs are welcome.\n\n## 🗺️ Ausprobieren\n\nAlles liegt im Repository:\n\n- Server:\n`examples/repo_rag_server.pipe`\n\n- Bibliothek:\n`examples/lib/repo_rag_lib.pipe`\n\n- Test-Suite:\n`scripts/repo-rag-code-index-test.pipe`\n\n- Doku: MCP-Kapitel §25.8 in\n`docs/de/25-mcp.md`\n\nPipe klonen, `REPO_RAG_URL`\n\nexportieren, Server starten — und deiner KI-IDE Augen in jede Codebase geben. Wenn du etwas damit baust — oder mehr Tools willst (Referenzsuche? git-log-Integration?) — Issues und PRs sind willkommen.", "url": "https://wpnews.pro/news/repo-rag-mcp-rag-over-any-git-repository-not-just-this-one", "canonical_source": "https://pipe-lang.com/blog/repo-rag-mcp.html", "published_at": "2026-08-23 00:00:00+00:00", "updated_at": "2026-08-23 13:13:32.619553+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "generative-ai", "artificial-intelligence"], "entities": ["MachuraHarry", "Pipe", "repo-rag MCP", "SQLite", "OpenRouter"], "alternates": {"html": "https://wpnews.pro/news/repo-rag-mcp-rag-over-any-git-repository-not-just-this-one", "markdown": "https://wpnews.pro/news/repo-rag-mcp-rag-over-any-git-repository-not-just-this-one.md", "text": "https://wpnews.pro/news/repo-rag-mcp-rag-over-any-git-repository-not-just-this-one.txt", "jsonld": "https://wpnews.pro/news/repo-rag-mcp-rag-over-any-git-repository-not-just-this-one.jsonld"}}