obsidian-mcp-server 2.0.4 → 2.0.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/CHANGELOG.md +17 -0
- package/README.md +80 -88
- package/dist/mcp-server/server.js +8 -8
- package/dist/mcp-server/tools/{obsidianDeleteFileTool → obsidianDeleteNoteTool}/index.d.ts +4 -4
- package/dist/mcp-server/tools/{obsidianDeleteFileTool → obsidianDeleteNoteTool}/index.js +4 -4
- package/dist/mcp-server/tools/{obsidianDeleteFileTool → obsidianDeleteNoteTool}/logic.d.ts +9 -9
- package/dist/mcp-server/tools/{obsidianDeleteFileTool → obsidianDeleteNoteTool}/logic.js +6 -6
- package/dist/mcp-server/tools/{obsidianDeleteFileTool → obsidianDeleteNoteTool}/registration.d.ts +2 -2
- package/dist/mcp-server/tools/{obsidianDeleteFileTool → obsidianDeleteNoteTool}/registration.js +12 -12
- package/dist/mcp-server/tools/{obsidianListFilesTool → obsidianListNotesTool}/index.d.ts +4 -4
- package/dist/mcp-server/tools/{obsidianListFilesTool → obsidianListNotesTool}/index.js +4 -4
- package/dist/mcp-server/tools/{obsidianListFilesTool → obsidianListNotesTool}/logic.d.ts +10 -10
- package/dist/mcp-server/tools/{obsidianListFilesTool → obsidianListNotesTool}/logic.js +14 -13
- package/dist/mcp-server/tools/{obsidianListFilesTool → obsidianListNotesTool}/registration.d.ts +4 -4
- package/dist/mcp-server/tools/{obsidianListFilesTool → obsidianListNotesTool}/registration.js +14 -14
- package/dist/mcp-server/tools/{obsidianReadFileTool → obsidianReadNoteTool}/index.d.ts +4 -4
- package/dist/mcp-server/tools/{obsidianReadFileTool → obsidianReadNoteTool}/index.js +4 -4
- package/dist/mcp-server/tools/{obsidianReadFileTool → obsidianReadNoteTool}/logic.d.ts +9 -9
- package/dist/mcp-server/tools/{obsidianReadFileTool → obsidianReadNoteTool}/logic.js +8 -8
- package/dist/mcp-server/tools/{obsidianReadFileTool → obsidianReadNoteTool}/registration.d.ts +2 -2
- package/dist/mcp-server/tools/{obsidianReadFileTool → obsidianReadNoteTool}/registration.js +12 -12
- package/dist/mcp-server/tools/{obsidianUpdateFileTool → obsidianUpdateNoteTool}/index.d.ts +4 -4
- package/dist/mcp-server/tools/{obsidianUpdateFileTool → obsidianUpdateNoteTool}/index.js +4 -4
- package/dist/mcp-server/tools/{obsidianUpdateFileTool → obsidianUpdateNoteTool}/logic.d.ts +8 -8
- package/dist/mcp-server/tools/{obsidianUpdateFileTool → obsidianUpdateNoteTool}/logic.js +7 -7
- package/dist/mcp-server/tools/{obsidianUpdateFileTool → obsidianUpdateNoteTool}/registration.d.ts +2 -2
- package/dist/mcp-server/tools/{obsidianUpdateFileTool → obsidianUpdateNoteTool}/registration.js +13 -13
- package/dist/mcp-server/transports/{authentication → auth/core}/authContext.d.ts +2 -2
- package/dist/mcp-server/transports/{authentication → auth/core}/authContext.js +1 -1
- package/dist/mcp-server/transports/{authentication/types.d.ts → auth/core/authTypes.d.ts} +1 -1
- package/dist/mcp-server/transports/{authentication/types.js → auth/core/authTypes.js} +1 -1
- package/dist/mcp-server/transports/{authentication → auth/core}/authUtils.d.ts +1 -1
- package/dist/mcp-server/transports/{authentication → auth/core}/authUtils.js +3 -3
- package/dist/mcp-server/transports/auth/index.d.ts +10 -0
- package/dist/mcp-server/transports/auth/index.js +9 -0
- package/dist/mcp-server/transports/{authentication/authMiddleware.d.ts → auth/strategies/jwt/jwtMiddleware.d.ts} +4 -7
- package/dist/mcp-server/transports/{authentication/authMiddleware.js → auth/strategies/jwt/jwtMiddleware.js} +40 -36
- package/dist/mcp-server/transports/{authentication → auth/strategies/oauth}/oauthMiddleware.d.ts +2 -6
- package/dist/mcp-server/transports/{authentication → auth/strategies/oauth}/oauthMiddleware.js +33 -18
- package/dist/mcp-server/transports/httpErrorHandler.d.ts +26 -0
- package/dist/mcp-server/transports/httpErrorHandler.js +73 -0
- package/dist/mcp-server/transports/httpTransport.d.ts +11 -14
- package/dist/mcp-server/transports/httpTransport.js +91 -379
- package/package.json +14 -19
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Core logic for the '
|
|
2
|
+
* @fileoverview Core logic for the 'obsidian_list_notes' tool.
|
|
3
3
|
* This module defines the input schema, response types, and processing logic for
|
|
4
4
|
* recursively listing files and directories in an Obsidian vault with filtering.
|
|
5
|
-
* @module src/mcp-server/tools/
|
|
5
|
+
* @module src/mcp-server/tools/obsidianListNotesTool/logic
|
|
6
6
|
*/
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { z } from "zod";
|
|
@@ -12,9 +12,9 @@ import { logger, retryWithDelay, } from "../../../utils/index.js";
|
|
|
12
12
|
// Schema Definitions for Input Validation
|
|
13
13
|
// ====================================================================================
|
|
14
14
|
/**
|
|
15
|
-
* Zod schema for validating the input parameters of the '
|
|
15
|
+
* Zod schema for validating the input parameters of the 'obsidian_list_notes' tool.
|
|
16
16
|
*/
|
|
17
|
-
export const
|
|
17
|
+
export const ObsidianListNotesInputSchema = z
|
|
18
18
|
.object({
|
|
19
19
|
/**
|
|
20
20
|
* The vault-relative path to the directory whose contents should be listed.
|
|
@@ -84,7 +84,7 @@ function formatTree(nodes, indent = "") {
|
|
|
84
84
|
*
|
|
85
85
|
* @param {string} dirPath - The path of the directory to process.
|
|
86
86
|
* @param {number} currentDepth - The current recursion depth.
|
|
87
|
-
* @param {
|
|
87
|
+
* @param {ObsidianListNotesInput} params - The original validated input parameters, including filters and max depth.
|
|
88
88
|
* @param {RequestContext} context - The request context for logging.
|
|
89
89
|
* @param {ObsidianRestApiService} obsidianService - The Obsidian API service instance.
|
|
90
90
|
* @returns {Promise<FileTreeNode[]>} A promise that resolves to an array of file tree nodes.
|
|
@@ -118,9 +118,7 @@ async function buildFileTree(dirPath, currentDepth, params, context, obsidianSer
|
|
|
118
118
|
if (regex && !regex.test(cleanName)) {
|
|
119
119
|
continue;
|
|
120
120
|
}
|
|
121
|
-
if (!isDirectory &&
|
|
122
|
-
fileExtensionFilter &&
|
|
123
|
-
fileExtensionFilter.length > 0) {
|
|
121
|
+
if (!isDirectory && fileExtensionFilter && fileExtensionFilter.length > 0) {
|
|
124
122
|
const extension = path.posix.extname(name);
|
|
125
123
|
if (!fileExtensionFilter.includes(extension)) {
|
|
126
124
|
continue;
|
|
@@ -153,20 +151,23 @@ async function buildFileTree(dirPath, currentDepth, params, context, obsidianSer
|
|
|
153
151
|
/**
|
|
154
152
|
* Processes the core logic for listing files and directories recursively within the Obsidian vault.
|
|
155
153
|
*
|
|
156
|
-
* @param {
|
|
154
|
+
* @param {ObsidianListNotesInput} params - The validated input parameters.
|
|
157
155
|
* @param {RequestContext} context - The request context for logging and correlation.
|
|
158
156
|
* @param {ObsidianRestApiService} obsidianService - An instance of the Obsidian REST API service.
|
|
159
|
-
* @returns {Promise<
|
|
157
|
+
* @returns {Promise<ObsidianListNotesResponse>} A promise resolving to the structured success response.
|
|
160
158
|
* @throws {McpError} Throws an McpError if the initial directory is not found or another error occurs.
|
|
161
159
|
*/
|
|
162
|
-
export const
|
|
160
|
+
export const processObsidianListNotes = async (params, context, obsidianService) => {
|
|
163
161
|
const { dirPath } = params;
|
|
164
162
|
const dirPathForLog = dirPath === "" || dirPath === "/" ? "/" : dirPath;
|
|
165
|
-
logger.debug(`Processing
|
|
163
|
+
logger.debug(`Processing obsidian_list_notes request for path: ${dirPathForLog}`, { ...context, params });
|
|
166
164
|
try {
|
|
167
165
|
const effectiveDirPath = dirPath === "" ? "/" : dirPath;
|
|
168
166
|
// --- Step 1: Build the file tree recursively with retry for the initial call ---
|
|
169
|
-
const buildTreeContext = {
|
|
167
|
+
const buildTreeContext = {
|
|
168
|
+
...context,
|
|
169
|
+
operation: "buildFileTreeWithRetry",
|
|
170
|
+
};
|
|
170
171
|
const shouldRetryNotFound = (err) => err instanceof McpError && err.code === BaseErrorCode.NOT_FOUND;
|
|
171
172
|
const fileTree = await retryWithDelay(() => buildFileTree(effectiveDirPath, 0, // Start at depth 0
|
|
172
173
|
params, buildTreeContext, obsidianService), {
|
package/dist/mcp-server/tools/{obsidianListFilesTool → obsidianListNotesTool}/registration.d.ts
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Registers the '
|
|
2
|
+
* @fileoverview Registers the 'obsidian_list_notes' tool with the MCP server.
|
|
3
3
|
* This file defines the tool's metadata and sets up the handler that links
|
|
4
4
|
* the tool call to its core processing logic.
|
|
5
|
-
* @module src/mcp-server/tools/
|
|
5
|
+
* @module src/mcp-server/tools/obsidianListNotesTool/registration
|
|
6
6
|
*/
|
|
7
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
8
|
import { ObsidianRestApiService } from "../../../services/obsidianRestAPI/index.js";
|
|
9
9
|
/**
|
|
10
|
-
* Registers the '
|
|
10
|
+
* Registers the 'obsidian_list_notes' tool with the MCP server.
|
|
11
11
|
*
|
|
12
12
|
* This tool lists the files and subdirectories within a specified directory
|
|
13
13
|
* in the user's Obsidian vault. It supports optional filtering by file extension,
|
|
@@ -20,4 +20,4 @@ import { ObsidianRestApiService } from "../../../services/obsidianRestAPI/index.
|
|
|
20
20
|
* @returns {Promise<void>} A promise that resolves when the tool registration is complete or rejects on error.
|
|
21
21
|
* @throws {McpError} Throws an McpError if registration fails critically.
|
|
22
22
|
*/
|
|
23
|
-
export declare const
|
|
23
|
+
export declare const registerObsidianListNotesTool: (server: McpServer, obsidianService: ObsidianRestApiService) => Promise<void>;
|
package/dist/mcp-server/tools/{obsidianListFilesTool → obsidianListNotesTool}/registration.js
RENAMED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Registers the '
|
|
2
|
+
* @fileoverview Registers the 'obsidian_list_notes' tool with the MCP server.
|
|
3
3
|
* This file defines the tool's metadata and sets up the handler that links
|
|
4
4
|
* the tool call to its core processing logic.
|
|
5
|
-
* @module src/mcp-server/tools/
|
|
5
|
+
* @module src/mcp-server/tools/obsidianListNotesTool/registration
|
|
6
6
|
*/
|
|
7
7
|
import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
|
|
8
8
|
import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js";
|
|
9
|
-
import {
|
|
9
|
+
import { ObsidianListNotesInputSchema, processObsidianListNotes, } from "./logic.js";
|
|
10
10
|
/**
|
|
11
|
-
* Registers the '
|
|
11
|
+
* Registers the 'obsidian_list_notes' tool with the MCP server.
|
|
12
12
|
*
|
|
13
13
|
* This tool lists the files and subdirectories within a specified directory
|
|
14
14
|
* in the user's Obsidian vault. It supports optional filtering by file extension,
|
|
@@ -21,25 +21,25 @@ import { ObsidianListFilesInputSchema, processObsidianListFiles, } from "./logic
|
|
|
21
21
|
* @returns {Promise<void>} A promise that resolves when the tool registration is complete or rejects on error.
|
|
22
22
|
* @throws {McpError} Throws an McpError if registration fails critically.
|
|
23
23
|
*/
|
|
24
|
-
export const
|
|
25
|
-
const toolName = "
|
|
24
|
+
export const registerObsidianListNotesTool = async (server, obsidianService) => {
|
|
25
|
+
const toolName = "obsidian_list_notes";
|
|
26
26
|
const toolDescription = "Lists files and subdirectories within a specified Obsidian vault folder. Supports optional filtering by extension or name regex, and recursive listing to a specified depth (-1 for infinite). Returns an object containing the listed directory path, a formatted tree string of its contents, and the total entry count. Use an empty string or '/' for dirPath to list the vault root.";
|
|
27
27
|
// Create a context specifically for the registration process.
|
|
28
28
|
const registrationContext = requestContextService.createRequestContext({
|
|
29
|
-
operation: "
|
|
29
|
+
operation: "RegisterObsidianListNotesTool",
|
|
30
30
|
toolName: toolName,
|
|
31
|
-
module: "
|
|
31
|
+
module: "ObsidianListNotesRegistration", // Identify the module
|
|
32
32
|
});
|
|
33
33
|
logger.info(`Attempting to register tool: ${toolName}`, registrationContext);
|
|
34
34
|
// Wrap the registration logic in a tryCatch block for robust error handling during server setup.
|
|
35
35
|
await ErrorHandler.tryCatch(async () => {
|
|
36
36
|
// Use the high-level SDK method `server.tool` for registration.
|
|
37
|
-
server.tool(toolName, toolDescription,
|
|
37
|
+
server.tool(toolName, toolDescription, ObsidianListNotesInputSchema.shape, // Provide the Zod schema shape for input definition.
|
|
38
38
|
/**
|
|
39
|
-
* The handler function executed when the '
|
|
39
|
+
* The handler function executed when the 'obsidian_list_notes' tool is called by the client.
|
|
40
40
|
*
|
|
41
|
-
* @param {
|
|
42
|
-
* validated against the
|
|
41
|
+
* @param {ObsidianListNotesInput} params - The input parameters received from the client,
|
|
42
|
+
* validated against the ObsidianListNotesInputSchema shape.
|
|
43
43
|
* @returns {Promise<CallToolResult>} A promise resolving to the structured result for the MCP client,
|
|
44
44
|
* containing either the successful response data (serialized JSON) or an error indication.
|
|
45
45
|
*/
|
|
@@ -48,7 +48,7 @@ export const registerObsidianListFilesTool = async (server, obsidianService) =>
|
|
|
48
48
|
// Create a specific context for this handler invocation.
|
|
49
49
|
const handlerContext = requestContextService.createRequestContext({
|
|
50
50
|
parentContext: registrationContext, // Link to registration context
|
|
51
|
-
operation: "
|
|
51
|
+
operation: "HandleObsidianListNotesRequest",
|
|
52
52
|
toolName: toolName,
|
|
53
53
|
params: {
|
|
54
54
|
// Log all relevant parameters for debugging
|
|
@@ -62,7 +62,7 @@ export const registerObsidianListFilesTool = async (server, obsidianService) =>
|
|
|
62
62
|
// Wrap the core logic execution in a tryCatch block.
|
|
63
63
|
return await ErrorHandler.tryCatch(async () => {
|
|
64
64
|
// Delegate the actual file listing and filtering logic to the processing function.
|
|
65
|
-
const response = await
|
|
65
|
+
const response = await processObsidianListNotes(params, handlerContext, obsidianService);
|
|
66
66
|
logger.debug(`'${toolName}' processed successfully`, handlerContext);
|
|
67
67
|
// Format the successful response object from the logic function into the required MCP CallToolResult structure.
|
|
68
68
|
return {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Barrel file for the '
|
|
2
|
+
* @fileoverview Barrel file for the 'obsidian_read_note' MCP tool.
|
|
3
3
|
*
|
|
4
|
-
* This file serves as the public entry point for the
|
|
5
|
-
* It re-exports the primary registration function (`
|
|
4
|
+
* This file serves as the public entry point for the obsidian_read_note tool module.
|
|
5
|
+
* It re-exports the primary registration function (`registerObsidianReadNoteTool`)
|
|
6
6
|
* from the './registration.js' module. This pattern simplifies imports for consumers
|
|
7
7
|
* of the tool, allowing them to import necessary components from a single location.
|
|
8
8
|
*
|
|
9
9
|
* Consumers (like the main server setup) should import the registration function
|
|
10
10
|
* from this file to integrate the tool into the MCP server instance.
|
|
11
11
|
*/
|
|
12
|
-
export {
|
|
12
|
+
export { registerObsidianReadNoteTool } from "./registration.js";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Barrel file for the '
|
|
2
|
+
* @fileoverview Barrel file for the 'obsidian_read_note' MCP tool.
|
|
3
3
|
*
|
|
4
|
-
* This file serves as the public entry point for the
|
|
5
|
-
* It re-exports the primary registration function (`
|
|
4
|
+
* This file serves as the public entry point for the obsidian_read_note tool module.
|
|
5
|
+
* It re-exports the primary registration function (`registerObsidianReadNoteTool`)
|
|
6
6
|
* from the './registration.js' module. This pattern simplifies imports for consumers
|
|
7
7
|
* of the tool, allowing them to import necessary components from a single location.
|
|
8
8
|
*
|
|
9
9
|
* Consumers (like the main server setup) should import the registration function
|
|
10
10
|
* from this file to integrate the tool into the MCP server instance.
|
|
11
11
|
*/
|
|
12
|
-
export {
|
|
12
|
+
export { registerObsidianReadNoteTool } from "./registration.js";
|
|
@@ -2,9 +2,9 @@ import { z } from "zod";
|
|
|
2
2
|
import { NoteJson, ObsidianRestApiService } from "../../../services/obsidianRestAPI/index.js";
|
|
3
3
|
import { RequestContext } from "../../../utils/index.js";
|
|
4
4
|
/**
|
|
5
|
-
* Zod schema for validating the input parameters of the '
|
|
5
|
+
* Zod schema for validating the input parameters of the 'obsidian_read_note' tool.
|
|
6
6
|
*/
|
|
7
|
-
export declare const
|
|
7
|
+
export declare const ObsidianReadNoteInputSchema: z.ZodObject<{
|
|
8
8
|
/**
|
|
9
9
|
* The vault-relative path to the target file (e.g., "Folder/My Note.md").
|
|
10
10
|
* Must include the file extension. The tool first attempts a case-sensitive match.
|
|
@@ -34,10 +34,10 @@ export declare const ObsidianReadFileInputSchema: z.ZodObject<{
|
|
|
34
34
|
includeStat?: boolean | undefined;
|
|
35
35
|
}>;
|
|
36
36
|
/**
|
|
37
|
-
* TypeScript type inferred from the input schema (`
|
|
37
|
+
* TypeScript type inferred from the input schema (`ObsidianReadNoteInputSchema`).
|
|
38
38
|
* Represents the validated input parameters used within the core processing logic.
|
|
39
39
|
*/
|
|
40
|
-
export type
|
|
40
|
+
export type ObsidianReadNoteInput = z.infer<typeof ObsidianReadNoteInputSchema>;
|
|
41
41
|
/**
|
|
42
42
|
* Represents the structure of file statistics after formatting, including
|
|
43
43
|
* human-readable timestamps and an estimated token count.
|
|
@@ -51,10 +51,10 @@ type FormattedStat = {
|
|
|
51
51
|
tokenCountEstimate: number;
|
|
52
52
|
};
|
|
53
53
|
/**
|
|
54
|
-
* Defines the structure of the successful response returned by the `
|
|
54
|
+
* Defines the structure of the successful response returned by the `processObsidianReadNote` function.
|
|
55
55
|
* This object is typically serialized to JSON and sent back to the client.
|
|
56
56
|
*/
|
|
57
|
-
export interface
|
|
57
|
+
export interface ObsidianReadNoteResponse {
|
|
58
58
|
/**
|
|
59
59
|
* The content of the file in the requested format.
|
|
60
60
|
* If format='markdown', this is a string.
|
|
@@ -75,13 +75,13 @@ export interface ObsidianReadFileResponse {
|
|
|
75
75
|
* internally to access file statistics. Finally, it formats the response
|
|
76
76
|
* according to the requested format ('markdown' or 'json') and the 'includeStat' flag.
|
|
77
77
|
*
|
|
78
|
-
* @param {
|
|
78
|
+
* @param {ObsidianReadNoteInput} params - The validated input parameters.
|
|
79
79
|
* @param {RequestContext} context - The request context for logging and correlation.
|
|
80
80
|
* @param {ObsidianRestApiService} obsidianService - An instance of the Obsidian REST API service.
|
|
81
|
-
* @returns {Promise<
|
|
81
|
+
* @returns {Promise<ObsidianReadNoteResponse>} A promise resolving to the structured success response
|
|
82
82
|
* containing the file content and optionally formatted statistics.
|
|
83
83
|
* @throws {McpError} Throws an McpError if the file cannot be found (even with fallback),
|
|
84
84
|
* if there's an ambiguous fallback match, or if any other API interaction fails.
|
|
85
85
|
*/
|
|
86
|
-
export declare const
|
|
86
|
+
export declare const processObsidianReadNote: (params: ObsidianReadNoteInput, context: RequestContext, obsidianService: ObsidianRestApiService) => Promise<ObsidianReadNoteResponse>;
|
|
87
87
|
export {};
|
|
@@ -10,14 +10,14 @@ import { createFormattedStatWithTokenCount, logger, retryWithDelay, } from "../.
|
|
|
10
10
|
* - 'markdown': Returns the raw Markdown content as a string.
|
|
11
11
|
* - 'json': Returns a structured NoteJson object including content, frontmatter, tags, and stats.
|
|
12
12
|
*/
|
|
13
|
-
const
|
|
13
|
+
const ReadNoteFormatSchema = z
|
|
14
14
|
.enum(["markdown", "json"])
|
|
15
15
|
.default("markdown")
|
|
16
16
|
.describe("Specifies the format for the returned content ('markdown' or 'json'). Defaults to 'markdown'.");
|
|
17
17
|
/**
|
|
18
|
-
* Zod schema for validating the input parameters of the '
|
|
18
|
+
* Zod schema for validating the input parameters of the 'obsidian_read_note' tool.
|
|
19
19
|
*/
|
|
20
|
-
export const
|
|
20
|
+
export const ObsidianReadNoteInputSchema = z
|
|
21
21
|
.object({
|
|
22
22
|
/**
|
|
23
23
|
* The vault-relative path to the target file (e.g., "Folder/My Note.md").
|
|
@@ -34,7 +34,7 @@ export const ObsidianReadFileInputSchema = z
|
|
|
34
34
|
* 'json' returns a structured NoteJson object containing content, parsed frontmatter, tags, and file metadata (stat).
|
|
35
35
|
* Defaults to 'markdown'.
|
|
36
36
|
*/
|
|
37
|
-
format:
|
|
37
|
+
format: ReadNoteFormatSchema.optional() // Optional, defaults to 'markdown' via ReadNoteFormatSchema
|
|
38
38
|
.describe("Format for the returned content ('markdown' or 'json'). Defaults to 'markdown'."),
|
|
39
39
|
/**
|
|
40
40
|
* If true and the requested format is 'markdown', includes formatted file statistics
|
|
@@ -59,18 +59,18 @@ export const ObsidianReadFileInputSchema = z
|
|
|
59
59
|
* internally to access file statistics. Finally, it formats the response
|
|
60
60
|
* according to the requested format ('markdown' or 'json') and the 'includeStat' flag.
|
|
61
61
|
*
|
|
62
|
-
* @param {
|
|
62
|
+
* @param {ObsidianReadNoteInput} params - The validated input parameters.
|
|
63
63
|
* @param {RequestContext} context - The request context for logging and correlation.
|
|
64
64
|
* @param {ObsidianRestApiService} obsidianService - An instance of the Obsidian REST API service.
|
|
65
|
-
* @returns {Promise<
|
|
65
|
+
* @returns {Promise<ObsidianReadNoteResponse>} A promise resolving to the structured success response
|
|
66
66
|
* containing the file content and optionally formatted statistics.
|
|
67
67
|
* @throws {McpError} Throws an McpError if the file cannot be found (even with fallback),
|
|
68
68
|
* if there's an ambiguous fallback match, or if any other API interaction fails.
|
|
69
69
|
*/
|
|
70
|
-
export const
|
|
70
|
+
export const processObsidianReadNote = async (params, context, obsidianService) => {
|
|
71
71
|
const { filePath: originalFilePath, format: requestedFormat, includeStat, } = params;
|
|
72
72
|
let effectiveFilePath = originalFilePath; // Track the actual path used (might change during fallback)
|
|
73
|
-
logger.debug(`Processing
|
|
73
|
+
logger.debug(`Processing obsidian_read_note request for path: ${originalFilePath}`, { ...context, format: requestedFormat, includeStat });
|
|
74
74
|
const shouldRetryNotFound = (err) => err instanceof McpError && err.code === BaseErrorCode.NOT_FOUND;
|
|
75
75
|
try {
|
|
76
76
|
let noteJson;
|
package/dist/mcp-server/tools/{obsidianReadFileTool → obsidianReadNoteTool}/registration.d.ts
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { ObsidianRestApiService } from "../../../services/obsidianRestAPI/index.js";
|
|
3
3
|
/**
|
|
4
|
-
* Registers the '
|
|
4
|
+
* Registers the 'obsidian_read_note' tool with the MCP server.
|
|
5
5
|
*
|
|
6
6
|
* This tool retrieves the content and optionally metadata of a specified file
|
|
7
7
|
* within the user's Obsidian vault. It supports specifying the output format
|
|
@@ -17,4 +17,4 @@ import { ObsidianRestApiService } from "../../../services/obsidianRestAPI/index.
|
|
|
17
17
|
* @returns {Promise<void>} A promise that resolves when the tool registration is complete or rejects on error.
|
|
18
18
|
* @throws {McpError} Throws an McpError if registration fails critically.
|
|
19
19
|
*/
|
|
20
|
-
export declare const
|
|
20
|
+
export declare const registerObsidianReadNoteTool: (server: McpServer, obsidianService: ObsidianRestApiService) => Promise<void>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
|
|
2
2
|
import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { ObsidianReadNoteInputSchema, processObsidianReadNote, } from "./logic.js";
|
|
4
4
|
/**
|
|
5
|
-
* Registers the '
|
|
5
|
+
* Registers the 'obsidian_read_note' tool with the MCP server.
|
|
6
6
|
*
|
|
7
7
|
* This tool retrieves the content and optionally metadata of a specified file
|
|
8
8
|
* within the user's Obsidian vault. It supports specifying the output format
|
|
@@ -18,26 +18,26 @@ import { ObsidianReadFileInputSchema, processObsidianReadFile, } from "./logic.j
|
|
|
18
18
|
* @returns {Promise<void>} A promise that resolves when the tool registration is complete or rejects on error.
|
|
19
19
|
* @throws {McpError} Throws an McpError if registration fails critically.
|
|
20
20
|
*/
|
|
21
|
-
export const
|
|
22
|
-
const toolName = "
|
|
21
|
+
export const registerObsidianReadNoteTool = async (server, obsidianService) => {
|
|
22
|
+
const toolName = "obsidian_read_note";
|
|
23
23
|
const toolDescription = "Retrieves the content and metadata of a specified file within the Obsidian vault. Tries the exact path first, then attempts a case-insensitive fallback. Returns an object containing the content (markdown string or full NoteJson object based on 'format'), and optionally formatted file stats ('stats' object with creationTime, modifiedTime, tokenCountEstimate). Use 'includeStat: true' with 'format: markdown' to include stats; stats are always included with 'format: json'.";
|
|
24
24
|
// Create a context specifically for the registration process.
|
|
25
25
|
const registrationContext = requestContextService.createRequestContext({
|
|
26
|
-
operation: "
|
|
26
|
+
operation: "RegisterObsidianReadNoteTool",
|
|
27
27
|
toolName: toolName,
|
|
28
|
-
module: "
|
|
28
|
+
module: "ObsidianReadNoteRegistration", // Identify the module
|
|
29
29
|
});
|
|
30
30
|
logger.info(`Attempting to register tool: ${toolName}`, registrationContext);
|
|
31
31
|
// Wrap the registration logic in a tryCatch block for robust error handling during server setup.
|
|
32
32
|
await ErrorHandler.tryCatch(async () => {
|
|
33
33
|
// Use the high-level SDK method `server.tool` for registration.
|
|
34
34
|
// It handles schema generation from the shape, basic validation, and routing.
|
|
35
|
-
server.tool(toolName, toolDescription,
|
|
35
|
+
server.tool(toolName, toolDescription, ObsidianReadNoteInputSchema.shape, // Provide the Zod schema shape for input definition.
|
|
36
36
|
/**
|
|
37
|
-
* The handler function executed when the '
|
|
37
|
+
* The handler function executed when the 'obsidian_read_note' tool is called by the client.
|
|
38
38
|
*
|
|
39
|
-
* @param {
|
|
40
|
-
* validated against the
|
|
39
|
+
* @param {ObsidianReadNoteInput} params - The input parameters received from the client,
|
|
40
|
+
* validated against the ObsidianReadNoteInputSchema shape. Note: The handler receives the raw input;
|
|
41
41
|
* stricter validation against the full schema should happen inside if needed, though in this case,
|
|
42
42
|
* the shape and the full schema are identical.
|
|
43
43
|
* @returns {Promise<CallToolResult>} A promise resolving to the structured result for the MCP client,
|
|
@@ -48,7 +48,7 @@ export const registerObsidianReadFileTool = async (server, obsidianService) => {
|
|
|
48
48
|
// Create a specific context for this handler invocation.
|
|
49
49
|
const handlerContext = requestContextService.createRequestContext({
|
|
50
50
|
parentContext: registrationContext, // Link to registration context
|
|
51
|
-
operation: "
|
|
51
|
+
operation: "HandleObsidianReadNoteRequest",
|
|
52
52
|
toolName: toolName,
|
|
53
53
|
params: {
|
|
54
54
|
// Log key parameters for debugging
|
|
@@ -63,7 +63,7 @@ export const registerObsidianReadFileTool = async (server, obsidianService) => {
|
|
|
63
63
|
// Delegate the actual file reading logic to the dedicated processing function.
|
|
64
64
|
// Pass the (already shape-validated) parameters, context, and the Obsidian service.
|
|
65
65
|
// The process function handles the refined validation internally if needed, but here shape = refined.
|
|
66
|
-
const response = await
|
|
66
|
+
const response = await processObsidianReadNote(params, // Pass params directly as shape matches refined schema
|
|
67
67
|
handlerContext, obsidianService);
|
|
68
68
|
logger.debug(`'${toolName}' processed successfully`, handlerContext);
|
|
69
69
|
// Format the successful response object from the logic function into the required MCP CallToolResult structure.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Barrel file for the '
|
|
2
|
+
* @fileoverview Barrel file for the 'obsidian_update_note' MCP tool.
|
|
3
3
|
*
|
|
4
|
-
* This file serves as the public entry point for the
|
|
5
|
-
* It re-exports the primary registration function (`
|
|
4
|
+
* This file serves as the public entry point for the obsidian_update_note tool module.
|
|
5
|
+
* It re-exports the primary registration function (`registerObsidianUpdateNoteTool`)
|
|
6
6
|
* from the './registration.js' module. This pattern simplifies imports for consumers
|
|
7
7
|
* of the tool, allowing them to import necessary components from a single location.
|
|
8
8
|
*
|
|
9
9
|
* Consumers (like the main server setup) should import the registration function
|
|
10
10
|
* from this file to integrate the tool into the MCP server instance.
|
|
11
11
|
*/
|
|
12
|
-
export {
|
|
12
|
+
export { registerObsidianUpdateNoteTool } from "./registration.js";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Barrel file for the '
|
|
2
|
+
* @fileoverview Barrel file for the 'obsidian_update_note' MCP tool.
|
|
3
3
|
*
|
|
4
|
-
* This file serves as the public entry point for the
|
|
5
|
-
* It re-exports the primary registration function (`
|
|
4
|
+
* This file serves as the public entry point for the obsidian_update_note tool module.
|
|
5
|
+
* It re-exports the primary registration function (`registerObsidianUpdateNoteTool`)
|
|
6
6
|
* from the './registration.js' module. This pattern simplifies imports for consumers
|
|
7
7
|
* of the tool, allowing them to import necessary components from a single location.
|
|
8
8
|
*
|
|
9
9
|
* Consumers (like the main server setup) should import the registration function
|
|
10
10
|
* from this file to integrate the tool into the MCP server instance.
|
|
11
11
|
*/
|
|
12
|
-
export {
|
|
12
|
+
export { registerObsidianUpdateNoteTool } from "./registration.js";
|
|
@@ -8,7 +8,7 @@ import { RequestContext } from "../../../utils/index.js";
|
|
|
8
8
|
* relying on the refined schema (`ObsidianUpdateFileInputSchema`) for stricter validation
|
|
9
9
|
* within the handler logic.
|
|
10
10
|
*/
|
|
11
|
-
declare const
|
|
11
|
+
declare const ObsidianUpdateNoteRegistrationSchema: z.ZodObject<{
|
|
12
12
|
/** Specifies the target note: 'filePath' (requires targetIdentifier), 'activeFile' (currently open file), or 'periodicNote' (requires targetIdentifier with period like 'daily'). */
|
|
13
13
|
targetType: z.ZodEnum<["filePath", "activeFile", "periodicNote"]>;
|
|
14
14
|
/** The content for the modification. Must be a string for whole-file operations. */
|
|
@@ -48,7 +48,7 @@ declare const ObsidianUpdateFileRegistrationSchema: z.ZodObject<{
|
|
|
48
48
|
* The shape of the registration schema, used by `server.tool` for basic validation.
|
|
49
49
|
* @see ObsidianUpdateFileRegistrationSchema
|
|
50
50
|
*/
|
|
51
|
-
export declare const
|
|
51
|
+
export declare const ObsidianUpdateNoteInputSchemaShape: {
|
|
52
52
|
/** Specifies the target note: 'filePath' (requires targetIdentifier), 'activeFile' (currently open file), or 'periodicNote' (requires targetIdentifier with period like 'daily'). */
|
|
53
53
|
targetType: z.ZodEnum<["filePath", "activeFile", "periodicNote"]>;
|
|
54
54
|
/** The content for the modification. Must be a string for whole-file operations. */
|
|
@@ -71,13 +71,13 @@ export declare const ObsidianUpdateFileInputSchemaShape: {
|
|
|
71
71
|
* received by the tool handler *before* refinement.
|
|
72
72
|
* @see ObsidianUpdateFileRegistrationSchema
|
|
73
73
|
*/
|
|
74
|
-
export type
|
|
74
|
+
export type ObsidianUpdateNoteRegistrationInput = z.infer<typeof ObsidianUpdateNoteRegistrationSchema>;
|
|
75
75
|
/**
|
|
76
76
|
* Refined Zod schema used internally within the tool's logic for strict validation.
|
|
77
77
|
* It builds upon `WholeFileUpdateSchema` and adds cross-field validation rules using `.refine()`.
|
|
78
78
|
* This ensures that `targetIdentifier` is provided and valid when required by `targetType`.
|
|
79
79
|
*/
|
|
80
|
-
export declare const
|
|
80
|
+
export declare const ObsidianUpdateNoteInputSchema: z.ZodEffects<z.ZodObject<{
|
|
81
81
|
/** Specifies the type of target note. */
|
|
82
82
|
targetType: z.ZodEnum<["filePath", "activeFile", "periodicNote"]>;
|
|
83
83
|
/** The content to use for the modification. Must be a string for whole-file operations. */
|
|
@@ -140,7 +140,7 @@ export declare const ObsidianUpdateFileInputSchema: z.ZodEffects<z.ZodObject<{
|
|
|
140
140
|
* TypeScript type inferred from the *refined* input schema (`ObsidianUpdateFileInputSchema`).
|
|
141
141
|
* This type represents the validated and structured input used within the core processing logic.
|
|
142
142
|
*/
|
|
143
|
-
export type
|
|
143
|
+
export type ObsidianUpdateNoteInput = z.infer<typeof ObsidianUpdateNoteInputSchema>;
|
|
144
144
|
/**
|
|
145
145
|
* Represents the structure of file statistics after formatting, including
|
|
146
146
|
* human-readable timestamps and an estimated token count.
|
|
@@ -157,7 +157,7 @@ type FormattedStat = {
|
|
|
157
157
|
* Defines the structure of the successful response returned by the `processObsidianUpdateFile` function.
|
|
158
158
|
* This object is typically serialized to JSON and sent back to the client.
|
|
159
159
|
*/
|
|
160
|
-
export interface
|
|
160
|
+
export interface ObsidianUpdateNoteResponse {
|
|
161
161
|
/** Indicates whether the operation was successful. */
|
|
162
162
|
success: boolean;
|
|
163
163
|
/** A human-readable message describing the outcome of the operation. */
|
|
@@ -178,6 +178,6 @@ export interface ObsidianUpdateFileResponse {
|
|
|
178
178
|
* @returns {Promise<ObsidianUpdateFileResponse>} A promise resolving to the structured success response.
|
|
179
179
|
* @throws {McpError} Throws an McpError if validation fails or the API interaction results in an error.
|
|
180
180
|
*/
|
|
181
|
-
export declare const
|
|
182
|
-
context: RequestContext, obsidianService: ObsidianRestApiService, vaultCacheService: VaultCacheService | undefined) => Promise<
|
|
181
|
+
export declare const processObsidianUpdateNote: (params: ObsidianUpdateNoteInput, // Use the refined, validated type
|
|
182
|
+
context: RequestContext, obsidianService: ObsidianRestApiService, vaultCacheService: VaultCacheService | undefined) => Promise<ObsidianUpdateNoteResponse>;
|
|
183
183
|
export {};
|
|
@@ -79,7 +79,7 @@ const WholeFileUpdateSchema = BaseUpdateSchema.extend({
|
|
|
79
79
|
* relying on the refined schema (`ObsidianUpdateFileInputSchema`) for stricter validation
|
|
80
80
|
* within the handler logic.
|
|
81
81
|
*/
|
|
82
|
-
const
|
|
82
|
+
const ObsidianUpdateNoteRegistrationSchema = z
|
|
83
83
|
.object({
|
|
84
84
|
/** Specifies the target note: 'filePath' (requires targetIdentifier), 'activeFile' (currently open file), or 'periodicNote' (requires targetIdentifier with period like 'daily'). */
|
|
85
85
|
targetType: TargetTypeSchema,
|
|
@@ -122,7 +122,7 @@ const ObsidianUpdateFileRegistrationSchema = z
|
|
|
122
122
|
* The shape of the registration schema, used by `server.tool` for basic validation.
|
|
123
123
|
* @see ObsidianUpdateFileRegistrationSchema
|
|
124
124
|
*/
|
|
125
|
-
export const
|
|
125
|
+
export const ObsidianUpdateNoteInputSchemaShape = ObsidianUpdateNoteRegistrationSchema.shape;
|
|
126
126
|
// ====================================================================================
|
|
127
127
|
// Refined Schema for Internal Logic and Strict Validation
|
|
128
128
|
// ====================================================================================
|
|
@@ -131,7 +131,7 @@ export const ObsidianUpdateFileInputSchemaShape = ObsidianUpdateFileRegistration
|
|
|
131
131
|
* It builds upon `WholeFileUpdateSchema` and adds cross-field validation rules using `.refine()`.
|
|
132
132
|
* This ensures that `targetIdentifier` is provided and valid when required by `targetType`.
|
|
133
133
|
*/
|
|
134
|
-
export const
|
|
134
|
+
export const ObsidianUpdateNoteInputSchema = WholeFileUpdateSchema.refine((data) => {
|
|
135
135
|
// Rule 1: If targetType is 'filePath' or 'periodicNote', targetIdentifier must be provided.
|
|
136
136
|
if ((data.targetType === "filePath" || data.targetType === "periodicNote") &&
|
|
137
137
|
!data.targetIdentifier) {
|
|
@@ -207,9 +207,9 @@ async function getFinalState(targetType, targetIdentifier, period, obsidianServi
|
|
|
207
207
|
* @returns {Promise<ObsidianUpdateFileResponse>} A promise resolving to the structured success response.
|
|
208
208
|
* @throws {McpError} Throws an McpError if validation fails or the API interaction results in an error.
|
|
209
209
|
*/
|
|
210
|
-
export const
|
|
210
|
+
export const processObsidianUpdateNote = async (params, // Use the refined, validated type
|
|
211
211
|
context, obsidianService, vaultCacheService) => {
|
|
212
|
-
logger.debug(`Processing
|
|
212
|
+
logger.debug(`Processing obsidian_update_note request (wholeFile mode)`, {
|
|
213
213
|
...context,
|
|
214
214
|
targetType: params.targetType,
|
|
215
215
|
wholeFileMode: params.wholeFileMode,
|
|
@@ -251,7 +251,7 @@ context, obsidianService, vaultCacheService) => {
|
|
|
251
251
|
existsBefore = true;
|
|
252
252
|
logger.debug(`Target exists before operation.`, checkContext);
|
|
253
253
|
}, {
|
|
254
|
-
operationName: "
|
|
254
|
+
operationName: "existenceCheckObsidianUpdateNote",
|
|
255
255
|
context: checkContext,
|
|
256
256
|
maxRetries: 3, // Total attempts: 1 initial + 2 retries
|
|
257
257
|
delayMs: 250,
|
|
@@ -263,7 +263,7 @@ context, obsidianService, vaultCacheService) => {
|
|
|
263
263
|
params.createIfNeeded;
|
|
264
264
|
if (error instanceof McpError &&
|
|
265
265
|
error.code === BaseErrorCode.NOT_FOUND) {
|
|
266
|
-
logger.debug(`
|
|
266
|
+
logger.debug(`existenceCheckObsidianUpdateNote: shouldRetry=${should} for NOT_FOUND (createIfNeeded: ${params.createIfNeeded})`, checkContext);
|
|
267
267
|
}
|
|
268
268
|
return should;
|
|
269
269
|
},
|
package/dist/mcp-server/tools/{obsidianUpdateFileTool → obsidianUpdateNoteTool}/registration.d.ts
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { ObsidianRestApiService, VaultCacheService } from "../../../services/obsidianRestAPI/index.js";
|
|
3
3
|
/**
|
|
4
|
-
* Registers the '
|
|
4
|
+
* Registers the 'obsidian_update_note' tool with the MCP server.
|
|
5
5
|
*
|
|
6
6
|
* This tool allows modification of Obsidian notes (specified by file path,
|
|
7
7
|
* the active file, or a periodic note) using whole-file operations:
|
|
@@ -18,4 +18,4 @@ import { ObsidianRestApiService, VaultCacheService } from "../../../services/obs
|
|
|
18
18
|
* @returns {Promise<void>} A promise that resolves when the tool registration is complete or rejects on error.
|
|
19
19
|
* @throws {McpError} Throws an McpError if registration fails critically.
|
|
20
20
|
*/
|
|
21
|
-
export declare const
|
|
21
|
+
export declare const registerObsidianUpdateNoteTool: (server: McpServer, obsidianService: ObsidianRestApiService, vaultCacheService: VaultCacheService | undefined) => Promise<void>;
|