Vaultdb
БесплатноНе проверенModel Context Protocol server exposing vaultdb-core to LLM agents
Описание
Model Context Protocol server exposing vaultdb-core to LLM agents
README
Markdown vaults, queryable everywhere you want to use them. vaultdb is a Rust library for treating folders of .md files with YAML frontmatter as a queryable database, plus the frontends that sit on it: a CLI (vaultdb), an MCP server for LLM agents (vaultdb-mcp), and a stable library API (vaultdb-core) that any markdown-vault tool can build on.
The thesis: a markdown vault is both a relational table (frontmatter is rows × columns) and a graph ([[wikilinks]] are edges). vaultdb's query AST treats both as first-class — you filter records by frontmatter, by graph predicates ("links to anything tagged X"), or by any combination.
use vaultdb_core::{Expr, Predicate, Query, Value, Vault};
let vault = Vault::discover(std::path::Path::new("."))?;
let records = vault.query(&Query {
folder: "notes".into(),
filter: Some(Expr::Predicate(Predicate::Equals {
field: "status".into(),
value: Value::String("active".into()),
})),
select: None,
sort: None,
limit: Some(10),
recursive: false,
})?;
Or from the CLI:
$ vaultdb query 3-Notes --where "tags contains topic/ai" --select "_name,_backlink_count" --sort _backlink_count --desc --limit 5
+-----------------------------+-----------------+
| _name | _backlink_count |
+==============================================+
| BERT | 43 |
| Machine Learning | 39 |
| Transformer Architecture | 38 |
| Natural Language Processing | 35 |
| Deep Learning | 29 |
+-----------------------------+-----------------+
What it does
- Treats folders of
.mdfiles as database tables - YAML frontmatter fields are queryable columns
[[wiki-links]]form a citation graph with backlink tracking- Supports relational joins across the link graph
- Graph traversal (BFS) with depth limits and filtering
- Bulk mutations (set fields, add/remove tags) with
--dry-runsafety - Rename with automatic wiki-link updates across the vault
- Schema inference and validation
- Library + CLI + MCP server in one workspace — pick whichever fits
No daemon, no cache, no state files. Every command reads the current .md files directly. Edit in Obsidian, query with vaultdb — they coexist without conflict.
Workspace
| Crate | What it is | Use for |
|---|---|---|
vaultdb-core |
Library: parse, query, link graph, mutation builders | Building a markdown-vault tool in Rust |
vaultdb |
CLI binary (this is what cargo install vaultdb ships) |
Command-line use over an existing vault |
vaultdb-mcp |
Model Context Protocol server (stdio) | Letting LLM agents (Claude, Cursor, etc.) query a vault |
See ARCHITECTURE.md for the design rules these frontends follow (library scope discipline, state boundaries, public API contract).
Install
# From crates.io
cargo install vaultdb
# Or from source
git clone https://github.com/rusenbb/vaultdb.git
cd vaultdb
cargo install --path .
Requires Rust 1.75+. Published at https://crates.io/crates/vaultdb.
Quick start
# Auto-detects vault root by finding .obsidian/ directory
cd ~/Documents/my-vault
# Or specify explicitly
vaultdb --vault ~/Documents/my-vault query 3-Notes ...
Data model
Folder = Database / Table
.md file = Record / Row
Frontmatter fields = Columns
[[wiki-links]] = Relations / Edges
Every record automatically has virtual fields:
| Field | Description |
|---|---|
_name |
Filename without .md |
_path |
Relative path from vault root |
_folder |
Parent folder name |
_modified |
File modification time |
_created |
File creation time |
_links |
Outgoing wiki-link targets |
_link_count |
Number of outgoing links |
_backlinks |
Notes that link to this note |
_backlink_count |
Number of incoming links |
_body |
The full body text (everything after the closing --- of the frontmatter) — use with contains, matches, etc. for body search |
_length |
Total file size in bytes |
_body_length |
Body length in bytes (excluding frontmatter) |
_body_links |
Markdown links [label](url) in the body, as {label, url} maps. Query element-wise with matches, e.g. _body_links matches "example\.com" |
Commands
Query
# Basic query with filtering, sorting, limiting
vaultdb query 3-Notes --where "tags contains topic/movies" --select "_name,director,year" --sort year --desc --limit 10
# Multiple --where flags are AND-ed
vaultdb query 3-Notes --where "tags contains topic/chinese" --where "hsk = 1" --select "_name,pinyin,anlam"
# OR within a single --where using ||
vaultdb query 3-Notes --where "status = to-watch || status = to-read" --select "_name,status"
# NOT with ! prefix
vaultdb query 3-Notes --where "tags !contains topic/movies" --where "status exists"
# Output formats: table (default), json, csv, yaml
vaultdb query 3-Notes --where "tags contains topic/ai" --format json
Where expression syntax
FIELD = VALUE # exact match
FIELD != VALUE # not equal
FIELD > VALUE # numeric/string comparison
FIELD < VALUE
FIELD >= VALUE
FIELD <= VALUE
FIELD contains VALUE # list membership or substring
FIELD !contains VALUE # negated
FIELD startswith VALUE
FIELD endswith VALUE
FIELD matches REGEX # regex match
FIELD IN (a, b, c) # SQL-style list membership
FIELD NOT IN (a, b, c) # negated
FIELD IS NULL # alias for `missing`
FIELD IS NOT NULL # alias for `exists`
FIELD exists # field is present and non-null
FIELD missing # field is absent or null
FIELD !exists # negated exists (same as missing)
Boolean composition inside a single --where:
# AND with && (SQL-conventional: binds tighter than ||)
--where "tags contains topic/ai && status = active"
# OR with ||
--where "status = active || status = pending"
# Mixed: AND binds tighter, so a || b && c parses as a || (b && c)
--where "status = draft || status = active && hsk = 1"
# Parenthesised grouping for explicit precedence
--where "(status = draft || status = active) && hsk = 1"
# Word-prefix NOT for negating a whole sub-expression
--where "NOT (status = archived || status = deleted)"
# Quoted string values for needles with spaces or special chars
--where 'title = "Two-word title"'
--where "status IN (\"in review\", \"needs follow-up\")"
Multiple --where flags are also AND-ed:
--where "status = active || status = pending" --where "tags contains topic/ai"
Body search
Use the _body virtual field to search inside note bodies (the text after the frontmatter):
# Find every note that mentions "Stanford" in its body
vaultdb query 3-Notes --where '_body contains "Stanford"'
# Combined with frontmatter filtering — runs through the streaming
# query path, so it's cheap on large vaults.
vaultdb query 3-Notes --where 'status = active && _body contains "machine learning"'
# Regex on the body
vaultdb query 3-Notes --where '_body matches "^# Conclusion"'
Body content is loaded only when a body predicate is referenced; queries that don't need it stay on the fast frontmatter-only path.
Export query results to a file
Use --output <vault-relative path> to save results into the vault. The
format is inferred from the extension — .csv, .tsv, .json,
.yaml/.yml, .xlsx are all supported. The path must stay inside the
vault; absolute paths, .. escapes, and .md extensions are rejected.
# CSV (default delimiter is comma)
vaultdb query 3-Notes --where "tags contains topic/ai" --output exports/ai-notes.csv
# Semicolon-delimited CSV (European convention)
vaultdb query 3-Notes --output exports/ai.csv --csv-delimiter semicolon
# Tab-separated; .tsv extension also forces tab by default
vaultdb query 3-Notes --output exports/ai.tsv
# JSON / YAML
vaultdb query 3-Notes --where "tags contains topic/ai" --output exports/ai.json
vaultdb query 3-Notes --where "tags contains topic/ai" --output exports/ai.yaml
# XLSX — typed cells (numbers as numbers, booleans as booleans)
vaultdb query 3-Notes --where "tags contains topic/ai" --output exports/ai.xlsx
On filename collision the file is auto-suffixed (1), (2), ... — no
overwrite mode by design. When --output is set, the resolved path is
printed and stdout no longer carries the result body. The same renderer
powers MCP's export parameter on every read tool (see below), so a
CLI export and an MCP export of the same query produce byte-identical
files.
Create
# Create a note from a template
vaultdb create 3-Notes --template "templates/Movie Notes.md" --name "Arrival" --set "director=Denis Villeneuve" --set "year=2016"
# Create without a template (minimal frontmatter)
vaultdb create 3-Notes --name "Computer Vision" --set "tags=type/concept"
# Batch create from unresolved links
vaultdb unresolved 3-Notes --from BERT --depth 2 | ... | while read name; do
vaultdb create 3-Notes --template templates/concept.md --name "$name"
done
The --template path is relative to vault root. Any .md file works as a template — vaultdb reads it, applies --set overrides to frontmatter, and writes the result.
Count, Fields, Tags
# Count matching records
vaultdb count 3-Notes --where "tags contains topic/chinese"
# List all frontmatter fields with types and frequencies
vaultdb fields 3-Notes
# List all tags with usage counts
vaultdb tags 3-Notes
Graph: Links, Traverse, Unresolved
# Show outgoing and incoming links for a note
vaultdb links React
# Find the most referenced notes
vaultdb query 3-Notes --select "_name,_backlink_count" --sort _backlink_count --desc --limit 10
# Find orphan notes (no links in or out)
vaultdb query 3-Notes --where "_backlink_count = 0" --where "_link_count = 0"
# BFS traversal from a starting note
vaultdb traverse Microservices --depth 2
vaultdb traverse Database --depth 1 --direction incoming
# Filter traversal results
vaultdb traverse BERT --depth 2 --where "tags contains type/concept" --select "_backlink_count"
# Find [[wiki-links]] pointing to non-existent files
vaultdb unresolved 3-Notes
# Scoped to a neighborhood
vaultdb unresolved 3-Notes --from BERT --depth 3
# Verbose: show which notes reference each unresolved link
vaultdb unresolved 3-Notes -v
Relational joins
# Notes that link to React
vaultdb query 3-Notes --links-to React
# Notes that React links to
vaultdb query 3-Notes --linked-from React
# Notes linking to ANY note tagged topic/ai (the join)
vaultdb query 3-Notes --links-to-where "tags contains topic/ai" --select "_name,_backlink_count" --sort _backlink_count --desc
# Notes linked from any movie note
vaultdb query 3-Notes --linked-from-where "tags contains topic/movies" --where "tags contains type/concept"
# Notes linking to both React AND Node.js
vaultdb query 3-Notes --links-to React --links-to "Node.js" --select "_name"
Mutations
All write operations support --dry-run to preview changes without writing.
# Set a field
vaultdb update 3-Notes --where "_name = 1917" --set "status=watched" --dry-run
# Add/remove tags
vaultdb update 3-Notes --where "director contains Chaplin" --add-tag "director/charlie-chaplin" --dry-run
# Remove a field
vaultdb update 3-Notes --where "_name = React" --unset "deprecated" --dry-run
# Replace the body (bash ANSI-C quoting `$'...'` lets you embed real newlines)
vaultdb update 3-Notes --where "_name = React" --set-body $'# React\n\nRewritten.\n' --dry-run
# Append to the body (default separator: a single \n; override with --body-separator)
vaultdb update 5-Tasks --where "_name = 2026-05-28" --append-body "- [ ] follow up" --dry-run
# Append with a blank-line section break instead
vaultdb update 5-Tasks --where "_name = 2026-05-28" \
--body-separator '\n\n' --append-body "## Notes" --dry-run
# Clear the body, keep the frontmatter
vaultdb update 3-Notes --where "_name = Scratch" --clear-body --dry-run
# Create a note with explicit body content
vaultdb create 5-Tasks --name "2026-05-28" --body $'## Today\n- [ ] write code\n'
# Move files
vaultdb move 5-Tasks --where "_name startswith 2026-02" --to 5-Tasks/archive --dry-run
# Delete (moves to .trash/ by default, --force for permanent)
vaultdb delete 3-Notes --where "_name = OldNote" --dry-run
# Rename with automatic wiki-link updates across the vault
vaultdb rename React "React.js" --folder 3-Notes --dry-run
Mutations require at least one --where condition to prevent accidental bulk changes.
Schema
# Infer a schema from existing data
vaultdb schema init 3-Notes
# Validate records against a schema file (vaultdb-schema.yaml)
vaultdb schema validate 3-Notes
# Show the current schema
vaultdb schema show 3-Notes
Performance
No caching, no indexing — reads files fresh on every command.
Numbers below are best-of-3 from cargo run --release --example bench -- <N>,
measured on an Intel i7-14700K desktop (full host details and
methodology in BENCHMARKS.md):
| Scale | Frontmatter query | Graph query | link_graph(All) |
|---|---|---|---|
| 1 000 notes | 5 ms | 7 ms | 6 ms |
| 10 000 notes | 59 ms | 88 ms | 70 ms |
| 100 000 notes | 651 ms | 1 032 ms | 819 ms |
Scaling is roughly linear in vault size — 10× the records costs about 10–12× the time, with no superlinear cliff up through 100k. Every operation finishes in under 1.1 seconds at 100k notes.
Reproduce with:
cargo run --release -p vaultdb-core --example bench -- 10000
Two-parser architecture: serde_yaml for fast reads, line-by-line string manipulation for formatting-preserving writes.
Safety
--dry-runpreviews all mutations before writingupdate,move,deleterefuse to run without--wheredeletewarns about dangling wiki-links before proceedingdeletemoves to.trash/by default (with collision-safe naming)renameauto-updates all[[wiki-links]]across the vault- Writer detects and refuses to modify flow-style YAML (
[a, b]) or multiline scalars (|,>) - Files without frontmatter are loaded with empty fields (queryable by virtual fields, never silently skipped)
Library usage (vaultdb-core)
Add to your Cargo.toml:
[dependencies]
vaultdb-core = { git = "https://github.com/rusenbb/vaultdb" }
The full public surface lives at the crate root: Vault, Record, Value, Query, Expr, Predicate, LinkPredicate, LinkGraph, GraphScope, Direction, UpdateBuilder, DeleteBuilder, MoveBuilder, RenameBuilder, MutationReport, LoadResult, ParseError, VaultdbError. All public data types are Serialize/Deserialize-able.
use vaultdb_core::{
Expr, LinkPredicate, Query, UpdateBuilder, Value, Vault,
};
let vault = Vault::discover(std::path::Path::new("/path/to/vault"))?;
// Records that link to anything tagged topic/ai
let q = Query {
folder: "notes".into(),
filter: Some(Expr::LinksTo(LinkPredicate::Where(Box::new(
Expr::parse("tags contains topic/ai")?,
)))),
select: None,
sort: None,
limit: None,
recursive: false,
};
let hits = vault.query(&q)?;
// Plan-only mutation: see what would change without writing
let filter = Expr::parse("status = draft")?;
let plan = UpdateBuilder::new("notes", filter)
.set("status", Value::String("published".into()))
.plan(&vault)?;
for change in &plan.changes {
println!("{}: {}", change.path.display(), change.description);
}
Every mutation builder exposes a plan(&vault) and an execute(self, &vault). plan is read-only; execute runs the same computation and writes the result. The CLI's --dry-run flag is just plan() + render.
MCP server (vaultdb-mcp)
vaultdb-mcp exposes the library as a Model Context Protocol server over stdio, so Claude, Cursor, and other MCP-aware clients can query and reason about a vault.
cargo install --path crates/vaultdb-mcp
Wire it into Claude Desktop's config (~/.config/claude/claude_desktop_config.json on Linux, ~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"vaultdb": {
"command": "vaultdb-mcp",
"args": ["--vault", "/absolute/path/to/your/vault"]
}
}
}
Tools exposed:
Read — query, find_by_name, list_folders, links, traverse, unresolved. Every read tool also accepts export: "<vault-relative path>" and csv_delimiter: "comma" | "semicolon" | "tab" — when export is set, the result is also written to a file under the vault (same path-safety rules as the CLI's --output) and the response is wrapped as { "data": <result>, "exported_to": "<path>" }. When export is unset, the response shape is unchanged.
Schema — schema_show, schema_infer. Both also accept export — use .json or .yaml for these since the schema shape isn't tabular.
Plan-only mutation (preview, never writes) — plan_create, plan_update, plan_delete, plan_move, plan_rename. Default flow: agents propose, you approve, hosts execute.
Execute — execute_create, execute_update, execute_move, execute_rename, execute_delete. Disabled by default. Enable per-capability via launch flags:
--dangerously-allow-create
--dangerously-allow-update (covers update + move + rename)
--dangerously-allow-delete (soft-delete to .trash/)
--dangerously-allow-permanent-delete (required in addition to -delete)
Every successful execute call appends a line to <vault>/.vaultdb/audit.log with the timestamp, tool name, params, and change count. The default mode (no flags) preserves the "propose, approve, execute via a separate path" pattern; opt-in flags shift execution to the agent for sessions where that's the desired ergonomics.
Claude Code integration
vaultdb ships with a Claude Code skill so LLM agents can use it directly. To install:
# Copy the skill to your personal skills directory
mkdir -p ~/.claude/skills/vaultdb
cp skills/vaultdb/SKILL.md ~/.claude/skills/vaultdb/SKILL.md
Then in any Claude Code session, the agent can invoke /vaultdb or use it automatically when you ask about your vault.
Not Obsidian-specific
Despite being designed for Obsidian vaults, vaultdb works with any folder of .md files with YAML frontmatter. Hugo, Jekyll, Astro, Zola, or any static site generator's content directory is a valid target.
License
MIT
Установка Vaultdb
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/rusenbb/vaultdbFAQ
Vaultdb MCP бесплатный?
Да, Vaultdb MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Vaultdb?
Нет, Vaultdb работает без API-ключей и переменных окружения.
Vaultdb — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Vaultdb в Claude Desktop, Claude Code или Cursor?
Открой Vaultdb на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Fetch
Web content fetching and conversion for efficient LLM usage.
AWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
автор: modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
автор: xuzexin-hzMCP-Agent
A simple, composable framework to build agents using Model Context Protocol by [LastMile AI](https://www.lastmileai.dev)
автор: lastmile-aiSpring AI MCP Client
Provides auto-configuration for MCP client functionality in Spring Boot applications.
mcp.natoma.ai
A Hosted MCP Platform to discover, install, manage and deploy MCP servers by [Natoma Labs](https://www.natoma.ai)
MCPHub
Website to list high quality MCP servers and reviews by real users. Also provide online chatbot for popular LLM models with MCP server support.
MCP Servers Rating and User Reviews
Website to rate MCP servers, write authentic user reviews, and [search engine for agent & mcp](http://www.deepnlp.org/search/agent)
mkinf
An Open Source registry of hosted MCP Servers to accelerate AI agent workflows.
Compare Vaultdb with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории ai
