Labsco
lyonzin logo

knowledge-rag

β˜… 213

from lyonzin

Local RAG system for Claude Code with hybrid search (semantic + BM25), cross-encoder reranking, markdown-aware chunking, 9 file formats, file watcher, and 12 MCP tools. Zero external servers. pip install knowledge-rag

πŸ”₯πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedFreeQuick setup

Knowledge RAG

<div align="center">

PyPI NPM PyPI Downloads Python License Platform GPU CI CodeQL Quality Gate Glama Score

Your docs, your machine, zero cloud. Claude Code searches them natively.

Drop your PDFs, markdown, code, notebooks β€” 1800+ files, 39K chunks, indexed in under 3 minutes.<br/> Hybrid search (BM25 + semantic vectors + cross-encoder reranking) through 13 MCP tools.<br/> Everything runs locally via ONNX. No Docker, no Ollama, no API keys, no data leaves your machine.

Copy & paste β€” that's it
pip install knowledge-rag β†’ restart Claude Code β†’ search_knowledge("your query")

13 MCP Tools | Hybrid Search + Reranking | 20 File Formats | Optional NVIDIA GPU | 100% Local

What's New | Supported Formats | Installation | Configuration | API Reference | Architecture

</div>

Star History

<div align="center"> <a href="https://www.star-history.com/?repos=lyonzin%2Fknowledge-rag&type=date&legend=top-left"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=lyonzin/knowledge-rag&type=date&theme=dark&legend=top-left" /> <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=lyonzin/knowledge-rag&type=date&legend=top-left" /> <img alt="Star History Chart" src="https://api.star-history.com/chart?repos=lyonzin/knowledge-rag&type=date&legend=top-left" /> </picture> </a> </div>

What's New in v4.2.0

Search Performance & Output Quality (v4.2.0)

128Γ— faster BM25 search β€” replaced rank-bm25 full-corpus scan with a custom inverted-index implementation. Only documents containing query terms are scored, using numpy.argpartition for O(n) top-k selection. Adjacent chunk fetching now uses a single batched ChromaDB call instead of N round-trips, and an O(1) reverse lookup (_source_to_docid) eliminates linear scans.

Smarter output β€” two new parameters on search_knowledge:

  • snippet_mode (default: true) β€” truncates content to ~500 characters at natural break points, reducing token consumption by ~72%. Adds content_length field with original size; use get_document() for full content.
  • min_score β€” filters results below a normalized relevance threshold (0.0–1.0). Eliminates low-quality noise from results. Response includes filtered_by_score count for transparency.

Both parameters are fully backwards-compatible (existing callers see no change in behavior).

Enterprise Concurrent Access β€” SSE/HTTP Transport (v4.0.0)

The server now supports SSE and streamable-http transport modes. Instead of spawning a separate process per client (stdio), a single server process serves all clients with shared resources β€” 1 embedding model, 1 ChromaDB, 1 query cache.

Copy & paste β€” that's it
# config.yaml
server:
  transport: "sse"        # "stdio" | "sse" | "streamable-http"
  host: "127.0.0.1"
  port: 8179

Or via CLI: knowledge-rag --transport sse

Optional enterprise features (all disabled by default):

  • Rate limiting: Sliding-window counter, configurable RPM and burst
  • Prometheus metrics: /metrics endpoint on separate port
  • Bearer auth: Token validation for SSE/HTTP connections

All 13 MCP tools are instrumented with @rate_limited and @instrument decorators β€” zero overhead when features are disabled. Default transport remains stdio for full backwards compatibility.

Migration: Existing users need zero changes. SSE mode is opt-in via server.transport: "sse" in config.yaml. See Configuration for details.

Quality Gate β€” 7-Pillar PR Validation

Every PR (including dependabot bumps and one-line fixes) is now evaluated against 35+ automated checks spread across 7 pillars before any human review:

PillarWhat it enforcesTools
1 SecuritySAST, secrets, CVEs, supply chainbandit, semgrep, gitleaks, pip-audit, dependency-review, Snyk, CodeQL, Socket
2 StabilityFlake detection, coverage trend, test count, deterministic runspytest-rerunfailures, codecov Β±0.5pp, test-count guard
3 Memory LeakRSS bounded under 1000-query load, no idle bloatpsutil-based baseline tests + nightly 50K-iteration soak
4 Versatility9 OSΓ—Python combos, 14 format parsers, 4 config presets, locale tolerance, property-based fuzzingmatrix CI on Linux+Windows+macOS Γ— 3.11+3.12+3.13, Hypothesis
5 ScalabilityPerformance regression > 10% blocks merge, public bench dashboardpytest-benchmark, GH Pages chart
6 VersioningAtomic version sync, API surface diff, conventional commits, CHANGELOG enforcement, backwards compatgriffe-style AST diff, custom guards
7 QualityType strictness, docstring coverage, complexity, dead codemypy strict, interrogate β‰₯80%, radon, vulture

Plus a nightly resilience workflow that runs chaos failure-injection (HF down, ChromaDB corruption, watchdog crash, ONNX zero-byte replay), determinism check (full suite Γ— 3), and mutation testing on selected modules.

Read the full philosophy in CONTRIBUTING.md. Report bugs via SECURITY.md or the issue templates.

Critical Hotfix β€” No More Silent Zero-Vector Corruption (v3.8.1)

FastEmbedEmbeddings.__call__ no longer swallows exceptions and returns [[0.0]*dim, ...] when the ONNX model fails to load. That bug pre-existed in master but was silent: ChromaDB happily stored zero embeddings, count() reported normal numbers, smart-reindex skipped them as "already indexed", and queries returned garbage similarity with no error visible. Now raises EmbeddingModelLoadError / EmbeddingError loudly. All v3.8.0 users should upgrade. Full details in Changelog.

Lazy-Loaded Embeddings β€” Cheaper Idle Processes (v3.8.0)

The FastEmbed ONNX model (~200MB resident) now loads on the first query, not at startup. Idle knowledge-rag processes are now genuinely cheap. Why this matters: MCP stdio is one-process-per-client by protocol β€” multiple Claude Code windows, Claude Desktop + IDE simultaneously, or review/approval flows that open extra connections all spawn their own processes. Before v3.8.0, every one of them paid the full embedding-model cost up front. Now only processes that actually serve queries load the model. Public API is unchanged.

Opt-In Single-Instance Guard (v3.8.0)

For users who measured their setup and want a hard cap of one server per data_dir:

Copy & paste β€” that's it
export KNOWLEDGE_RAG_SINGLE_INSTANCE=1

A second instance exits immediately with code 75. OFF by default so multi-client MCP usage continues to work unchanged. Stale-PID recovery + SIGINT/SIGTERM cleanup wired correctly. Full guide in docs/single-instance.md. Sample MCP config in examples/mcp-config-single-instance.json.

5 Ways to Install

Copy & paste β€” that's it
npx -y knowledge-rag                    # NPM β€” zero setup, auto-manages Python venv
pip install knowledge-rag               # PyPI β€” classic Python install
curl -fsSL .../install.sh | bash        # One-line installer (Linux/macOS/Windows)
docker pull ghcr.io/lyonzin/knowledge-rag  # Docker β€” models pre-downloaded
git clone ... && pip install -r ...     # From source

All methods produce the same MCP server. See Installation for full instructions.

Recent Highlights

  • v4.0.0 β€” Enterprise concurrent access: SSE/HTTP transport (1 server β†’ N clients), thread-safe shared state, optional rate limiting + Prometheus metrics, ChromaDB WAL mode, --transport CLI
  • v3.9.0 β€” Quality Gate activated: 35+ automated PR checks across 7 pillars (Security, Stability, Memory Leak, Versatility, Scalability, Versioning, Quality) + nightly resilience suite (chaos, soak, determinism, mutation)
  • v3.8.1 β€” Critical hotfix: loud-fail embeddings (no more silent zero-vector corruption); Windows CI flake erradicated (HF_HUB_OFFLINE + shell:bash + atexit wrapper)
  • v3.8.0 β€” Lazy-load embeddings, opt-in single-instance guard, version sync across PyPI/NPM/Docker
  • v3.6.0 β€” Multi-language code parsing (C/C++/JS/TS/XML), NPM wrapper, Docker image, automated release pipeline
  • v3.5.2 β€” CUDA DLL auto-discovery from pip packages, graceful GPUβ†’CPU fallback, explicit CPU provider (no CUDA noise when gpu: false), BASE_DIR resolution fix for editable installs
  • v3.5.1 β€” Remove Python <3.13 upper bound β€” 3.13 and 3.14 now supported
  • v3.5.0 β€” Optional GPU acceleration, supported formats table, full README rewrite
  • v3.4.3 β€” MCP stdout save/restore fix (v3.4.2 broke JSON-RPC responses)
  • v3.4.0 β€” Persistent model cache, exclude patterns, Jupyter Notebook parser, inotify resilience, MetaTrader support

See Changelog for full history.


Supported Formats

FormatExtensionParserDefaultNotes
Markdown.mdSection-aware (splits at ##)YesHeaders preserved as chunk boundaries
Plain Text.txtFixed-size chunkingYes1000 chars + 200 overlap
PDF.pdfPyMuPDF extractionYesText-based PDFs only (no OCR)
Python.pyCode-aware parserYesFunctions/classes as chunks
JSON.jsonStructure-awareYesFlattened key-value extraction
CSV.csvRow-based parserYesHeaders + rows as text
Word.docxpython-docxYesHeadings preserved as markdown
Excel.xlsxopenpyxlYesSheet-by-sheet extraction
PowerPoint.pptxpython-pptxYesSlide-by-slide extraction
Jupyter Notebook.ipynbCell-aware parserYesMarkdown + code cells only, no outputs/base64
C Source.cCode-aware parserYesFunctions/structs/includes extracted
C/C++ Header.hCode-aware parserYesFunction declarations/structs extracted
C++ Source.cppCode-aware parserYesClasses/structs/includes extracted
JavaScript.jsCode-aware parserYesFunctions/classes/imports (ESM + CJS)
React JSX.jsxCode-aware parserYesSame as JS parser
TypeScript.tsCode-aware parserYesFunctions/classes/interfaces/enums/imports
React TSX.tsxCode-aware parserYesSame as TS parser
XML.xmlXML parserYesRoot element and namespace extraction
MQL4 Header.mqhCode parserNoMetaTrader β€” add to supported_formats to enable
MQL4 Source.mq4Code parserNoMetaTrader β€” add to supported_formats to enable

Tip: The parser dispatch is extensible. Any format mapped in _parsers can be enabled via supported_formats in config.yaml.


Features

FeatureDescription
Hybrid SearchSemantic + BM25 keyword search with Reciprocal Rank Fusion
Cross-Encoder RerankerXenova/ms-marco-MiniLM-L-6-v2 re-scores top candidates for precision
GPU AccelerationOptional ONNX CUDA support for 5-10x faster indexing
YAML ConfigurationFully customizable via config.yaml with domain-specific presets
Query ExpansionConfigurable synonym mappings (69 security-term defaults)
Markdown-Aware Chunking.md files split by ##/### sections instead of fixed windows
In-Process EmbeddingsFastEmbed ONNX Runtime (BAAI/bge-small-en-v1.5, 384D)
Keyword RoutingWord-boundary aware routing for domain-specific queries
20 Format ParsersMD, TXT, PDF, PY, C, H, CPP, JS, JSX, TS, TSX, JSON, XML, CSV, DOCX, XLSX, PPTX, IPYNB + opt-in MQH/MQ4
Category OrganizationOrganize docs by folder, auto-tagged by path
Incremental IndexingChange detection via mtime/size β€” only re-indexes modified files
Chunk DeduplicationSHA256 content hashing prevents duplicate chunks
Query CacheLRU cache with 5-min TTL for instant repeat queries
Document CRUDAdd, update, remove documents via MCP tools
URL IngestionFetch URLs, strip HTML, convert to markdown, index
Similarity SearchFind documents similar to a reference document
Retrieval EvaluationBuilt-in MRR@5 and Recall@5 metrics
File WatcherAuto-reindex on document changes via watchdog (5s debounce)
Exclude PatternsGlob-based file/directory exclusion during indexing
MMR DiversificationMaximal Marginal Relevance reduces redundant results
Persistent Model CacheEmbedding models cached in models_cache/ β€” survives reboots
Auto-MigrationDetects embedding dimension mismatch and rebuilds automatically
13 MCP ToolsFull CRUD + search + evaluation via Claude Code

Architecture

System Overview

Copy & paste β€” that's it
flowchart TB
    subgraph MCP["MCP SERVER (FastMCP)"]
        direction TB
        TOOLS["13 MCP Tools<br/>search | get | add | update | remove<br/>reindex | reindex_status | list | stats | url | similar | evaluate"]
    end

    subgraph SEARCH["HYBRID SEARCH ENGINE"]
        direction LR
        ROUTER["Keyword Router<br/>(word boundaries)"]
        SEMANTIC["Semantic Search<br/>(ChromaDB)"]
        BM25["BM25 Keyword<br/>(inverted-index + expansion)"]
        RRF["Reciprocal Rank<br/>Fusion (RRF)"]
        RERANK["Cross-Encoder<br/>Reranker"]

        ROUTER --> SEMANTIC
        ROUTER --> BM25
        SEMANTIC --> RRF
        BM25 --> RRF
        RRF --> RERANK
    end

    subgraph STORAGE["STORAGE LAYER"]
        direction LR
        CHROMA[("ChromaDB<br/>Vector Database")]
        COLLECTIONS["Collections<br/>security | ctf<br/>logscale | development"]
        CHROMA --- COLLECTIONS
    end

    subgraph EMBED["EMBEDDINGS (In-Process)"]
        FASTEMBED["FastEmbed ONNX<br/>BAAI/bge-small-en-v1.5<br/>(384D, CPU or GPU)"]
        CROSSENC["Cross-Encoder<br/>ms-marco-MiniLM-L-6-v2"]
        FASTEMBED --- CROSSENC
    end

    subgraph INGEST["DOCUMENT INGESTION"]
        PARSERS["20 Parsers<br/>MD | PDF | TXT | PY | C | H | CPP | JS | JSX | TS | TSX | JSON | XML | CSV<br/>DOCX | XLSX | PPTX | IPYNB | MQH | MQ4"]
        CHUNKER["Chunking<br/>MD: section-aware<br/>Other: 1000 chars + 200 overlap"]
        PARSERS --> CHUNKER
    end

    CLAUDE["Claude Code"] --> MCP
    MCP --> SEARCH
    SEARCH --> STORAGE
    STORAGE --> EMBED
    INGEST --> EMBED
    EMBED --> STORAGE

Query Processing Flow

Copy & paste β€” that's it
flowchart TB
    QUERY["User Query<br/>'mimikatz credential dump'"] --> EXPAND

    subgraph EXPANSION["Query Expansion"]
        EXPAND["Synonym Expansion<br/>mimikatz -> mimikatz, sekurlsa, logonpasswords"]
    end

    EXPAND --> ROUTER

    subgraph ROUTING["Keyword Routing"]
        ROUTER["Keyword Router"]
        MATCH{"Word Boundary<br/>Match?"}
        CATEGORY["Filter: redteam"]
        NOFILTER["No Filter"]

        ROUTER --> MATCH
        MATCH -->|Yes| CATEGORY
        MATCH -->|No| NOFILTER
    end

    subgraph HYBRID["Hybrid Search"]
        direction LR
        SEMANTIC["Semantic Search<br/>(ChromaDB embeddings)<br/>Conceptual similarity"]
        BM25["BM25 Inverted-Index<br/>(posting lists + numpy top-k)<br/>Exact term matching"]
    end

    subgraph FUSION["Result Fusion + Reranking"]
        RRF["Reciprocal Rank Fusion<br/>score = alpha * 1/(k+rank_sem)<br/>+ (1-alpha) * 1/(k+rank_bm25)"]
        RERANK["Cross-Encoder Reranker<br/>Re-scores top 3x candidates<br/>query+doc pair scoring"]
        SORT["Sort by Reranker Score<br/>Normalize to 0-1"]
        ADJ["Adjacent Chunk Expansion<br/>(batch fetch Β±1 chunk)"]

        RRF --> RERANK --> SORT --> ADJ
    end

    subgraph OUTPUT["Output Processing"]
        MINSCORE["min_score Filter<br/>(discard below threshold)"]
        SNIPPET["snippet_mode Truncation<br/>(~500 chars at natural break)"]

        MINSCORE --> SNIPPET
    end

    CATEGORY --> HYBRID
    NOFILTER --> HYBRID
    SEMANTIC --> RRF
    BM25 --> RRF

    ADJ --> MINSCORE
    SNIPPET --> RESULTS["Results<br/>search_method: hybrid|semantic|keyword<br/>score + filtered_by_score + content_length"]

Document Ingestion Flow

Copy & paste β€” that's it
flowchart LR
    subgraph INPUT["Input"]
        FILES["documents/<br/>β”œβ”€β”€ security/<br/>β”œβ”€β”€ development/<br/>β”œβ”€β”€ ctf/<br/>└── general/"]
    end

    subgraph PARSE["Parse (20 formats)"]
        MD["Markdown"]
        PDF["PDF<br/>(PyMuPDF)"]
        OFFICE["DOCX | XLSX<br/>PPTX | CSV"]
        CODE["PY | C | H | CPP | JS | JSX<br/>TS | TSX | JSON | XML | IPYNB"]
    end

    subgraph CHUNK["Chunk"]
        MDSPLIT["MD: Section-Aware<br/>Split at ## headers"]
        TXTSPLIT["Other: Fixed-Size<br/>1000 chars + 200 overlap"]
        DEDUP["SHA256 Dedup<br/>Skip duplicate content"]
    end

    subgraph EMBED["Embed"]
        FASTEMBED["FastEmbed ONNX<br/>bge-small-en-v1.5<br/>(384D, CPU or GPU)"]
    end

    subgraph STORE["Store"]
        CHROMADB[("ChromaDB")]
        BM25IDX["BM25 Index"]
    end

    FILES --> MD & PDF & OFFICE & CODE
    MD --> MDSPLIT
    PDF & OFFICE & CODE --> TXTSPLIT
    MDSPLIT --> DEDUP
    TXTSPLIT --> DEDUP
    DEDUP --> EMBED
    EMBED --> STORE

hybrid_alpha Parameter Effect

Copy & paste β€” that's it
flowchart LR
    subgraph ALPHA["hybrid_alpha values"]
        A0["0.0<br/>Pure BM25<br/>Instant"]
        A3["0.3 (default)<br/>Keyword-heavy<br/>Fast"]
        A5["0.5<br/>Balanced"]
        A7["0.7<br/>Semantic-heavy"]
        A10["1.0<br/>Pure Semantic"]
    end

    subgraph USE["Best For"]
        U0["CVEs, tool names<br/>exact matches"]
        U3["Technical queries<br/>specific terms"]
        U5["General queries"]
        U7["Conceptual queries<br/>related topics"]
        U10["'How to...' questions<br/>conceptual search"]
    end

    A0 --- U0
    A3 --- U3
    A5 --- U5
    A7 --- U7
    A10 --- U10

API Reference

Search & Query

search_knowledge

Hybrid search combining semantic search + BM25 keyword search with cross-encoder reranking.

ParameterTypeDefaultDescription
querystringrequiredSearch query text (1-3 keywords recommended)
max_resultsint5Maximum results to return (1-20)
categorystringnullFilter by category
hybrid_alphafloat0.3Balance: 0.0 = keyword only, 1.0 = semantic only
min_scorefloat0.0Minimum relevance score (0.0-1.0) to include a result. Use 0.2-0.4 to cut noise
snippet_modebooltrueTruncate content to ~500 chars at natural break points. Adds content_length field

Returns:

Copy & paste β€” that's it
{
  "status": "success",
  "query": "mimikatz credential dump",
  "hybrid_alpha": 0.5,
  "result_count": 3,
  "filtered_by_score": 2,
  "cache_hit_rate": "0.0%",
  "results": [
    {
      "content": "Mimikatz can extract credentials from memory...",
      "source": "documents/security/credential-attacks.md",
      "filename": "credential-attacks.md",
      "category": "security",
      "score": 0.9823,
      "raw_rrf_score": 0.016393,
      "reranker_score": 0.987654,
      "semantic_rank": 2,
      "bm25_rank": 1,
      "search_method": "hybrid",
      "keywords": ["mimikatz", "credential", "lsass"],
      "routed_by": "redteam"
    }
  ]
}

Search Method Values:

  • hybrid: Found by both semantic and BM25 search (highest confidence)
  • semantic: Found only by semantic search
  • keyword: Found only by BM25 keyword search

get_document

Retrieve the full content of a specific document.

ParameterTypeDescription
filepathstringPath to the document file

Returns: JSON with document content, metadata, keywords, and chunk count.


reindex_documents

Index or reindex all documents in the knowledge base. Runs in background β€” returns immediately. Poll progress via get_reindex_status().

ParameterTypeDefaultDescription
forceboolfalseSmart reindex: detects changes, rebuilds BM25. Fast.
full_rebuildboolfalseNuclear rebuild: deletes everything, re-embeds all documents. Use after model change.

Returns: {"status": "started", "operation": "..."} immediately. If already running, returns {"status": "already_running", "progress": "1200/3734"}.


get_reindex_status

Get the current status of a background reindex operation. Lightweight β€” does not compute full index statistics.

Returns (active):

Copy & paste β€” that's it
{
  "status": "success",
  "reindex": {
    "active": true,
    "operation": "nuclear_rebuild",
    "progress": "1200/3734",
    "percent": 32,
    "indexed": 1200,
    "skipped": 0,
    "errors": 0,
    "started_at": "2026-06-17T18:29:49"
  }
}

Returns (idle): {"status": "success", "reindex": {"active": false}}


list_categories

List all document categories with their document counts.

Returns:

Copy & paste β€” that's it
{
  "status": "success",
  "categories": {
    "security": 52,
    "development": 8,
    "ctf": 12,
    "general": 3
  },
  "total_documents": 75
}

list_documents

List all indexed documents, optionally filtered by category.

ParameterTypeDescription
categorystringOptional category filter

Returns: JSON array of documents with id, source, category, format, chunks, and keywords.


get_index_stats

Get statistics about the knowledge base index.

Returns:

Copy & paste β€” that's it
{
  "status": "success",
  "stats": {
    "total_documents": 75,
    "total_chunks": 9256,
    "categories": {"security": 52, "development": 8},
    "supported_formats": [".md", ".txt", ".pdf", ".py", ".json", ".docx", ".xlsx", ".pptx", ".csv", ".ipynb"],
    "embedding_model": "BAAI/bge-small-en-v1.5",
    "embedding_dim": 384,
    "reranker_model": "Xenova/ms-marco-MiniLM-L-6-v2",
    "chunk_size": 1000,
    "chunk_overlap": 200,
    "query_cache": {
      "size": 12,
      "max_size": 100,
      "ttl_seconds": 300,
      "hits": 45,
      "misses": 23,
      "hit_rate": "66.2%"
    }
  }
}

Document Management

add_document

Add a new document to the knowledge base from raw content. Saves the file to the documents directory and indexes it immediately.

ParameterTypeDefaultDescription
contentstringrequiredFull text content of the document
filepathstringrequiredRelative path within documents dir (e.g., security/new-technique.md)
categorystring"general"Document category

update_document

Update an existing document. Removes old chunks from the index and re-indexes with new content.

ParameterTypeDescription
filepathstringFull path to the document file
contentstringNew content for the document

remove_document

Remove a document from the knowledge base index. Optionally deletes the file from disk.

ParameterTypeDefaultDescription
filepathstringrequiredPath to the document file
delete_fileboolfalseIf true, also delete the file from disk

add_from_url

Fetch content from a URL, strip HTML (scripts, styles, nav, footer, header), convert to markdown, and add to the knowledge base.

ParameterTypeDefaultDescription
urlstringrequiredURL to fetch content from
categorystring"general"Document category
titlestringnullCustom title (auto-detected from <title> tag if not provided)

search_similar

Find documents similar to a given document using embedding similarity.

ParameterTypeDefaultDescription
filepathstringrequiredPath to the reference document
max_resultsint5Number of similar documents to return (1-20)

evaluate_retrieval

Evaluate retrieval quality with test queries. Useful for tuning hybrid_alpha, testing query expansion effectiveness, or validating after reindexing.

ParameterTypeDescription
test_casesstring (JSON)Array of test cases: [{"query": "...", "expected_filepath": "..."}, ...]

Metrics:

  • MRR@5 (Mean Reciprocal Rank): Average of 1/rank for expected documents. 1.0 = always first result.
  • Recall@5: Fraction of expected documents found in top 5 results. 1.0 = all found.

Project Structure

Copy & paste β€” that's it
knowledge-rag/
β”œβ”€β”€ mcp_server/
β”‚   β”œβ”€β”€ __init__.py          # Stdout protection + version
β”‚   β”œβ”€β”€ config.py            # YAML config loader + defaults
β”‚   β”œβ”€β”€ ingestion.py         # 20 parsers, chunking, metadata extraction
β”‚   └── server.py            # MCP server, ChromaDB, BM25, reranker, 12 tools
β”œβ”€β”€ config.example.yaml      # Documented config template (copy to config.yaml)
β”œβ”€β”€ config.yaml              # Your active configuration (git-ignored)
β”œβ”€β”€ presets/                  # Ready-to-use domain configurations
β”‚   β”œβ”€β”€ cybersecurity.yaml
β”‚   β”œβ”€β”€ developer.yaml
β”‚   β”œβ”€β”€ research.yaml
β”‚   └── general.yaml
β”œβ”€β”€ documents/               # Your documents (scanned recursively)
β”œβ”€β”€ data/
β”‚   β”œβ”€β”€ chroma_db/           # ChromaDB vector database
β”‚   └── index_metadata.json  # Incremental indexing state
β”œβ”€β”€ models_cache/            # Persistent embedding model cache
β”œβ”€β”€ tests/                   # Test suite (82 tests)
β”œβ”€β”€ install.sh               # Linux/macOS installer
β”œβ”€β”€ install.ps1              # Windows installer
β”œβ”€β”€ venv/                    # Python virtual environment
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ pyproject.toml
β”œβ”€β”€ LICENSE
└── README.md

Changelog

Unreleased

  • NEW: Cross-platform, multi-LLM-client installer (install.py) driving both install.sh (Linux/macOS) and install.ps1 (Windows) as thin wrappers. One codebase, one behavior across every OS.
  • NEW: Auto-detects and registers knowledge-rag in 8 LLM clients β€” Claude Code, Claude Desktop, Cursor, Windsurf, VS Code (Copilot Chat), Cline, Gemini CLI, Zed β€” writing to each tool's canonical config path with the correct JSON schema per client (VS Code uses servers, Zed uses context_servers, everyone else uses mcpServers).
  • NEW: --for <clients> / --exclude <clients> opt-in/opt-out selection, --dry-run preview, --list-clients registry inspection, --pypi-version <ver> pinning, --skip-init / --skip-model for fast reruns. See python install.py --help.
  • FIX: install.ps1 no longer writes MCP config to ~/.claude/mcp.json (a stale secondary path); it now targets ~/.claude.json β€” the file Claude Code actually reads β€” via idempotent JSON merge that preserves every existing MCP server entry with an automatic .knowledge-rag.bak backup.
  • FIX: install.ps1 gains PyPI mode (pip install knowledge-rag) and runs mcp_server.server init on install β€” feature parity with install.sh.
  • FIX: MCP server spec no longer uses the fragile cmd /c cd /d ... && python ... wrapper on Windows; it emits the standard command + cwd shape supported natively by every modern client.
  • FIX: install.sh guards against sh install.sh (bash-only features now emit a clear error instead of a cryptic syntax failure).
  • FIX: Both scripts now correctly advertise 13 MCP tools (was outdated at 12; get_reindex_status shipped in v4.3.0).
  • FIX: Windows-side install.ps1 prefers winget install Python.Python.3.12 --scope user (no admin), falls back to python.org 3.12.7 (was pinned to 3.12.0).
  • TEST: New tests/test_installer_no_data_loss.py (22 tests) locks in the installer's zero-data-loss contract across all three JSON schemas (mcpServers / servers / context_servers): top-level keys preserved, sibling MCP servers byte-identical, .knowledge-rag.bak backup written before every mutation, idempotent second run, --dry-run writes nothing, atomic os.replace write. Baseline: 231 β†’ 266.

v4.3.1 (2026-06-22) β€” Hybrid Search Fixes

  • FIX: Accept "general" as a valid category in search_knowledge. The parser hardcodes "general" as the fallback in _detect_category (ingestion.py), but the validator only built valid_categories from config.keyword_routes + config.category_mappings.values() β€” so users who customized config.yaml and dropped the default "general": "general" mapping hit Invalid category even though the index contained general documents. Validator now always tolerates "general". (#98, thanks @Hohlas)
  • FIX: Skip BM25-only search results when Chroma can no longer resolve the chunk ID. Stale BM25 indices (typically right after remove_document or in the window between async reindex and BM25 rebuild) returned hits whose collection.get() came back empty; the previous fallback inserted entries with document="" / metadata={} into the reranker, polluting results with empty matches. The pipeline now continues past those, dropping the stale hit cleanly. (#98, thanks @Hohlas)
  • TEST: Added tests/test_pr98_regression.py (4 tests) pinning both contracts so future refactors cannot silently revert either fix. Test count baseline: 227 β†’ 231. (#99)
  • CI: Bumped [tool.mypy] python_version from 3.11 to 3.12 to accept PEP 695 type statements in the numpy stub (numpy/__init__.pyi) which were breaking the Pillar 7 strict gate. Only affects static analysis; requires-python = ">=3.11" unchanged. (#100)

v4.3.0 (2026-06-17) β€” Async Reindex, GPU CUDA 12, 13th MCP Tool

  • NEW: get_reindex_status MCP tool β€” lightweight reindex progress polling without computing full index stats. Returns active/idle status, percent, processed/total, errors, and last result.
  • NEW: reindex_documents now runs in background via daemon thread β€” returns immediately with {"status": "started"}. Eliminates MCP timeout on large document sets (5K+ files). Concurrent calls return already_running with current progress.
  • NEW: GPU acceleration with full CUDA 12 support β€” onnxruntime-gpu + 7 NVIDIA pip packages (cublas, cudnn, cuda-runtime, cufft, cusparse, cusolver, curand, nvjitlink). Server auto-detects GPU on startup with 4-step verification (providers, DLLs, nvidia-smi, session creation). Falls back to CPU gracefully.
  • NEW: _setup_cuda_dll_paths() adds NVIDIA pip package DLL directories to PATH automatically on Windows β€” onnxruntime finds CUDA 12 DLLs without a full CUDA Toolkit install.
  • DEPS: [gpu] extra expanded from 3 to 8 packages (added cufft, cusparse, cusolver, curand, nvjitlink).
  • FIX: GPU status reporting now uses actual ONNX session creation test instead of just checking get_available_providers() β€” prevents false "GPU ACTIVE" when CUDA DLLs are missing.
  • DOCS: GPU Acceleration section rewritten with complete requirements table, setup steps, verification instructions, and fallback behavior.
  • DOCS: Tool reference updated β€” reindex_documents async behavior documented, get_reindex_status reference added.
  • TEST: Backwards-compat baseline updated for 13 MCP tools.

v4.2.0 (2026-06-17) β€” Search Performance & Output Quality

  • PERF: Custom inverted-index BM25 replaces rank-bm25 full-corpus scan β€” 128Γ— faster keyword search on 50K+ chunk corpora. Only documents containing query terms are scored via posting lists.
  • PERF: numpy.argpartition for O(n) top-k selection instead of O(n log n) sort.
  • PERF: Batched adjacent chunk fetch β€” single ChromaDB collection.get() call replaces N round-trips per result.
  • PERF: O(1) reverse lookup via _source_to_docid dict eliminates linear scans of _indexed_docs in search_similar, update_document, remove_document, and _expand_with_adjacent_chunks.
  • NEW: snippet_mode parameter on search_knowledge (default: true) β€” truncates content to ~500 chars at natural break points with content_length field. Reduces token consumption by ~72%.
  • NEW: min_score parameter on search_knowledge (default: 0.0) β€” filters results below a normalized relevance threshold. Response includes filtered_by_score count.
  • NEW: filtered_by_score field in search response JSON for transparency.
  • DEPS: numpy added as direct dependency (was transitive via fastembed); rank-bm25 import removed from server.py.
  • TEST: 6 new tests for min_score filtering and snippet_mode truncation.
  • TEST: Updated backwards-compat baseline to include new search_knowledge parameters.

v4.1.2 (2026-06-17)

  • FIX: _save_metadata dict snapshot prevents concurrent modification crash during file watcher events.
  • STYLE: ruff format applied to server.py.

v4.1.1 (2026-06-17)

  • FIX: All _indexed_docs iterations now use list() snapshot, preventing dictionary changed size during iteration crash when FileWatcher modifies the index concurrently with MCP tool calls (affects search_knowledge, search_similar, update_document, remove_document, evaluate_retrieval, list_categories, list_documents)

v4.1.0 (2026-06-17)

  • Added: query_expansion_groups config for symmetric synonym expansion (#92)
  • Improved: expand_query() now returns deterministic expansion order (set β†’ ordered list with dedup)

v4.0.1 (2026-06-16)

  • FIX: Orphan cleanup now runs before indexing loop, preventing chunk loss when files are moved (#90).
  • FIX: Chunk deduplication is now per-document instead of global, preventing cross-document chunk deletion (#91).
  • FIX: Added on_moved handler to DocumentWatcher for proper file move detection.
  • FIX: Startup preflight probes ChromaDB in a child process and moves crashing persistent indexes to data/backups/auto-repair-* before MCP initialization.
  • FIX: Reranker load failures now fall back to RRF ordering instead of failing search_knowledge on offline machines.
  • FIX: Virtualenv project-root detection now handles Python symlinks that resolve to the system interpreter.
  • NEW: knowledge-rag-guarded console script kept as an explicit guarded startup alias.

v4.0.0 (2026-06-09) β€” Enterprise Concurrent Access

  • NEW: SSE and streamable-http transport modes β€” 1 server serves N clients (server.transport: "sse" in config.yaml or --transport sse CLI).
  • NEW: Thread-safe shared state for concurrent queries β€” QueryCache locking, BM25 build lock, orchestrator double-checked locking.
  • NEW: ChromaDB WAL mode enabled automatically in SSE/HTTP mode for concurrent read performance.
  • NEW: Optional rate limiting β€” sliding-window counter, configurable RPM and burst, disabled by default.
  • NEW: Optional Prometheus metrics endpoint β€” tool call counts, latency histograms, separate port, disabled by default.
  • NEW: All 13 MCP tools instrumented with @rate_limited and @instrument decorators (zero-cost when disabled).
  • NEW: --transport CLI override for Docker/systemd deployments.
  • NEW: pip install knowledge-rag[server] optional dependency for SSE/HTTP (uvicorn).
  • CHANGED: SSE/HTTP mode auto-enables single-instance lock (port collision prevention).
  • CHANGED: mcp dependency bumped to >=1.6.0 (SSE/streamable-http support).
  • MIGRATION: Default transport remains stdio β€” existing users need zero changes. See config.example.yaml for SSE setup.

v3.9.1 (2026-06-08)

  • FIX: Expand ~ in config.yaml path values (documents_dir, data_dir, models_cache_dir) via expanduser() on all platforms (#86).
  • FIX: Warn when documents_dir resolves to a non-existent path instead of silently indexing zero files.
  • FIX: File watcher now uses accumulate-mode debounce β€” bulk file copies no longer starve the reindex trigger.
  • FIX: Concurrent index_all() calls are serialized via _index_lock to prevent ChromaDB SQLite corruption.
  • FIX: collection.add() is batched (500 chunks/call) to cap memory usage during large reindex operations.
  • NEW: KNOWLEDGE_RAG_WATCHER_DISABLED=1 env var to disable the file watcher for troubleshooting.
  • NEW: Progress logging every 10% for reindex operations with >100 documents.

v3.9.0 (2026-05-10) β€” Quality Gate

Major governance + CI hardening release. No runtime behavior change in mcp_server/. Public API surface unchanged from v3.8.1.

  • NEW Quality Gate workflow (.github/workflows/quality-gate.yml) enforcing the 7 pillars on every PR: Security, Stability, Memory Leak, Versatility, Scalability, Versioning, Quality. 35+ status checks total.
  • NEW Nightly resilience workflow (.github/workflows/nightly.yml): chaos suite (failure injection), 1h soak test (50K-iteration loop), determinism check (full suite Γ— 3), mutation testing (mutmut). Auto-opens GitHub issue on any nightly failure.
  • NEW Performance benchmark suite under bench/ (12 microbenchmarks, pytest-benchmark) with 10% regression gate on every PR.
  • NEW Public performance dashboard via GitHub Pages (.github/workflows/bench-pages.yml) β€” chart of latency/throughput per commit. Dormant until repo Pages is enabled.
  • NEW Property-based fuzzing of all parsers via Hypothesis (tests/test_ingestion_property.py) β€” 200 random examples per CI run.
  • NEW Memory baseline regression tests (tests/test_memory_baseline.py, cross-platform via psutil) β€” RSS bounded under 1000 queries; nightly soak amplifies to 50K iterations.
  • NEW Property/locale/format/preset matrices (tests/test_presets.py, tests/test_locale.py, tests/test_format_smoke.py).
  • NEW Backwards-compatibility regression tests (tests/test_backwards_compat.py) β€” legacy YAML configs from v3.6.0 / v3.7.0 still parse; all 13 MCP tool parameter names frozen.
  • NEW AST-based public API surface diff (scripts/check_api_surface.py) β€” any breaking change blocks merge, baseline at .github/api-surface-baseline.json.
  • NEW CHANGELOG enforcement (scripts/check_changelog.py) β€” user-facing PRs must add a bullet under ## Unreleased; bypass via skip-changelog label.
  • NEW Test count anti-regression (scripts/check_test_count.py) β€” guards against silent test deletion.
  • NEW Conventional commits required on every PR title (commitlint via amannn/action-semantic-pull-request).
  • NEW mypy --strict rolling out per-module (currently instance_lock.py + preflight.py + scripts/); interrogate docstring coverage β‰₯ 80%; radon, vulture, PR-size guard report-only.
  • NEW CI matrix expanded to 9 cells: Linux + Windows + macOS Γ— 3.11 + 3.12 + 3.13 (all required at v3.9.0; macOS / 3.13 promoted from experimental after two clean cycles).
  • NEW Governance docs: CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md, .github/PULL_REQUEST_TEMPLATE.md, 3 issue templates, expanded CODEOWNERS.
  • NEW Pre-commit hooks: ruff, gitleaks, version-sync, conventional commits.
  • CHORE .github/codecov.yml enforcing coverage trend gate (-0.5pp blocks; new code β‰₯ 70%).

v3.8.1 (2026-05-10) β€” hotfix

  • FIX (critical): FastEmbedEmbeddings.__call__ no longer returns vectors of zeros when the ONNX model fails to load or embed() raises. The previous behavior silently corrupted the index β€” ChromaDB stored zero embeddings, count() reported normal numbers, smart-reindex skipped the bad chunks, and queries returned garbage scores with no error visible. Now raises EmbeddingModelLoadError / EmbeddingError. (#36)
  • FIX: Sticky _load_failed flag β€” after a load failure, subsequent calls re-raise immediately instead of looping through HuggingFace download attempts (was the "frozen query" UX in v3.8.0).
  • NEW: Sanity checks in __call__ β€” embed count and dim mismatches raise EmbeddingError instead of silently returning malformed vectors.
  • TEST: 7 new regression cases in tests/test_lazy_embeddings.py, including test_does_not_return_zero_vectors_silently as a guard for the whole class of bug.
  • NOTE: This is a pre-existing bug in master, not introduced by v3.8.0. v3.8.0 lazy-load expanded the impact (failures moved to query time). All v3.8.0 users should upgrade.

v3.8.0 (2026-05-10)

  • NEW: Lazy-load FastEmbed embedding model (~200MB ONNX runtime). Loads on first query instead of startup β€” idle knowledge-rag processes are now cheap, which matters when MCP stdio clients spawn parallel server processes (multiple Claude Code windows, Claude Desktop + IDE, etc.). Public API unchanged. (#32)
  • NEW: Opt-in single-instance guard via KNOWLEDGE_RAG_SINGLE_INSTANCE=1 env var. OFF by default β€” multi-client MCP usage continues to work unchanged. When enabled, a second server process for the same data_dir exits with code 75 (EX_TEMPFAIL). Includes stale-PID recovery and SIGINT/SIGTERM handlers. See docs/single-instance.md. (#33, original concept by @Hohlas in #31)
  • NEW: examples/mcp-config-single-instance.json β€” sample MCP client config for the opt-in guard.
  • DOCS: New docs/single-instance.md β€” when to use, when NOT to use, troubleshooting, full activation reference.
  • DOCS: README troubleshooting section for "Multiple MCP clients spawn duplicate servers" + memory-usage note for lazy embeddings.
  • CHORE: Sync version across pyproject.toml, mcp_server/__init__.py, and npm/package.json (was drifting since v3.5.x).
  • CHORE: pytest tmp_path_retention_count=1 to avoid Windows atexit cleanup race in CI.
  • ROADMAP: Tracked v4.0 shared-service architecture (one daemon, many thin MCP clients) as the long-term fix for multi-process resource duplication. (#34)

v3.6.2 (2026-04-23)

  • INFRA: NPM provenance attestation (SLSA supply chain security), full README on npm page
  • DOCS: Reorganize Installation section β€” add NPX and Docker install methods, update What's New to v3.6.0

v3.6.0 (2026-04-23)

  • NEW: Multi-language code parsing β€” C (.c), C++ (.cpp/.h), JavaScript (.js/.jsx), TypeScript (.ts/.tsx) with per-language function/class/import extraction
  • NEW: XML parser (.xml) β€” root element and namespace metadata extraction
  • NEW: All 8 new formats default enabled β€” no config change needed
  • NEW: NPM wrapper (npx knowledge-rag) + Docker image (ghcr.io/lyonzin/knowledge-rag)
  • NEW: Automated release pipeline β€” PyPI (Trusted Publishing), NPM, Docker GHCR
  • IMPROVED: Code parser reports correct language metadata per file type (was hardcoded to "python" for all code files)

v3.5.2 (2026-04-16)

  • NEW: Auto-discovery of CUDA 12 DLLs from pip-installed NVIDIA packages β€” no manual PATH configuration needed
  • NEW: Graceful GPUβ†’CPU fallback with [WARN] log when CUDA init fails (missing drivers, wrong version, etc.)
  • FIX: Explicit CPUExecutionProvider when gpu: false β€” eliminates noisy CUDA probe errors in logs
  • FIX: BASE_DIR resolution now correctly prefers directories with config.yaml over those with only config.example.yaml (fixes editable installs)

v3.5.1 (2026-04-16)

  • FIX: Removed Python upper bound constraint (<3.13 β†’ >=3.11). Python 3.13 and 3.14 now supported β€” onnxruntime ships wheels for both.

v3.5.0 (2026-04-16)

  • NEW: Optional GPU acceleration for ONNX embeddings β€” pip install knowledge-rag[gpu] + models.embedding.gpu: true in config. 5-10x faster indexing on NVIDIA GPUs with automatic CPU fallback.
  • DOCS: Supported formats table added to README (20 formats)

v3.4.3 (2026-04-16)

  • FIX: Correct stdout protection via save/restore pattern β€” __init__.py saves original stdout and redirects to stderr during init, server.py main() restores it before mcp.run(). v3.4.2's global redirect broke MCP JSON-RPC response channel.

v3.4.1 (2026-04-16)

  • FIX: pip install knowledge-rag now auto-detects project directory from venv location
  • NEW: install.sh β€” Linux/macOS installer with pip and from-source modes
  • IMPROVED: BASE_DIR resolution chain: env var β†’ source dir β†’ venv parent β†’ CWD β†’ fallback

v3.4.0 (2026-04-16)

  • NEW: models_cache_dir β€” persistent embedding model cache, prevents re-download after reboots
  • NEW: exclude_patterns β€” glob-based file/directory exclusion during indexing
  • NEW: Jupyter Notebook (.ipynb) parser β€” extracts markdown and code cell sources only
  • NEW: MCP stdout protection β€” redirects stdout to stderr before server start
  • NEW: File watcher resilience β€” graceful fallback when Linux inotify limits are reached
  • NEW: MetaTrader (.mq4, .mqh) support β€” opt-in code parsing
  • NEW: 23 new tests (exclude patterns, ipynb parser, stdout protection)
  • Community credit: @Hohlas (PR #18)

v3.3.x

  • v3.3.2: Full type validation on YAML config, bounds checking, version sync
  • v3.3.1: YAML null value crash fix, presets bundled in pip wheel, knowledge-rag init CLI
  • v3.3.0: YAML configuration system, 4 domain presets, generic use support

v3.2.x

  • v3.2.4: Symlink support with circular loop protection
  • v3.2.3: BASE_DIR smart detection for pip installs
  • v3.2.2: Plug-and-play pip install, KNOWLEDGE_RAG_DIR env var
  • v3.2.1: Auto-recovery from corrupted ChromaDB
  • v3.2.0: Parallel BM25 + Semantic search, adjacent chunk retrieval

v3.1.x

  • v3.1.1: Code block protection in markdown chunker, AAR category, 14 CVE aliases
  • v3.1.0: DOCX/XLSX/PPTX/CSV support, file watcher, MMR diversification, PyPI publish

v3.0.0 (2026-03-19)

  • Replaced Ollama with FastEmbed (ONNX in-process)
  • Cross-encoder reranking, markdown-aware chunking, query expansion
  • 6 new MCP tools (12 total), auto-migration from v2.x
<details> <summary>v2.x and earlier</summary>
  • v2.2.0: hybrid_alpha=0 skips Ollama, default changed from 0.5 to 0.3
  • v2.1.0: Mermaid architecture diagrams
  • v2.0.0: Hybrid search, RRF fusion, hybrid_alpha parameter
  • v1.1.0: Incremental indexing, query cache, chunk deduplication
  • v1.0.1: Auto-cleanup orphan folders, removed hardcoded paths
  • v1.0.0: Initial release
</details>

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.


Acknowledgments


Author

Lyon.

Security Researcher | Developer


<div align="center">

Back to Top

</div>