OnMind-RAG
A lightweight knowledge base MCP server that enables full-text search and retrieval of markdown documents from indexed sites using Orama BM25.
README
OnMind-RAG
A complementary and independent project from OnMind-PUB: a lightweight knowledge base (light RAG) that exposes an MCP server so an agent (MCP client) can query the content of one or more sites.
It is not part of the init → index → build → publish workflow. It only reads the _index.json already generated by a site and, on demand, the markdown.
Idea
- On startup, the server loads
docs/public/_index.jsonfrom each configured site. - Normalizes in memory (stable IDs, clean tags,
visibility, path to.md). - Body cache: reads each
.mdonce, storesbodyText(no frontmatter) and logs time/size to stderr. - Search engine: Orama BM25 full-text by default;
hybrid/vectormodes opt-in with embeddings. - Exposes compact MCP tools: summary → search (meta + body) → document reading.
No _catalog.json is written. If the site re-indexes externally, use the reload_catalog tool.
Requirements
- Node.js ≥ 18 (or Bun with Node compatibility)
- At least one site with
docs/public/_index.json(e.g.sites/knowfrom OnMind-PUB)
Setup
cd rag
cp .env.example .env # optional; you can also export vars
bun install # or: npm install
Variables (see .env.example):
| Variable | Meaning |
|---|---|
RAG_SITES |
Paths to site roots, comma-separated (required) |
RAG_SITE_NAMES |
Optional labels (same order) |
RAG_VISIBILITY |
public (default) | protected | all |
RAG_MAX_BODY |
Max chars returned by read_document (default 50000; increase for very long docs) |
RAG_CACHE_BODY |
1 (default) caches body at startup → Orama indexes body → full-text on markdown. 0 = metadata only (title/desc/tags) → no body search; read_document falls back to disk. |
RAG_SEARCH_MODE |
fulltext (default, BM25) | hybrid | vector (last two require RAG_EMBEDDINGS=1) |
RAG_EMBEDDINGS |
1 enables local hash embeddings for hybrid/vector; 0 (default) |
RAG_EMBED_DIMS |
Vector dimensions (default 384) |
RAG_SNAPSHOT |
1 saves/loads Orama snapshot to disk; 0 (default) |
RAG_SNAPSHOT_PATH |
Snapshot path (default ./data/orama-snapshot.json) |
Example:
export RAG_SITES=../sites/know
# or multiple:
# export RAG_SITES=../sites/know,../sites/andrey
Smoke test (no MCP)
RAG_SITES=../sites/know bun run smoke
With embeddings + hybrid:
RAG_SITES=../sites/know RAG_EMBEDDINGS=1 RAG_SEARCH_MODE=hybrid bun run smoke
With snapshot (2nd load ~100 ms):
RAG_SITES=../sites/know RAG_SNAPSHOT=1 bun run smoke # first: saved
RAG_SITES=../sites/know RAG_SNAPSHOT=1 bun run smoke # second: loaded
Start MCP server (stdio)
RAG_SITES=../sites/know bun run mcp
MCP Client (Cursor / Claude Desktop / Grok / Jan)
{
"mcpServers": {
"onmind-rag": {
"command": "bun",
"args": ["/absolute/path/to/pub/rag/src/server.js"],
"env": {
"RAG_SITES": "/absolute/path/to/pub/sites/know",
"RAG_VISIBILITY": "public",
"RAG_SEARCH_MODE": "fulltext",
"RAG_EMBEDDINGS": "0",
"RAG_SNAPSHOT": "0"
}
}
}
}
You can also use
nodeinstead ofbun
{
"command": "node",
"args": ["/absolute/path/to/pub/rag/src/server.js"],
"env": { "RAG_SITES": "/absolute/path/to/pub/sites/know" }
}
Tools
| Tool | Purpose |
|---|---|
list_sites |
Loaded sites, body-cache stats, search-engine status (Orama, embeddings, snapshot) |
catalog_summary |
Stats by category / language / tags (orientation) |
search_content |
Full-text Orama (BM25) by default on title/description/tags/body. mode: fulltext|hybrid|vector optional. Returns cards with match.score and match.snippet. |
get_entry |
One record by id (site:url) |
read_document |
Markdown body (preferably from cache; truncatable) |
list_series |
Series ordered by filename within a category |
reload_catalog |
Re-reads _index.json + body cache + rebuilds index |
Typical agent flow:
catalog_summary → search_content → get_entry / list_series → read_document
Relation to OnMind-PUB
| OnMind-PUB | onmind-rag |
|---|---|
Generates _index.json and the static site |
Only consumes it |
| Publish workflow | Outside that flow |
| Lives in monorepo for convenience | Movable: just point RAG_SITES to any folder with docs/public/_index.json |
Body cache (startup)
In stderr you'll see something like:
[onmind-rag] index: 289 entries from 1 site(s) in 3ms at ...
[onmind-rag] body cache: 289 docs, 3533.3 KiB in 59ms (missing path=0, read errors=0)
[onmind-rag] search engine: orama · mode=fulltext · embeddings=off · 289 docs · 450ms
With RAG_CACHE_BODY=1 (default): Orama indexes the body field → search_content performs full-text BM25 over the entire markdown. read_document answers from memory (fromCache: true).
With RAG_CACHE_BODY=0: Orama only indexes metadata (title, description, tags) → search_content does not find matches in the document body. read_document falls back to disk reads.
Disable only if RAM is very tight or corpus > 50 MB and you accept metadata-only search.
Search engine (Orama)
| Mode | What it does |
|---|---|
fulltext (default) |
BM25 with stemming, typo tolerance, field boosting. Fast, no external deps. |
hybrid |
BM25 + vector (cosine) — needs RAG_EMBEDDINGS=1 |
vector |
Vector similarity only — needs RAG_EMBEDDINGS=1 |
Embeddings (opt-in)
RAG_EMBEDDINGS=1 uses local feature-hashing (no TensorFlow, no API keys) — a portable baseline to exercise the vector/hybrid path. Not a SOTA semantic model. For real quality, replace embed.js with a provider (OpenAI, Xenova/transformers.js, etc.) keeping the embedText(text, { dims }) interface.
Snapshot (opt-in)
RAG_SNAPSHOT=1 serializes the Orama index to disk (data/orama-snapshot.json + .meta.json). On subsequent starts, if the corpus fingerprint (ids, titles, body length, hide, embeddings flag/dims) matches, it loads the snapshot in ~100 ms instead of re-indexing (~450 ms).
Limits (by design)
- Lexical/BM25 retrieval + hash vectors (no SOTA embeddings unless you plug them in).
- No knowledge graph / neighbors yet (next step: markdown links).
- Designed as a useful, portable base — not a managed vector engine.
Why Spanish tokenizer?
The corpus is predominantly Spanish (~80%). Orama's default English tokenizer treats short technical codes like "XDB", "IAM", "UCDM" as stop-words/noise. Setting language: 'spanish' in the tokenizer indexes them correctly.
Based on onmind-rag v0.2.0 — MCP server for knowledge retrieval with Orama BM25 + opt-in hybrid/vector + snapshot
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。