mcp-local-rag
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-local-rag find where the function parseJson is defined"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP Local RAG
π΄ Forked from shinpr/mcp-local-rag β original work by Shinsuke Kagawa
Local code intelligence engine for AI coding assistants. AST-level semantic chunking + keyword boost for pinpointing functions, classes, and APIs β fully private, zero setup.
π δΈζζζ‘£
Table of Contents
4.1 Ingest Tools
4.2 Search Tools
4.3 Management Tools
4.5 System Tools
5.1 Basic Commands
Related MCP server: lynx-mcp
1. Features
Smart dual-strategy chunking β AST-level code chunking via tree-sitter (splits at function/class/method boundaries, injects scope chain + imports). Semantic chunking for documents (splits by meaning, not character count).
Semantic search + keyword boost β Vector search first, then keyword matching boosts exact terms.
useEffect, error codes, class names rank higher β not just semantically guessed.15 MCP tools β Ingest, search, manage, code intelligence, and system ops in one server.
AST code intelligence β
find_definitionandfind_referencesfor IDE-level code navigation, powered by tree-sitter metadata captured at ingest time.Three-tier mirror auto-fallback β
huggingface.co β hf-mirror.com β modelscope.cn, zero config for users in mainland China.Runs entirely locally β No API keys, no cloud, no data leaving your machine. Works offline after the first model download.
Zero-friction setup β One
npxcommand. No Docker, Python, or servers to manage.
2. Quick Start
Set BASE_DIR to the folder you want to search (BASE_DIRS for multiple roots β see Configuration).
2.1 Configure Your AI Coding Tool
Cursor β ~/.cursor/mcp.json:
{
"mcpServers": {
"local-rag": {
"command": "npx",
"args": ["-y", "@damoqiongqiu/mcp-local-rag"],
"env": { "BASE_DIR": "/path/to/your/project" }
}
}
}Claude Code:
claude mcp add local-rag --scope user --env BASE_DIR=/path/to/your/project -- npx -y @damoqiongqiu/mcp-local-ragCodex β ~/.codex/config.toml:
[mcp_servers.local-rag]
command = "npx"
args = ["-y", "@damoqiongqiu/mcp-local-rag"]
[mcp_servers.local-rag.env]
BASE_DIR = "/path/to/your/project"WorkBuddy β Settings β Custom Connectors β Add:
{
"mcpServers": {
"local-rag": {
"command": "npx",
"args": ["-y", "@damoqiongqiu/mcp-local-rag"],
"env": { "BASE_DIR": "/path/to/your/project" }
}
}
}β οΈ WorkBuddy: you MUST click "Trust" in the Custom Connectors list after adding, otherwise the server is silently blocked.
2.2 CLI Quick Start
No MCP needed β run directly from the terminal:
npx @damoqiongqiu/mcp-local-rag ingest ./src/
npx @damoqiongqiu/mcp-local-rag query "auth middleware"
npx @damoqiongqiu/mcp-local-rag statusThat's it. No Docker, Python, or server setup.
2.3 First-Time Project Indexing
You: "Index the src directory of this project"
Assistant: Successfully ingested 156 files (2,847 chunks created)
You: "Where's the middleware that handles API rate limiting?"
Assistant: src/middleware/rateLimiter.ts β useRateLimiter(), lines 42β89
You: "How is the database connection pool configured?"
Assistant: src/config/database.ts β createPool() default max: 20, idle: 53. Core Concepts
3.1 Dual-Strategy Chunking
Chunking strategy is chosen per file type:
Code files (50+ languages) β
CodeChunkerparses source via tree-sitter AST, splits at structural boundaries (functions, classes, methods). Each chunk'scontextualizedTextincludes its scope chain and import context for precise semantic search.Documents (PDF/DOCX/TXT/MD/HTML) β
SemanticChunkersplits into sentences, groups by embedding similarity to find natural topic boundaries. Markdown code blocks remain intact β never split mid-block.
3.2 Hybrid Search
Search = semantic similarity + keyword boost (RAG_HYBRID_WEIGHT, default 0.6):
Query vectorization β semantic search finds most relevant chunks
Quality filters apply (distance threshold, grouping)
Keyword matching boosts exact-term rankings
Exact identifiers like useEffect are never buried by semantic approximations.
3.3 Security Boundary
Only files under BASE_DIR / BASE_DIRS are accessible for ingest, list, delete, or read-neighbor operations. Symlinks resolved outside roots are rejected. Sibling-prefix paths (e.g., /foo/barista when root is /foo/bar) are also blocked β prevents path traversal attacks.
4. MCP Tool Reference
15 tools organized into 5 categories.
4.1 Ingest Tools
# | Tool | Purpose | Example |
1 |
| Single file (PDF/DOCX/TXT/MD/code) |
|
2 |
| In-memory text/HTML |
|
3 |
| Bulk directory ingest |
|
ingest_file supports 50+ code languages. PDFs support an optional visual mode β a local VLM generates captions for figure pages, making visual content searchable. Two profiles available:
Profile | Model | Cache | Suited for |
| SmolVLM-256M | ~250 MB | Light visual indexing |
| Qwen2.5-VL-3B-ONNX | ~2.9 GB | Figures with in-image text |
# CLI
npx @damoqiongqiu/mcp-local-rag ingest ./spec.pdf --visual --visual-quality quality
# MCP
"Ingest ./spec.pdf with visual: true, visualQuality: 'quality'"ingest_data runs Readability β Markdown β index. Perfect for web content fetched by your AI assistant. Re-ingesting replaces old versions automatically.
ingest_directory scans recursively, respects .gitignore, shows real-time progress via MCP notifications.
4.2 Search Tools
# | Tool | Purpose | Key Parameters |
4 |
| Hybrid search (semantic + keyword) |
|
5 |
| Expand context around results |
|
query_documents β scope accepts a single path prefix or list, restricting results to that subtree. highlightContext returns snippets around matched terms. fromTimestamp / untilTimestamp enable time-range filtering.
read_chunk_neighbors β defaults to 2 chunks before and after (like grep -C 2), max 50 each. Response includes the target chunk marked isTarget: true.
4.3 Management Tools
# | Tool | Purpose |
6 |
| List files with ingestion status ( |
7 |
| Delete by file path or source URL |
8 |
| Index stats: docs, chunks, memory, search mode |
list_files supports scope filtering with the same prefix-match semantics as search. In large directories, scope accelerates the scan by skipping out-of-scope subtrees.
4.4 Code Intelligence
# | Tool | Purpose | Input |
9 |
| Locate symbol definition (file, line range, scope) | Exact symbol name |
10 |
| Find all references (import + text mention) | Symbol name |
Both tools depend on AST metadata (imports, entities, scope chains) extracted by tree-sitter at ingest time. Only works for code files ingested with CodeChunker β files ingested before v0.18.7 lack this metadata and require reindex_all to rebuild.
find_references uses a two-phase strategy: (1) exact match in codeMeta.imports β (2) FTS full-text search for the symbol name. Results are deduplicated by (filePath, chunkIndex), with import references listed first.
4.5 System Tools
# | Tool | Purpose |
11 |
| Runtime hot read/write config β no restart needed |
12 |
| SHA256 + Jaccard similarity to detect duplicate files |
13 |
| Export entire index as JSON (backup or migration) |
14 |
| Full re-chunk + re-embed (after model change) |
15 |
| Re-ingest only files modified on disk (incremental sync) |
config hot-swaps hybridWeight, modelName, cacheDir, baseDir/baseDirs, etc. Switching models auto-disposes the old Embedder and initializes the new one β note: changing models alters the embedding space and requires reindex_all.
dedup_check is especially useful in monorepos β spot β futures mirror code is typically flagged with similarity 1.0.
5. CLI
5.1 Basic Commands
# Ingest
npx @damoqiongqiu/mcp-local-rag ingest ./src/
# Search (with scope)
npx @damoqiongqiu/mcp-local-rag query "auth middleware"
npx @damoqiongqiu/mcp-local-rag query "auth" --scope /docs/api
# Context expansion
npx @damoqiongqiu/mcp-local-rag read-neighbors --file-path /abs/path.md --chunk-index 5
# Management
npx @damoqiongqiu/mcp-local-rag list --scope /docs/api
npx @damoqiongqiu/mcp-local-rag status
npx @damoqiongqiu/mcp-local-rag delete ./docs/old.pdf
npx @damoqiongqiu/mcp-local-rag delete --source "https://..."query, read-neighbors, list, status, delete emit JSON to stdout (pipe to jq). ingest emits progress to stderr.
Global options (--db-path, --cache-dir, --model-name) go before the subcommand:
npx @damoqiongqiu/mcp-local-rag --helpβ οΈ The CLI does NOT read your MCP client config (
mcp.json, etc.). Configure via flags or environment variables.
5.2 CLI Configuration
Flags β global options before, subcommand options after:
npx @damoqiongqiu/mcp-local-rag --db-path ./my-db query "auth" --base-dir ./docs--base-dir is repeatable on ingest and list:
npx @damoqiongqiu/mcp-local-rag ingest --base-dir ./docs --base-dir ./specs ./docs/readme.mdEnvironment variables:
export DB_PATH=./my-db
export BASE_DIR=./docs
npx @damoqiongqiu/mcp-local-rag query "auth"For multiple roots, use BASE_DIRS (JSON array):
export BASE_DIRS='["/Users/me/work","/Users/me/specs"]'Precedence: CLI flags > environment variables > defaults.
6. Network & Models
6.1 Mirror Auto-Detection
huggingface.co is inaccessible from mainland China. Built-in three-tier mirror chain with automatic fallback:
huggingface.co β hf-mirror.com β modelscope.cnAt startup, each mirror is HEAD-probed (3s timeout). The first reachable mirror with a complete API is selected:
With proxy (
HTTPS_PROXY) β direct to huggingface.coNo proxy β auto-switch to hf-mirror.com
hf-mirror API unavailable β fallback to modelscope.cn
No manual HF_ENDPOINT required. For manual control:
Env Var | Effect |
| Disable auto-detection, use huggingface.co only |
| Force a specific mirror, skip auto-detection |
v0.18.5+ uses
setGlobalDispatcher(ProxyAgent)β all Node.js 22 network requests go through the proxy.
6.2 Model Selection
6 embedding models with alias resolution via model-registry:
Model | Alias | Size | Dims |
|
| ~90 MB | 384 |
| β | ~120 MB | 384 |
|
| ~130 MB | 384 |
|
| ~420 MB | 768 |
| β | ~420 MB | 768 |
|
| ~420 MB | 768 |
Guidance: code repos β default model + high keyword boost; multilingual β consider embeddinggemma-300m; scientific papers β consider allenai-specter.
RAG_DTYPE controls ONNX precision (fp32 / fp16 / q8). Default fp32; use q8 when memory-constrained. β οΈ Changing models or dtype requires deleting DB_PATH and re-indexing.
6.3 File Watching
Set RAG_WATCH=true β the server starts recursive fs.watch on baseDirs (500ms debounce):
File creation/modification β auto
ingest_fileFile deletion β auto
delete_file
Ideal for actively changing projects.
7. Search Tuning
Variable | Default | Description |
|
| Keyword boost: 0 = semantic only, 1 = keyword only |
| unset |
|
| unset | Filter low-relevance results (e.g., |
| unset | Limit results to top N files |
Code-focused tuning (recommended default):
{ "RAG_HYBRID_WEIGHT": "0.7", "RAG_GROUPING": "similar" }Document-focused tuning:
{ "RAG_HYBRID_WEIGHT": "0.4", "RAG_GROUPING": "related" }Keyword boost is applied after semantic filtering β improves precision without introducing noise.
8. Performance Tuning
Beyond search accuracy, inference performance is also configurable. All optimizations are environment variables β no code changes required.
8.1 Quantization Precision (RAG_DTYPE)
Controls ONNX model inference precision. For all-MiniLM-L6-v2, three levels are available:
Value | Model Size | Speed | Memory | Precision Loss | Best For |
| ~90 MB | baseline | ~80 MB | none | First use, maximum accuracy |
| ~45 MB | 20-30% faster | ~45 MB | negligible | Recommended for daily use |
| ~45 MB | 30-50% faster | ~45 MB | minor | Low memory, large projects |
"env": { "RAG_DTYPE": "fp16", "BASE_DIR": "..." }β οΈ Changing dtype requires index rebuild β embedding spaces are incompatible.
Verify it works: After restart, call status via MCP and check the dtype field. Should match your setting (e.g., "fp16").
If it fails: Startup throws EmbeddingError with a list of supported dtypes. Common cause: the model doesn't provide the q8 variant β switch to fp16.
8.2 Execution Device (RAG_DEVICE)
Controls which ONNX Runtime backend to use:
Value | Backend | Notes |
| CPU | Most stable, no extra dependencies |
| GPU (WebGPU) | β οΈ Experimental: M1/M2 Mac uses Metal, NVIDIA uses Vulkan |
"env": { "RAG_DEVICE": "webgpu", "RAG_DTYPE": "fp16", "BASE_DIR": "..." }β οΈ Changing device changes the embedding space β requires index rebuild. Stacks with RAG_DTYPE β fp16 + webgpu gives both model-size reduction and GPU speedup.
Verify it works: MCP startup log should show Loading model on device "webgpu". status should show device: "webgpu".
If it fails:
Unsupported deviceat startup β WebGPU unavailable in your environment, revert to"cpu"Starts successfully but inference crashes β likely an ONNX WebGPU backend bug, revert to
"cpu"Just delete the
RAG_DEVICEline to fall back β other config is untouched
8.3 Minimum Chunk Length (CHUNK_MIN_LENGTH)
Filters out chunks shorter than this value during ingest. Default 50 keeps nearly everything; 200 drops 30-40% of noise fragments.
"env": { "CHUNK_MIN_LENGTH": "200", "BASE_DIR": "..." }β οΈ Blunt instrument β short but important code (e.g., config constants) may also be discarded. Requires index rebuild. Sweet spot: 100-200.
8.4 Recommended Configurations
Scenario | Config |
Daily development |
|
Large project + M1/M2 Mac |
|
Memory-constrained |
|
All changes require reindex_all (MCP) or re-running ingest (CLI). If something breaks, delete the failing env line to revert to defaults.
9. Configuration Reference
MCP server: environment variables only (via your MCP client's env block).
CLI: environment variables + equivalent flags (flags take precedence).
Env Var | CLI Flag | Default | Description |
|
|
| Document root (security boundary) |
| β | unset | JSON array of roots, overrides |
|
|
| Vector database path |
|
|
| Model cache β recommend absolute path |
|
|
| HuggingFace model ID |
|
| 100 MB | Max file size in bytes |
|
|
| Min chunk length (1β10000 chars) |
| β |
| ONNX execution device |
| β |
| Quantization ( |
| β | unset | Model download proxy. v0.18.5+ globally effective |
| β |
| Manual mirror override |
| β |
| Auto-detection toggle |
| β | unset | File watching ( |
Root resolution order: CLI --base-dir > BASE_DIRS > BASE_DIR > cwd. BASE_DIRS and BASE_DIR are never merged. Only JSON array syntax supported for BASE_DIRS β delimiter syntax is intentionally rejected.
10. Troubleshooting
Symptoms: fetch failed, status shows searchMode: fts instead of hybrid.
Solutions:
Network restriction (mainland China, etc.) β use proxy:
"env": { "HTTPS_PROXY": "http://127.0.0.1:7890" }Set in your MCP client config, not the terminal. v0.18.5+ globally effective via
setGlobalDispatcher.Auto-mirror fallback (v0.18.2+, default) β three-tier probe. Usually works without any config.
Manual override β
HF_ENDPOINT=https://modelscope.cnor download models manually intoCACHE_DIR.npx cached old version β clear and restart:
rm -rf ~/.npm/_npx/
Verify config file syntax
WorkBuddy users: confirm "Trust" button clicked
Restart client completely (Cmd+Q on macOS)
Test directly:
npx @damoqiongqiu/mcp-local-ragshould run without errors
After switching models or when the database is corrupted:
Stop the MCP service
Delete
DB_PATHdirectory (default./lancedb/) β safe, doesn't affect source filesRestart MCP β fresh database auto-created
Bulk re-ingest:
npx @damoqiongqiu/mcp-local-rag ingest ./src/
Private? Yes. After model download, nothing leaves your machine.
Offline? Yes, once models are cached.
Supported formats? 50+ code languages + PDF/DOCX/TXT/MD/HTML. No Excel, PPT, or images.
GPU acceleration? Opt-in via
RAG_DEVICE. Support depends on your system, Node.js version, and the ONNX backend.Backup? Copy the
DB_PATHdirectory.
11. Development
git clone https://github.com/damoqiongqiu/mcp-local-rag.git
cd mcp-local-rag
pnpm installpnpm test # All tests
pnpm run type-check # TypeScript check
pnpm run check:fix # Lint + format
pnpm run check:all # Full CI pipelinesrc/
index.ts # Entry point
server/ # MCP tool handlers
cli/ # CLI subcommands
parser/ # PDF/DOCX/TXT/MD/code parsing
chunker/ # SemanticChunker + CodeChunker
embedder/ # Transformers.js embeddings
vectordb/ # LanceDB operations
utils/ # Shared utilities (security, scan, scope)
__tests__/ # Test suitesLicense
MIT License. Free for personal and commercial use.
Acknowledgments
Built with Model Context Protocol (Anthropic), LanceDB, and Transformers.js.
Available Tools
16 toolsconfigA
Read or update runtime configuration. Without arguments, returns current config (hybridWeight, maxDistance, maxFiles, grouping). With arguments, updates the specified keys and returns the new config. Changes take effect immediately β no restart required.
Inputs: grouping, maxFiles, maxDistance, hybridWeight.
dedup_checkA
Detect near-duplicate documents in the index by computing content hashes for every chunk. Returns file pairs with high chunk overlap, sorted by similarity. Use to identify accidentally duplicated or re-ingested content.
Inputs: threshold.
delete_fileA
Delete a previously ingested file or data from the vector database. Use filePath for files ingested via ingest_file, or source for data ingested via ingest_data. Either filePath or source must be provided. Returns deleted (operation succeeded), removedChunks, and existed (whether anything was actually present).
Inputs: source, filePath.
export_indexA
Export the current index to a JSON file for backup or migration. Returns the export file path and stats (document count, chunk count, file size). The exported file can be re-imported with a future import_index tool.
Inputs: outputPath.
find_definitionA
Find where a symbol (function, class, variable, etc.) is defined in code files. Searches AST-level entity metadata extracted during code chunking. Returns { totalMatches, matches: [{ filePath, chunkIndex, entityName, entityType, lineRange?, scope? }] }. Only works for code files that were ingested with AST-level chunking (CodeChunker).
Inputs: symbolName (required).
find_referencesA
Find all references to a symbol across ingested code files using a two-phase strategy: (1) import metadata scan for exact import name matches, (2) FTS text search for in-code mentions. Results merge with import references first, deduplicated by (filePath, chunkIndex). Returns { totalMatches, matches: [{ filePath, chunkIndex, referenceType, context?, importSource?, isDefault?, isNamespace? }] }. Only works for code files ingested with AST-level chunking.
Inputs: symbolName (required), limit.
health_checkA
Diagnose server health and configuration. Checks embedder (model loaded?), LanceDB (readable?), BASE_DIRs (reachable on disk?), and cache directory (writable?). Returns structured pass/fail results with a human-readable summary and per-check fix suggestions for any failures.
Inputs: no named parameters.
ingest_dataA
Ingest in-memory content as a string (use ingest_file for files on disk). The source identifier enables re-ingestion to update existing content. Returns { filePath, chunkCount, timestamp, fileTitle }.
Inputs: content (required), metadata (required).
ingest_directoryA
Batch ingest all supported files in a directory. Recursively scans for code and document files under the given path, ingesting each one with AST-level (code) / semantic chunking. Returns per-file status plus totals. Use this for initial bulk ingestion or after deleting the database.
Inputs: path (required), extensionFilter.
ingest_fileA
Ingest a document file (PDF, DOCX, TXT, MD) into the vector database. Path must be absolute; re-ingesting the same path replaces its existing data. Returns { filePath, chunkCount, timestamp, fileTitle }.
Inputs: filePath (required), visual, visualQuality.
list_filesA
List supported files (PDF, DOCX, TXT, MD) under the configured base directories and whether each is ingested. Returns { baseDirs, files, sources }; sources lists ingested items reported apart from the file scan, chiefly ingest_data content (web pages, clipboard, etc.).
Inputs: scope, instance.
query_documentsA
Search ingested documents with hybrid keyword + semantic matching. Returns results sorted by relevance, each with filePath, chunkIndex, text, fileTitle, score (0 = best, higher = worse), and source (for ingest_data items).
Inputs: query (required), limit, scope, instance, +4 more.
read_chunk_neighborsA
Read the chunks immediately before and after a query_documents result, in the same document, for more surrounding context. Pass chunkIndex from the result plus exactly one of filePath (ingest_file) or source (ingest_data). Returns the target chunk (isTarget: true) and its neighbors, ascending by chunkIndex; an out-of-range chunkIndex returns []. Defaults: before=2, after=2 (max 50 each).
Inputs: chunkIndex (required), after, before, source, +1 more.
reindex_allA
Re-ingest ALL indexed files from scratch. Delete existing chunks, then re-ingest every previously-indexed file. Use after changing the embedding model, chunker parameters, or when the index is corrupted. This is a slow, destructive operation β prefer reindex_stale for routine updates.
Inputs: optimizeAfter.
reindex_staleA
Re-ingest all files whose disk contents have changed since the last ingestion (detected via mtime comparison). Returns the count of stale files that were re-ingested. Use when you know files have been modified but the index is out of date.
Inputs: no named parameters.
statusA
Get index status: { documentCount, chunkCount, memoryUsage (MB), uptime (s), ftsIndexEnabled, searchMode, instances }. When multiple instances are configured, pass instance name for per-instance status.
Inputs: instance.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelogβ¦
TDQS
Scored across 16 tools
Tools are largely distinct, but status and health_check both report on system state, and reindex_stale/reindex_all share a purpose though descriptions clarify the difference. Most tools target unique resource+action combinations (ingest, query, delete, list, config).
Nearly all tools follow a verb_noun pattern in snake_case (query_documents, ingest_file, delete_file, reindex_stale). Exceptions like 'status' and 'config' are bare nouns, and 'dedup_check' reverses the order, but the overall pattern is predictable.
16 tools is slightly above the typical 3-15 range but justified given the server's broad scope (ingestion, querying, index management, code analysis, configuration, health, export). Each tool serves a distinct purpose and the count feels reasonable for a full-featured RAG server.
The tool surface covers the core RAG lifecycle: multiple ingestion methods, querying with context reading, deletion, listing, reindexing (stale/all), deduplication, configuration, export, and health checks. Minor gaps exist, such as no explicit 'get_document' tool, but query_documents and read_chunk_neighbors provide adequate access. Code analysis is well-covered with find_definition and find_references.
Maintenance
Related MCP Connectors
Self-hosted AI workspace: semantic RAG document search, long-term memory, and AI chat via MCP.
Cloud or self-hosted knowledge for AI agents: hybrid search, reranking, GraphRAG, scoped MCP tools.
Code intelligence for coding agents: semantic, AST, graph, and full-text search. 279+ languages.
Shared memory MCP server for Claude Code, Codex, Gemini CLI and Cursor. Cited, editable.
Related MCP Servers
- AlicenseAqualityBmaintenanceLocal MCP server for semantic code search using Tree-sitter AST parsing, local embeddings, and hybrid search; enables indexing and querying codebases entirely offline.7MIT
- AlicenseAqualityBmaintenanceA 100% local MCP server for semantic and lexical search over your code, library docs, and PDFs, featuring hybrid BM25 and dense retrieval, syntax aware chunking, and an optional code knowledge graph. It also ships a Coral integration, so you can expose your code search as SQL and join it with live data, all without anything leaving your machine.1685 PyPI11Apache 2.0
- AlicenseAqualityDmaintenanceLocal-first MCP server for semantic + keyword hybrid code search. Zero external services, no API keys required.2MIT
- AlicenseAqualityBmaintenanceMCP server for semantic code search with AST-aware chunking, hybrid vectors, and query syntax.121Apache 2.0