AgentStack
MCP verified MIT Self-run

Roowet Semantic Vault Search

mcp-brodewa369-roowet-semantic-vault-search · by brodewa369

Local RAG semantic search for Obsidian vaults — Ollama + LanceDB + MCP. Search your markdown vault by meaning, not keyword.

No reviews yet
0 installs
0 views
view→install

Install

$ agentstack add mcp-brodewa369-roowet-semantic-vault-search

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Roowet Semantic Vault Search? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Semantic Vault MCP

Local RAG semantic search for Obsidian vaults — powered by Ollama + LanceDB + MCP.

Search your markdown vault by meaning (not keyword matching). Runs fully local — zero API costs, zero data leaves your machine.

User query → Ollama embed → LanceDB vector search → relevant chunks → LLM context

Features

  • 🔍 Semantic search — find notes by concept, not keyword
  • Batch embedding — 30-50x faster than serial (50 chunks per HTTP call)
  • 👁️ Auto file watcher — re-index files as they change (via watchdog)
  • 🧩 MCP server — drop-in tool for Claude Desktop / Claude Code / Hermes
  • 💾 Persistent hash store — incremental indexing, only re-index what changed
  • 🔄 Crash-safe — circuit breaker for Ollama, batch writes to LanceDB

Quick Start

Prerequisites

  • Python 3.10+
  • Ollama running locally
  • An Obsidian vault (or any markdown folder)

1. Install

# Clone
git clone https://github.com/brodewa369/roowet-semantic-vault-search.git
cd semantic-vault-mcp

# Windows
setup.bat

# Linux/Mac
chmod +x setup.sh && ./setup.sh

2. Configure

Edit .env:

VAULT_ROOT=C:/Users/you/your-obsidian-vault
OLLAMA_BASE_URL=http://localhost:11434
EMBED_MODEL=bge-m3

3. Index your vault

python indexer/vault_indexer.py --once

4. Add MCP to Claude Desktop / Hermes

{
  "mcpServers": {
    "semantic-vault": {
      "command": "python",
      "args": ["-m", "mcp_server.server"],
      "env": {
        "VAULT_ROOT": "C:/Users/you/your-vault",
        "LANCEDB_PATH": "./data/lancedb",
        "OLLAMA_BASE_URL": "http://localhost:11434",
        "EMBED_MODEL": "bge-m3"
      }
    }
  }
}

Restart Claude Desktop. You now have search_vault(), read_vault_file(), vault_stats() in your agent's toolbelt.

Architecture

graph TB
    subgraph Vault["📁 Markdown Vault (VAULT_ROOT)"]
        MD[".md files01-AGENT-MEMORY/ 02-KNOWLEDGE/03-RESEARCH/ ... (excl: .obsidian .trash .git)"]
    end

    subgraph Indexer["⚙️ vault_indexer.py"]
        SCAN["Scan .md (rglob)"]
        CHUNK["Chunk by ## headers(CHUNK_SIZE=512, OVERLAP=64)"]
        HASH["MD5 hash store(incremental change detect)"]
        EMBED["OllamaEmbedder.embed_batch()/api/embed — 50 chunks/callcircuit breaker (5 fails → 60s pause)"]
        LOCK["Instance lock (msvcrt)+ backup before index"]
    end

    subgraph Store["💾 LanceDB (LANCEDB_PATH)"]
        LANCE["vault_chunks.lance tablechunk_id | source | text | vector[1024] | indexed_at"]
        HASHJSON["vault_indexer_hashes.jsonfilepath → MD5"]
    end

    subgraph Ollama["🤖 Ollama (localhost:11434)"]
        MODEL["EMBED_MODEL: bge-m3(1024-dim, multilingual)"]
    end

    subgraph MCP["🔌 mcp_server/server.py (stdio JSON-RPC)"]
        TOOLS["Tools:search_vault · read_vault_filevault_stats · get_chunkreindex_file · index_stats"]
        QEMBED["embed_query()/api/embeddings"]
    end

    subgraph Client["🤖 MCP Client (Agent)"]
        AGENT["Claude / Hermes / Codex / OpenClawSOUL.md (non-Claude) · CLAUDE.md (Claude)"]
        SKILL["/scanthissession skill(scan → write vault)"]
    end

    Vault --> SCAN
    SCAN --> CHUNK --> HASH
    CHUNK --> EMBED --> Ollama
    Ollama --> MODEL
    EMBED --> LANCE
    HASH --> HASHJSON
    LOCK -.-> Store

    Client -->|MCP tools/call| MCP
    AGENT --> SKILL
    TOOLS --> QEMBED --> Ollama
    QEMBED --> LANCE
    TOOLS -->|read_vault_file| Vault
    MCP -->|search results| Agent

Full Pipeline

flowchart TD
    %% ===== STAGE 5 CLASSIFICATION (agent detects need first) =====
    S1["User query / task"] --> S5{"Stage 5: ClassificationNeed detail from vault?"}
    S5 -->|NO — SIMPLE| S5a["Answer directly(1–3 tool calls, no vault)"]
    S5 -->|YES — MEDIUM/COMPLEX| S5b["search_vault(query, top_k=5)"]

    S5b --> S5c{"Relevant chunksfound?"}
    S5c -->|YES| S5d["Read context (read_vault_file if needed)+ Holographic Memory + prior session"]
    S5c -->|NO / score (state 'not found in vault')"]
    S5d --> S6["Execution (tool calls, code, write)"]
    S5e --> S6
    S5a --> S6
    S6 --> S7["Generate & deliver response"]
    S7 --> S8["Post-task: auto-log vault + memory update(/scanthissession)"]

    %% ===== QUERY MECHANISM =====
    S5b -.->|MCP call| Q1["mcp_server/server.pytool_search_vault()"]
    Q1 --> Q2["embed_query(query)POST /api/embeddings → Ollama bge-m3"]
    Q2 --> Q3["LanceDB table.search(vector).limit(top_k)"]
    Q3 --> Q4["return: source, text, score"]
    Q4 -.-> S5c

    %% ===== INDEX PIPELINE =====
    subgraph IDX["🔄 INDEX PIPELINE (--once / --watch / --reindex)"]
        I1["vault_indexer.py"] --> I2["Scan VAULT_ROOT *.md(excl .obsidian/.trash/.git)"]
        I2 --> I3["MD5 vs hash store(skip if unchanged)"]
        I3 -->|changed| I4["chunk_file() by ## headers"]
        I4 --> I5["embed_batch(50/call)POST /api/embed → Ollama"]
        I5 --> I6["table.add(rows)chunk_id|source|text|vector[1024]|indexed_at"]
        I6 --> I7["update hash store"]
    end
    I5 -.-> OLLAMA[(Ollama bge-m3)]
    I6 --> LANCE[(LanceDB vault_chunks.lance)]
    Q3 --> LANCE
    LANCE -.->|watchdog --watch| I3

    %% ===== MAINTENANCE =====
    M1["cron every 6h: --once (incremental)"] -.-> I1
    M2["reindex_file(filepath) MCP tool"] -.-> I4

Commands

| Command | Description | |---------|-------------| | python indexer/vault_indexer.py --once | Index all vault files once | | python indexer/vault_indexer.py --watch | Run as file watcher daemon | | python indexer/vault_indexer.py --reindex | Clear and re-index everything | | python -m mcp_server.server | Start MCP server (stdio transport) |

MCP Tools

| Tool | Description | |------|-------------| | search_vault(query, top_k=5) | Semantic search by meaning | | read_vault_file(filepath) | Read full file content | | vault_stats() | Index statistics | | get_chunk(source) | Get all chunks for a file | | reindex_file(filepath) | Re-index a specific file | | index_stats() | Hash-store statistics |

Environment Variables

| Variable | Required | Default | Description | |----------|----------|---------|-------------| | VAULT_ROOT | ✅ | ./vault | Path to markdown vault | | LANCEDB_PATH | ✅ | ./data/lancedb | Vector store path | | OLLAMA_BASE_URL | ✅ | http://localhost:11434 | Ollama endpoint | | EMBED_MODEL | ✅ | bge-m3 | Embedding model | | EMBED_DIM | ❌ | 1024 | Embedding dimensions | | CHUNK_SIZE | ❌ | 512 | Chunk size (chars) | | OVERLAP | ❌ | 64 | Chunk overlap | | BATCH_SIZE | ❌ | 50 | Embedding batch size | | EXCLUDE_DIRS | ❌ | .obsidian,.trash,.git | Folders to skip | | MAX_BACKUPS | ❌ | 2 | Backup retention |

Project Structure

semantic-vault-mcp/
├── README.md               # Quick start + MCP config
├── CLAUDE.md              # Agent identity template — PURPOSE: Claude / Claude Code
├── AGENTS.md               # Technical MCP context + Hermes integration
├── SOUL.md                # Agent identity template — PURPOSE: agent non-Claude (Hermes/Codex/OpenClaw/OpenCode)
├── skills/                 # Agent skills
│   └── scanthissession/    # /scanthissession — scan session → write to vault
├── LICENSE                 # MIT
├── pyproject.toml        # pip install .
├── requirements.txt
├── .env.example           # All 12 env vars documented
├── .gitignore
├── setup.bat              # Windows one-click setup
├── setup.sh               # Linux/Mac one-click setup
├── indexer/
│   ├── __init__.py
│   └── vault_indexer.py    # Scan → chunk → embed → store
├── mcp_server/
│   ├── __init__.py
│   └── server.py           # MCP protocol server
├── vault-structure/         # Example vault layout
│   ├── README.md           # Folder structure explained
│   ├── obsidian-setup.md   # Recommended Obsidian plugins
│   ├── 00-NOTES/ … 08-DOCS/ # 30+ empty folders
│   ├── 06-SYSTEM/rules/    # Naming, routing, MOC creation
│   └── 06-SYSTEM/templates/ # 28 note templates
└── docs/
    └── ARCHITECTURE.md     # Data flow + design decisions

Requirements

  • Ollama with any embedding model (tested: bge-m3, nomic-embed-text)
  • Python packages: lancedb, pyarrow, requests, watchdog
  • ~2GB RAM for LanceDB (depends on vault size)

Keeping Your Index Fresh

Why regular indexing matters:

The RAG search is only as good as your index. If you add/edit 50 files but haven't re-indexed, the search will return stale chunks — or miss new content entirely.

The indexer uses MD5 content hashes to detect changes, so re-indexing is fast:

# Incremental — only processes changed files (usually ` | Path to your markdown vault | `C:/Users/you/vault` | `~/vault` |
| `` | Path to Hermes scripts | `AppData/Local/hermes/scripts` | `~/.hermes/scripts` |

In `skills/scanthissession/SKILL.md`: replace `` (line ~48) and `` (line ~52) with your environment paths.
`SOUL.md` / `CLAUDE.md` are generic templates — set `VAULT_ROOT` in `.env` (see `AGENTS.md`) so `search_vault()` works.

**Different purpose:** `SOUL.md` = non-Claude agents (Hermes/Codex/OpenClaw/OpenCode). `CLAUDE.md` = Claude/Claude Code. Content is the SAME.

## Skills

### `/scanthissession` — Session Scanner & Vault Writer

The agent scans the session transcript, detects vault-relevant items (errors, decisions, corrections, lessons, etc.), then **automatically writes them to the correct vault folder**. This solves agents "forgetting" to log — the skill FORCES scan + write, instead of relying on passive instructions.

```bash
/scanthissession
# or say: "scan session", "log session ini"

When: after a long session (>10 tool calls), before ending a session. Output: files written to /01-AGENT-MEMORY/... + daily-note updated.

License

MIT

Source & license

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

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

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.