Skip to main content
Glama

qkb — Query Knowledge Base

An on-device hybrid search engine for Obsidian vaults that understands YAML frontmatter metadata. Combines BM25 keyword search (SQLite FTS5) and vector semantic search (sqlite-vec) with metadata filtering, sibling-document surfacing, and two first-class interfaces: a CLI for humans and an MCP server for LLM agents.

Status: TypeScript rewrite — feature-parity with the Python v0.3.0 original, plus multi-provider embeddings and GPU-accelerated (Metal) local embedding on Apple Silicon.

Quickstart

1. Install (isolated global CLI):

npm i -g @miguelarios/qkb

Requires Node ≥20. No separate service, no compile step for the default provider — node-llama-cpp ships prebuilt native binaries (Metal-accelerated on Apple Silicon) that download automatically on install.

2. Point qkb at your vault — create ~/.config/qkb/config.toml:

[vault]
path = "~/Documents/MyVault"   # your Obsidian vault (read-only to qkb)
name = "MyVault"               # used to build obsidian:// links

3. Opt notes in. Only notes whose frontmatter has a context and/or source property are indexed — and an opted-in note also needs an id and a parseable date (created or date):

---
id: f47ac10b-58cc-4372-a567-0e02b2c3d401
context: homelab
created: 2026-03-15
---

4. Index in two phases, then search:

qkb status                       # verify config, vault, and model resolve
qkb ingest                       # keyword index — fast, no model needed
qkb search "certificate renewal" # keyword (BM25) search works right away
qkb embed                        # compute vectors (downloads the model once; resumable)
qkb query "certificate renewal"  # full hybrid (keyword + semantic) search
qkb mcp                          # stdio MCP server for Claude Code / Desktop

Indexing is split so nothing blocks for hours: qkb ingest builds the keyword index in seconds (no model), so qkb search works immediately; qkb embed then computes the vectors that power semantic/hybrid search. qkb embed is resumable — Ctrl-C is safe, and re-running continues where it left off — and qkb status shows how many vectors are still pending.

Claude Code MCP registration:

claude mcp add qkb -- qkb mcp

Related MCP server: mcp-duckvault

Why the rewrite: Apple Silicon embedding is fast now

The Python original (qkb-search, still on PyPI — see Migrating from the Python version below) runs embeddings via onnxruntime, which is CPU-only on macOS: a full re-embed of a ~3,000-note vault takes roughly 4 hours. The TypeScript rewrite's default provider, node-llama-cpp, ships prebuilt Metal-accelerated binaries — the same full re-embed drops to ~10–15 minutes on an Apple Silicon Mac. Same model (embeddinggemma-300M), same search quality; the win is entirely in embedding throughput.

Embedding providers

Four interchangeable providers, set via [embedding].provider in config.toml:

provider

how it runs

when to use

llama (default)

in-process via node-llama-cpp (GGUF, Metal-accelerated on Apple Silicon, prebuilt binaries — no compile)

just works, fastest on-device option, especially on Apple Silicon

ollama

the Ollama HTTP API

you already run Ollama (e.g. a Linux box or shared server)

openai

any OpenAI-compatible /v1/embeddings endpoint

OpenAI itself, Azure OpenAI, or a local server (LM Studio, vLLM, llamafile)

fake

deterministic hash-based vectors, no model

tests and CI only

Switching provider or model changes the vectors, so run qkb embed --full afterward to re-embed everything.

# ~/.config/qkb/config.toml — llama (default)
[embedding]
provider = "llama"
model = "embeddinggemma-300M-Q8_0"
dimension = 768
# local_gguf_repo / local_gguf_file / model_cache_dir also configurable — see below
# ~/.config/qkb/config.toml — ollama
[embedding]
provider = "ollama"
model = "embeddinggemma"
dimension = 768
ollama_host = "http://localhost:11434"
# ~/.config/qkb/config.toml — openai-compatible
[embedding]
provider = "openai"
model = "text-embedding-3-small"
dimension = 1536
openai_base_url = "https://api.openai.com"  # or a local/compatible endpoint

The OpenAI API key is read from the QKB_OPENAI_API_KEY environment variable only — it's never stored in config.toml.

Configuration reference

~/.config/qkb/config.toml (all keys optional; shown with their defaults). QKB_CONFIG=/path/to/alt-config.toml points at a different config file entirely.

[vault]
path = "~/Notes"
name = "Notes"

[database]
path = "~/.local/share/qkb/qkb.db"

[embedding]
provider = "llama"                                     # llama | ollama | openai | fake
model = "embeddinggemma-300M-Q8_0"
dimension = 768
ollama_host = "http://localhost:11434"
local_gguf_repo = "ggml-org/embeddinggemma-300M-GGUF"
local_gguf_file = "embeddinggemma-300M-Q8_0.gguf"
model_cache_dir = "~/.cache/qkb/models"
openai_base_url = ""                                   # optional override
# doc_template / query_template: optional explicit "{t}"-placeholder prompt
# templates, overriding the per-model default asymmetric prefixing.

[chunking]
target_tokens = 500
overlap_percent = 15

[search]
default_limit = 10
rrf_k = 60
vec_candidates = 30
fts_candidates = 30
fts_weights = [5.0, 3.0, 2.0, 1.0, 0.5]

[frontmatter]
# Optional alias mapping for non-default frontmatter property names, e.g.:
# id = ["uuid"]
# created = ["created", "date created"]

Environment-variable overrides

Only the keys below have a QKB_* environment-variable override — [chunking], [search], and [frontmatter] keys do not (config-file-only). An env var always wins over config.toml.

config.toml key

env var

vault.path

QKB_VAULT_PATH

vault.name

QKB_VAULT_NAME

database.path

QKB_DB_PATH

embedding.provider

QKB_EMBEDDING_PROVIDER

embedding.model

QKB_EMBEDDING_MODEL

embedding.dimension

QKB_EMBEDDING_DIM

embedding.ollama_host

QKB_OLLAMA_HOST

embedding.doc_template

QKB_EMBEDDING_DOC_TEMPLATE

embedding.query_template

QKB_EMBEDDING_QUERY_TEMPLATE

embedding.local_gguf_repo

QKB_LOCAL_GGUF_REPO

embedding.local_gguf_file

QKB_LOCAL_GGUF_FILE

embedding.model_cache_dir

QKB_MODEL_CACHE_DIR

embedding.openai_base_url

QKB_OPENAI_BASE_URL

(no config.toml key — env only)

QKB_OPENAI_API_KEY

Plus QKB_CONFIG, which isn't a per-key override — it points qkb at a different config.toml path entirely.

MCP usage

qkb mcp runs a stdio MCP server exposing three tools to LLM agents:

  • qkb — hybrid BM25 + vector search with the same filters as the CLI (context, source, type, tags, date range, limit).

  • qkb_get — retrieve a single document by id (or unambiguous id prefix).

  • qkb_status — index health: document/chunk/vector counts, contexts, pending-vector count.

Register with Claude Code:

claude mcp add qkb -- qkb mcp

Or point any MCP-compatible client at the qkb mcp stdio command directly.

Homebrew

A single-file formula lives at Formula/qkb.rb in this repo (depends_on "node", installs the published npm package). Until a dedicated homebrew-qkb tap exists, install it directly from the repo:

brew install --formula https://raw.githubusercontent.com/miguelarios/qkb/main/Formula/qkb.rb

The Short Version

Notes opt in to indexing via frontmatter (context and/or source properties). An ingestion pipeline walks the vault, chunks markdown with structure-aware break-point scoring, embeds in-process (node-llama-cpp/GGUF by default; Ollama or an OpenAI-compatible endpoint optional), and stores everything in a single SQLite file. A search engine layers BM25 (document-level, weighted columns), vector similarity (chunk-level), and Reciprocal Rank Fusion on top — exposed as qkb search / vsearch / query, qkb get <UUID>, and qkb mcp.

Inspired by QMD's search architecture and its GPU-fast native-binary distribution model, adapted for structured knowledge systems with frontmatter metadata.

Documents

Migrating from the Python version

The original Python implementation (qkb-search, PyPI, v0.3.0) is kept in this repo at legacy/python/ and remains installable (pip install qkb-search / uv tool install qkb-search) but is superseded by this npm package — no further Python releases are planned except emergency patches. Both share the same ~/.config/qkb/config.toml, ~/.local/share/qkb/qkb.db, and ~/.cache/qkb/models paths, but switching between them (or between embedding providers) changes the vectors, so run qkb embed --full after switching.

Development

npm ci
npm test          # vitest, offline (FakeProvider — no Ollama/OpenAI/model download)
npm run typecheck # tsc --noEmit
npm run lint       # biome check
npm run build       # tsc -p tsconfig.build.json -> dist/
npm run golden-queries -- ~/.config/qkb/golden_queries.yaml   # acceptance harness (needs a real index)

npm run golden-queries scores each query in the YAML file against the hybrid top-3 (PRD target: ≥80%); see legacy/python/scripts/golden_queries.example.yaml for the schema. Your real golden-queries file is personal vault data and must never be committed to this repo.

License

MIT

A
license - permissive license
-
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
0dRelease cycle
10Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    D
    maintenance
    Provides semantic search and keyword search over Obsidian notes, along with direct note retrieval, allowing external AI agents to query and access the vault.
    18
    BSD Zero Clause
  • A
    license
    -
    quality
    D
    maintenance
    Enables AI agents to navigate, search, and rank notes in an Obsidian vault using graph relationships, providing context-aware access to knowledge without exposing raw file contents.
    MIT
  • A
    license
    -
    quality
    F
    maintenance
    Persistent semantic memory server for Obsidian vaults, enabling AI agents to search, read, write, and explore notes with semantic understanding and incremental indexing.
    Apache 2.0

View all related MCP servers

Related MCP Connectors

  • Search your knowledge bases from any AI assistant using hybrid RAG.

  • Search your Obsidian vault to quickly find notes by title or keyword, summarize related content, a…

  • Search and reason over your Obsidian-style Markdown vault, right from ChatGPT.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/miguelarios/qkb'

If you have feedback or need assistance with the MCP directory API, please join our Discord server