@oomkapwn/enquire-mcp 2.0.0-beta.4 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +246 -0
- package/README.md +170 -393
- package/dist/fts5.d.ts +11 -0
- package/dist/fts5.d.ts.map +1 -1
- package/dist/fts5.js +77 -11
- package/dist/fts5.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +406 -4
- package/dist/index.js.map +1 -1
- package/dist/tools.d.ts +128 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +523 -67
- package/dist/tools.js.map +1 -1
- package/docs/api.md +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,484 +1,261 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<a href="https://github.com/oomkapwn/enquire-mcp"><img src="./assets/social-preview.png" alt="enquire — MCP server for Obsidian vaults. Wikilinks, frontmatter, backlinks, Dataview,
|
|
3
|
+
<a href="https://github.com/oomkapwn/enquire-mcp"><img src="./assets/social-preview.png" alt="enquire — MCP server for Obsidian vaults. Hybrid retrieval (BM25 + TF-IDF + ML embeddings via RRF). Wikilinks, frontmatter, backlinks, Dataview, multilingual semantic search. For Claude Code, Cursor, Codex." width="100%"></a>
|
|
4
4
|
|
|
5
|
-
# enquire
|
|
5
|
+
# enquire — MCP server for Obsidian
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
**enquire** turns your **Obsidian** vault into structured, searchable memory for **Claude Code, Cursor, OpenClaw 🦞, Codex**, and any MCP-compatible agent.
|
|
10
|
-
|
|
11
|
-
Wikilinks resolved with aliases and sections. Backlinks ranked with snippets. Frontmatter typed. Dataview queries first-class. **Hybrid retrieval** (BM25 + TF-IDF + ML embeddings, fused via Reciprocal Rank Fusion) that catches paraphrases and synonyms the way Smart Connections does — but free, offline-capable, and open-source.
|
|
12
|
-
|
|
13
|
-
Read-only by default. No Obsidian plugin required. One command to install.
|
|
7
|
+
**Hybrid retrieval (BM25 + TF-IDF + ML embeddings, RRF-fused) for your Obsidian vault.** Drop-in for Claude Code, Cursor, OpenClaw 🦞, Codex, Devin, and any MCP-compatible agent. Free. Multilingual (50+ languages). Offline-capable. No Obsidian plugin required.
|
|
14
8
|
|
|
15
9
|
[](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml)
|
|
16
|
-
[](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
|
|
11
|
+
[](https://www.npmjs.com/package/@oomkapwn/enquire-mcp/v/beta)
|
|
12
|
+
[](#engineering)
|
|
13
|
+
[](./LICENSE)
|
|
20
14
|
[](https://modelcontextprotocol.io/)
|
|
15
|
+
[](https://slsa.dev/spec/v1.0/levels#build-l3)
|
|
21
16
|
|
|
22
17
|
</div>
|
|
23
18
|
|
|
24
|
-
### Quick start (30 seconds)
|
|
25
|
-
|
|
26
|
-
> **🚧 Two release channels right now.** Stable `npm install … @latest` is **v1.x** (28 tools, no ML embeddings, no hybrid search). The headline `obsidian_search` (BM25 + TF-IDF + ML embeddings via RRF) and `obsidian_embeddings_search` ship under the **`@beta` channel** — opt in with `@oomkapwn/enquire-mcp@beta`. Stable v2.0 promotes once `@beta` proves out.
|
|
27
|
-
|
|
28
19
|
```bash
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-- npx -y @oomkapwn/enquire-mcp serve --vault ~/path/to/your/vault
|
|
32
|
-
|
|
33
|
-
# Beta (v2.0 — adds obsidian_search hybrid + obsidian_embeddings_search):
|
|
34
|
-
claude mcp add --transport stdio obsidian \
|
|
35
|
-
-- npx -y @oomkapwn/enquire-mcp@beta serve --vault ~/path/to/your/vault
|
|
36
|
-
|
|
37
|
-
# Cursor / OpenClaw / Codex / others — drop this into your MCP config:
|
|
38
|
-
{
|
|
39
|
-
"mcpServers": {
|
|
40
|
-
"obsidian": {
|
|
41
|
-
"command": "npx",
|
|
42
|
-
"args": ["-y", "@oomkapwn/enquire-mcp@beta", "serve", "--vault", "/path/to/vault"]
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
20
|
+
npm install -g @oomkapwn/enquire-mcp
|
|
21
|
+
enquire-mcp serve --vault ~/Documents/Obsidian\ Vault
|
|
46
22
|
```
|
|
47
23
|
|
|
48
|
-
|
|
24
|
+
That's it. Your AI now has structured access to wikilinks, backlinks, frontmatter, Dataview queries, and **`obsidian_search`** — a single hybrid-retrieval tool that auto-fuses BM25 + TF-IDF + ML embeddings.
|
|
49
25
|
|
|
50
|
-
|
|
51
|
-
You: "What was I working on yesterday in the Apollo project?"
|
|
52
|
-
Claude: → obsidian_get_recent_edits({ since_minutes: 1440, folder: "01_Projects" })
|
|
53
|
-
→ obsidian_read_note({ title: "Apollo" })
|
|
54
|
-
→ obsidian_get_backlinks({ title: "Apollo" })
|
|
55
|
-
"You shipped the v0.3 spec, opened 3 open questions in [[Apollo/Open Threads]],
|
|
56
|
-
and 2 daily notes link back to it. Top blocker: the auth review."
|
|
57
|
-
```
|
|
26
|
+
---
|
|
58
27
|
|
|
59
|
-
|
|
28
|
+
## Why enquire (vs alternatives)
|
|
29
|
+
|
|
30
|
+
| | Other Obsidian-MCPs | Smart Connections (paid plugin) | **enquire** |
|
|
31
|
+
|---|:---:|:---:|:---:|
|
|
32
|
+
| Read-only by default | varies | n/a | ✅ |
|
|
33
|
+
| Resolves wikilinks (alias / section / block) | partial | n/a | ✅ full |
|
|
34
|
+
| Backlinks ranked + snippeted | rare | n/a | ✅ |
|
|
35
|
+
| Dataview-style queries | needs plugin | n/a | ✅ first-class |
|
|
36
|
+
| Canvas (`.canvas`) read | rare | n/a | ✅ typed nodes + edges |
|
|
37
|
+
| BM25 full-text search | rare | ❌ | ✅ FTS5 SQLite |
|
|
38
|
+
| TF-IDF semantic search | ❌ | ❌ | ✅ |
|
|
39
|
+
| **ML embeddings (multilingual)** | ❌ | ✅ paid | ✅ **free** |
|
|
40
|
+
| **Hybrid (BM25+TF-IDF+embeddings, RRF)** | ❌ | ❌ | ✅ **only here** |
|
|
41
|
+
| Per-signal observability on each hit | ❌ | ❌ | ✅ |
|
|
42
|
+
| Privacy filter (`--exclude-glob` / `--read-paths`) | ❌ | n/a | ✅ verified at search + write paths |
|
|
43
|
+
| Standalone (no Obsidian plugin) | varies | ❌ requires Obsidian | ✅ direct vault read |
|
|
44
|
+
| MCP-native (any agent) | varies | ❌ Obsidian-only | ✅ stdio JSON-RPC |
|
|
45
|
+
| SLSA-3 provenance | ❌ | n/a | ✅ |
|
|
46
|
+
| Test suite | rare | n/a | ✅ 408 unit tests |
|
|
60
47
|
|
|
61
48
|
---
|
|
62
49
|
|
|
63
|
-
##
|
|
64
|
-
|
|
65
|
-
There are several Obsidian-MCP servers out there. enquire differentiates on three axes — **standalone**, **read-rich**, and **safe-by-default**:
|
|
66
|
-
|
|
67
|
-
| Capability (✅ = good for you) | Most Obsidian-MCPs | enquire |
|
|
68
|
-
|---|:---:|:---:|
|
|
69
|
-
| Works with `.md` files | ✅ | ✅ |
|
|
70
|
-
| **Standalone** — runs without Obsidian's Local REST API plugin | ❌ usually requires it | ✅ direct vault read |
|
|
71
|
-
| Resolves `[[Wikilink]]` with alias, section, block, `../` relative | partial | ✅ full |
|
|
72
|
-
| Surfaces `![[Embed]]` separately from links | ❌ | ✅ |
|
|
73
|
-
| Finds every note linking to X (**backlinks**) | rare | ✅ ranked + snippets |
|
|
74
|
-
| Finds every **broken `[[wikilink]]`** in the vault | ❌ | ✅ vault-hygiene tool |
|
|
75
|
-
| Lists **outbound links** for one note with resolution status | ❌ | ✅ |
|
|
76
|
-
| Built-in **Dataview-style queries** (`LIST` / `TABLE`, `AND`/`OR`, `LIKE`) | only via Obsidian plugin | ✅ first-class |
|
|
77
|
-
| **MCP resources** for browsing the vault as a tree | ❌ | ✅ |
|
|
78
|
-
| **MCP prompts** (`summarize_recent_edits`, `weekly_review`, `monthly_review`, `find_orphans`, `extract_todos`, `process_inbox`, `review_tag`, `consolidate_tags`, `find_duplicates`, `lint_wiki`) | ❌ | ✅ 10 prompts |
|
|
79
|
-
| **Read-only by default** (write tools require explicit flag) | ❌ usually write-default | ✅ `--enable-write` |
|
|
80
|
-
| Symlink-escape safety, realpath-checked reads & writes | rare | ✅ |
|
|
81
|
-
| Persistent on-disk cache for warm cold-starts | ❌ | ✅ `--persistent-cache` |
|
|
82
|
-
| **Per-folder privacy filter** (`--exclude-glob '02_Personal/**'`) | ❌ | ✅ |
|
|
83
|
-
| **Periodic-note aliases** (`title: "today"` / `"weekly"` / `"monthly"` / `"quarterly"` / `"yearly"` — honors Daily Notes & Periodic Notes plugin config) | rare | ✅ |
|
|
84
|
-
| **Per-tool gating** (`--disabled-tools obsidian_xxx ...` — narrow the surface for restricted agents) | ❌ | ✅ |
|
|
85
|
-
| **`Did you mean: ...`** suggestions on note-not-found errors | rare | ✅ |
|
|
86
|
-
| **Document-map projection** (`format: "map"`: headings + counts, no body) | ❌ | ✅ |
|
|
87
|
-
| **Anti-slop write validator** (`obsidian_validate_note_proposal` lints YAML + wikilinks + tags before write) | ❌ | ✅ |
|
|
88
|
-
| **Graph-aware retrieval** (`find_similar` + `get_note_neighbors` — multi-signal lexical hybrid, no embeddings) | ❌ | ✅ |
|
|
89
|
-
| **Vault dashboard** (`obsidian_stats`: orphans, broken links, top tags) | ❌ | ✅ |
|
|
90
|
-
| **Rename + auto-backlink rewrite** (`obsidian_rename_note` — atomic, code-fence-aware, dry-run preview) | ❌ usually breaks links | ✅ |
|
|
91
|
-
| **Bulk find/replace across vault** (`obsidian_replace_in_notes` — code-fence-aware, dry-run, refuses footguns) | ❌ rare or unsafe | ✅ |
|
|
92
|
-
| **Archive workflow** (`obsidian_archive_note` — wraps rename, default `Archive/` folder, preserves backlinks) | ❌ | ✅ |
|
|
93
|
-
| **Live watcher mode** (`--watch` — incremental cache + FTS5 reindex on file changes) | ❌ usually requires restart | ✅ |
|
|
94
|
-
| **Karpathy LLM-Wiki `/lint` workflow** (`obsidian_lint_wiki` + `lint_wiki` prompt — orphans, broken links, stubs, stale, concept candidates) | ❌ | ✅ reference impl |
|
|
95
|
-
| **Multi-hop graph path-finding** (`obsidian_find_path` — BFS shortest path between two notes over the wikilink graph, with alternatives) | ❌ | ✅ |
|
|
96
|
-
| **Strict path allowlist** (`--read-paths '01_Projects/**'` — only paths matching one of these globs are visible; complement to `--exclude-glob` denylist) | ❌ | ✅ |
|
|
97
|
-
| **Canvas (`.canvas`) read tools** (`obsidian_list_canvases` + `obsidian_read_canvas` — typed nodes + edges, broken-ref detection) | ❌ rare / partial | ✅ first-class |
|
|
98
|
-
| **Semantic search** (`obsidian_semantic_search` — TF-IDF cosine, free / offline / no model download) | ❌ usually paywalled (Smart Connections) | ✅ in-tree |
|
|
99
|
-
| **ML embeddings search** (`obsidian_embeddings_search` — paraphrase-multilingual-MiniLM-L12-v2, 50+ languages, persistent SQLite vector index) | ❌ usually paywalled (Smart Connections) | ✅ free + offline-capable (v2.0 beta) |
|
|
100
|
-
| TypeScript strict + Biome lint + 405+ unit tests | varies | ✅ |
|
|
101
|
-
|
|
102
|
-
That's the gap. enquire closes it in ~7500 lines of TypeScript with five mandatory runtime dependencies (`@modelcontextprotocol/sdk`, `chokidar`, `commander`, `gray-matter`, `zod`) plus two optional (`better-sqlite3` for `--persistent-index` and the `build-embeddings` subcommand; `@huggingface/transformers` for ML embeddings — both are no-ops when not invoked).
|
|
103
|
-
|
|
104
|
-
> **Not affiliated with Obsidian.md.** Obsidian and the Obsidian logo are trademarks of Dynalist Inc. enquire-mcp is an independent open-source project that reads Obsidian-format vaults. The name «enquire» is a tribute to Tim Berners-Lee's 1980 hypertext system, not a trademark claim against any party.
|
|
50
|
+
## Architecture
|
|
105
51
|
|
|
106
|
-
|
|
52
|
+
```mermaid
|
|
53
|
+
graph LR
|
|
54
|
+
Q[Query]
|
|
55
|
+
Q --> S[obsidian_search]
|
|
56
|
+
S --> BM25[BM25 / FTS5<br/>opt-in: --persistent-index]
|
|
57
|
+
S --> TFIDF[TF-IDF<br/>always on]
|
|
58
|
+
S --> EMB[ML embeddings<br/>opt-in: build-embeddings]
|
|
59
|
+
BM25 --> RRF{RRF fusion<br/>k=60}
|
|
60
|
+
TFIDF --> RRF
|
|
61
|
+
EMB --> RRF
|
|
62
|
+
RRF --> R[Ranked hits<br/>per_signal observability]
|
|
63
|
+
```
|
|
107
64
|
|
|
108
|
-
|
|
65
|
+
`obsidian_search` auto-detects available signals and fuses them via Reciprocal Rank Fusion (Cormack et al, 2009). Returns per-signal contributions on every hit so agents can see WHY each result ranked.
|
|
109
66
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
67
|
+
```
|
|
68
|
+
Tier 1: serve --vault <path> → TF-IDF (zero setup, instant)
|
|
69
|
+
Tier 2: serve --vault <path> --persistent-index → + BM25 (sub-100ms top-10)
|
|
70
|
+
Tier 3: + install-model + build-embeddings → + ML embeddings (multilingual)
|
|
71
|
+
```
|
|
113
72
|
|
|
114
73
|
---
|
|
115
74
|
|
|
116
|
-
##
|
|
75
|
+
## Quick start
|
|
117
76
|
|
|
118
|
-
**
|
|
77
|
+
> **Two channels:** `npm install @oomkapwn/enquire-mcp` → **v2.0** (stable, hybrid retrieval). `@beta` → preview track. `@1` → legacy v1.x line.
|
|
119
78
|
|
|
120
|
-
|
|
79
|
+
**Claude Desktop / Claude Code / Cursor / Codex / any MCP client**:
|
|
121
80
|
|
|
122
81
|
```json
|
|
123
|
-
// Stable v1.x — 28 tools, no hybrid search
|
|
124
|
-
{
|
|
125
|
-
"mcpServers": {
|
|
126
|
-
"obsidian": {
|
|
127
|
-
"command": "npx",
|
|
128
|
-
"args": ["-y", "@oomkapwn/enquire-mcp", "serve", "--vault", "/Users/you/Documents/Obsidian Vault"]
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Beta v2.0 — adds obsidian_search (BM25 + TF-IDF + ML embeddings via RRF)
|
|
134
82
|
{
|
|
135
83
|
"mcpServers": {
|
|
136
84
|
"obsidian": {
|
|
137
85
|
"command": "npx",
|
|
138
|
-
"args": ["-y", "@oomkapwn/enquire-mcp
|
|
86
|
+
"args": ["-y", "@oomkapwn/enquire-mcp", "serve", "--vault", "/path/to/vault"]
|
|
139
87
|
}
|
|
140
88
|
}
|
|
141
89
|
}
|
|
142
90
|
```
|
|
143
91
|
|
|
144
|
-
**Where to drop that JSON, by client:**
|
|
145
|
-
|
|
146
92
|
| Client | Config file |
|
|
147
93
|
|---|---|
|
|
148
|
-
|
|
|
149
|
-
|
|
|
150
|
-
|
|
|
151
|
-
|
|
|
152
|
-
| **Codex / Codex CLI** | per-project `.mcp.json` or environment-specific config |
|
|
153
|
-
| **Devin / any other MCP client** | wherever your client expects MCP server JSON |
|
|
94
|
+
| Claude Desktop | macOS `~/Library/Application Support/Claude/claude_desktop_config.json` · Windows `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
95
|
+
| Claude Code (CLI) | `~/.claude.json` (global) or `.mcp.json` (per-project) |
|
|
96
|
+
| Cursor | `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (per-project) |
|
|
97
|
+
| Codex / OpenClaw / Devin | per-tool MCP config |
|
|
154
98
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
<details>
|
|
158
|
-
<summary><b>Alternative: global npm install</b></summary>
|
|
99
|
+
**Enable hybrid retrieval** (one-time setup, ~10 min for a 100-note vault):
|
|
159
100
|
|
|
160
101
|
```bash
|
|
161
|
-
|
|
162
|
-
enquire-mcp
|
|
102
|
+
enquire-mcp install-model multilingual # ~120MB, 50+ languages
|
|
103
|
+
enquire-mcp build-embeddings --vault <path> # ~30ms/chunk on M1
|
|
104
|
+
# Add --persistent-index to your serve invocation for BM25.
|
|
163
105
|
```
|
|
164
106
|
|
|
165
|
-
Then in your client config use `"command": "enquire-mcp"` instead of `"command": "npx"`.
|
|
166
|
-
|
|
167
|
-
</details>
|
|
168
|
-
|
|
169
|
-
<details>
|
|
170
|
-
<summary><b>Alternative: from source (development)</b></summary>
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
git clone https://github.com/oomkapwn/enquire-mcp
|
|
174
|
-
cd enquire-mcp && npm install && npm run build
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
Then `"command": "node"` with `"args": ["/absolute/path/to/dist/index.js", "serve", "--vault", "..."]`.
|
|
178
|
-
|
|
179
|
-
</details>
|
|
180
|
-
|
|
181
|
-
Restart your client. The server logs `enquire <version> ready (read-only, vault=…)` on stderr — that's your "it's connected" signal.
|
|
182
|
-
|
|
183
107
|
---
|
|
184
108
|
|
|
185
|
-
##
|
|
109
|
+
## Tools (36 total)
|
|
186
110
|
|
|
187
|
-
###
|
|
111
|
+
### 25 always-on read tools
|
|
188
112
|
|
|
189
113
|
| Tool | What it does |
|
|
190
114
|
|---|---|
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `
|
|
194
|
-
| `
|
|
195
|
-
| `
|
|
196
|
-
| `
|
|
197
|
-
| `
|
|
198
|
-
| `
|
|
199
|
-
| `
|
|
200
|
-
| `
|
|
201
|
-
| `
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
204
|
-
| `
|
|
205
|
-
| `
|
|
206
|
-
| `
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
210
|
-
| `
|
|
211
|
-
| `
|
|
212
|
-
| `
|
|
213
|
-
| `
|
|
214
|
-
| `
|
|
215
|
-
| `
|
|
216
|
-
|
|
217
|
-
###
|
|
218
|
-
|
|
219
|
-
| Tool |
|
|
220
|
-
|---|---|
|
|
221
|
-
| `obsidian_create_note` | Create a note with optional frontmatter. Refuses to overwrite by default. |
|
|
222
|
-
| `obsidian_append_to_note` | Append a markdown block to an existing note. Configurable separator. |
|
|
223
|
-
| `obsidian_rename_note` | **Atomic rename + automatic backlink rewrite.** Renames a note AND rewrites every `[[wikilink]]` / `![[embed]]` in the rest of the vault that resolved to it — preserving alias/section/block + the user's bare-vs-path target convention. Code-fence-aware: wikilinks inside ``` / ~~~ blocks stay verbatim. `dry_run: true` previews the plan without touching disk. |
|
|
224
|
-
| `obsidian_replace_in_notes` | **Bulk find/replace across notes, code-fence-aware.** Walks the vault (or a `folder` subset), substitutes every literal occurrence of `search` with `replace` outside fenced code blocks, returns per-file occurrence counts. `dry_run: true` previews. `case_sensitive: false` for case-insensitive substring match. Refuses identical search/replace + empty search (footgun guards). |
|
|
225
|
-
| `obsidian_archive_note` | Convenience wrapper around `obsidian_rename_note` for the common archive workflow. Moves the note's basename into `archive_folder` (default `Archive/`) and rewrites every wikilink/embed pointing at it. All `rename_note` guarantees apply (code-fence-aware, dry-run preview, refuses to clobber). |
|
|
226
|
-
|
|
227
|
-
### MCP resources
|
|
228
|
-
|
|
229
|
-
- `obsidian://vault/info` — root, note count, write flag, byte/cache limits, server version.
|
|
230
|
-
- `obsidian://note/{path}` — every note as a first-class browsable resource. Compatible clients show your vault as a tree.
|
|
231
|
-
|
|
232
|
-
### MCP prompts
|
|
233
|
-
|
|
234
|
-
| Prompt | Args | What it scaffolds |
|
|
115
|
+
| `obsidian_search` | **Hybrid retrieval** — fuses BM25 + TF-IDF + ML embeddings via RRF. The default search tool. Auto-detects available signals. v2.2.0: `granularity: "block"` arg returns chunks instead of notes. |
|
|
116
|
+
| `obsidian_context_pack` | **v2.2.0.** Token-budgeted context bundling: takes a question, runs hybrid search, gathers note bodies + backlinks + optionally recent dailies, returns one ready-to-paste markdown bundle. Saves ~5 tool calls. |
|
|
117
|
+
| `obsidian_chat_thread_read` | **v2.2.0.** Parse a note's `## Chat: <title>` block into structured messages (role/timestamp/content/line-range). Pair with `_append` (write) for note-tethered AI conversations. |
|
|
118
|
+
| `obsidian_frontmatter_get` | **v2.3.0.** Read parsed YAML frontmatter for a note. With `key`, returns just that field. |
|
|
119
|
+
| `obsidian_frontmatter_search` | **v2.3.0.** Find notes by frontmatter predicate (`equals` / `exists` / `contains`). Useful as a precursor to bulk `_set`. |
|
|
120
|
+
| `obsidian_read_note` | Full content + frontmatter + wikilinks + embeds + tags. Also accepts periodic-note aliases (`title: "today"` / `"weekly"` / `"monthly"`). |
|
|
121
|
+
| `obsidian_list_notes` | Vault-wide or folder-scoped. Includes title + tags + mtime + counts. |
|
|
122
|
+
| `obsidian_resolve_wikilink` | Resolves `[[Note]]`, `[[Note\|Alias]]`, `[[Note#Section]]`, `[[Note#^block]]`, with did-you-mean on near-miss. |
|
|
123
|
+
| `obsidian_get_backlinks` | Every note linking to X, ranked + snippeted. |
|
|
124
|
+
| `obsidian_get_outbound_links` | Outbound `[[wikilinks]]` from one note, with resolution status. |
|
|
125
|
+
| `obsidian_get_unresolved_wikilinks` | Vault-wide broken-link audit. |
|
|
126
|
+
| `obsidian_get_recent_edits` | Notes modified in the last N minutes. |
|
|
127
|
+
| `obsidian_list_tags` | Tag census across vault (frontmatter + inline). |
|
|
128
|
+
| `obsidian_dataview_query` | First-class Dataview-style queries (`LIST` / `TABLE`, `WHERE`, `AND` / `OR` / `LIKE` / `contains`). |
|
|
129
|
+
| `obsidian_find_path` | Multi-hop graph BFS between two notes (with alternatives). |
|
|
130
|
+
| `obsidian_find_similar` | Note-to-note similarity (tag + folder + content signals). |
|
|
131
|
+
| `obsidian_get_note_neighbors` | Outbound + inbound + tag-sibling for one note. |
|
|
132
|
+
| `obsidian_stats` | Vault dashboard: note count, tag count, broken links. |
|
|
133
|
+
| `obsidian_lint_wiki` | Karpathy LLM-Wiki `/lint` workflow (orphans / broken / stubs / stale). |
|
|
134
|
+
| `obsidian_open_questions` | Find open `?` questions across the vault. |
|
|
135
|
+
| `obsidian_paper_audit` | Track arXiv references and read-status. |
|
|
136
|
+
| `obsidian_validate_note_proposal` | Lint a draft note before writing (closes the #1 LLM-write pain). |
|
|
137
|
+
| `obsidian_list_canvases` | List `.canvas` files with node + edge counts. |
|
|
138
|
+
| `obsidian_read_canvas` | Parse `.canvas` into typed nodes (text/file/link/group) + edges. |
|
|
139
|
+
| `obsidian_open_in_ui` | Emit `obsidian://open?vault=...` URI. |
|
|
140
|
+
|
|
141
|
+
### 4 opt-in read tools
|
|
142
|
+
|
|
143
|
+
| Tool | Flag | Notes |
|
|
235
144
|
|---|---|---|
|
|
236
|
-
| `
|
|
237
|
-
| `
|
|
238
|
-
| `
|
|
239
|
-
| `
|
|
240
|
-
| `monthly_review` | `folder?` | 30-day version: themes, what stalled, focus vs intent. |
|
|
241
|
-
| `extract_todos` | `folder?`, `tag?` | Every TODO / FIXME / QUESTION, grouped by note. |
|
|
242
|
-
| `process_inbox` | `folder` | Move / Merge / Promote / Archive proposals for an inbox folder. |
|
|
243
|
-
| `consolidate_tags` | `min_count?` | Surface near-duplicate tags (`#productivity` vs `#productive`) and propose canonical merges. Read-only. |
|
|
244
|
-
| `find_duplicates` | `folder?`, `min_score?` | Walk the vault for clusters of structurally-similar notes via `obsidian_find_similar`. Read-only — outputs merge proposals only. |
|
|
245
|
-
| `lint_wiki` | `folder?` | **Karpathy LLM-Wiki `/lint`** — orchestrates `obsidian_lint_wiki` + `obsidian_open_questions` + `obsidian_paper_audit`, picks the 5 highest-leverage fixes across all three reports, proposes concrete `obsidian_*` calls. Read-only — proposes only. |
|
|
246
|
-
|
|
247
|
-
---
|
|
248
|
-
|
|
249
|
-
## Example workflows
|
|
250
|
-
|
|
251
|
-
### 1. Scan tagged ideas
|
|
252
|
-
> "Show me notes tagged `#idea` from the last two weeks."
|
|
253
|
-
|
|
254
|
-
`obsidian_list_notes({ tag: "idea", since_date: "2026-04-18" })`
|
|
255
|
-
|
|
256
|
-
### 2. Follow wikilinks
|
|
257
|
-
> "Read [[Project Apollo]] and summarise the open questions."
|
|
258
|
-
|
|
259
|
-
`obsidian_resolve_wikilink({ wikilink: "Project Apollo" })` → walk any `[[…]]` inside the result.
|
|
260
|
-
|
|
261
|
-
### 3. Pick up where you left off
|
|
262
|
-
> "What was I editing today?"
|
|
263
|
-
|
|
264
|
-
`obsidian_get_recent_edits({ since_minutes: 720 })`
|
|
265
|
-
|
|
266
|
-
### 4. Audit a hub note
|
|
267
|
-
> "Which notes link to [[Project Apollo]]?"
|
|
268
|
-
|
|
269
|
-
`obsidian_get_backlinks({ title: "Project Apollo" })` → ranked list with snippets.
|
|
270
|
-
|
|
271
|
-
### 5. Run a Dataview-style query
|
|
272
|
-
> "List active ideas, sorted by mtime."
|
|
273
|
-
|
|
274
|
-
```text
|
|
275
|
-
TABLE status FROM #idea WHERE status = "active" SORT file.mtime DESC
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### 6. Daily journaling (write mode)
|
|
279
|
-
> "Append a 'shipped today' bullet to today's daily note."
|
|
280
|
-
|
|
281
|
-
With `--enable-write`: `obsidian_append_to_note({ title: "2026-05-03", content: "- shipped a thing" })`
|
|
282
|
-
|
|
283
|
-
---
|
|
284
|
-
|
|
285
|
-
## Architecture
|
|
286
|
-
|
|
287
|
-
```
|
|
288
|
-
┌─────────────────┐ stdio JSON-RPC ┌─────────────────────┐
|
|
289
|
-
│ Claude Code / │ ◄────────────────────► │ enquire │
|
|
290
|
-
│ Cursor / │ tools/resources/ │ (this server) │
|
|
291
|
-
│ OpenClaw / │ │ │
|
|
292
|
-
│ Codex │ │ │
|
|
293
|
-
└─────────────────┘ prompts └─────────┬───────────┘
|
|
294
|
-
│
|
|
295
|
-
┌───────────┼────────────┐
|
|
296
|
-
│ │ │
|
|
297
|
-
▼ ▼ ▼
|
|
298
|
-
┌─────────┐ ┌──────────┐ ┌──────────┐
|
|
299
|
-
│ Vault │ │ Parser │ │ DQL │
|
|
300
|
-
│ walker │ │ (gray- │ │ engine │
|
|
301
|
-
│ + cache │ │ matter) │ │ │
|
|
302
|
-
└────┬────┘ └──────────┘ └──────────┘
|
|
303
|
-
│
|
|
304
|
-
▼
|
|
305
|
-
┌─────────────────────┐
|
|
306
|
-
│ ~/Documents/ │
|
|
307
|
-
│ Obsidian Vault/ │
|
|
308
|
-
│ *.md *.md *.md ... │
|
|
309
|
-
└─────────────────────┘
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
- **Vault walker** — recursive, skips `.git` / `.obsidian` / `.trash` / dot-dirs / symlinks. Realpath-checks every read and write to prevent symlink-escape attacks.
|
|
313
|
-
- **Cache** — mtime-keyed, LRU-evicted. Default cap 1024 entries.
|
|
314
|
-
- **Parser** — `gray-matter` for YAML, hand-rolled regex for wikilinks / embeds / tags. Fenced code blocks are stripped before tag extraction.
|
|
315
|
-
- **DQL engine** — quote-aware tokenizer for keywords (`FROM`, `WHERE`, `SORT`, `LIMIT`, `AND`); won't mis-split on `WHERE x = "foo SORT bar"`.
|
|
145
|
+
| `obsidian_full_text_search` | `--persistent-index` + `--diagnostic-search-tools` | BM25 ranking, sub-100ms. |
|
|
146
|
+
| `obsidian_search_text` | `--diagnostic-search-tools` | Token search (all/any/phrase modes). |
|
|
147
|
+
| `obsidian_semantic_search` | `--diagnostic-search-tools` | TF-IDF cosine standalone. |
|
|
148
|
+
| `obsidian_embeddings_search` | `--diagnostic-search-tools` | ML embeddings standalone. |
|
|
316
149
|
|
|
317
|
-
###
|
|
150
|
+
### 7 opt-in write tools (`--enable-write`)
|
|
318
151
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
|
322
|
-
|
|
323
|
-
| `
|
|
324
|
-
| `
|
|
325
|
-
| `
|
|
326
|
-
| `
|
|
327
|
-
| `
|
|
328
|
-
| `find_similar` | 45 / 49 | 1 065 / 1 120 |
|
|
329
|
-
| `get_note_neighbors` | 76 / 81 | 2 002 / 2 279 |
|
|
330
|
-
| `vault_stats` | 45 / 45 | 1 058 / 1 319 |
|
|
331
|
-
| `validate_note_proposal` | 79 / 80 | 1 353 / 1 459 |
|
|
152
|
+
| Tool | Notes |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `obsidian_create_note` | Refuses overwrite without `overwrite=true`. Empty path rejected. |
|
|
155
|
+
| `obsidian_append_to_note` | Symlink-safe; respects `--max-file-bytes`. |
|
|
156
|
+
| `obsidian_rename_note` | Rewrites every wikilink across vault. Code-fence-aware. `dry_run` available. |
|
|
157
|
+
| `obsidian_replace_in_notes` | Bulk find/replace. Per-file errors collected; `partial: true` on mid-loop fail. |
|
|
158
|
+
| `obsidian_archive_note` | Wraps rename to `Archive/`. Preserves backlinks. |
|
|
159
|
+
| `obsidian_chat_thread_append` | **v2.2.0.** Append a user/assistant/system message to a note's `## Chat:` block. Creates note + heading if absent. Threads stored as markdown — searchable, version-controllable, survive sessions. |
|
|
160
|
+
| `obsidian_frontmatter_set` | **v2.3.0.** Surgical YAML manipulation — set/unset keys on a note atomically. Pass `null` as value to delete. Round-trips through gray-matter so YAML formatting stays consistent. `dry_run` supported. |
|
|
332
161
|
|
|
333
|
-
|
|
162
|
+
Plus **2 + 1 opt-in MCP resources** (`obsidian://note/...`, `obsidian://vault-info`, `obsidian://chunk/...`) and **17 MCP prompts** (`summarize_recent_edits`, `weekly_review`, `monthly_review`, `find_orphans`, `extract_todos`, `process_inbox`, `review_tag`, `consolidate_tags`, `find_duplicates`, `lint_wiki`, `search_with_query_expansion`, `vault_synth`, `vault_wiki_compile`, `vault_lint_extended`, `vault_capture`, `vault_persona_search`, `vault_automation_setup`).
|
|
334
163
|
|
|
335
|
-
|
|
164
|
+
> **v2.4.0 strategic position:** enquire-mcp is the open-source backend for **Karpathy-style LLM Wikis** on top of your existing Obsidian vault. The `vault_synth` + `vault_wiki_compile` + `vault_lint_extended` prompts implement the [Karpathy LLM-Wiki workflow](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) (ingest → query → lint → compile) natively over Obsidian's `.md` + `[[wikilinks]]` substrate. Knowledge that compounds, traceable to sources.
|
|
336
165
|
|
|
337
166
|
---
|
|
338
167
|
|
|
339
168
|
## Configuration
|
|
340
169
|
|
|
341
|
-
| Flag | Default |
|
|
170
|
+
| Flag | Default | Notes |
|
|
342
171
|
|---|---|---|
|
|
343
|
-
| `--vault <path>` |
|
|
344
|
-
| `--enable-write` | off | Register the
|
|
345
|
-
| `--
|
|
346
|
-
| `--
|
|
347
|
-
| `--persistent-
|
|
348
|
-
| `--cache
|
|
349
|
-
| `--
|
|
350
|
-
| `--
|
|
351
|
-
| `--
|
|
352
|
-
| `--
|
|
353
|
-
| `--
|
|
354
|
-
| `--
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
When `--persistent-cache` is on, parsed notes are serialized to disk so subsequent server restarts skip re-parsing. By default the file lives at `~/Library/Caches/enquire/<sha1>.json` on macOS, `~/.cache/enquire/<sha1>.json` on Linux. Important caveats:
|
|
361
|
-
|
|
362
|
-
- **Full note bodies are stored**, not just metadata. Anyone who can read your home cache directory can read your vault.
|
|
363
|
-
- **File mode is `0600`** (user-read/write only) and the parent directory is `0700`. We don't trust shared home directories.
|
|
364
|
-
- **Deleted notes are purged** on the next server start: when enquire sees a cached entry whose source file no longer exists, it drops the entry from memory and rewrites the cache file without it on shutdown.
|
|
365
|
-
- **Stale entries** (file mtime changed since cache write) are silently dropped on load; the source file is re-parsed.
|
|
366
|
-
- **Manual purge:** run `enquire-mcp clear-cache --vault <path>` to delete the cache file for a specific vault.
|
|
367
|
-
- The cache file is **never read or written for vaults other than the one whose realpath matches the cache file's `root` field** — protects against cross-vault content leaks if you share a cache dir.
|
|
368
|
-
|
|
369
|
-
The server logs `WRITE-ENABLED` to stderr on boot when the flag is on, so you can verify the mode at a glance.
|
|
172
|
+
| `--vault <path>` | required | Path to Obsidian vault root. |
|
|
173
|
+
| `--enable-write` | off | Register the 5 write tools. |
|
|
174
|
+
| `--exclude-glob <pat...>` | none | Privacy denylist. Repeatable. Example: `'02_Personal/**'`. |
|
|
175
|
+
| `--read-paths <pat...>` | none | Privacy allowlist (only matching paths visible). Repeatable. |
|
|
176
|
+
| `--persistent-index` | off | SQLite FTS5 BM25. Enables `obsidian_full_text_search` (with `--diagnostic-search-tools`). |
|
|
177
|
+
| `--persistent-cache` | off | Persist parsed-note cache across restarts. |
|
|
178
|
+
| `--watch` | off | Live invalidation on `.md` add/change/unlink. |
|
|
179
|
+
| `--diagnostic-search-tools` | off | Register 4 single-ranker search tools (defaults: hybrid `obsidian_search` only). |
|
|
180
|
+
| `--enabled-tools <name...>` | all | Strict allowlist (gate to a subset). |
|
|
181
|
+
| `--disabled-tools <name...>` | none | Denylist. |
|
|
182
|
+
| `--max-file-bytes <n>` | 5 MB | Per-file read/write cap. |
|
|
183
|
+
| `--cache-size <n>` | 1024 | LRU cap for parsed-note cache. |
|
|
184
|
+
|
|
185
|
+
Subcommands: `serve` · `clear-cache` · `clear-index` · `index` (cold-build FTS5) · `install-model` · `build-embeddings` · `clear-embeddings`.
|
|
186
|
+
|
|
187
|
+
Full reference: [docs/api.md](./docs/api.md).
|
|
370
188
|
|
|
371
189
|
---
|
|
372
190
|
|
|
373
191
|
## Security
|
|
374
192
|
|
|
375
|
-
- **Read-only by default.** Write tools
|
|
376
|
-
- **Path traversal blocked.**
|
|
377
|
-
- **
|
|
378
|
-
-
|
|
379
|
-
- **
|
|
193
|
+
- **Read-only by default.** Write tools require `--enable-write`.
|
|
194
|
+
- **Path traversal blocked.** Realpath check on every read+write target. Symlinks inside the vault that resolve outside are rejected.
|
|
195
|
+
- **Privacy boundary verified across all paths**, including persistent indexes (FTS5 / embed-db search-time filter) and the `obsidian://chunk/...` resource. Privacy fail-closed: empty `--read-paths` / `--exclude-glob` patterns refuse to start.
|
|
196
|
+
- **`gray-matter` (`js-yaml` safeLoad)** — no code execution via frontmatter.
|
|
197
|
+
- **DQL parser** — no shell, no `eval`, no template expansion.
|
|
198
|
+
- **Cache + index files** — chmod 0600, parent dir 0700.
|
|
199
|
+
- **SLSA-3 provenance** on every npm release.
|
|
200
|
+
- **Branch protection ruleset** with `bypass_mode: pull_request` — every change goes through PR with audit trail. Release pipeline verifies SHA-on-main + 8 required CI checks before publishing.
|
|
380
201
|
|
|
381
|
-
|
|
202
|
+
Full posture: [SECURITY.md](./SECURITY.md). Report vulnerabilities to `oomkapwn@gmail.com`.
|
|
382
203
|
|
|
383
204
|
---
|
|
384
205
|
|
|
385
|
-
##
|
|
386
|
-
|
|
387
|
-
**Does it support Roam / Logseq / TiddlyWiki?**
|
|
388
|
-
No. Obsidian's wikilink semantics, frontmatter conventions, and folder structure are baked in. Other tools are out of scope.
|
|
389
|
-
|
|
390
|
-
**Will it modify my vault?**
|
|
391
|
-
Not unless you start it with `--enable-write`. By default the server is strictly read-only. With write enabled, the five write tools refuse to overwrite existing notes by default (`obsidian_create_note` and `obsidian_rename_note` both require `overwrite=true` to clobber; `obsidian_replace_in_notes` refuses identical search/replace + empty search; `obsidian_archive_note` is a thin rename-into-archive wrapper that inherits the same guards), and all writes refuse to land outside the vault even if a parent dir is symlinked away.
|
|
392
|
-
|
|
393
|
-
**Does it work over the network?**
|
|
394
|
-
No. It's a local stdio MCP server, designed for one client process per vault. There's no HTTP transport, no auth, no rate limiting — and that's intentional.
|
|
395
|
-
|
|
396
|
-
**My DQL query returned nothing.**
|
|
397
|
-
Verify the source. `LIST FROM "01_Projects"` matches notes whose path starts with `01_Projects/`. `LIST FROM #idea` matches notes carrying the `idea` tag. Mix them with `WHERE`. See [docs/api.md](./docs/api.md) for the supported subset and grammar.
|
|
398
|
-
|
|
399
|
-
**What about the full Dataview plugin?**
|
|
400
|
-
We implement a deliberately small subset (`LIST` / `TABLE`, `FROM "folder" | #tag`, `WHERE pred (AND|OR pred)*`, `SORT`, `LIMIT`; ops `=`, `!=`, `contains`, `like`). No arithmetic / functions / `FLATTEN` / `GROUP BY` / joins / parenthesized precedence. PRs that close those gaps are welcome — see [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
401
|
-
|
|
402
|
-
**How big a vault can it handle?**
|
|
403
|
-
Tested daily against a ~120-note vault; benched up to 1000 synthetic notes (see [`scripts/bench-search.mjs`](./scripts/bench-search.mjs)). The walker is O(notes) per call; the in-memory cache makes repeat reads O(1). For multi-thousand-note vaults pass `--persistent-index` — the SQLite FTS5 backend gives sub-millisecond BM25 search (37–103x faster than the linear-scan path on 100–1000 notes).
|
|
404
|
-
|
|
405
|
-
**Why scoped npm name (`@oomkapwn/enquire-mcp`)?**
|
|
406
|
-
A scoped name protects the brand and side-steps the very crowded `obsidian-mcp` / `mcp-obsidian` namespace on npm. The CLI binary is `enquire-mcp` to match the npm package name.
|
|
407
|
-
|
|
408
|
-
---
|
|
206
|
+
## Engineering
|
|
409
207
|
|
|
410
|
-
|
|
208
|
+
| Surface | Posture |
|
|
209
|
+
|---|---|
|
|
210
|
+
| Language | TypeScript strict + `noUncheckedIndexedAccess` |
|
|
211
|
+
| Lint | Biome 2 (zero-warning policy) |
|
|
212
|
+
| Tests | 408 unit tests across 19 files |
|
|
213
|
+
| CI | ubuntu × {Node 20, 22, 24} required + macOS advisory job |
|
|
214
|
+
| Coverage | Lines ≥86%, statements ≥82%, functions ≥75%, branches ≥73% (gated) |
|
|
215
|
+
| Audit | `npm audit --audit-level=moderate` for prod; high for dev |
|
|
216
|
+
| Runtime deps | 5 mandatory (`@modelcontextprotocol/sdk`, `chokidar`, `commander`, `gray-matter`, `zod`) + 2 optional (`better-sqlite3` for FTS5 / embed-db; `@huggingface/transformers` for ML embeddings) |
|
|
217
|
+
| Releases | npm + GitHub release per tag · semver · provenance attached · channels: `latest` (stable), `beta`, `alpha` |
|
|
411
218
|
|
|
412
219
|
```bash
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
npm
|
|
416
|
-
npm run lint
|
|
417
|
-
npm run
|
|
418
|
-
node scripts/smoke.mjs [vault-path] # end-to-end JSON-RPC smoke
|
|
220
|
+
git clone https://github.com/oomkapwn/enquire-mcp.git
|
|
221
|
+
cd enquire-mcp && npm install
|
|
222
|
+
npm test # full suite
|
|
223
|
+
npm run lint # zero warnings
|
|
224
|
+
npm run build # tsc → dist/
|
|
419
225
|
```
|
|
420
226
|
|
|
421
|
-
Coverage on the latest release: **82% lines · 78% statements · 73% branches**. CI uploads the full HTML report as a workflow artifact (`coverage-report`).
|
|
422
|
-
|
|
423
|
-
Build runs `tsc` and marks `dist/index.js` executable. CI tests Node 20 / 22 / 24, runs the smoke against a synthetic vault, generates a coverage report, and runs `npm audit --audit-level=high`.
|
|
424
|
-
|
|
425
227
|
---
|
|
426
228
|
|
|
427
|
-
##
|
|
229
|
+
## FAQ
|
|
428
230
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
- **"File too large" on a `.md` you didn't expect** — usually a sync conflict or binary accidentally renamed `.md`. Bump `--max-file-bytes` if you really want it ingested.
|
|
432
|
-
- **Write tool not visible to the client** — start the server with `--enable-write`, *after* the `serve` subcommand.
|
|
433
|
-
- **Russian / non-ASCII titles** — supported. Both inline `#тег` and YAML `tags: [идея]` are picked up.
|
|
231
|
+
**Q: Do I need Obsidian installed?**
|
|
232
|
+
No. enquire reads `.md` + `.canvas` files directly. Works against any Obsidian-format vault.
|
|
434
233
|
|
|
435
|
-
|
|
234
|
+
**Q: Will this write to my vault?**
|
|
235
|
+
No, unless you explicitly start with `--enable-write`. Even then, all 5 write tools are gated by privacy filters and refuse to overwrite without `overwrite: true`.
|
|
436
236
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
Semantic versioning. See [CHANGELOG.md](./CHANGELOG.md) for the full history.
|
|
440
|
-
|
|
441
|
-
- **1.9.x** — **Bulk find/replace** (`obsidian_replace_in_notes` — code-fence-aware, dry-run preview, footgun guards). Reuses rename_note's line walker. v1.8.1 patch fixed 3 P1 bugs (findPath O(N²) → O(N), semanticSearch frontmatter leak, exclusion error message accuracy).
|
|
442
|
-
- **1.8.x** — **Semantic search** (`obsidian_semantic_search`) — pure-JS TF-IDF cosine retrieval. Free / offline / no model download. Catches the synonym + related-term matches BM25 misses. Real ML embedding retrieval is the v2.0 follow-up.
|
|
443
|
-
- **1.7.x** — **Canvas (`.canvas`) read tools** (`obsidian_list_canvases` + `obsidian_read_canvas` — parses Obsidian's whiteboard format into typed nodes + edges, surfaces broken file refs).
|
|
444
|
-
- **1.6.x** — **Multi-hop graph traversal** (`obsidian_find_path` BFS) + **`obsidian_open_in_ui`** (obsidian:// URI hand-off) + **strict allowlist** (`--read-paths` complement to `--exclude-glob`).
|
|
445
|
-
- **1.5.x** — **Karpathy LLM-Wiki `/lint` workflow** — `obsidian_lint_wiki` (orphans/broken/stubs/stale/concept candidates) + `obsidian_open_questions` + `obsidian_paper_audit` + `lint_wiki` prompt.
|
|
446
|
-
- **1.4.x** — Three new MCP prompts (`consolidate_tags`, `find_duplicates`, `monthly_review`) bringing the total to 9.
|
|
447
|
-
- **1.3.x** — **Performance + benchmarks.** `findBestMatch` rebuilt around a basename + relPath index (O(N²) → O(1) avg) — 24–46% faster across graph-aware tools at 10k notes. New `scripts/bench.mjs` + reproducible numbers in `bench/results.md`.
|
|
448
|
-
- **1.2.0** — **Watcher mode** (`--watch`) — incremental cache + FTS5 reindex on file changes. Editor saves debounced. `--exclude-glob` honored.
|
|
449
|
-
- **1.1.x** — `obsidian_rename_note` (atomic rename + automatic backlink rewrite, code-fence-aware, dry-run preview).
|
|
450
|
-
- **1.0.0** — **Stable. API freeze.** Stability promise across tool names, argument shapes, resource URIs, prompt names, CLI flags. SLSA-3 release provenance.
|
|
451
|
-
- **0.13.x** — Graph-aware retrieval: `obsidian_find_similar` (multi-signal lexical hybrid), `obsidian_get_note_neighbors` (1-hop graph context in one call), `obsidian_stats` (vault dashboard).
|
|
452
|
-
- **0.12.x** — Anti-slop write validator (`obsidian_validate_note_proposal`) — lints YAML + wikilinks + tags before write.
|
|
453
|
-
- **0.11.x** — Privacy filter (`--exclude-glob`), periodic-note aliases (`title: "today"`), `Did you mean: …` suggestions, document-map projection (`format: "map"`). *(0.11.0 tag preserved for history; npm publish failed on a runner-availability incident — features rolled into 0.12.0.)*
|
|
454
|
-
- **0.10.x** — SQLite FTS5 inverted index (opt-in via `--persistent-index`), BM25 ranking, sub-millisecond search on multi-thousand-note vaults (37–103x faster than the linear scan path), chunk-level addressing via `obsidian://chunk/{n}/{path}` resource. Filter API on full-text search (`tag`, `since`, `folder`).
|
|
455
|
-
- **0.9.x** — `search_text` switched to AND-tokenizer default with structured response (BREAKING). Parallel file reads in scan path.
|
|
456
|
-
- **0.8.x** — DQL `contains` semantics for arrays (membership, not substring). Code of Conduct.
|
|
457
|
-
- **0.7.x** — Renamed `obsidian-mcp` → `enquire-mcp` (via brief `memex` detour) to escape the crowded `obsidian-mcp` npm namespace and to land on a name with a clear historical referent — Tim Berners-Lee's 1980 ENQUIRE prototype of the Web.
|
|
458
|
-
- **Roadmap (1.x)** — Embedding-based retrieval (sqlite-vec + a small JS-runnable model, layered on top of the existing lexical hybrid).
|
|
237
|
+
**Q: Is my data sent anywhere?**
|
|
238
|
+
Only on `enquire-mcp install-model` (downloads ONNX weights from HuggingFace). The serve mode itself never makes outbound HTTP. Embeddings run on CPU locally.
|
|
459
239
|
|
|
460
|
-
|
|
240
|
+
**Q: How is this different from Smart Connections?**
|
|
241
|
+
Smart Connections is a paid Obsidian plugin that does ML embeddings inside Obsidian. enquire-mcp is a standalone MCP server: free, MCP-native (works with Claude / Cursor / Codex / any agent), and adds hybrid retrieval (BM25 + TF-IDF + embeddings via RRF) for higher recall than embeddings alone.
|
|
461
242
|
|
|
462
|
-
|
|
243
|
+
**Q: Performance on large vaults?**
|
|
244
|
+
Cold-build of FTS5 on a 1k-note vault: ~5s. Warm BM25 top-10: sub-100ms. Embedding build: ~30ms/chunk on M1 (8s for 256 chunks, ~8min for 8k chunks). Hybrid query latency: <200ms typical.
|
|
463
245
|
|
|
464
|
-
|
|
246
|
+
**Q: Does it support languages other than English?**
|
|
247
|
+
Yes. Default embedding model is `paraphrase-multilingual-MiniLM-L12-v2` (50+ languages). Validated end-to-end on Russian + English bilingual vaults. CJK requires the upcoming Intl.Segmenter pre-pass (v2.1 backlog).
|
|
465
248
|
|
|
466
249
|
---
|
|
467
250
|
|
|
468
|
-
##
|
|
469
|
-
|
|
470
|
-
If enquire-mcp saves you keystrokes or makes your AI assistant smarter about your vault, **consider [starring the repo](https://github.com/oomkapwn/enquire-mcp) to show your ❤️ and support.** Stars help other Obsidian users find the project, and they tell us where to invest the next cycle.
|
|
471
|
-
|
|
472
|
-
Other ways to help:
|
|
473
|
-
- 🐛 **File a bug** — the more concrete the repro (vault shape, exact tool call, server stderr), the faster the fix. Use [the bug template](https://github.com/oomkapwn/enquire-mcp/issues/new?template=bug_report.yml).
|
|
474
|
-
- 💡 **Propose a feature** — open a [feature request](https://github.com/oomkapwn/enquire-mcp/issues/new?template=feature_request.yml) and we'll align on scope before any code is written.
|
|
475
|
-
- 🔧 **Send a PR** — bug fixes always welcome. New tools should pass the «useful against an Obsidian vault on day 1» bar. See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
476
|
-
- 💬 **Tell us how you use it** — open a thread in [Discussions](https://github.com/oomkapwn/enquire-mcp/discussions) and we'll figure out what to build next from real workflows.
|
|
251
|
+
## Contributing
|
|
477
252
|
|
|
478
|
-
|
|
253
|
+
Issues and PRs welcome. Read [CONTRIBUTING.md](./CONTRIBUTING.md). All changes go through PR review per branch protection ruleset.
|
|
479
254
|
|
|
480
255
|
## License & credits
|
|
481
256
|
|
|
482
|
-
[MIT](./LICENSE). Built by Alex — [GitHub `@oomkapwn`](https://github.com/oomkapwn) · [X `@OomkaBear`](https://x.com/OomkaBear).
|
|
257
|
+
[MIT](./LICENSE). Built by Alex — [GitHub `@oomkapwn`](https://github.com/oomkapwn) · [X `@OomkaBear`](https://x.com/OomkaBear).
|
|
258
|
+
|
|
259
|
+
Named after [ENQUIRE](https://en.wikipedia.org/wiki/ENQUIRE) — Tim Berners-Lee's 1980 hypertext prototype of the World Wide Web.
|
|
483
260
|
|
|
484
|
-
|
|
261
|
+
> **Not affiliated with Obsidian.md.** Obsidian and the Obsidian logo are trademarks of Dynalist Inc. enquire-mcp is an independent open-source project that reads Obsidian-format vaults.
|