@mauricio.wolff/mcp-obsidian 0.5.1 → 0.5.4
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 +10 -10
- package/dist/server.js +1 -1
- package/dist/src/filesystem.js +4 -2
- package/dist/src/frontmatter.js +2 -3
- package/package.json +3 -5
- package/server.ts +0 -516
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ A lightweight Model Context Protocol (MCP) server for safe Obsidian vault access
|
|
|
16
16
|
|
|
17
17
|
If using the published package:
|
|
18
18
|
```bash
|
|
19
|
-
npx @modelcontextprotocol/inspector npx @mauricio.wolff/mcp-obsidian /path/to/your/vault
|
|
19
|
+
npx @modelcontextprotocol/inspector npx @mauricio.wolff/mcp-obsidian@latest /path/to/your/vault
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
3. **Configure your AI client:**
|
|
@@ -27,7 +27,7 @@ A lightweight Model Context Protocol (MCP) server for safe Obsidian vault access
|
|
|
27
27
|
"mcpServers": {
|
|
28
28
|
"obsidian": {
|
|
29
29
|
"command": "npx",
|
|
30
|
-
"args": ["@mauricio.wolff/mcp-obsidian", "/path/to/your/vault"]
|
|
30
|
+
"args": ["@mauricio.wolff/mcp-obsidian@latest", "/path/to/your/vault"]
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -39,7 +39,7 @@ A lightweight Model Context Protocol (MCP) server for safe Obsidian vault access
|
|
|
39
39
|
"mcpServers": {
|
|
40
40
|
"obsidian": {
|
|
41
41
|
"command": "npx",
|
|
42
|
-
"args": ["@mauricio.wolff/mcp-obsidian", "/path/to/your/vault"],
|
|
42
|
+
"args": ["@mauricio.wolff/mcp-obsidian@latest", "/path/to/your/vault"],
|
|
43
43
|
"env": {}
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -88,7 +88,7 @@ A lightweight Model Context Protocol (MCP) server for safe Obsidian vault access
|
|
|
88
88
|
No installation needed! Use `npx` to run directly:
|
|
89
89
|
|
|
90
90
|
```bash
|
|
91
|
-
npx @mauricio.wolff/mcp-obsidian /path/to/your/obsidian/vault
|
|
91
|
+
npx @mauricio.wolff/mcp-obsidian@latest /path/to/your/obsidian/vault
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
### For Developers
|
|
@@ -110,7 +110,7 @@ npx @modelcontextprotocol/inspector npm start /path/to/your/vault
|
|
|
110
110
|
|
|
111
111
|
**End users:**
|
|
112
112
|
```bash
|
|
113
|
-
npx @mauricio.wolff/mcp-obsidian /path/to/your/obsidian/vault
|
|
113
|
+
npx @mauricio.wolff/mcp-obsidian@latest /path/to/your/obsidian/vault
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
**Developers:**
|
|
@@ -130,7 +130,7 @@ Add to your Claude Desktop configuration file:
|
|
|
130
130
|
"mcpServers": {
|
|
131
131
|
"obsidian": {
|
|
132
132
|
"command": "npx",
|
|
133
|
-
"args": ["@mauricio.wolff/mcp-obsidian", "/Users/yourname/Documents/MyVault"]
|
|
133
|
+
"args": ["@mauricio.wolff/mcp-obsidian@latest", "/Users/yourname/Documents/MyVault"]
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
}
|
|
@@ -142,11 +142,11 @@ Add to your Claude Desktop configuration file:
|
|
|
142
142
|
"mcpServers": {
|
|
143
143
|
"obsidian-personal": {
|
|
144
144
|
"command": "npx",
|
|
145
|
-
"args": ["@mauricio.wolff/mcp-obsidian", "/Users/yourname/Documents/PersonalVault"]
|
|
145
|
+
"args": ["@mauricio.wolff/mcp-obsidian@latest", "/Users/yourname/Documents/PersonalVault"]
|
|
146
146
|
},
|
|
147
147
|
"obsidian-work": {
|
|
148
148
|
"command": "npx",
|
|
149
|
-
"args": ["@mauricio.wolff/mcp-obsidian", "/Users/yourname/Documents/WorkVault"]
|
|
149
|
+
"args": ["@mauricio.wolff/mcp-obsidian@latest", "/Users/yourname/Documents/WorkVault"]
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
}
|
|
@@ -182,7 +182,7 @@ Edit `~/.claude.json`:
|
|
|
182
182
|
"mcpServers": {
|
|
183
183
|
"obsidian": {
|
|
184
184
|
"command": "npx",
|
|
185
|
-
"args": ["@mauricio.wolff/mcp-obsidian", "/path/to/your/vault"],
|
|
185
|
+
"args": ["@mauricio.wolff/mcp-obsidian@latest", "/path/to/your/vault"],
|
|
186
186
|
"env": {}
|
|
187
187
|
}
|
|
188
188
|
}
|
|
@@ -198,7 +198,7 @@ Edit `.claude.json` in your project or add to the projects section:
|
|
|
198
198
|
"mcpServers": {
|
|
199
199
|
"obsidian": {
|
|
200
200
|
"command": "npx",
|
|
201
|
-
"args": ["@mauricio.wolff/mcp-obsidian", "/path/to/your/vault"]
|
|
201
|
+
"args": ["@mauricio.wolff/mcp-obsidian@latest", "/path/to/your/vault"]
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
}
|
package/dist/server.js
CHANGED
|
@@ -18,7 +18,7 @@ const fileSystem = new FileSystemService(vaultPath, pathFilter, frontmatterHandl
|
|
|
18
18
|
const searchService = new SearchService(vaultPath, pathFilter);
|
|
19
19
|
const server = new Server({
|
|
20
20
|
name: "mcp-obsidian",
|
|
21
|
-
version: "0.5.
|
|
21
|
+
version: "0.5.4"
|
|
22
22
|
}, {
|
|
23
23
|
capabilities: {
|
|
24
24
|
tools: {},
|
package/dist/src/filesystem.js
CHANGED
|
@@ -130,13 +130,15 @@ export class FileSystemService {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
async listDirectory(path = '') {
|
|
133
|
-
|
|
133
|
+
// Normalize path: treat '.' as root directory
|
|
134
|
+
const normalizedPath = path === '.' ? '' : path;
|
|
135
|
+
const fullPath = this.resolvePath(normalizedPath);
|
|
134
136
|
try {
|
|
135
137
|
const entries = await readdir(fullPath, { withFileTypes: true });
|
|
136
138
|
const files = [];
|
|
137
139
|
const directories = [];
|
|
138
140
|
for (const entry of entries) {
|
|
139
|
-
const entryPath =
|
|
141
|
+
const entryPath = normalizedPath ? `${normalizedPath}/${entry.name}` : entry.name;
|
|
140
142
|
if (!this.pathFilter.isAllowed(entryPath)) {
|
|
141
143
|
continue;
|
|
142
144
|
}
|
package/dist/src/frontmatter.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import matter from 'gray-matter';
|
|
2
|
-
import * as yaml from 'js-yaml';
|
|
3
2
|
export class FrontmatterHandler {
|
|
4
3
|
parse(content) {
|
|
5
4
|
try {
|
|
@@ -38,8 +37,8 @@ export class FrontmatterHandler {
|
|
|
38
37
|
warnings: []
|
|
39
38
|
};
|
|
40
39
|
try {
|
|
41
|
-
// Test if the frontmatter can be serialized to valid YAML using
|
|
42
|
-
|
|
40
|
+
// Test if the frontmatter can be serialized to valid YAML using gray-matter
|
|
41
|
+
matter.stringify('', frontmatterData);
|
|
43
42
|
}
|
|
44
43
|
catch (error) {
|
|
45
44
|
result.isValid = false;
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mauricio.wolff/mcp-obsidian",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "Lightweight MCP server for safe Obsidian vault access",
|
|
5
5
|
"author": "bitbonsai",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
8
|
-
"main": "server.
|
|
8
|
+
"main": "dist/server.js",
|
|
9
9
|
"bin": {
|
|
10
10
|
"mcp-obsidian": "./dist/server.js",
|
|
11
11
|
"@mauricio.wolff/mcp-obsidian": "./dist/server.js"
|
|
@@ -34,9 +34,7 @@
|
|
|
34
34
|
"@types/node": "^20.0.0",
|
|
35
35
|
"tsx": "^4.0.0",
|
|
36
36
|
"typescript": "^5.0.0",
|
|
37
|
-
"vitest": "^1.0.0"
|
|
38
|
-
"js-yaml": "^4.1.0",
|
|
39
|
-
"@types/js-yaml": "^4.0.0"
|
|
37
|
+
"vitest": "^1.0.0"
|
|
40
38
|
},
|
|
41
39
|
"engines": {
|
|
42
40
|
"node": ">=18.0.0"
|
package/server.ts
DELETED
|
@@ -1,516 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
-
import {
|
|
6
|
-
CallToolRequestSchema,
|
|
7
|
-
ListToolsRequestSchema,
|
|
8
|
-
} from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
-
import { FileSystemService } from "./src/filesystem.js";
|
|
10
|
-
import { FrontmatterHandler } from "./src/frontmatter.js";
|
|
11
|
-
import { PathFilter } from "./src/pathfilter.js";
|
|
12
|
-
import { SearchService } from "./src/search.js";
|
|
13
|
-
|
|
14
|
-
const vaultPath = process.argv[2];
|
|
15
|
-
if (!vaultPath) {
|
|
16
|
-
console.error("Usage: npx @mauricio.wolff/mcp-obsidian /path/to/vault");
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Initialize services
|
|
21
|
-
const pathFilter = new PathFilter();
|
|
22
|
-
const frontmatterHandler = new FrontmatterHandler();
|
|
23
|
-
const fileSystem = new FileSystemService(vaultPath, pathFilter, frontmatterHandler);
|
|
24
|
-
const searchService = new SearchService(vaultPath, pathFilter);
|
|
25
|
-
|
|
26
|
-
const server = new Server({
|
|
27
|
-
name: "mcp-obsidian",
|
|
28
|
-
version: "0.5.1"
|
|
29
|
-
}, {
|
|
30
|
-
capabilities: {
|
|
31
|
-
tools: {},
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
36
|
-
return {
|
|
37
|
-
tools: [
|
|
38
|
-
{
|
|
39
|
-
name: "read_note",
|
|
40
|
-
description: "Read a note from the Obsidian vault",
|
|
41
|
-
inputSchema: {
|
|
42
|
-
type: "object",
|
|
43
|
-
properties: {
|
|
44
|
-
path: {
|
|
45
|
-
type: "string",
|
|
46
|
-
description: "Path to the note relative to vault root"
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
required: ["path"]
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: "write_note",
|
|
54
|
-
description: "Write a note to the Obsidian vault",
|
|
55
|
-
inputSchema: {
|
|
56
|
-
type: "object",
|
|
57
|
-
properties: {
|
|
58
|
-
path: {
|
|
59
|
-
type: "string",
|
|
60
|
-
description: "Path to the note relative to vault root"
|
|
61
|
-
},
|
|
62
|
-
content: {
|
|
63
|
-
type: "string",
|
|
64
|
-
description: "Content of the note"
|
|
65
|
-
},
|
|
66
|
-
frontmatter: {
|
|
67
|
-
type: "object",
|
|
68
|
-
description: "Frontmatter object (optional)"
|
|
69
|
-
},
|
|
70
|
-
mode: {
|
|
71
|
-
type: "string",
|
|
72
|
-
enum: ["overwrite", "append", "prepend"],
|
|
73
|
-
description: "Write mode: 'overwrite' (default), 'append', or 'prepend'",
|
|
74
|
-
default: "overwrite"
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
required: ["path", "content"]
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
name: "list_directory",
|
|
82
|
-
description: "List files and directories in the vault",
|
|
83
|
-
inputSchema: {
|
|
84
|
-
type: "object",
|
|
85
|
-
properties: {
|
|
86
|
-
path: {
|
|
87
|
-
type: "string",
|
|
88
|
-
description: "Path relative to vault root (default: '/')",
|
|
89
|
-
default: "/"
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
name: "delete_note",
|
|
96
|
-
description: "Delete a note from the Obsidian vault (requires confirmation)",
|
|
97
|
-
inputSchema: {
|
|
98
|
-
type: "object",
|
|
99
|
-
properties: {
|
|
100
|
-
path: {
|
|
101
|
-
type: "string",
|
|
102
|
-
description: "Path to the note relative to vault root"
|
|
103
|
-
},
|
|
104
|
-
confirmPath: {
|
|
105
|
-
type: "string",
|
|
106
|
-
description: "Confirmation: must exactly match the path parameter to proceed with deletion"
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
required: ["path", "confirmPath"]
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
name: "search_notes",
|
|
114
|
-
description: "Search for notes in the vault by content or frontmatter",
|
|
115
|
-
inputSchema: {
|
|
116
|
-
type: "object",
|
|
117
|
-
properties: {
|
|
118
|
-
query: {
|
|
119
|
-
type: "string",
|
|
120
|
-
description: "Search query text"
|
|
121
|
-
},
|
|
122
|
-
limit: {
|
|
123
|
-
type: "number",
|
|
124
|
-
description: "Maximum number of results (default: 5, max: 20)",
|
|
125
|
-
default: 5
|
|
126
|
-
},
|
|
127
|
-
searchContent: {
|
|
128
|
-
type: "boolean",
|
|
129
|
-
description: "Search in note content (default: true)",
|
|
130
|
-
default: true
|
|
131
|
-
},
|
|
132
|
-
searchFrontmatter: {
|
|
133
|
-
type: "boolean",
|
|
134
|
-
description: "Search in frontmatter (default: false)",
|
|
135
|
-
default: false
|
|
136
|
-
},
|
|
137
|
-
caseSensitive: {
|
|
138
|
-
type: "boolean",
|
|
139
|
-
description: "Case sensitive search (default: false)",
|
|
140
|
-
default: false
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
required: ["query"]
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: "move_note",
|
|
148
|
-
description: "Move or rename a note in the vault",
|
|
149
|
-
inputSchema: {
|
|
150
|
-
type: "object",
|
|
151
|
-
properties: {
|
|
152
|
-
oldPath: {
|
|
153
|
-
type: "string",
|
|
154
|
-
description: "Current path of the note"
|
|
155
|
-
},
|
|
156
|
-
newPath: {
|
|
157
|
-
type: "string",
|
|
158
|
-
description: "New path for the note"
|
|
159
|
-
},
|
|
160
|
-
overwrite: {
|
|
161
|
-
type: "boolean",
|
|
162
|
-
description: "Allow overwriting existing file (default: false)",
|
|
163
|
-
default: false
|
|
164
|
-
}
|
|
165
|
-
},
|
|
166
|
-
required: ["oldPath", "newPath"]
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
name: "read_multiple_notes",
|
|
171
|
-
description: "Read multiple notes in a batch (max 10 files)",
|
|
172
|
-
inputSchema: {
|
|
173
|
-
type: "object",
|
|
174
|
-
properties: {
|
|
175
|
-
paths: {
|
|
176
|
-
type: "array",
|
|
177
|
-
items: { type: "string" },
|
|
178
|
-
description: "Array of note paths to read",
|
|
179
|
-
maxItems: 10
|
|
180
|
-
},
|
|
181
|
-
includeContent: {
|
|
182
|
-
type: "boolean",
|
|
183
|
-
description: "Include note content (default: true)",
|
|
184
|
-
default: true
|
|
185
|
-
},
|
|
186
|
-
includeFrontmatter: {
|
|
187
|
-
type: "boolean",
|
|
188
|
-
description: "Include frontmatter (default: true)",
|
|
189
|
-
default: true
|
|
190
|
-
}
|
|
191
|
-
},
|
|
192
|
-
required: ["paths"]
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
name: "update_frontmatter",
|
|
197
|
-
description: "Update frontmatter of a note without changing content",
|
|
198
|
-
inputSchema: {
|
|
199
|
-
type: "object",
|
|
200
|
-
properties: {
|
|
201
|
-
path: {
|
|
202
|
-
type: "string",
|
|
203
|
-
description: "Path to the note"
|
|
204
|
-
},
|
|
205
|
-
frontmatter: {
|
|
206
|
-
type: "object",
|
|
207
|
-
description: "Frontmatter object to update"
|
|
208
|
-
},
|
|
209
|
-
merge: {
|
|
210
|
-
type: "boolean",
|
|
211
|
-
description: "Merge with existing frontmatter (default: true)",
|
|
212
|
-
default: true
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
required: ["path", "frontmatter"]
|
|
216
|
-
}
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
name: "get_notes_info",
|
|
220
|
-
description: "Get metadata for notes without reading full content",
|
|
221
|
-
inputSchema: {
|
|
222
|
-
type: "object",
|
|
223
|
-
properties: {
|
|
224
|
-
paths: {
|
|
225
|
-
type: "array",
|
|
226
|
-
items: { type: "string" },
|
|
227
|
-
description: "Array of note paths to get info for"
|
|
228
|
-
}
|
|
229
|
-
},
|
|
230
|
-
required: ["paths"]
|
|
231
|
-
}
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
name: "get_frontmatter",
|
|
235
|
-
description: "Extract frontmatter from a note without reading the content",
|
|
236
|
-
inputSchema: {
|
|
237
|
-
type: "object",
|
|
238
|
-
properties: {
|
|
239
|
-
path: {
|
|
240
|
-
type: "string",
|
|
241
|
-
description: "Path to the note relative to vault root"
|
|
242
|
-
}
|
|
243
|
-
},
|
|
244
|
-
required: ["path"]
|
|
245
|
-
}
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
name: "manage_tags",
|
|
249
|
-
description: "Add, remove, or list tags in a note",
|
|
250
|
-
inputSchema: {
|
|
251
|
-
type: "object",
|
|
252
|
-
properties: {
|
|
253
|
-
path: {
|
|
254
|
-
type: "string",
|
|
255
|
-
description: "Path to the note relative to vault root"
|
|
256
|
-
},
|
|
257
|
-
operation: {
|
|
258
|
-
type: "string",
|
|
259
|
-
enum: ["add", "remove", "list"],
|
|
260
|
-
description: "Operation to perform: 'add', 'remove', or 'list'"
|
|
261
|
-
},
|
|
262
|
-
tags: {
|
|
263
|
-
type: "array",
|
|
264
|
-
items: { type: "string" },
|
|
265
|
-
description: "Array of tags (required for 'add' and 'remove' operations)"
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
required: ["path", "operation"]
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
]
|
|
272
|
-
};
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// Helper function to trim path arguments
|
|
276
|
-
function trimPaths(args: any): any {
|
|
277
|
-
const trimmed = { ...args };
|
|
278
|
-
|
|
279
|
-
// Trim single path properties
|
|
280
|
-
if (trimmed.path && typeof trimmed.path === 'string') {
|
|
281
|
-
trimmed.path = trimmed.path.trim();
|
|
282
|
-
}
|
|
283
|
-
if (trimmed.oldPath && typeof trimmed.oldPath === 'string') {
|
|
284
|
-
trimmed.oldPath = trimmed.oldPath.trim();
|
|
285
|
-
}
|
|
286
|
-
if (trimmed.newPath && typeof trimmed.newPath === 'string') {
|
|
287
|
-
trimmed.newPath = trimmed.newPath.trim();
|
|
288
|
-
}
|
|
289
|
-
if (trimmed.confirmPath && typeof trimmed.confirmPath === 'string') {
|
|
290
|
-
trimmed.confirmPath = trimmed.confirmPath.trim();
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Trim path arrays
|
|
294
|
-
if (trimmed.paths && Array.isArray(trimmed.paths)) {
|
|
295
|
-
trimmed.paths = trimmed.paths.map((p: any) =>
|
|
296
|
-
typeof p === 'string' ? p.trim() : p
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return trimmed;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
304
|
-
const { name, arguments: args } = request.params;
|
|
305
|
-
const trimmedArgs = trimPaths(args);
|
|
306
|
-
|
|
307
|
-
try {
|
|
308
|
-
switch (name) {
|
|
309
|
-
case "read_note": {
|
|
310
|
-
const note = await fileSystem.readNote(trimmedArgs.path);
|
|
311
|
-
return {
|
|
312
|
-
content: [
|
|
313
|
-
{
|
|
314
|
-
type: "text",
|
|
315
|
-
text: JSON.stringify({
|
|
316
|
-
path: trimmedArgs.path,
|
|
317
|
-
frontmatter: note.frontmatter,
|
|
318
|
-
content: note.content
|
|
319
|
-
}, null, 2)
|
|
320
|
-
}
|
|
321
|
-
]
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
case "write_note": {
|
|
326
|
-
await fileSystem.writeNote({
|
|
327
|
-
path: trimmedArgs.path,
|
|
328
|
-
content: trimmedArgs.content,
|
|
329
|
-
frontmatter: trimmedArgs.frontmatter,
|
|
330
|
-
mode: trimmedArgs.mode || 'overwrite'
|
|
331
|
-
});
|
|
332
|
-
return {
|
|
333
|
-
content: [
|
|
334
|
-
{
|
|
335
|
-
type: "text",
|
|
336
|
-
text: `Successfully wrote note: ${trimmedArgs.path} (mode: ${trimmedArgs.mode || 'overwrite'})`
|
|
337
|
-
}
|
|
338
|
-
]
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
case "list_directory": {
|
|
343
|
-
const listing = await fileSystem.listDirectory(trimmedArgs.path || '');
|
|
344
|
-
return {
|
|
345
|
-
content: [
|
|
346
|
-
{
|
|
347
|
-
type: "text",
|
|
348
|
-
text: JSON.stringify({
|
|
349
|
-
path: trimmedArgs.path || '/',
|
|
350
|
-
directories: listing.directories,
|
|
351
|
-
files: listing.files
|
|
352
|
-
}, null, 2)
|
|
353
|
-
}
|
|
354
|
-
]
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
case "delete_note": {
|
|
359
|
-
const result = await fileSystem.deleteNote({
|
|
360
|
-
path: trimmedArgs.path,
|
|
361
|
-
confirmPath: trimmedArgs.confirmPath
|
|
362
|
-
});
|
|
363
|
-
return {
|
|
364
|
-
content: [
|
|
365
|
-
{
|
|
366
|
-
type: "text",
|
|
367
|
-
text: JSON.stringify(result, null, 2)
|
|
368
|
-
}
|
|
369
|
-
],
|
|
370
|
-
isError: !result.success
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
case "search_notes": {
|
|
375
|
-
const results = await searchService.search({
|
|
376
|
-
query: trimmedArgs.query,
|
|
377
|
-
limit: trimmedArgs.limit,
|
|
378
|
-
searchContent: trimmedArgs.searchContent,
|
|
379
|
-
searchFrontmatter: trimmedArgs.searchFrontmatter,
|
|
380
|
-
caseSensitive: trimmedArgs.caseSensitive
|
|
381
|
-
});
|
|
382
|
-
return {
|
|
383
|
-
content: [
|
|
384
|
-
{
|
|
385
|
-
type: "text",
|
|
386
|
-
text: JSON.stringify({
|
|
387
|
-
query: trimmedArgs.query,
|
|
388
|
-
resultCount: results.length,
|
|
389
|
-
results: results
|
|
390
|
-
}, null, 2)
|
|
391
|
-
}
|
|
392
|
-
]
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
case "move_note": {
|
|
397
|
-
const result = await fileSystem.moveNote({
|
|
398
|
-
oldPath: trimmedArgs.oldPath,
|
|
399
|
-
newPath: trimmedArgs.newPath,
|
|
400
|
-
overwrite: trimmedArgs.overwrite
|
|
401
|
-
});
|
|
402
|
-
return {
|
|
403
|
-
content: [
|
|
404
|
-
{
|
|
405
|
-
type: "text",
|
|
406
|
-
text: JSON.stringify(result, null, 2)
|
|
407
|
-
}
|
|
408
|
-
],
|
|
409
|
-
isError: !result.success
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
case "read_multiple_notes": {
|
|
414
|
-
const result = await fileSystem.readMultipleNotes({
|
|
415
|
-
paths: trimmedArgs.paths,
|
|
416
|
-
includeContent: trimmedArgs.includeContent,
|
|
417
|
-
includeFrontmatter: trimmedArgs.includeFrontmatter
|
|
418
|
-
});
|
|
419
|
-
return {
|
|
420
|
-
content: [
|
|
421
|
-
{
|
|
422
|
-
type: "text",
|
|
423
|
-
text: JSON.stringify({
|
|
424
|
-
successful: result.successful,
|
|
425
|
-
failed: result.failed,
|
|
426
|
-
summary: {
|
|
427
|
-
successCount: result.successful.length,
|
|
428
|
-
failureCount: result.failed.length
|
|
429
|
-
}
|
|
430
|
-
}, null, 2)
|
|
431
|
-
}
|
|
432
|
-
]
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
case "update_frontmatter": {
|
|
437
|
-
await fileSystem.updateFrontmatter({
|
|
438
|
-
path: trimmedArgs.path,
|
|
439
|
-
frontmatter: trimmedArgs.frontmatter,
|
|
440
|
-
merge: trimmedArgs.merge
|
|
441
|
-
});
|
|
442
|
-
return {
|
|
443
|
-
content: [
|
|
444
|
-
{
|
|
445
|
-
type: "text",
|
|
446
|
-
text: `Successfully updated frontmatter for: ${trimmedArgs.path}`
|
|
447
|
-
}
|
|
448
|
-
]
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
case "get_notes_info": {
|
|
453
|
-
const result = await fileSystem.getNotesInfo(trimmedArgs.paths);
|
|
454
|
-
return {
|
|
455
|
-
content: [
|
|
456
|
-
{
|
|
457
|
-
type: "text",
|
|
458
|
-
text: JSON.stringify({
|
|
459
|
-
notes: result,
|
|
460
|
-
count: result.length
|
|
461
|
-
}, null, 2)
|
|
462
|
-
}
|
|
463
|
-
]
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
case "get_frontmatter": {
|
|
468
|
-
const note = await fileSystem.readNote(trimmedArgs.path);
|
|
469
|
-
return {
|
|
470
|
-
content: [
|
|
471
|
-
{
|
|
472
|
-
type: "text",
|
|
473
|
-
text: JSON.stringify({
|
|
474
|
-
path: trimmedArgs.path,
|
|
475
|
-
frontmatter: note.frontmatter
|
|
476
|
-
}, null, 2)
|
|
477
|
-
}
|
|
478
|
-
]
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
case "manage_tags": {
|
|
483
|
-
const result = await fileSystem.manageTags({
|
|
484
|
-
path: trimmedArgs.path,
|
|
485
|
-
operation: trimmedArgs.operation,
|
|
486
|
-
tags: trimmedArgs.tags
|
|
487
|
-
});
|
|
488
|
-
return {
|
|
489
|
-
content: [
|
|
490
|
-
{
|
|
491
|
-
type: "text",
|
|
492
|
-
text: JSON.stringify(result, null, 2)
|
|
493
|
-
}
|
|
494
|
-
],
|
|
495
|
-
isError: !result.success
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
default:
|
|
500
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
501
|
-
}
|
|
502
|
-
} catch (error) {
|
|
503
|
-
return {
|
|
504
|
-
content: [
|
|
505
|
-
{
|
|
506
|
-
type: "text",
|
|
507
|
-
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
508
|
-
}
|
|
509
|
-
],
|
|
510
|
-
isError: true
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
const transport = new StdioServerTransport();
|
|
516
|
-
await server.connect(transport);
|