obsidian-mcp-server 1.1.1 → 1.2.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 +45 -1
- package/build/properties.js +156 -0
- package/build/propertyTools.js +186 -0
- package/build/propertyTypes.js +43 -0
- package/build/server.js +4 -1
- package/build/tools.js +118 -13
- package/package.json +4 -2
- package/src/properties.ts +188 -0
- package/src/propertyTools.ts +207 -0
- package/src/propertyTypes.ts +70 -0
- package/src/server.ts +7 -1
- package/src/tools.ts +118 -13
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.typescriptlang.org/)
|
|
4
4
|
[](https://modelcontextprotocol.io/)
|
|
5
|
-
[]()
|
|
6
6
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
7
7
|
[]()
|
|
8
8
|
[](https://github.com/cyanheads/obsidian-mcp-server)
|
|
@@ -25,6 +25,12 @@ Requires the Local REST API plugin in Obsidian.
|
|
|
25
25
|
- Configurable context boundaries and token limits
|
|
26
26
|
- Optimized query processing
|
|
27
27
|
|
|
28
|
+
### Property Management
|
|
29
|
+
- YAML frontmatter parsing and validation
|
|
30
|
+
- Intelligent property merging and updates
|
|
31
|
+
- Automatic timestamp management
|
|
32
|
+
- Custom field support
|
|
33
|
+
|
|
28
34
|
### Security & Performance
|
|
29
35
|
- API key authentication and rate limiting
|
|
30
36
|
- SSL verification options
|
|
@@ -120,6 +126,38 @@ obsidian_patch_content: {
|
|
|
120
126
|
}
|
|
121
127
|
```
|
|
122
128
|
|
|
129
|
+
### Property Management
|
|
130
|
+
```typescript
|
|
131
|
+
// Get note properties
|
|
132
|
+
obsidian_get_properties: {
|
|
133
|
+
filepath: string // Path relative to vault root
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Update note properties
|
|
137
|
+
obsidian_update_properties: {
|
|
138
|
+
filepath: string, // Path relative to vault root
|
|
139
|
+
properties: {
|
|
140
|
+
title?: string,
|
|
141
|
+
created?: string, // ISO date
|
|
142
|
+
modified?: string, // ISO date (auto-updated)
|
|
143
|
+
author?: string,
|
|
144
|
+
type?: Array<"concept" | "architecture" | "specification" |
|
|
145
|
+
"protocol" | "api" | "research" | "implementation" |
|
|
146
|
+
"guide" | "reference">,
|
|
147
|
+
tags?: string[], // Must start with #
|
|
148
|
+
status?: Array<"draft" | "in-progress" | "review" | "complete">,
|
|
149
|
+
version?: string,
|
|
150
|
+
platform?: string,
|
|
151
|
+
repository?: string, // URL
|
|
152
|
+
dependencies?: string[],
|
|
153
|
+
sources?: string[],
|
|
154
|
+
urls?: string[], // URLs
|
|
155
|
+
papers?: string[],
|
|
156
|
+
custom?: Record<string, unknown>
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
123
161
|
## Best Practices
|
|
124
162
|
|
|
125
163
|
### File Operations
|
|
@@ -134,6 +172,12 @@ obsidian_patch_content: {
|
|
|
134
172
|
- Handle large result sets
|
|
135
173
|
- Consider token limits
|
|
136
174
|
|
|
175
|
+
### Property Management
|
|
176
|
+
- Validate property values before updates
|
|
177
|
+
- Use appropriate property types
|
|
178
|
+
- Handle array merging appropriately
|
|
179
|
+
- Consider custom field implications
|
|
180
|
+
|
|
137
181
|
### Error Prevention
|
|
138
182
|
- Validate inputs thoroughly
|
|
139
183
|
- Handle API errors gracefully
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { parse, stringify } from 'yaml';
|
|
2
|
+
import { ObsidianPropertiesSchema } from './propertyTypes.js';
|
|
3
|
+
export class PropertyManager {
|
|
4
|
+
client;
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Parse YAML frontmatter from note content
|
|
10
|
+
*/
|
|
11
|
+
parseProperties(content) {
|
|
12
|
+
try {
|
|
13
|
+
// Extract frontmatter between --- markers
|
|
14
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
15
|
+
if (!match) {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
const frontmatter = match[1];
|
|
19
|
+
const properties = parse(frontmatter);
|
|
20
|
+
// Validate against schema
|
|
21
|
+
const result = ObsidianPropertiesSchema.safeParse(properties);
|
|
22
|
+
if (!result.success) {
|
|
23
|
+
console.warn('Property validation warnings:', result.error);
|
|
24
|
+
// Return partial valid properties rather than throwing
|
|
25
|
+
return properties;
|
|
26
|
+
}
|
|
27
|
+
return result.data;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error('Error parsing properties:', error);
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generate YAML frontmatter from properties
|
|
36
|
+
*/
|
|
37
|
+
generateProperties(properties) {
|
|
38
|
+
try {
|
|
39
|
+
// Remove undefined values
|
|
40
|
+
const cleanProperties = Object.fromEntries(Object.entries(properties).filter(([_, v]) => v !== undefined));
|
|
41
|
+
// Generate YAML
|
|
42
|
+
const yaml = stringify(cleanProperties);
|
|
43
|
+
return `---\n${yaml}---\n`;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.error('Error generating properties:', error);
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Validate property values
|
|
52
|
+
*/
|
|
53
|
+
validateProperties(properties) {
|
|
54
|
+
const result = ObsidianPropertiesSchema.safeParse(properties);
|
|
55
|
+
if (result.success) {
|
|
56
|
+
return { valid: true, errors: [] };
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
valid: false,
|
|
60
|
+
errors: result.error.errors.map(err => `${err.path.join('.')}: ${err.message}`)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Merge new properties with existing ones
|
|
65
|
+
*/
|
|
66
|
+
mergeProperties(existing, updates) {
|
|
67
|
+
const merged = { ...existing };
|
|
68
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
69
|
+
if (value === undefined)
|
|
70
|
+
continue;
|
|
71
|
+
const currentValue = merged[key];
|
|
72
|
+
// Special handling for arrays - merge rather than replace
|
|
73
|
+
if (Array.isArray(value) && Array.isArray(currentValue)) {
|
|
74
|
+
merged[key] = [
|
|
75
|
+
...new Set([...currentValue, ...value])
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
// Special handling for custom object - deep merge
|
|
79
|
+
else if (key === 'custom' && typeof value === 'object' && value !== null) {
|
|
80
|
+
merged.custom = {
|
|
81
|
+
...merged.custom,
|
|
82
|
+
...value
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// Default case - replace value
|
|
86
|
+
else {
|
|
87
|
+
merged[key] = value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Always update modified date
|
|
91
|
+
merged.modified = new Date().toISOString();
|
|
92
|
+
return merged;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get properties from a note
|
|
96
|
+
*/
|
|
97
|
+
async getProperties(filepath) {
|
|
98
|
+
try {
|
|
99
|
+
const content = await this.client.getFileContents(filepath);
|
|
100
|
+
const properties = this.parseProperties(content);
|
|
101
|
+
return {
|
|
102
|
+
success: true,
|
|
103
|
+
message: 'Properties retrieved successfully',
|
|
104
|
+
properties
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
message: `Failed to get properties: ${error instanceof Error ? error.message : String(error)}`,
|
|
111
|
+
errors: [String(error)]
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Update properties of a note
|
|
117
|
+
*/
|
|
118
|
+
async updateProperties(filepath, newProperties) {
|
|
119
|
+
try {
|
|
120
|
+
// Validate new properties
|
|
121
|
+
const validation = this.validateProperties(newProperties);
|
|
122
|
+
if (!validation.valid) {
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
message: 'Invalid properties',
|
|
126
|
+
errors: validation.errors
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// Get existing content and properties
|
|
130
|
+
const content = await this.client.getFileContents(filepath);
|
|
131
|
+
const existingProperties = this.parseProperties(content);
|
|
132
|
+
// Merge properties
|
|
133
|
+
const mergedProperties = this.mergeProperties(existingProperties, newProperties);
|
|
134
|
+
// Generate new frontmatter
|
|
135
|
+
const newFrontmatter = this.generateProperties(mergedProperties);
|
|
136
|
+
// Replace existing frontmatter or prepend to file
|
|
137
|
+
const newContent = content.replace(/^---[\s\S]*?---\n/, '') || '';
|
|
138
|
+
const updatedContent = newFrontmatter + newContent;
|
|
139
|
+
// Update file
|
|
140
|
+
await this.client.updateContent(filepath, updatedContent);
|
|
141
|
+
return {
|
|
142
|
+
success: true,
|
|
143
|
+
message: 'Properties updated successfully',
|
|
144
|
+
properties: mergedProperties
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
return {
|
|
149
|
+
success: false,
|
|
150
|
+
message: `Failed to update properties: ${error instanceof Error ? error.message : String(error)}`,
|
|
151
|
+
errors: [String(error)]
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=properties.js.map
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { BaseToolHandler } from "./tools.js";
|
|
2
|
+
import { PropertyManager } from "./properties.js";
|
|
3
|
+
const TOOL_NAMES = {
|
|
4
|
+
GET_PROPERTIES: "obsidian_get_properties",
|
|
5
|
+
UPDATE_PROPERTIES: "obsidian_update_properties"
|
|
6
|
+
};
|
|
7
|
+
export class GetPropertiesToolHandler extends BaseToolHandler {
|
|
8
|
+
propertyManager;
|
|
9
|
+
constructor(client) {
|
|
10
|
+
super(TOOL_NAMES.GET_PROPERTIES, client);
|
|
11
|
+
this.propertyManager = new PropertyManager(client);
|
|
12
|
+
}
|
|
13
|
+
getToolDescription() {
|
|
14
|
+
return {
|
|
15
|
+
name: this.name,
|
|
16
|
+
description: "Get properties (title, tags, status, etc.) from an Obsidian note's YAML frontmatter. Returns all available properties including custom fields.",
|
|
17
|
+
examples: [
|
|
18
|
+
{
|
|
19
|
+
description: "Get properties from a note",
|
|
20
|
+
args: {
|
|
21
|
+
filepath: "path/to/note.md"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
description: "Get properties from a documentation file",
|
|
26
|
+
args: {
|
|
27
|
+
filepath: "docs/architecture.md"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: {
|
|
34
|
+
filepath: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Path to the note file (relative to vault root)",
|
|
37
|
+
format: "path"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
required: ["filepath"]
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async runTool(args) {
|
|
45
|
+
try {
|
|
46
|
+
const result = await this.propertyManager.getProperties(args.filepath);
|
|
47
|
+
return this.createResponse(result);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
return this.handleError(error);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export class UpdatePropertiesToolHandler extends BaseToolHandler {
|
|
55
|
+
propertyManager;
|
|
56
|
+
constructor(client) {
|
|
57
|
+
super(TOOL_NAMES.UPDATE_PROPERTIES, client);
|
|
58
|
+
this.propertyManager = new PropertyManager(client);
|
|
59
|
+
}
|
|
60
|
+
getToolDescription() {
|
|
61
|
+
return {
|
|
62
|
+
name: this.name,
|
|
63
|
+
description: "Update properties in an Obsidian note's YAML frontmatter. Intelligently merges arrays (tags, type, status), handles custom fields, and automatically updates the modified timestamp. Existing properties not included in the update are preserved.",
|
|
64
|
+
examples: [
|
|
65
|
+
{
|
|
66
|
+
description: "Update basic metadata",
|
|
67
|
+
args: {
|
|
68
|
+
filepath: "path/to/note.md",
|
|
69
|
+
properties: {
|
|
70
|
+
title: "Architecture Overview",
|
|
71
|
+
author: "Development Team",
|
|
72
|
+
type: ["architecture", "specification"]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
description: "Update tags and status",
|
|
78
|
+
args: {
|
|
79
|
+
filepath: "docs/feature.md",
|
|
80
|
+
properties: {
|
|
81
|
+
tags: ["#feature", "#in-development", "#high-priority"],
|
|
82
|
+
status: ["in-progress"],
|
|
83
|
+
version: "2.0.0"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
description: "Add custom fields",
|
|
89
|
+
args: {
|
|
90
|
+
filepath: "projects/project-x.md",
|
|
91
|
+
properties: {
|
|
92
|
+
custom: {
|
|
93
|
+
priority: "high",
|
|
94
|
+
reviewedBy: ["Alice", "Bob"],
|
|
95
|
+
dueDate: "2025-03-01"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: "object",
|
|
103
|
+
properties: {
|
|
104
|
+
filepath: {
|
|
105
|
+
type: "string",
|
|
106
|
+
description: "Path to the note file (relative to vault root)",
|
|
107
|
+
format: "path"
|
|
108
|
+
},
|
|
109
|
+
properties: {
|
|
110
|
+
type: "object",
|
|
111
|
+
description: "Properties to update",
|
|
112
|
+
properties: {
|
|
113
|
+
title: { type: "string" },
|
|
114
|
+
created: { type: "string", format: "date-time" },
|
|
115
|
+
modified: { type: "string", format: "date-time" },
|
|
116
|
+
author: { type: "string" },
|
|
117
|
+
type: {
|
|
118
|
+
type: "array",
|
|
119
|
+
items: {
|
|
120
|
+
type: "string",
|
|
121
|
+
enum: [
|
|
122
|
+
"concept",
|
|
123
|
+
"architecture",
|
|
124
|
+
"specification",
|
|
125
|
+
"protocol",
|
|
126
|
+
"api",
|
|
127
|
+
"research",
|
|
128
|
+
"implementation",
|
|
129
|
+
"guide",
|
|
130
|
+
"reference"
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
tags: {
|
|
135
|
+
type: "array",
|
|
136
|
+
items: { type: "string", pattern: "^#" }
|
|
137
|
+
},
|
|
138
|
+
status: {
|
|
139
|
+
type: "array",
|
|
140
|
+
items: {
|
|
141
|
+
type: "string",
|
|
142
|
+
enum: ["draft", "in-progress", "review", "complete"]
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
version: { type: "string" },
|
|
146
|
+
platform: { type: "string" },
|
|
147
|
+
repository: { type: "string", format: "uri" },
|
|
148
|
+
dependencies: {
|
|
149
|
+
type: "array",
|
|
150
|
+
items: { type: "string" }
|
|
151
|
+
},
|
|
152
|
+
sources: {
|
|
153
|
+
type: "array",
|
|
154
|
+
items: { type: "string" }
|
|
155
|
+
},
|
|
156
|
+
urls: {
|
|
157
|
+
type: "array",
|
|
158
|
+
items: { type: "string", format: "uri" }
|
|
159
|
+
},
|
|
160
|
+
papers: {
|
|
161
|
+
type: "array",
|
|
162
|
+
items: { type: "string" }
|
|
163
|
+
},
|
|
164
|
+
custom: {
|
|
165
|
+
type: "object",
|
|
166
|
+
additionalProperties: true
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
additionalProperties: false
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
required: ["filepath", "properties"]
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
async runTool(args) {
|
|
177
|
+
try {
|
|
178
|
+
const result = await this.propertyManager.updateProperties(args.filepath, args.properties);
|
|
179
|
+
return this.createResponse(result);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
return this.handleError(error);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=propertyTools.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Define validation schemas
|
|
3
|
+
export const PropertyTypeEnum = z.enum([
|
|
4
|
+
"concept",
|
|
5
|
+
"architecture",
|
|
6
|
+
"specification",
|
|
7
|
+
"protocol",
|
|
8
|
+
"api",
|
|
9
|
+
"research",
|
|
10
|
+
"implementation",
|
|
11
|
+
"guide",
|
|
12
|
+
"reference"
|
|
13
|
+
]);
|
|
14
|
+
export const StatusEnum = z.enum([
|
|
15
|
+
"draft",
|
|
16
|
+
"in-progress",
|
|
17
|
+
"review",
|
|
18
|
+
"complete"
|
|
19
|
+
]);
|
|
20
|
+
export const ObsidianPropertiesSchema = z.object({
|
|
21
|
+
// Basic Metadata
|
|
22
|
+
title: z.string().optional(),
|
|
23
|
+
created: z.string().datetime().optional(),
|
|
24
|
+
modified: z.string().datetime().optional(),
|
|
25
|
+
author: z.string().optional(),
|
|
26
|
+
// Classification
|
|
27
|
+
type: z.array(PropertyTypeEnum).optional(),
|
|
28
|
+
// Organization
|
|
29
|
+
tags: z.array(z.string().startsWith("#")).optional(),
|
|
30
|
+
// Technical Metadata
|
|
31
|
+
status: z.array(StatusEnum).optional(),
|
|
32
|
+
version: z.string().optional(),
|
|
33
|
+
platform: z.string().optional(),
|
|
34
|
+
repository: z.string().url().optional(),
|
|
35
|
+
dependencies: z.array(z.string()).optional(),
|
|
36
|
+
// References
|
|
37
|
+
sources: z.array(z.string()).optional(),
|
|
38
|
+
urls: z.array(z.string().url()).optional(),
|
|
39
|
+
papers: z.array(z.string()).optional(),
|
|
40
|
+
// Custom Fields
|
|
41
|
+
custom: z.record(z.unknown()).optional()
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=propertyTypes.js.map
|
package/build/server.js
CHANGED
|
@@ -5,6 +5,7 @@ import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprot
|
|
|
5
5
|
import { ObsidianClient } from "./obsidian.js";
|
|
6
6
|
import { ObsidianError, DEFAULT_RATE_LIMIT_CONFIG } from "./types.js";
|
|
7
7
|
import { ListFilesInVaultToolHandler, ListFilesInDirToolHandler, GetFileContentsToolHandler, FindInFileToolHandler, AppendContentToolHandler, PatchContentToolHandler, ComplexSearchToolHandler } from "./tools.js";
|
|
8
|
+
import { GetPropertiesToolHandler, UpdatePropertiesToolHandler } from "./propertyTools.js";
|
|
8
9
|
// Load environment variables
|
|
9
10
|
config();
|
|
10
11
|
const API_KEY = process.env.OBSIDIAN_API_KEY;
|
|
@@ -57,7 +58,9 @@ const handlers = [
|
|
|
57
58
|
new FindInFileToolHandler(client),
|
|
58
59
|
new AppendContentToolHandler(client),
|
|
59
60
|
new PatchContentToolHandler(client),
|
|
60
|
-
new ComplexSearchToolHandler(client)
|
|
61
|
+
new ComplexSearchToolHandler(client),
|
|
62
|
+
new GetPropertiesToolHandler(client),
|
|
63
|
+
new UpdatePropertiesToolHandler(client)
|
|
61
64
|
];
|
|
62
65
|
handlers.forEach(handler => toolHandlers.set(handler.name, handler));
|
|
63
66
|
// Create MCP server
|
package/build/tools.js
CHANGED
|
@@ -101,11 +101,31 @@ export class ListFilesInVaultToolHandler extends BaseToolHandler {
|
|
|
101
101
|
getToolDescription() {
|
|
102
102
|
return {
|
|
103
103
|
name: this.name,
|
|
104
|
-
description: "Lists all files and directories in the root directory of your Obsidian vault.",
|
|
104
|
+
description: "Lists all files and directories in the root directory of your Obsidian vault. Returns a hierarchical structure of files and folders, including metadata like file type.",
|
|
105
105
|
examples: [
|
|
106
106
|
{
|
|
107
107
|
description: "List all files in vault",
|
|
108
108
|
args: {}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
description: "Example response",
|
|
112
|
+
args: {},
|
|
113
|
+
response: [
|
|
114
|
+
{
|
|
115
|
+
"path": "Daily Notes",
|
|
116
|
+
"type": "folder",
|
|
117
|
+
"children": [
|
|
118
|
+
{ "path": "Daily Notes/2025-01-24.md", "type": "file" }
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"path": "Projects",
|
|
123
|
+
"type": "folder",
|
|
124
|
+
"children": [
|
|
125
|
+
{ "path": "Projects/MCP.md", "type": "file" }
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
]
|
|
109
129
|
}
|
|
110
130
|
],
|
|
111
131
|
inputSchema: {
|
|
@@ -132,13 +152,36 @@ export class ListFilesInDirToolHandler extends BaseToolHandler {
|
|
|
132
152
|
getToolDescription() {
|
|
133
153
|
return {
|
|
134
154
|
name: this.name,
|
|
135
|
-
description: "Lists all files and directories that exist in a specific Obsidian directory.",
|
|
155
|
+
description: "Lists all files and directories that exist in a specific Obsidian directory. Returns a hierarchical structure showing files, folders, and their relationships. Useful for exploring vault organization and finding specific files.",
|
|
136
156
|
examples: [
|
|
137
157
|
{
|
|
138
158
|
description: "List files in Documents folder",
|
|
139
159
|
args: {
|
|
140
160
|
dirpath: "Documents"
|
|
141
161
|
}
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
description: "Example response structure",
|
|
165
|
+
args: {
|
|
166
|
+
dirpath: "Projects"
|
|
167
|
+
},
|
|
168
|
+
response: [
|
|
169
|
+
{
|
|
170
|
+
"path": "Projects/Active",
|
|
171
|
+
"type": "folder",
|
|
172
|
+
"children": [
|
|
173
|
+
{ "path": "Projects/Active/ProjectA.md", "type": "file" },
|
|
174
|
+
{ "path": "Projects/Active/ProjectB.md", "type": "file" }
|
|
175
|
+
]
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"path": "Projects/Archive",
|
|
179
|
+
"type": "folder",
|
|
180
|
+
"children": [
|
|
181
|
+
{ "path": "Projects/Archive/OldProject.md", "type": "file" }
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
]
|
|
142
185
|
}
|
|
143
186
|
],
|
|
144
187
|
inputSchema: {
|
|
@@ -171,7 +214,21 @@ export class GetFileContentsToolHandler extends BaseToolHandler {
|
|
|
171
214
|
getToolDescription() {
|
|
172
215
|
return {
|
|
173
216
|
name: this.name,
|
|
174
|
-
description: "Return the content of a single file in your vault.",
|
|
217
|
+
description: "Return the content of a single file in your vault. Supports markdown files, text files, and other readable formats. Returns the raw content including any YAML frontmatter.",
|
|
218
|
+
examples: [
|
|
219
|
+
{
|
|
220
|
+
description: "Get content of a markdown note",
|
|
221
|
+
args: {
|
|
222
|
+
filepath: "Projects/research.md"
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
description: "Get content of a configuration file",
|
|
227
|
+
args: {
|
|
228
|
+
filepath: "configs/settings.yml"
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
],
|
|
175
232
|
inputSchema: {
|
|
176
233
|
type: "object",
|
|
177
234
|
properties: {
|
|
@@ -202,17 +259,43 @@ export class FindInFileToolHandler extends BaseToolHandler {
|
|
|
202
259
|
getToolDescription() {
|
|
203
260
|
return {
|
|
204
261
|
name: this.name,
|
|
205
|
-
description: "
|
|
262
|
+
description: "Full-text search across all files in the vault. Returns matching files with surrounding context for each match. Useful for finding specific content, references, or patterns across notes.",
|
|
263
|
+
examples: [
|
|
264
|
+
{
|
|
265
|
+
description: "Search for a specific term",
|
|
266
|
+
args: {
|
|
267
|
+
query: "neural networks",
|
|
268
|
+
contextLength: 20
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
description: "Search with default context",
|
|
273
|
+
args: {
|
|
274
|
+
query: "#todo"
|
|
275
|
+
},
|
|
276
|
+
response: [
|
|
277
|
+
{
|
|
278
|
+
"filename": "Projects/AI.md",
|
|
279
|
+
"matches": [
|
|
280
|
+
{
|
|
281
|
+
"context": "Research needed:\n#todo Implement transformer architecture\nDeadline: Next week",
|
|
282
|
+
"match": { "start": 15, "end": 45 }
|
|
283
|
+
}
|
|
284
|
+
]
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
}
|
|
288
|
+
],
|
|
206
289
|
inputSchema: {
|
|
207
290
|
type: "object",
|
|
208
291
|
properties: {
|
|
209
292
|
query: {
|
|
210
293
|
type: "string",
|
|
211
|
-
description: "Text to search for
|
|
294
|
+
description: "Text pattern to search for. Can include tags, keywords, or phrases."
|
|
212
295
|
},
|
|
213
296
|
contextLength: {
|
|
214
297
|
type: "integer",
|
|
215
|
-
description: "
|
|
298
|
+
description: "Number of characters to include before and after each match for context (default: 10)",
|
|
216
299
|
default: 10
|
|
217
300
|
}
|
|
218
301
|
},
|
|
@@ -334,23 +417,45 @@ export class ComplexSearchToolHandler extends BaseToolHandler {
|
|
|
334
417
|
getToolDescription() {
|
|
335
418
|
return {
|
|
336
419
|
name: this.name,
|
|
337
|
-
description: "
|
|
420
|
+
description: "Advanced search functionality using JsonLogic queries. Enables complex file filtering based on paths, metadata, modification times, and content patterns. Supports logical operations, date comparisons, and pattern matching.",
|
|
338
421
|
examples: [
|
|
339
422
|
{
|
|
340
|
-
description: "Find
|
|
423
|
+
description: "Find markdown files in a specific folder",
|
|
424
|
+
args: {
|
|
425
|
+
query: {
|
|
426
|
+
"and": [
|
|
427
|
+
{ "glob": ["Projects/*.md", { "var": "path" }] },
|
|
428
|
+
{ "contains": [{ "var": "content" }, "#active"] }
|
|
429
|
+
]
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
description: "Find recently modified documentation",
|
|
341
435
|
args: {
|
|
342
436
|
query: {
|
|
343
|
-
"
|
|
437
|
+
"and": [
|
|
438
|
+
{ "glob": ["docs/*.md", { "var": "path" }] },
|
|
439
|
+
{ ">=": [
|
|
440
|
+
{ "var": "mtime" },
|
|
441
|
+
{ "date": "-7 days" }
|
|
442
|
+
] },
|
|
443
|
+
{ "!=": [{ "var": "size" }, 0] }
|
|
444
|
+
]
|
|
344
445
|
}
|
|
345
446
|
}
|
|
346
447
|
},
|
|
347
448
|
{
|
|
348
|
-
description: "Find files
|
|
449
|
+
description: "Find files by multiple criteria",
|
|
349
450
|
args: {
|
|
350
451
|
query: {
|
|
351
|
-
"
|
|
352
|
-
{ "
|
|
353
|
-
|
|
452
|
+
"and": [
|
|
453
|
+
{ "or": [
|
|
454
|
+
{ "glob": ["*.md", { "var": "path" }] },
|
|
455
|
+
{ "glob": ["*.txt", { "var": "path" }] }
|
|
456
|
+
] },
|
|
457
|
+
{ "contains": [{ "var": "content" }, "TODO"] },
|
|
458
|
+
{ "<": [{ "var": "size" }, 10000] }
|
|
354
459
|
]
|
|
355
460
|
}
|
|
356
461
|
}
|