# Vast Rag

> MCP server for semantic search over VAST Data documentation (ChromaDB + sentence-transformers)

- **Type:** MCP server
- **Install:** `agentstack add mcp-ssotoa70-vast-rag`
- **Verified:** Pending review
- **Seller:** [ssotoa70](https://agentstack.voostack.com/s/ssotoa70)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [ssotoa70](https://github.com/ssotoa70)
- **Source:** https://github.com/ssotoa70/vast-rag

## Install

```sh
agentstack add mcp-ssotoa70-vast-rag
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Local RAG: Semantic Search for VAST Data Documentation

**Tech Stack:**

A production-ready MCP (Model Context Protocol) server that provides fast, local semantic search over technical documentation using ChromaDB and sentence-transformers. This system enables Claude and other AI tools to access your complete documentation repository with natural language queries, all without any external API calls.

## What is Local RAG?

Local RAG combines **Retrieval-Augmented Generation (RAG)** with the **Model Context Protocol (MCP)** to create a local, self-contained semantic search system. Unlike traditional keyword-based search, Local RAG understands the semantic meaning of your queries and documents, finding relevant information even when exact keywords don't match.

### Why Local RAG Matters

- **Privacy**: All documents remain on your machine. No data is sent to external services.
- **Cost**: No API calls to vector databases or language model services.
- **Speed**: Latency measured in milliseconds, not seconds.
- **Reliability**: Works offline. No dependency on cloud services.
- **Control**: You choose which documents to index and how to organize them.

### What is the Model Context Protocol (MCP)?

MCP is a standardized protocol that allows AI assistants like Claude to securely invoke custom tools and access resources on your local system. VAST RAG implements MCP tools that Claude can use to search your documentation, making your knowledge accessible directly within conversations.

## System Architecture

```mermaid
graph TD
    subgraph "Document Ingestion Pipeline"
        A["📂 Source Documents(~/projects/RAG/)"]
        B["👁 File Watcher(watchdog)"]
        C["🔍 Parser Factory(format detection)"]
        D["📄 Format Parsers(PDF/MD/HTML/DOCX/text)"]
        E["✂️ Semantic Chunker(500 tokens, 50 overlap)"]
        F["📊 Hash Index(SHA-256 change detection)"]
    end

    subgraph "Indexing & Storage"
        G["🤖 Embedding Service(BAAI/bge-base-en-v1.5)"]
        H["🗂️ ChromaDB Vector Store(dual collections)"]
        I["📑 vast-data collection(VAST product docs)"]
        J["📚 general-tech collection(other technical docs)"]
    end

    subgraph "Query Pipeline"
        K["🎯 User Query"]
        L["🔀 Query Embedding(same model)"]
        M["🔎 ChromaDB Similarity Search(L2 distance → 0-1 score)"]
        N["📋 Result Aggregation(with metadata)"]
    end

    subgraph "MCP Server & Client"
        O["🛠️ MCP Server(stdio interface)"]
        P["💬 Claude Desktop(or other MCP client)"]
    end

    subgraph "MCP Tools"
        Q["🔍 search_docs"]
        R["📋 list_collections"]
        S["📄 get_document"]
    end

    subgraph "Storage Locations"
        T["~/.claude/rag-data/chroma/ (database)logs/ (rotating)model-cache/ (embeddings)"]
    end

    A -->|monitors| B
    B -->|detects changes| F
    F -->|new/changed files| C
    C -->|routes to parser| D
    D -->|parsed content| E
    E -->|text chunks| G
    G -->|768-dim vectors| H
    H -->|stores in| I
    H -->|stores in| J

    K -->|user query| O
    O -->|embedding| L
    L -->|vector search| M
    M -->|semantic results| N
    N -->|returns via| Q
    O -->|list call| R
    O -->|document call| S
    Q -->|MCP tool| P
    R -->|MCP tool| P
    S -->|MCP tool| P

    H -.->|persists to| T

    style A fill:#e1f5ff
    style H fill:#fff3e0
    style O fill:#f3e5f5
    style P fill:#e8f5e9
```

## Pipeline Details

### Indexing Pipeline

The indexing pipeline automatically discovers, processes, and indexes documents whenever they are added or modified in the source directory.

#### 1. File Watcher (watchdog)

The system uses the `watchdog` library to monitor `~/projects/RAG/` for file system events. When a new document is added or modified, the watcher immediately triggers the parsing pipeline. This enables live-reload functionality—documents are searchable within seconds of being added to the directory.

The file watcher tracks all file system events and filters for supported document formats (PDF, Markdown, HTML, DOCX, plain text, and common code files).

#### 2. Parser Factory and Format-Specific Parsers

When a file is detected, the parser factory examines its extension and content to determine the appropriate parser. Local RAG includes specialized parsers for each supported format:

- **PDFParser**: Extracts text using PyPDF2 with pdfplumber as a fallback. Preserves page numbers for citation purposes.
- **MarkdownParser**: Extracts sections and hierarchy from Markdown files, preserving structure metadata.
- **HTMLParser**: Uses BeautifulSoup to parse HTML, strips script and style tags, and extracts clean text.
- **DOCXParser**: Parses Microsoft Word documents using python-docx.
- **TextParser**: Handles plain text files and common code formats (Python, JavaScript, Java, etc.).

Each parser returns a `ParsedDocument` object containing the full text content and metadata (title, source file, modification date).

#### 3. Semantic Chunker

Raw documents can be very large—a single PDF might contain 100+ pages. The semantic chunker divides documents into manageable chunks optimized for semantic search. The chunker uses the following strategy:

- **Token-based sizing**: Uses tiktoken to count actual tokens. Each chunk is approximately 500 tokens (roughly 300-400 words, depending on language).
- **Overlap for context**: Each chunk overlaps with the previous by 50 tokens, ensuring that semantic boundaries don't split related concepts across chunks.
- **Metadata preservation**: Each chunk retains its source file, section information, and page number (if available).

This approach balances two competing needs: chunks must be small enough to be semantically coherent but large enough to contain sufficient context.

#### 4. Hash Index and Idempotent Indexing

To avoid re-embedding the entire document collection on every run, Local RAG maintains a SHA-256 hash index of all processed files. Before processing a document, the system compares the current file's hash against the stored hash. If they match, the file is skipped; if they differ, the file is re-parsed and re-embedded.

This makes indexing idempotent and efficient—re-running the indexer only processes changed files.

#### 5. Embedding Service

The embedding service uses the BAAI/bge-base-en-v1.5 model to convert text chunks into 768-dimensional vector embeddings. This model is specifically trained for semantic search and performs well across general and technical content.

Key design choices:

- **Lazy loading**: The model is only downloaded and loaded when first needed (either during indexing or the first query). This keeps startup time fast.
- **Batch processing**: Embeddings are computed in batches of 32 chunks by default, balancing memory usage and speed.
- **Automatic caching**: Downloaded models are cached in `~/.claude/rag-data/model-cache/` to avoid re-downloading on subsequent runs.

#### 6. Dual Collection Storage (ChromaDB)

Embeddings are stored in a ChromaDB vector database with a deliberate dual-collection design:

- **vast-data collection**: Contains all documents related to specific knowledge domains. Documents are automatically categorized based on file paths—any document with "vast" in the path is placed in this collection.
- **general-tech collection**: Contains all other technical documentation (architecture notes, design documents, external references, etc.).

This dual design provides these benefits:

- **Flexible scoping**: Users can search all documentation or narrow results to Domain-specific content only.
- **Improved relevance**: Keeping related documents together reduces semantic drift in search results.
- **Future extensibility**: The design easily accommodates additional specialized collections.

### Query Pipeline

When a user asks Claude a question that could benefit from searching your documentation, Claude invokes the `search_docs` MCP tool.

#### 1. Query Embedding

The user's query is embedded using the same BAAI/bge-base-en-v1.5 model that was used to embed documents. This ensures that queries and documents exist in the same vector space, making direct distance comparisons meaningful.

#### 2. Semantic Search in ChromaDB

The query vector is compared against all document chunk vectors using L2 distance (Euclidean distance). ChromaDB performs this search efficiently, returning the top-N most similar chunks.

ChromaDB returns raw distance values; these are converted to similarity scores using the formula: `similarity = 1 / (1 + distance)`. This converts distances in the range [0, ∞) to similarity scores in the range (0, 1], where 1 indicates perfect match and values close to 0 indicate dissimilarity.

#### 3. Result Aggregation and Ranking

Search results are returned in order of similarity score (highest first). Each result includes:

- **Text content**: The actual chunk of text, providing the answer or relevant information.
- **Source file**: The original document filename for citation.
- **Page number**: The page within the PDF (if available), for quick reference.
- **Section**: Extracted section heading (if the source document has hierarchical structure).
- **Similarity score**: The computed 0-1 similarity metric (for transparency and filtering).
- **Category**: Whether the source document is in vast-data or general-tech collection.

### Logging and Observability

All system activity is logged to `~/.claude/rag-data/logs/vast-rag.log`. The log file uses rotating file handler with a maximum of 10 MB per file and 5 backup files retained. Logs are written to stderr (not stdout) because the MCP server communicates over stdio with Claude Desktop.

## MCP Tools

The Local RAG MCP server exposes three core tools that Claude and other MCP clients can invoke:

### search_docs

Performs semantic search across indexed documents.

**Parameters:**
- `query` (string, required): The search query in natural language. Examples: "How do I optimize VastDB queries?", "What is the VAST Data Engine architecture?", "Memory management in distributed systems"
- `category` (string, optional): Filter results to a specific collection. Valid values: `"vast-data"`, `"general-tech"`, or omit for all collections.
- `n_results` (integer, optional): Number of results to return. Default: 5. Maximum: 20.

**Returns:** Array of search results, each containing:
```json
{
  "text": "The chunk of text matching your query...",
  "source": "vdb-optimization.pdf",
  "score": 0.87,
  "category": "vast-data",
  "page": 42,
  "section": "Query Execution Planning"
}
```

**Example Usage (via Claude):**
```
"Search the VAST documentation for information about query optimization.
Use the search_docs tool with category='vast-data' to find relevant content."
```

### list_collections

Lists all available collections and their document counts.

**Parameters:** None

**Returns:** Object containing collection metadata:
```json
{
  "collections": [
    { "name": "vast-data", "count": 1234 },
    { "name": "general-tech", "count": 456 }
  ],
  "total_chunks": 1690
}
```

**Purpose:** Helps users understand what documentation is available and how much content has been indexed.

### get_document

Retrieves full metadata and information about a specific indexed document.

**Parameters:**
- `source_file` (string, required): The filename or path of the document (as returned by search_docs).
- `category` (string, required): The collection containing the document (`"vast-data"` or `"general-tech"`).

**Returns:** Document metadata object (first matching chunk):
```json
{
  "id": "vdb-architecture.pdf_chunk_0",
  "source": "vdb-architecture.pdf",
  "text": "First chunk of text from the document...",
  "metadata": {
    "source_file": "vdb-architecture.pdf",
    "category": "vast-data",
    "chunk_index": 0
  }
}
```

**Purpose:** Allows users to examine a complete document or verify that a specific source file is indexed.

## Project Structure

```
vast-rag/
├── README.md                          # This file
├── LICENSE                            # License information
├── pyproject.toml                     # Python project metadata and dependencies
├── pytest.ini                         # pytest configuration
│
├── src/vast_rag/
│   ├── __init__.py                    # Package initialization
│   ├── __main__.py                    # python -m vast_rag entry point
│   ├── server.py                      # Production MCP entry point (stdio)
│   ├── config.py                      # Pydantic configuration with env var support
│   ├── types.py                       # TypedDict and dataclass definitions
│   ├── indexer.py                     # DocumentIndexer orchestration layer
│   │
│   ├── core/
│   │   ├── __init__.py
│   │   ├── chunker.py                 # SemanticChunker (tiktoken, 500 tokens)
│   │   ├── embeddings.py              # EmbeddingService (bge-base-en-v1.5)
│   │   ├── hash_index.py              # FileHashIndex (SHA-256 change detection)
│   │   ├── vector_store.py            # ChromaDBManager (dual collections)
│   │   └── watcher.py                 # FileWatcher (watchdog-based)
│   │
│   ├── mcp/
│   │   ├── __init__.py
│   │   └── server.py                  # MCPServer wrapper class
│   │
│   └── parsers/
│       ├── __init__.py
│       ├── factory.py                 # ParserFactory (format detection)
│       ├── pdf.py                     # PDFParser (PyPDF2 + pdfplumber fallback)
│       ├── markdown.py                # MarkdownParser (section extraction)
│       ├── html.py                    # HTMLParser (BeautifulSoup)
│       ├── docx.py                    # DOCXParser (python-docx)
│       └── text.py                    # TextParser (plain text and code)
│
├── tests/
│   ├── unit/
│   │   ├── test_chunker.py            # SemanticChunker tests
│   │   ├── test_config.py             # Configuration tests
│   │   ├── test_embeddings.py         # EmbeddingService tests
│   │   ├── test_hash_index.py         # FileHashIndex tests
│   │   ├── test_vector_store.py       # ChromaDBManager tests
│   │   ├── test_parsers.py            # Parser factory and format tests
│   │   ├── test_mcp_server.py         # MCP server wrapper tests
│   │   └── test_server_entry.py       # Production server entry point tests
│   └── integration/
│       ├── test_indexer.py            # DocumentIndexer integration tests (17)
│       └── test_e2e_pipeline.py       # End-to-end pipeline tests (15)
│
├── deployment/
│   ├── README.md                      # Detailed deployment documentation
│   ├── common.sh                      # Shared utilities (logging, validation)
│   ├── setup.sh                       # Creates venv, downloads model, sets up dirs
│   ├── install.sh                     # Registers with Claude Desktop
│   ├── verify.sh                      # Runs 6 health checks
│   ├── uninstall.sh                   # Clean removal with interactive prompts
│   └── deploy.sh                      # Orchestrator script (setup → install → verify)
│
├── docs/
│   ├── plans/
│   │   ├── 2026-02-12-vast-rag-system-design.md     # High-level system design
│   │   └── 2026-02-12-vast-rag-implementation.md    # Implementation details
│   └── guides/
│       └── deployment-troubleshooting.md             # Common issues and solutions
│
└── .github/
    └── workflows/
        ├── test.yml                   # CI: Run pytest suite
        └── lint.yml                   # CI: Run ruff linting
```

### Core Modules Explained

**server.py** — Production entry point. Starts the MCP server over stdio with deferred initialization: the MCP handshake completes immediately while document indexing runs in a background task. Includes workarounds for macOS 26+ xzone malloc crashes in native extensions (OpenMP, tokenizers).

**indexer.py** — Orchestration layer that coordinates all indexing components. The DocumentIndexer class manages the end-to-end pipeline: watching for file changes, parsing documents, chunking, embedding, and storin

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [ssotoa70](https://github.com/ssotoa70)
- **Source:** [ssotoa70/vast-rag](https://github.com/ssotoa70/vast-rag)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-ssotoa70-vast-rag
- Seller: https://agentstack.voostack.com/s/ssotoa70
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
