@oomkapwn/enquire-mcp 1.6.0 → 1.8.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 +57 -0
- package/README.md +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -2
- package/dist/index.js.map +1 -1
- package/dist/tools.d.ts +106 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +375 -0
- package/dist/tools.js.map +1 -1
- package/dist/vault.d.ts +8 -0
- package/dist/vault.d.ts.map +1 -1
- package/dist/vault.js +75 -0
- package/dist/vault.js.map +1 -1
- package/docs/api.md +52 -1
- package/package.json +1 -1
package/docs/api.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# enquire — API
|
|
2
2
|
|
|
3
|
-
**enquire is an MCP server for Obsidian vaults.**
|
|
3
|
+
**enquire is an MCP server for Obsidian vaults.** 26 MCP tools (22 always-on read + 1 opt-in read via `--persistent-index` + 3 opt-in write via `--enable-write`), 2 + 1 opt-in MCP resources, 10 MCP prompts. The server speaks stdio JSON-RPC and is launched per-vault.
|
|
4
4
|
|
|
5
5
|
> Versioned dynamically — see [`CHANGELOG.md`](../CHANGELOG.md) for the current release.
|
|
6
6
|
|
|
@@ -346,6 +346,57 @@ Returns an `obsidian://open?vault=<v>&file=<f>` URI for hand-off to the running
|
|
|
346
346
|
|
|
347
347
|
**Returns:** `{ uri, vault_name, path, title }`. The `vault_name` is the leaf folder of the vault root path; Obsidian matches on this OR on the absolute file path, so the URI works even if the user's Obsidian instance opened the vault under a different name.
|
|
348
348
|
|
|
349
|
+
## `obsidian_list_canvases`
|
|
350
|
+
|
|
351
|
+
Lists `.canvas` files (Obsidian's whiteboard format — JSON nodes + edges) in the vault, with each canvas's node and edge counts. Honors `--exclude-glob` and `--read-paths`. Use this to discover which canvases exist before calling `obsidian_read_canvas`.
|
|
352
|
+
|
|
353
|
+
| Argument | Type | Notes |
|
|
354
|
+
|----------|------------------|---------------------------------------------|
|
|
355
|
+
| `folder` | `string?` | Restrict the listing to a subfolder. |
|
|
356
|
+
| `limit` | `number?` (≤ 500)| Max canvases to return. Default 100. |
|
|
357
|
+
|
|
358
|
+
**Returns:** `Array<{ path, name, size_bytes, mtime, node_count, edge_count }>`, sorted newest-first.
|
|
359
|
+
|
|
360
|
+
## `obsidian_read_canvas`
|
|
361
|
+
|
|
362
|
+
Parses one `.canvas` file into typed nodes + edges. Each node has a `kind` field — `text` / `file` / `link` / `group` / `unknown` (forward-compat for new Obsidian canvas node types). Each `file` node carries a `file_resolved` field — the vault-relative path the canvas's file reference resolved to (or `null` if broken).
|
|
363
|
+
|
|
364
|
+
| Argument | Type | Notes |
|
|
365
|
+
|----------|----------|--------------------------------------------------------|
|
|
366
|
+
| `path` | `string` | Vault-relative path of the `.canvas` file (`.canvas` extension auto-appended). |
|
|
367
|
+
|
|
368
|
+
**Returns:** `{ path, name, size_bytes, mtime, nodes: CanvasNode[], edges: CanvasEdge[], summary: { text, file, link, group, unknown }, broken_file_refs: string[] }`. Throws on path-traversal, missing file, or invalid JSON.
|
|
369
|
+
|
|
370
|
+
`CanvasNode` discriminated union by `kind`:
|
|
371
|
+
- `{ kind: "text", id, x, y, width, height, text, color? }`
|
|
372
|
+
- `{ kind: "file", id, x, y, width, height, file, file_resolved, subpath?, color? }`
|
|
373
|
+
- `{ kind: "link", id, x, y, width, height, url, color? }`
|
|
374
|
+
- `{ kind: "group", id, x, y, width, height, label?, color? }`
|
|
375
|
+
- `{ kind: "unknown", id, raw_type, raw }` — preserves any future canvas node type unchanged.
|
|
376
|
+
|
|
377
|
+
`CanvasEdge`: `{ id, from_node, from_side?, to_node, to_side?, label?, color? }`.
|
|
378
|
+
|
|
379
|
+
`broken_file_refs` lists canvas `file:` nodes that didn't resolve to any markdown in the current vault — useful as a vault-hygiene signal alongside `obsidian_get_unresolved_wikilinks`.
|
|
380
|
+
|
|
381
|
+
## `obsidian_semantic_search`
|
|
382
|
+
|
|
383
|
+
Pure-JS TF-IDF cosine retrieval. Tokenizes (alphanumeric + hyphen, stop-words filtered, ≥ 2 chars), TF-IDFs, L2-normalizes every note's body once per session, then ranks notes by cosine similarity to the query. Catches synonym + related-term matches that `obsidian_search_text` (substring) and `obsidian_full_text_search` (BM25) miss.
|
|
384
|
+
|
|
385
|
+
| Argument | Type | Notes |
|
|
386
|
+
|-------------|------------------|--------------------------------------------------------------------------------|
|
|
387
|
+
| `query` | `string` | Required. Free-form, multi-word, natural language is fine. |
|
|
388
|
+
| `folder` | `string?` | Restrict to a subfolder. |
|
|
389
|
+
| `limit` | `number?` (≤ 100)| Max hits. Default 10. |
|
|
390
|
+
| `min_score` | `number?` (0–1) | Drop hits below this cosine score. Default 0.05. Cosine ranges 0–1. |
|
|
391
|
+
|
|
392
|
+
**Returns:** `{ query, total_docs, method: "tfidf-cosine", matches: [{ path, title, score, snippet, matched_terms, mtime }] }`. `matched_terms` is sorted highest-IDF first (the most-discriminating terms in the corpus). `snippet` is taken from the first occurrence of the highest-IDF matched term.
|
|
393
|
+
|
|
394
|
+
**Caching:** the IDF index is built lazily on first call and memoized via `WeakMap` keyed on the `entries` array. Subsequent calls reuse the index when `listMarkdown()` returns the same paths + mtimes; the index rebuilds automatically when the vault changes.
|
|
395
|
+
|
|
396
|
+
**Performance:** at 10k notes the cold-build is ~5–10s on Apple silicon (similar to FTS5 cold-build). Warm cosine is sub-100ms. For very large vaults, prefer `--persistent-index` + `obsidian_full_text_search` for raw query latency, and use `obsidian_semantic_search` when BM25 misses.
|
|
397
|
+
|
|
398
|
+
**Why not embeddings?** Real ML embedding retrieval (v2.0 roadmap) would need a 25–50 MB model file and an ONNX/WASM runtime. TF-IDF cosine ships zero new deps, runs offline, and meaningfully improves over BM25 alone for the related-term case. Smart Connections (the dominant Obsidian semantic-search plugin) paywalled this functionality — enquire-mcp gives it free.
|
|
399
|
+
|
|
349
400
|
## Write tools (opt-in)
|
|
350
401
|
|
|
351
402
|
All three write tools are **only registered when the server is started with `--enable-write`**. Without that flag the tools are not advertised to the client at all.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oomkapwn/enquire-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Drop-in MCP server for Obsidian vaults. Wikilinks resolved, backlinks ranked, frontmatter typed, Dataview-style queries. Read-only by default; opt-in writes. Works with Claude Code, Cursor, OpenClaw, Codex, Devin, and any MCP-compatible client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|