obsidian-mcp-server 1.5.4 → 1.5.6
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/Dockerfile +3 -2
- package/README.md +2 -2
- package/build/index.js +1 -1
- package/build/mcp/handlers.js +3 -6
- package/build/mcp/index.js +1 -1
- package/build/mcp/server.js +5 -5
- package/build/obsidian/client.js +5 -8
- package/build/obsidian/index.js +1 -1
- package/build/resources/index.js +1 -1
- package/build/resources/tags.js +36 -8
- package/build/tools/base.js +2 -2
- package/build/tools/files/content.js +10 -10
- package/build/tools/files/index.js +4 -4
- package/build/tools/files/list.js +3 -3
- package/build/tools/index.js +2 -2
- package/build/tools/properties/index.js +1 -1
- package/build/tools/properties/manager.js +160 -59
- package/build/tools/properties/tools.js +8 -7
- package/build/tools/properties/types.js +1 -0
- package/build/tools/search/complex.js +35 -19
- package/build/tools/search/index.js +2 -2
- package/build/tools/search/simple.js +6 -6
- package/docs/tree.md +5 -1
- package/package.json +3 -3
- package/src/index.ts +2 -1
- package/src/mcp/handlers.ts +12 -15
- package/src/mcp/index.ts +3 -2
- package/src/mcp/server.ts +13 -13
- package/src/mcp/types.ts +0 -2
- package/src/obsidian/client.ts +17 -17
- package/src/obsidian/errors.ts +1 -1
- package/src/obsidian/index.ts +2 -1
- package/src/resources/index.ts +1 -1
- package/src/resources/tags.ts +42 -11
- package/src/tools/base.ts +3 -3
- package/src/tools/files/content.ts +13 -13
- package/src/tools/files/index.ts +11 -11
- package/src/tools/files/list.ts +4 -4
- package/src/tools/index.ts +3 -3
- package/src/tools/properties/index.ts +1 -1
- package/src/tools/properties/manager.ts +188 -60
- package/src/tools/properties/tools.ts +10 -9
- package/src/tools/properties/types.ts +1 -0
- package/src/tools/search/complex.ts +54 -38
- package/src/tools/search/index.ts +2 -2
- package/src/tools/search/simple.ts +7 -7
- package/src/utils/index.ts +1 -1
package/Dockerfile
CHANGED
|
@@ -24,7 +24,8 @@ RUN npm prune --production
|
|
|
24
24
|
FROM node:22-slim
|
|
25
25
|
|
|
26
26
|
ENV NODE_ENV=production \
|
|
27
|
-
PATH="/home/service-user/.local/bin:${PATH}"
|
|
27
|
+
PATH="/home/service-user/.local/bin:${PATH}" \
|
|
28
|
+
OBSIDIAN_API_KEY="abc"
|
|
28
29
|
|
|
29
30
|
# Install mcp-proxy globally for runtime use
|
|
30
31
|
# Combine update, install, and clean in one layer
|
|
@@ -59,4 +60,4 @@ USER service-user
|
|
|
59
60
|
|
|
60
61
|
# Define the command to run the application
|
|
61
62
|
# CMD ["mcp-proxy", "node", "build/index.js"] # Keep original for reference
|
|
62
|
-
CMD ["
|
|
63
|
+
CMD ["node", "build/index.js"]
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Obsidian MCP Server
|
|
2
2
|
|
|
3
3
|
[](https://www.typescriptlang.org/)
|
|
4
|
-
[](https://modelcontextprotocol.io/)
|
|
5
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
6
6
|
[]()
|
|
7
7
|
[](https://github.com/cyanheads/obsidian-mcp-server)
|
|
8
8
|
|
package/build/index.js
CHANGED
|
@@ -14,7 +14,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
14
14
|
// Export the run function and other important modules
|
|
15
15
|
export { run } from "./mcp/server.js";
|
|
16
16
|
export * from "./obsidian/index.js";
|
|
17
|
-
export * from "./tools/index.js";
|
|
18
17
|
export * from "./resources/index.js";
|
|
18
|
+
export * from "./tools/index.js";
|
|
19
19
|
export * from "./utils/index.js";
|
|
20
20
|
//# sourceMappingURL=index.js.map
|
package/build/mcp/handlers.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
* MCP server request handlers
|
|
3
|
-
*/
|
|
4
|
-
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
1
|
+
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
2
|
import { ObsidianError } from "../utils/errors.js";
|
|
6
|
-
import { validateToolArguments } from "../utils/validation.js";
|
|
7
|
-
import { rateLimiter } from "../utils/rate-limiting.js";
|
|
8
3
|
import { createLogger, ErrorCategoryType } from "../utils/logging.js";
|
|
4
|
+
import { rateLimiter } from "../utils/rate-limiting.js";
|
|
5
|
+
import { validateToolArguments } from "../utils/validation.js";
|
|
9
6
|
import { DEFAULT_TIMEOUT_CONFIG, McpErrorCode } from "./types.js";
|
|
10
7
|
// Create a logger for request handlers
|
|
11
8
|
const logger = createLogger('McpHandlers');
|
package/build/mcp/index.js
CHANGED
package/build/mcp/server.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP server implementation
|
|
3
3
|
*/
|
|
4
|
-
import { config } from "dotenv";
|
|
5
4
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { config } from "dotenv";
|
|
7
|
+
import { ObsidianClient } from "../obsidian/client.js";
|
|
8
|
+
import { createTagResource } from "../resources/index.js";
|
|
9
|
+
import { createToolHandlerMap, createToolHandlers } from "../tools/index.js";
|
|
7
10
|
import { ObsidianError } from "../utils/errors.js"; // Import ObsidianError
|
|
8
11
|
import { createLogger, ErrorCategoryType } from "../utils/logging.js";
|
|
9
12
|
import { rateLimiter } from "../utils/rate-limiting.js";
|
|
10
|
-
import {
|
|
11
|
-
import { createToolHandlers, createToolHandlerMap } from "../tools/index.js";
|
|
12
|
-
import { ObsidianClient } from "../obsidian/client.js";
|
|
13
|
-
import { setupToolListingHandler, setupToolCallingHandler, setupResourceListingHandler, setupResourceReadingHandler } from "./handlers.js";
|
|
13
|
+
import { setupResourceListingHandler, setupResourceReadingHandler, setupToolCallingHandler, setupToolListingHandler } from "./handlers.js";
|
|
14
14
|
import { McpErrorCode } from "./types.js";
|
|
15
15
|
// Create a logger for the server
|
|
16
16
|
const logger = createLogger('McpServer');
|
package/build/obsidian/client.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Obsidian REST API client implementation
|
|
3
|
-
*/
|
|
4
1
|
import axios from "axios";
|
|
5
|
-
import { Agent } from "node:https";
|
|
6
2
|
import { readFileSync } from "fs";
|
|
7
|
-
import {
|
|
3
|
+
import { Agent } from "node:https";
|
|
8
4
|
import { dirname, join } from "path";
|
|
9
|
-
import {
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
10
6
|
import { ObsidianError } from '../utils/errors.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
7
|
+
import { createLogger } from '../utils/logging.js';
|
|
8
|
+
import { sanitizeHeader, validateFilePath } from '../utils/validation.js';
|
|
13
9
|
import { createMissingAPIKeyMessage, handleAxiosError } from './errors.js';
|
|
10
|
+
import { DEFAULT_OBSIDIAN_CONFIG } from './types.js';
|
|
14
11
|
// Logger for the ObsidianClient
|
|
15
12
|
const logger = createLogger('ObsidianClient');
|
|
16
13
|
// Get package version for user agent
|
package/build/obsidian/index.js
CHANGED
package/build/resources/index.js
CHANGED
package/build/resources/tags.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pLimit from 'p-limit'; // Import p-limit
|
|
2
|
-
import { PropertyManager } from "../tools/properties/manager.js";
|
|
3
2
|
import { sep } from "path";
|
|
3
|
+
import { PropertyManager } from "../tools/properties/manager.js";
|
|
4
4
|
import { createLogger, ErrorCategoryType } from "../utils/logging.js";
|
|
5
5
|
// Create a logger for tag resources
|
|
6
6
|
const logger = createLogger('TagResource');
|
|
@@ -77,8 +77,13 @@ export class TagResource {
|
|
|
77
77
|
// This call is now rate-limited
|
|
78
78
|
const content = await this.client.getFileContents(filename);
|
|
79
79
|
// Only extract tags from frontmatter YAML
|
|
80
|
-
const
|
|
81
|
-
|
|
80
|
+
const parseResult = this.propertyManager.parseProperties(content);
|
|
81
|
+
// Handle potential parsing errors before accessing properties
|
|
82
|
+
if (parseResult.error) {
|
|
83
|
+
logger.warn(`Skipping tags for ${filename} due to parsing error: ${parseResult.error.message}`);
|
|
84
|
+
return { filename, tags: [] }; // Return empty tags on error
|
|
85
|
+
}
|
|
86
|
+
return { filename, tags: parseResult.properties.tags || [] };
|
|
82
87
|
}
|
|
83
88
|
catch (error) {
|
|
84
89
|
logger.error(`Failed to process file ${filename}:`, errorToObject(error));
|
|
@@ -175,9 +180,11 @@ export class TagResource {
|
|
|
175
180
|
}
|
|
176
181
|
}
|
|
177
182
|
/**
|
|
178
|
-
* Get the content for the resource
|
|
183
|
+
* Get the content for the resource, optionally filtering by path.
|
|
184
|
+
* Note: The path filtering logic assumes the tool handler passes the path correctly.
|
|
179
185
|
*/
|
|
180
|
-
|
|
186
|
+
// TODO: Verify how the path argument is passed from the tool handler
|
|
187
|
+
async getContent(filterPath) {
|
|
181
188
|
logger.startTimer('get_tags_content');
|
|
182
189
|
try {
|
|
183
190
|
if (!this.isInitialized) {
|
|
@@ -187,15 +194,36 @@ export class TagResource {
|
|
|
187
194
|
else {
|
|
188
195
|
await this.updateCacheIfNeeded();
|
|
189
196
|
}
|
|
197
|
+
let filteredTagEntries = [];
|
|
198
|
+
// Filter tags based on the provided path
|
|
199
|
+
if (filterPath) {
|
|
200
|
+
// Normalize path to ensure it ends with a separator for accurate startsWith check
|
|
201
|
+
const normalizedFilterPath = filterPath.endsWith(sep) ? filterPath : filterPath + sep;
|
|
202
|
+
logger.debug(`Filtering tags for path: ${normalizedFilterPath}`);
|
|
203
|
+
filteredTagEntries = Array.from(this.tagCache.entries())
|
|
204
|
+
.map(([name, files]) => {
|
|
205
|
+
// Filter files within each tag entry
|
|
206
|
+
const relevantFiles = Array.from(files).filter(file => file.startsWith(normalizedFilterPath));
|
|
207
|
+
return { name, files: new Set(relevantFiles) };
|
|
208
|
+
})
|
|
209
|
+
.filter(tagEntry => tagEntry.files.size > 0); // Keep only tags that exist in the filtered path
|
|
210
|
+
logger.debug(`Found ${filteredTagEntries.length} tags after filtering.`);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
// If no path provided, use all tags from the cache
|
|
214
|
+
filteredTagEntries = Array.from(this.tagCache.entries()).map(([name, files]) => ({ name, files }));
|
|
215
|
+
}
|
|
190
216
|
const response = {
|
|
191
|
-
tags:
|
|
192
|
-
.map((
|
|
217
|
+
tags: filteredTagEntries
|
|
218
|
+
.map(({ name, files }) => ({
|
|
193
219
|
name,
|
|
194
220
|
count: files.size,
|
|
195
221
|
files: Array.from(files).sort()
|
|
196
222
|
}))
|
|
197
|
-
.sort((a, b) => b.count - a.count || a.name.localeCompare(b.name)),
|
|
223
|
+
.sort((a, b) => b.count - a.count || a.name.localeCompare(b.name)), // Sort filtered results
|
|
198
224
|
metadata: {
|
|
225
|
+
// Note: Metadata currently reflects the entire vault cache, even when filtered.
|
|
226
|
+
// Adjust calculation here if path-specific metadata is desired.
|
|
199
227
|
totalOccurrences: Array.from(this.tagCache.values())
|
|
200
228
|
.reduce((sum, files) => sum + files.size, 0),
|
|
201
229
|
uniqueTags: this.tagCache.size,
|
package/build/tools/base.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { McpErrorCode } from "../mcp/types.js";
|
|
1
2
|
import { ObsidianError } from "../utils/errors.js";
|
|
2
|
-
import { tokenCounter } from "../utils/tokenization.js";
|
|
3
3
|
import { createLogger, ErrorCategoryType } from "../utils/logging.js";
|
|
4
|
-
import {
|
|
4
|
+
import { tokenCounter } from "../utils/tokenization.js";
|
|
5
5
|
// Create a logger for tool operations
|
|
6
6
|
const logger = createLogger('Tools');
|
|
7
7
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseToolHandler } from "../base.js";
|
|
2
1
|
import { createLogger } from "../../utils/logging.js";
|
|
2
|
+
import { BaseToolHandler } from "../base.js";
|
|
3
3
|
// Create a logger for file content operations
|
|
4
4
|
const logger = createLogger('FileContentTools');
|
|
5
5
|
/**
|
|
@@ -8,7 +8,7 @@ const logger = createLogger('FileContentTools');
|
|
|
8
8
|
export const FILE_CONTENT_TOOL_NAMES = {
|
|
9
9
|
GET_FILE_CONTENTS: "obsidian_get_file_contents",
|
|
10
10
|
APPEND_CONTENT: "obsidian_append_content",
|
|
11
|
-
|
|
11
|
+
UPDATE_CONTENT: "obsidian_update_content" // Renamed from PATCH_CONTENT
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
14
14
|
* Tool handler for getting file contents
|
|
@@ -20,7 +20,7 @@ export class GetFileContentsToolHandler extends BaseToolHandler {
|
|
|
20
20
|
getToolDescription() {
|
|
21
21
|
return {
|
|
22
22
|
name: this.name,
|
|
23
|
-
description: "
|
|
23
|
+
description: "Retrieves the full content of a specified file within your Obsidian vault. Supports various readable file formats.",
|
|
24
24
|
examples: [
|
|
25
25
|
{
|
|
26
26
|
description: "Get content of a markdown note",
|
|
@@ -69,7 +69,7 @@ export class AppendContentToolHandler extends BaseToolHandler {
|
|
|
69
69
|
getToolDescription() {
|
|
70
70
|
return {
|
|
71
71
|
name: this.name,
|
|
72
|
-
description: "
|
|
72
|
+
description: "Appends the provided content to the end of a specified file in the vault. If the file does not exist, it will be created.",
|
|
73
73
|
examples: [
|
|
74
74
|
{
|
|
75
75
|
description: "Append a new task",
|
|
@@ -120,17 +120,17 @@ export class AppendContentToolHandler extends BaseToolHandler {
|
|
|
120
120
|
/**
|
|
121
121
|
* Tool handler for updating file content
|
|
122
122
|
*/
|
|
123
|
-
export class
|
|
123
|
+
export class UpdateContentToolHandler extends BaseToolHandler {
|
|
124
124
|
constructor(client) {
|
|
125
|
-
super(FILE_CONTENT_TOOL_NAMES.
|
|
125
|
+
super(FILE_CONTENT_TOOL_NAMES.UPDATE_CONTENT, client); // Renamed from PATCH_CONTENT
|
|
126
126
|
}
|
|
127
127
|
getToolDescription() {
|
|
128
128
|
return {
|
|
129
|
-
name: this.name,
|
|
130
|
-
description: "
|
|
129
|
+
name: this.name, // Will be obsidian_update_content
|
|
130
|
+
description: "Overwrites the entire content of a specified file in the vault with the provided content. If the file does not exist, it will be created.",
|
|
131
131
|
examples: [
|
|
132
132
|
{
|
|
133
|
-
description: "
|
|
133
|
+
description: "Overwrite a note's content",
|
|
134
134
|
args: {
|
|
135
135
|
filepath: "project.md",
|
|
136
136
|
content: "# Project Notes\n\nThis will replace the entire content of the note."
|
|
@@ -147,7 +147,7 @@ export class PatchContentToolHandler extends BaseToolHandler {
|
|
|
147
147
|
},
|
|
148
148
|
content: {
|
|
149
149
|
type: "string",
|
|
150
|
-
description: "
|
|
150
|
+
description: "The new, complete content for the file (overwrites existing content)."
|
|
151
151
|
}
|
|
152
152
|
},
|
|
153
153
|
required: ["filepath", "content"]
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* File operation tools exports
|
|
3
3
|
*/
|
|
4
|
-
export * from './list.js';
|
|
5
4
|
export * from './content.js';
|
|
6
|
-
|
|
7
|
-
import {
|
|
5
|
+
export * from './list.js';
|
|
6
|
+
import { AppendContentToolHandler, GetFileContentsToolHandler, UpdateContentToolHandler } from './content.js';
|
|
7
|
+
import { ListFilesInDirToolHandler, ListFilesInVaultToolHandler } from './list.js';
|
|
8
8
|
/**
|
|
9
9
|
* Create all file-related tool handlers
|
|
10
10
|
* @param client The ObsidianClient instance
|
|
@@ -16,7 +16,7 @@ export function createFileToolHandlers(client) {
|
|
|
16
16
|
new ListFilesInDirToolHandler(client),
|
|
17
17
|
new GetFileContentsToolHandler(client),
|
|
18
18
|
new AppendContentToolHandler(client),
|
|
19
|
-
new
|
|
19
|
+
new UpdateContentToolHandler(client)
|
|
20
20
|
];
|
|
21
21
|
}
|
|
22
22
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseToolHandler } from "../base.js";
|
|
2
1
|
import { createLogger } from "../../utils/logging.js";
|
|
2
|
+
import { BaseToolHandler } from "../base.js";
|
|
3
3
|
// Create a logger for file operations
|
|
4
4
|
const logger = createLogger('FileTools');
|
|
5
5
|
/**
|
|
@@ -19,7 +19,7 @@ export class ListFilesInVaultToolHandler extends BaseToolHandler {
|
|
|
19
19
|
getToolDescription() {
|
|
20
20
|
return {
|
|
21
21
|
name: this.name,
|
|
22
|
-
description: "Lists all files and directories
|
|
22
|
+
description: "Lists all files and directories within the root of your Obsidian vault. Returns a hierarchical structure detailing files, folders, and their types.",
|
|
23
23
|
examples: [
|
|
24
24
|
{
|
|
25
25
|
description: "List all files in vault",
|
|
@@ -74,7 +74,7 @@ export class ListFilesInDirToolHandler extends BaseToolHandler {
|
|
|
74
74
|
getToolDescription() {
|
|
75
75
|
return {
|
|
76
76
|
name: this.name,
|
|
77
|
-
description: "Lists
|
|
77
|
+
description: "Lists files and directories within a specific folder in your Obsidian vault. Returns a hierarchical structure. Note: Empty directories may not be included in the results. Useful for exploring vault organization.",
|
|
78
78
|
examples: [
|
|
79
79
|
{
|
|
80
80
|
description: "List files in Documents folder",
|
package/build/tools/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createFileToolHandlers } from './files/index.js';
|
|
2
|
-
import { createSearchToolHandlers } from './search/index.js';
|
|
3
2
|
import { createPropertyToolHandlers } from './properties/index.js';
|
|
3
|
+
import { createSearchToolHandlers } from './search/index.js';
|
|
4
4
|
// Export the base handler and all submodules
|
|
5
5
|
export * from './base.js';
|
|
6
6
|
export * from './files/index.js';
|
|
7
|
-
export * from './search/index.js';
|
|
8
7
|
export * from './properties/index.js';
|
|
8
|
+
export * from './search/index.js';
|
|
9
9
|
/**
|
|
10
10
|
* Create all tool handlers
|
|
11
11
|
* @param client The ObsidianClient instance
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Properties module exports
|
|
3
3
|
*/
|
|
4
|
-
export * from './types.js';
|
|
5
4
|
export * from './manager.js';
|
|
6
5
|
export * from './tools.js';
|
|
6
|
+
export * from './types.js';
|
|
7
7
|
import { GetPropertiesToolHandler, UpdatePropertiesToolHandler } from './tools.js';
|
|
8
8
|
/**
|
|
9
9
|
* Create all property-related tool handlers
|