@bitbonsai/mcpvault 0.15.0 → 0.16.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 CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![MCP Toplist](https://mcptoplist.com/badge/glama%2Fbitbonsai%2Fmcpvault.svg)](https://mcptoplist.com/server/glama%2Fbitbonsai%2Fmcpvault)
6
6
 
7
- A universal AI bridge for Obsidian vaults using the Model Context Protocol (MCP) standard. Connect any MCP-compatible AI assistant to your knowledge base - works with Claude, ChatGPT, and future AI tools. This server provides safe read/write access to your notes while preventing YAML frontmatter corruption.
7
+ A local MCP server that lets compatible clients read, search, and edit notes in an Obsidian vault. MCPVault works directly with vault files, restricts file operations to the configured vault root, and preserves formatting for unchanged frontmatter fields.
8
8
 
9
9
  <div align="center">
10
10
 
@@ -20,18 +20,18 @@ A universal AI bridge for Obsidian vaults using the Model Context Protocol (MCP)
20
20
 
21
21
  </div>
22
22
 
23
- ## Universal Compatibility
23
+ ## Supported clients
24
24
 
25
- Works with any MCP-compatible AI assistant including Claude Desktop, Claude Code, ChatGPT Desktop (Enterprise+), OpenCode, Gemini CLI, OpenAI Codex, IntelliJ IDEA 2025.1+, Cursor IDE, Windsurf IDE, Ontheia, and future AI platforms that adopt the MCP standard.
25
+ Configuration examples are available for Claude Desktop, Claude Code, ChatGPT Desktop (Enterprise+), OpenCode, Gemini CLI, OpenAI Codex, IntelliJ IDEA 2025.1+, Cursor, Windsurf, and Ontheia. Other clients can use MCPVault if they support local stdio MCP servers.
26
26
 
27
27
  https://github.com/user-attachments/assets/657ac4c6-1cd2-4cc3-829f-fd095a32f71c
28
28
 
29
- ## Quick Start (5 minutes)
29
+ ## Quick start
30
30
 
31
31
  1. **Install Node.js runtime:**
32
32
 
33
33
  ```bash
34
- # Download from https://nodejs.org (v18.0.0 or later)
34
+ # Download from https://nodejs.org (v20.0.0 or later)
35
35
  # or use a package manager like nvm, brew, apt, etc.
36
36
  ```
37
37
 
@@ -99,57 +99,41 @@ https://github.com/user-attachments/assets/657ac4c6-1cd2-4cc3-829f-fd095a32f71c
99
99
  - "Read my note called 'project-ideas.md'"
100
100
  - "Create a new note with today's date"
101
101
 
102
- **Success indicators:** Your AI should be able to list files and read notes from your vault.
102
+ To verify the connection, ask your client to list MCPVault tools or read a known note.
103
103
 
104
- ## Why MCPVault?
104
+ ## How it connects
105
105
 
106
- ### Universal AI Compatibility
107
-
108
- Built on the open Model Context Protocol standard, MCPVault is not locked to any single AI provider. As more AI assistants adopt MCP, your investment in this tool grows more valuable. Today it works with Claude and ChatGPT - tomorrow it will work with whatever AI tools emerge.
109
-
110
- ### Future-Proof Your Knowledge Base
111
-
112
- Instead of waiting for each AI company to build Obsidian integrations, MCPVault provides a universal adapter that works with any MCP-compatible assistant. One tool, endless possibilities.
113
-
114
- ### Open Standard, No Lock-in
115
-
116
- MCP is an open protocol. You're not tied to any specific vendor or platform. Your notes remain yours, accessible through any compatible AI assistant.
106
+ An MCP client starts MCPVault as a local stdio process and passes the vault path. MCPVault exposes the same tools to each supported client, so the server is not tied to one AI provider. Obsidian does not need to be running, and no Obsidian plugin is required.
117
107
 
118
108
  ## Features
119
109
 
120
- - ✅ Safe frontmatter parsing and validation using gray-matter with AST-aware updates that preserve raw formatting for unmodified fields
121
- - ✅ Path filtering to exclude `.obsidian` directory and other system files
122
- - ✅ **Complete MCP toolkit**: 18 tools covering all vault operations
110
+ - AST-aware frontmatter updates preserve formatting for unchanged YAML fields.
111
+ - Path checks block traversal, symlink escapes, dotfiles, `.obsidian`, `.git`, and `node_modules`.
112
+ - Eighteen MCP tools cover note and file operations:
123
113
  - File operations: `read_note`, `write_note`, `patch_note`, `delete_note`, `move_note`, `move_file`
124
- - Partial reads: `get_note_outline` (headings without loading the full file), `read_note_lines` (a specific line range)
125
- - Directory operations: `list_directory`
126
- - Batch operations: `read_multiple_notes`
127
- - Search: `search_notes` with multi-word matching and BM25 relevance reranking
128
- - Metadata: `get_frontmatter`, `update_frontmatter`, `get_notes_info`, `get_vault_stats`
129
- - Tag management: `manage_tags` (add, remove, list), `list_all_tags`
130
- - Wiki links: `wiki_link` picks the shallowest match first (vault root before nested folders), then uses locale-aware path sorting at the same depth. Other matches are returned as alternatives; punctuation may sort before digits, so `_Inbox` can come before `00.projects`.
131
- - ✅ Write modes: `overwrite`, `append`, `prepend` for flexible content editing
132
- - ✅ Tag management: add, remove, and list tags in notes
133
- - ✅ Safe deletion with confirmation requirement to prevent accidents
134
- - ✅ Automatic path trimming to handle whitespace in inputs
135
- - ✅ TypeScript support with Node.js runtime (using tsx for execution)
136
- - ✅ Comprehensive error handling and validation
137
- - ✅ **Token-optimized responses**: 40-60% smaller responses with minified field names and compact JSON (v0.6.3+)
138
- - ✅ **Optional pretty-printing**: Set `prettyPrint: true` for human-readable debugging
139
- - ✅ **Performance optimized**: No unnecessary token consumption, efficient for large vaults
140
- - ✅ **Zero dependencies**: No Obsidian plugins required, works with any vault structure
114
+ - Partial reads: `get_note_outline`, `read_note_lines`
115
+ - Directory and batch reads: `list_directory`, `read_multiple_notes`
116
+ - Search: `search_notes` with multi-word matching and BM25 reranking
117
+ - Metadata and tags: `get_frontmatter`, `update_frontmatter`, `get_notes_info`, `get_vault_stats`, `manage_tags`, `list_all_tags`
118
+ - Wiki links: `wiki_link` resolves names and returns alternative paths when a name is ambiguous
119
+ - `write_note` supports overwrite, append, and prepend modes.
120
+ - `delete_note` and `move_file` require matching confirmation paths.
121
+ - Path arguments are trimmed before validation.
122
+ - Search and batch tools return compact fields by default; set `prettyPrint: true` for expanded output.
123
+ - The package exports TypeScript declarations and public types.
124
+ - MCPVault requires no Obsidian plugin.
141
125
 
142
126
  ## Prerequisites
143
127
 
144
- - [Node.js](https://nodejs.org) runtime (v18.0.0 or later)
128
+ - [Node.js](https://nodejs.org) runtime (v20.0.0 or later)
145
129
  - An Obsidian vault (local directory with `.md`, `.markdown`, `.txt`, `.base`, or `.canvas` files)
146
130
  - MCP-compatible AI client (Claude Desktop, ChatGPT Desktop, Claude Code, etc.)
147
131
 
148
132
  ## Installation
149
133
 
150
- ### For End Users (Recommended)
134
+ ### For end users
151
135
 
152
- No installation needed! Use `npx` to run directly:
136
+ `npx` downloads and runs the package:
153
137
 
154
138
  ```bash
155
139
  npx @bitbonsai/mcpvault@latest /path/to/your/obsidian/vault
@@ -157,7 +141,7 @@ npx @bitbonsai/mcpvault@latest /path/to/your/obsidian/vault
157
141
 
158
142
  If you omit the vault path, the server uses your current working directory as the vault root.
159
143
 
160
- ### For Developers
144
+ ### For developers
161
145
 
162
146
  1. Clone this repository
163
147
  2. Use the correct Node.js version:
@@ -178,7 +162,7 @@ npm install # Corepack automatically uses npm 10.9.0
178
162
  npx @modelcontextprotocol/inspector npm start /path/to/your/vault
179
163
  ```
180
164
 
181
- **Pro tip:** Use MCP Inspector to test all server functionality before configuring with AI clients:
165
+ Use MCP Inspector to test the server before adding it to a client:
182
166
 
183
167
  ```bash
184
168
  # Install globally for easier access
@@ -375,12 +359,12 @@ Most modern MCP clients use similar JSON configuration patterns. Refer to your s
375
359
  - "List all markdown files in my 'Projects' folder"
376
360
  - "Delete the old draft note 'draft-ideas.md' (with confirmation)"
377
361
 
378
- #### Advanced Use Cases:
362
+ #### Example workflows
379
363
 
380
- - **Knowledge Synthesis**: "Summarize all my research notes tagged with 'machine-learning' from the last month"
381
- - **Project Management**: "Update the status in all project notes to 'completed' and add today's date"
382
- - **Content Analysis**: "Find all notes that mention 'API design' and create a comprehensive guide"
383
- - **Smart Tagging**: "Review my untagged notes and suggest appropriate tags based on content"
364
+ - "Summarize my research notes tagged with 'machine-learning' from the last month"
365
+ - "Update the status in my project notes to 'completed' and add today's date"
366
+ - "Find notes that mention 'API design' and draft a guide from them"
367
+ - "Review my untagged notes and suggest tags based on their content"
384
368
 
385
369
  ## Troubleshooting
386
370
 
@@ -459,7 +443,7 @@ Read a note from the vault with parsed frontmatter.
459
443
  }
460
444
  ```
461
445
 
462
- **Response (optimized for tokens):**
446
+ **Compact response:**
463
447
 
464
448
  ```json
465
449
  {
@@ -536,7 +520,7 @@ Write a note to the vault with optional frontmatter and write mode.
536
520
 
537
521
  ### `patch_note`
538
522
 
539
- Efficiently replace an exact string inside an existing note without rewriting the full file.
523
+ Replace an exact string inside an existing note without rewriting the full file.
540
524
 
541
525
  **Request:**
542
526
 
@@ -592,7 +576,7 @@ Note: this includes non-note filenames (for example `pdf`, `png`, `jpg`) so AI a
592
576
  }
593
577
  ```
594
578
 
595
- **Response (optimized):**
579
+ **Compact response:**
596
580
 
597
581
  ```json
598
582
  {
@@ -643,7 +627,7 @@ Delete a note from the vault (requires confirmation for safety).
643
627
  }
644
628
  ```
645
629
 
646
- **⚠️ Safety Note:** The `confirmPath` parameter must exactly match the `path` parameter to proceed with deletion. This prevents accidental deletions.
630
+ **Confirmation:** `confirmPath` must exactly match `path` before deletion proceeds.
647
631
 
648
632
  ### `get_frontmatter`
649
633
 
@@ -661,7 +645,7 @@ Extract only the frontmatter from a note without reading the full content.
661
645
  }
662
646
  ```
663
647
 
664
- **Response (optimized, returns frontmatter directly):**
648
+ **Compact response, returning frontmatter directly:**
665
649
 
666
650
  ```json
667
651
  {
@@ -745,7 +729,7 @@ Search for notes in the vault by content or frontmatter with multi-word matching
745
729
  }
746
730
  ```
747
731
 
748
- **Response (optimized with minified field names):**
732
+ **Compact response:**
749
733
 
750
734
  ```json
751
735
  [
@@ -827,7 +811,7 @@ Move or rename any file in the vault with binary-safe file operations (file-only
827
811
  }
828
812
  ```
829
813
 
830
- **Safety Note:** `confirmOldPath` must exactly match `oldPath`, and `confirmNewPath` must exactly match `newPath`, otherwise the move is rejected.
814
+ **Confirmation:** `confirmOldPath` must match `oldPath`, and `confirmNewPath` must match `newPath`.
831
815
 
832
816
  ### `read_multiple_notes`
833
817
 
@@ -847,7 +831,7 @@ Read multiple notes in a batch (maximum 10 files).
847
831
  }
848
832
  ```
849
833
 
850
- **Response (optimized, shortened field names):**
834
+ **Compact response:**
851
835
 
852
836
  ```json
853
837
  {
@@ -911,7 +895,7 @@ Get metadata for notes without reading full content.
911
895
  }
912
896
  ```
913
897
 
914
- **Response (optimized, returns array directly):**
898
+ **Compact response, returning an array directly:**
915
899
 
916
900
  ```json
917
901
  [
@@ -940,7 +924,7 @@ Get high-level vault statistics without reading note contents.
940
924
  }
941
925
  ```
942
926
 
943
- **Response (optimized):**
927
+ **Compact response:**
944
928
 
945
929
  ```json
946
930
  {
@@ -957,9 +941,9 @@ Get high-level vault statistics without reading note contents.
957
941
  }
958
942
  ```
959
943
 
960
- ## Security Considerations
944
+ ## Security boundaries
961
945
 
962
- This MCP server implements several security measures to protect your Obsidian vault:
946
+ MCPVault applies these checks before file operations:
963
947
 
964
948
  ### Path Security
965
949
 
@@ -992,13 +976,13 @@ This MCP server implements several security measures to protect your Obsidian va
992
976
  - **Vault Structure:** Directory structure is visible to AI assistants
993
977
  - **File Metadata:** Creation times, file sizes, etc. are accessible
994
978
 
995
- **⚠️ Important:** Only grant vault access to trusted AI conversations. The server provides full read/write access to your notes within the security boundaries above.
979
+ Only grant write access to clients and conversations you trust. Use `--read-only` when the client does not need to modify notes.
996
980
 
997
981
  ## Architecture
998
982
 
999
983
  - `server.ts` - MCP server entry point
1000
984
  - `src/frontmatter.ts` - YAML frontmatter handling with gray-matter
1001
- - `src/filesystem.ts` - Safe file operations with path validation
985
+ - `src/filesystem.ts` - File operations with path validation
1002
986
  - `src/pathfilter.ts` - Directory and file filtering
1003
987
  - `src/search.ts` - Note search functionality with content and frontmatter support
1004
988
  - `src/uri.ts` - Obsidian URI generation for deep links
@@ -1012,6 +996,8 @@ This MCP server implements several security measures to protect your Obsidian va
1012
996
  4. Ensure all tests pass: `npm test`
1013
997
  5. Submit a pull request
1014
998
 
999
+ Maintainers: production publishing is driven by GitHub Releases. See [RELEASING.md](RELEASING.md).
1000
+
1015
1001
  ## License
1016
1002
 
1017
1003
  MIT
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import { serveStdio } from "@modelcontextprotocol/server/stdio";
3
3
  import { createServer } from "./src/createServer.js";
4
4
  import { parseCliArgs } from "./src/cli.js";
5
5
  import { readFileSync } from "fs";
@@ -50,9 +50,9 @@ Examples:
50
50
  // unquoted vault paths with spaces. When omitted, use the current directory.
51
51
  const { vaultPathArg, readOnly } = parseCliArgs(cliArgs);
52
52
  const vaultPath = resolve(vaultPathArg || process.cwd());
53
- const server = createServer(vaultPath, { version: VERSION, readOnly });
54
- const transport = new StdioServerTransport();
55
- await server.connect(transport);
53
+ // Serve both the legacy handshake-based protocol and MCP 2026-07-28 from the
54
+ // same process. The opening exchange selects the era for this connection.
55
+ const serverHandle = serveStdio(() => createServer(vaultPath, { version: VERSION, readOnly }), { onerror: (error) => console.error(error) });
56
56
  // Exit when the client disconnects (stdin EOF) or the process is asked to
57
57
  // terminate. Hosts that don't send an MCP shutdown request otherwise leave
58
58
  // this process running forever, orphaned once stdin closes (#159).
@@ -62,7 +62,7 @@ async function shutdown() {
62
62
  return;
63
63
  isShuttingDown = true;
64
64
  try {
65
- await server.close();
65
+ await serverHandle.close();
66
66
  }
67
67
  catch {
68
68
  // Best-effort: exit regardless of transport close errors.
@@ -1,4 +1,4 @@
1
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
1
+ import { Server } from "@modelcontextprotocol/server";
2
2
  import { FrontmatterHandler } from "./frontmatter.js";
3
3
  import { PathFilter } from "./pathfilter.js";
4
4
  export interface CreateServerOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"createServer.d.ts","sourceRoot":"","sources":["../../src/createServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAMnE,OAAO,EAAE,kBAAkB,EAAoB,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAK7C,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAYD,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAsezF"}
1
+ {"version":3,"file":"createServer.d.ts","sourceRoot":"","sources":["../../src/createServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAa,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EAAE,kBAAkB,EAAoB,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAK7C,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAYD,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAsezF"}
@@ -1,5 +1,4 @@
1
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
- import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
1
+ import { Server } from "@modelcontextprotocol/server";
3
2
  import { FileSystemService } from "./filesystem.js";
4
3
  import { FrontmatterHandler, parseFrontmatter } from "./frontmatter.js";
5
4
  import { PathFilter } from "./pathfilter.js";
@@ -23,7 +22,7 @@ export function createServer(vaultPath, options = {}) {
23
22
  const server = new Server({ name, version }, {
24
23
  capabilities: { tools: {} },
25
24
  });
26
- server.setRequestHandler(ListToolsRequestSchema, async () => {
25
+ server.setRequestHandler("tools/list", async () => {
27
26
  const tools = [
28
27
  {
29
28
  name: "read_note",
@@ -272,7 +271,7 @@ export function createServer(vaultPath, options = {}) {
272
271
  : tools,
273
272
  };
274
273
  });
275
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
274
+ server.setRequestHandler("tools/call", async (request) => {
276
275
  const { name: toolName, arguments: args } = request.params;
277
276
  const trimmedArgs = trimPaths(args);
278
277
  if (readOnly && MUTATING_TOOLS.has(toolName)) {
@@ -1,4 +1,4 @@
1
- import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
1
+ import type { CallToolResult } from '@modelcontextprotocol/server';
2
2
  import type { FileSystemService } from '../filesystem.js';
3
3
  export interface WikiLinkToolArgs {
4
4
  document: string;
@@ -1 +1 @@
1
- {"version":3,"file":"wikiLinkTool.d.ts","sourceRoot":"","sources":["../../../src/wikilink/wikiLinkTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,iBAAiB,EAC7B,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,cAAc,CAAC,CAiDzB"}
1
+ {"version":3,"file":"wikiLinkTool.d.ts","sourceRoot":"","sources":["../../../src/wikilink/wikiLinkTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,iBAAiB,EAC7B,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,cAAc,CAAC,CAiDzB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitbonsai/mcpvault",
3
- "version": "0.15.0",
3
+ "version": "0.16.1",
4
4
  "description": "Universal AI bridge for Obsidian vaults - connect any MCP-compatible assistant",
5
5
  "homepage": "https://mcpvault.org",
6
6
  "author": "bitbonsai",
@@ -33,19 +33,24 @@
33
33
  "prepack": "npm install",
34
34
  "publish:dry": "npm publish --dry-run",
35
35
  "publish:beta": "npm publish --tag beta",
36
- "publish:latest": "npm publish"
36
+ "publish:latest": "npm publish",
37
+ "ship": "bun scripts/ship.ts",
38
+ "ship:setup": "bun scripts/ship.ts --setup",
39
+ "ship:update": "bun scripts/ship.ts --update"
37
40
  },
38
41
  "dependencies": {
39
- "@modelcontextprotocol/sdk": "^1.30.0",
42
+ "@modelcontextprotocol/server": "^2.3.1",
40
43
  "gray-matter": "^4.0.3",
41
- "trash": "^10.1.1",
44
+ "trash": "9.0.0",
42
45
  "yaml": "^2.9.0"
43
46
  },
44
47
  "devDependencies": {
48
+ "@clack/prompts": "^1.7.0",
49
+ "@modelcontextprotocol/client": "^2.3.1",
45
50
  "@types/node": "^26.1.2",
46
51
  "tsx": "^4.23.9",
47
52
  "typescript": "^7.0.2",
48
- "vitest": "^4.1.10"
53
+ "vitest": "^4.1.12"
49
54
  },
50
55
  "engines": {
51
56
  "node": ">=20.0.0"