neuro-vault-mcp 1.3.1 → 1.4.1
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/README.md +205 -61
- package/dist/cli.d.ts +19 -3
- package/dist/cli.js +159 -41
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,133 +1,277 @@
|
|
|
1
1
|
# Neuro Vault MCP
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Semantic vault search and expansion for your Obsidian vault — right inside your AI assistant.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/neuro-vault-mcp)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
[](LICENSE)
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
> "What did I write about that idea last month?"
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
Neuro Vault MCP provides semantic search over your Obsidian vault and semantic expansion for related notes. Agents can combine it with structural tools for exact note, path, date, tag, property, and link lookups when those tools are available. It reuses the embeddings already computed by [Smart Connections](https://github.com/brianpetro/obsidian-smart-connections) — no re-indexing, no extra infrastructure, no API keys.
|
|
12
|
+
|
|
13
|
+
---
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
## How It Works
|
|
14
16
|
|
|
15
|
-
```text
|
|
16
|
-
<vault>/.smart-env/multi/*.ajson
|
|
17
17
|
```
|
|
18
|
+
Your question
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
AI assistant
|
|
22
|
+
│ routes by intent
|
|
23
|
+
▼
|
|
24
|
+
├──────────────► Structural tools
|
|
25
|
+
│ (exact file, title, path, daily note, tag, property, wikilink, backlink, link traversal)
|
|
26
|
+
│
|
|
27
|
+
└──────────────► search_notes
|
|
28
|
+
(semantic retrieval)
|
|
29
|
+
│
|
|
30
|
+
▼
|
|
31
|
+
get_similar_notes
|
|
32
|
+
(semantic expansion)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The server loads `.smart-env/multi/*.ajson` into memory at startup and keeps it there. No background processes, no watchers, no database.
|
|
18
36
|
|
|
19
|
-
|
|
37
|
+
## Search Routing
|
|
38
|
+
|
|
39
|
+
Tool routing and retrieval policy are related, but not the same thing.
|
|
40
|
+
|
|
41
|
+
- Use structural tools first for exact file, title, path, daily note, tag, property, wikilink, backlink, and link traversal requests.
|
|
42
|
+
- Use `search_notes` for fuzzy topic, concept, and semantic retrieval.
|
|
43
|
+
- Use `get_similar_notes` after you already have a relevant note and want semantic expansion.
|
|
44
|
+
- Treat the routing guidance as behavior, not enforcement; the server does not hard-block other tool choices.
|
|
45
|
+
- Use semantic retrieval to find likely notes, then switch to structural tools when you need exact anchors.
|
|
46
|
+
|
|
47
|
+
---
|
|
20
48
|
|
|
21
49
|
## Requirements
|
|
22
50
|
|
|
23
|
-
- Node.js 20
|
|
24
|
-
-
|
|
25
|
-
- Smart Connections data
|
|
51
|
+
- Node.js 20+
|
|
52
|
+
- Obsidian vault with [Smart Connections](https://github.com/brianpetro/obsidian-smart-connections) plugin (embeddings must be generated)
|
|
53
|
+
- Smart Connections data at `<vault>/.smart-env/multi/*.ajson`
|
|
54
|
+
|
|
55
|
+
---
|
|
26
56
|
|
|
27
|
-
##
|
|
57
|
+
## Quick Start
|
|
28
58
|
|
|
29
|
-
Install
|
|
59
|
+
**1. Install**
|
|
30
60
|
|
|
31
61
|
```bash
|
|
32
62
|
npm install -g neuro-vault-mcp
|
|
33
63
|
```
|
|
34
64
|
|
|
35
|
-
|
|
65
|
+
**2. Configure your MCP client**
|
|
36
66
|
|
|
37
|
-
|
|
38
|
-
npx -y neuro-vault-mcp --vault /absolute/path/to/vault
|
|
39
|
-
```
|
|
67
|
+
For Claude Code (`~/.claude/settings.json` or `.claude/settings.json` in your project):
|
|
40
68
|
|
|
41
|
-
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"mcpServers": {
|
|
72
|
+
"neuro-vault": {
|
|
73
|
+
"command": "neuro-vault-mcp",
|
|
74
|
+
"args": ["--vault", "/absolute/path/to/your/vault"]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
42
79
|
|
|
43
|
-
|
|
80
|
+
For Cursor or Windsurf (`.cursor/mcp.json` / `.windsurf/mcp.json`):
|
|
44
81
|
|
|
45
82
|
```json
|
|
46
83
|
{
|
|
47
|
-
"
|
|
48
|
-
|
|
84
|
+
"mcpServers": {
|
|
85
|
+
"neuro-vault": {
|
|
86
|
+
"command": "neuro-vault-mcp",
|
|
87
|
+
"args": ["--vault", "/absolute/path/to/your/vault"]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
49
90
|
}
|
|
50
91
|
```
|
|
51
92
|
|
|
52
|
-
|
|
93
|
+
Or run without installing using `npx`:
|
|
53
94
|
|
|
54
95
|
```json
|
|
55
96
|
{
|
|
56
97
|
"mcpServers": {
|
|
57
98
|
"neuro-vault": {
|
|
58
|
-
"command": "
|
|
59
|
-
"args": ["--vault", "/absolute/path/to/vault"]
|
|
99
|
+
"command": "npx",
|
|
100
|
+
"args": ["-y", "neuro-vault-mcp", "--vault", "/absolute/path/to/your/vault"]
|
|
60
101
|
}
|
|
61
102
|
}
|
|
62
103
|
}
|
|
63
104
|
```
|
|
64
105
|
|
|
65
|
-
|
|
106
|
+
**3. Try it**
|
|
66
107
|
|
|
67
|
-
|
|
108
|
+
Ask your assistant:
|
|
68
109
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
110
|
+
> "What did I write about building AI agents?"
|
|
111
|
+
|
|
112
|
+
> "Find my notes on productivity systems"
|
|
113
|
+
|
|
114
|
+
> "What are all my ideas related to embeddings?"
|
|
115
|
+
|
|
116
|
+
On first run the embedding model downloads automatically (~40 MB). Subsequent starts are fast.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Features
|
|
121
|
+
|
|
122
|
+
### Mode-Based Search
|
|
123
|
+
|
|
124
|
+
Every search picks a mode that controls retrieval depth:
|
|
72
125
|
|
|
73
|
-
|
|
126
|
+
| Mode | Use when | Limit | Threshold | Expansion |
|
|
127
|
+
| ------- | --------------------------------- | ----- | --------- | --------- |
|
|
128
|
+
| `quick` | Specific question, need 1-2 notes | 3 | 0.50 | off |
|
|
129
|
+
| `deep` | Broad topic, need an overview | 8 | 0.35 | on |
|
|
74
130
|
|
|
75
|
-
|
|
131
|
+
The AI assistant picks the mode automatically based on your question. You can also pass it explicitly.
|
|
132
|
+
|
|
133
|
+
### Block-Level Results (Deep Mode)
|
|
134
|
+
|
|
135
|
+
In `deep` mode the server also searches by individual note sections (blocks), not just whole notes. This surfaces the exact paragraphs that are most relevant, not just the note they live in.
|
|
136
|
+
|
|
137
|
+
### Expansion (Deep Mode)
|
|
138
|
+
|
|
139
|
+
After finding top results, the server uses their embeddings to discover neighboring notes. This catches related notes that don't directly match your query but are semantically close to what you found.
|
|
140
|
+
|
|
141
|
+
### Automatic Fallback
|
|
142
|
+
|
|
143
|
+
When vector search returns nothing, the server retries with a lower similarity threshold (0.3). If still nothing — the AI assistant can search vault files using its own tools.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Tools Reference
|
|
76
148
|
|
|
77
149
|
### `search_notes`
|
|
78
150
|
|
|
79
|
-
Search the
|
|
151
|
+
Search the vault by semantic similarity.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
search_notes({
|
|
155
|
+
query: string, // short keyword query (1-4 words)
|
|
156
|
+
mode?: "quick" | "deep", // default: "quick"
|
|
157
|
+
threshold?: number, // override mode default (0–1)
|
|
158
|
+
expansion?: boolean, // override mode default
|
|
159
|
+
expansion_limit?: number, // how many top results to expand (default: 3)
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Returns `results` (ranked notes) and `blockResults` (ranked sections — scoped to matched notes in quick mode, all sources in deep mode).
|
|
164
|
+
|
|
165
|
+
**Tips for better results:**
|
|
80
166
|
|
|
81
|
-
|
|
167
|
+
- Use short keyword queries (1–4 words), not full sentences
|
|
168
|
+
- Call multiple times for synonyms and translations: `"embeddings"`, then `"векторний пошук"`, then `"vector search"`
|
|
169
|
+
- Lower the threshold to `0.3` if nothing comes back
|
|
170
|
+
- Use `deep` mode for exploratory questions
|
|
82
171
|
|
|
83
|
-
|
|
84
|
-
- `limit` `number` optional, default `10`, must be a positive integer
|
|
85
|
-
- `threshold` `number` optional, default `0.5`, must be between `0` and `1`
|
|
172
|
+
---
|
|
86
173
|
|
|
87
174
|
### `get_similar_notes`
|
|
88
175
|
|
|
89
|
-
Find notes similar to a
|
|
176
|
+
Find notes similar to a given note path.
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
get_similar_notes({
|
|
180
|
+
note_path: string, // vault-relative POSIX path, e.g. "Projects/neuro-vault.md"
|
|
181
|
+
limit?: number, // default: 10
|
|
182
|
+
threshold?: number, // default: 0.5
|
|
183
|
+
})
|
|
184
|
+
```
|
|
90
185
|
|
|
91
|
-
|
|
186
|
+
Use this after `search_notes` finds a relevant note — it discovers related content without needing a text query.
|
|
92
187
|
|
|
93
|
-
|
|
94
|
-
- `limit` `number` optional, default `10`, must be a positive integer
|
|
95
|
-
- `threshold` `number` optional, default `0.5`, must be between `0` and `1`
|
|
188
|
+
---
|
|
96
189
|
|
|
97
190
|
### `find_duplicates`
|
|
98
191
|
|
|
99
192
|
Find note pairs with high embedding similarity.
|
|
100
193
|
|
|
101
|
-
|
|
194
|
+
```typescript
|
|
195
|
+
find_duplicates({
|
|
196
|
+
threshold?: number, // default: 0.9
|
|
197
|
+
})
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Useful for vault maintenance: identifies notes that cover the same topic and could be merged.
|
|
102
201
|
|
|
103
|
-
|
|
202
|
+
---
|
|
104
203
|
|
|
105
204
|
### `get_stats`
|
|
106
205
|
|
|
107
|
-
Report corpus
|
|
206
|
+
Report loaded corpus statistics.
|
|
108
207
|
|
|
109
|
-
|
|
208
|
+
Returns: `{ totalNotes, totalBlocks, embeddingDimension, modelKey }`
|
|
110
209
|
|
|
111
|
-
|
|
210
|
+
---
|
|
112
211
|
|
|
113
|
-
##
|
|
212
|
+
## AGENTS.md / CLAUDE.md Snippet
|
|
114
213
|
|
|
115
|
-
|
|
214
|
+
Add this to your `AGENTS.md` or `CLAUDE.md` to help the AI assistant use the vault effectively:
|
|
116
215
|
|
|
117
|
-
|
|
216
|
+
```markdown
|
|
217
|
+
## Vault search
|
|
218
|
+
|
|
219
|
+
Use vault-aware tools when vault context matters.
|
|
220
|
+
Do not guess about note contents when the vault can be searched.
|
|
221
|
+
Follow the Neuro Vault MCP server instructions for routing and retrieval.
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Configuration
|
|
227
|
+
|
|
228
|
+
### CLI Arguments
|
|
229
|
+
|
|
230
|
+
| Argument | Required | Description |
|
|
231
|
+
| --------- | -------- | --------------------------------------------- |
|
|
232
|
+
| `--vault` | yes | Absolute path to the Obsidian vault directory |
|
|
233
|
+
| `--help` | no | Show help |
|
|
234
|
+
|
|
235
|
+
### Startup Behavior
|
|
236
|
+
|
|
237
|
+
- Smart Connections `.ajson` files are loaded into memory once at startup
|
|
238
|
+
- The embedding model (`TaylorAI/bge-micro-v2`) is downloaded on first run and cached by `@xenova/transformers`
|
|
239
|
+
- If the vault path is missing or Smart Connections data is absent, the server exits immediately with an error
|
|
240
|
+
|
|
241
|
+
### Troubleshooting
|
|
242
|
+
|
|
243
|
+
**"Smart Connections directory does not exist"** — make sure the Smart Connections plugin has run and generated embeddings. Open Obsidian, let Smart Connections finish indexing, then restart the MCP server.
|
|
244
|
+
|
|
245
|
+
**First startup is slow** — the embedding model (~40 MB) is downloading. Subsequent starts use the cached model.
|
|
246
|
+
|
|
247
|
+
**Search returns nothing** — try lowering the threshold: `threshold: 0.3`. Also check that `get_stats` shows a non-zero `totalNotes`.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Development
|
|
118
252
|
|
|
119
253
|
```bash
|
|
120
|
-
npm run build
|
|
121
|
-
npm run
|
|
122
|
-
npm run
|
|
123
|
-
npm run format
|
|
124
|
-
npm run
|
|
254
|
+
npm run build # compile TypeScript to dist/
|
|
255
|
+
npm run test # run tests with vitest
|
|
256
|
+
npm run lint # ESLint
|
|
257
|
+
npm run format # check formatting with Prettier
|
|
258
|
+
npm run format:write # fix formatting
|
|
125
259
|
```
|
|
126
260
|
|
|
127
|
-
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Limitations
|
|
128
264
|
|
|
129
265
|
- Requires Smart Connections `.ajson` files already present in the vault
|
|
130
|
-
-
|
|
131
|
-
-
|
|
132
|
-
-
|
|
133
|
-
-
|
|
266
|
+
- In-memory search only — no persistent index, no background re-indexing
|
|
267
|
+
- stdio transport only — not HTTP or SSE
|
|
268
|
+
- Local vault path only — no remote vaults
|
|
269
|
+
- Embedding model loaded at startup; first run can be slow
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## License
|
|
274
|
+
|
|
275
|
+
ISC — see [LICENSE](LICENSE).
|
|
276
|
+
|
|
277
|
+
Changelog: [Releases](https://github.com/AlexMost/neuro-vault/releases)
|
package/dist/cli.d.ts
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
|
|
5
|
+
interface RetrievalOutput {
|
|
6
|
+
results: SearchResult[];
|
|
7
|
+
blockResults?: BlockSearchResult[];
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
interface SmartBlock {
|
|
6
11
|
key: string;
|
|
7
12
|
heading: string;
|
|
@@ -13,14 +18,15 @@ interface SmartSource {
|
|
|
13
18
|
embedding: number[];
|
|
14
19
|
blocks: SmartBlock[];
|
|
15
20
|
}
|
|
16
|
-
interface
|
|
21
|
+
interface BlockSearchResult {
|
|
22
|
+
path: string;
|
|
17
23
|
heading: string;
|
|
18
24
|
lines: [number, number];
|
|
25
|
+
similarity: number;
|
|
19
26
|
}
|
|
20
27
|
interface SearchResult {
|
|
21
28
|
path: string;
|
|
22
29
|
similarity: number;
|
|
23
|
-
blocks: SearchResultBlock[];
|
|
24
30
|
}
|
|
25
31
|
interface DuplicatePair {
|
|
26
32
|
note_a: string;
|
|
@@ -39,15 +45,25 @@ interface SearchEngine {
|
|
|
39
45
|
limit?: number;
|
|
40
46
|
excludePath?: string;
|
|
41
47
|
}): SearchResult[];
|
|
48
|
+
findBlockNeighbors(args: {
|
|
49
|
+
queryVector: number[];
|
|
50
|
+
sources: Iterable<SmartSource>;
|
|
51
|
+
threshold: number;
|
|
52
|
+
limit?: number;
|
|
53
|
+
}): BlockSearchResult[];
|
|
42
54
|
findDuplicates(args: {
|
|
43
55
|
sources: Iterable<SmartSource>;
|
|
44
56
|
threshold: number;
|
|
45
57
|
}): DuplicatePair[];
|
|
46
58
|
}
|
|
59
|
+
type SearchMode = 'quick' | 'deep';
|
|
47
60
|
interface SearchNotesInput {
|
|
48
61
|
query: string;
|
|
62
|
+
mode?: SearchMode;
|
|
49
63
|
limit?: number;
|
|
50
64
|
threshold?: number;
|
|
65
|
+
expansion?: boolean;
|
|
66
|
+
expansion_limit?: number;
|
|
51
67
|
}
|
|
52
68
|
interface GetSimilarNotesInput {
|
|
53
69
|
note_path: string;
|
|
@@ -72,7 +88,7 @@ interface ToolHandlerDependencies {
|
|
|
72
88
|
modelKey: string;
|
|
73
89
|
}
|
|
74
90
|
interface ToolHandlers {
|
|
75
|
-
searchNotes(input: SearchNotesInput): Promise<
|
|
91
|
+
searchNotes(input: SearchNotesInput): Promise<RetrievalOutput>;
|
|
76
92
|
getSimilarNotes(input: GetSimilarNotesInput): Promise<SearchResult[]>;
|
|
77
93
|
findDuplicates(input?: FindDuplicatesInput): Promise<DuplicatePair[]>;
|
|
78
94
|
getStats(): Promise<ToolStats>;
|