obsidian-mcp-server 2.0.7 → 3.1.0

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.
Files changed (254) hide show
  1. package/CLAUDE.md +364 -0
  2. package/Dockerfile +99 -0
  3. package/LICENSE +4 -6
  4. package/README.md +246 -206
  5. package/changelog/3.0.x/3.0.0.md +102 -0
  6. package/changelog/3.1.x/3.1.0.md +26 -0
  7. package/changelog/template.md +51 -0
  8. package/dist/config/server-config.d.ts +19 -0
  9. package/dist/config/server-config.d.ts.map +1 -0
  10. package/dist/config/server-config.js +55 -0
  11. package/dist/config/server-config.js.map +1 -0
  12. package/dist/index.d.ts +7 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +23 -295
  15. package/dist/index.js.map +1 -0
  16. package/dist/mcp-server/prompts/definitions/index.d.ts +8 -0
  17. package/dist/mcp-server/prompts/definitions/index.d.ts.map +1 -0
  18. package/dist/mcp-server/prompts/definitions/index.js +8 -0
  19. package/dist/mcp-server/prompts/definitions/index.js.map +1 -0
  20. package/dist/mcp-server/resources/definitions/index.d.ts +36 -0
  21. package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -0
  22. package/dist/mcp-server/resources/definitions/index.js +9 -0
  23. package/dist/mcp-server/resources/definitions/index.js.map +1 -0
  24. package/dist/mcp-server/resources/definitions/obsidian-status.resource.d.ts +23 -0
  25. package/dist/mcp-server/resources/definitions/obsidian-status.resource.d.ts.map +1 -0
  26. package/dist/mcp-server/resources/definitions/obsidian-status.resource.js +47 -0
  27. package/dist/mcp-server/resources/definitions/obsidian-status.resource.js.map +1 -0
  28. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts +13 -0
  29. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts.map +1 -0
  30. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js +30 -0
  31. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js.map +1 -0
  32. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.d.ts +21 -0
  33. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.d.ts.map +1 -0
  34. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.js +38 -0
  35. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.js.map +1 -0
  36. package/dist/mcp-server/tools/definitions/_shared/schemas.d.ts +45 -0
  37. package/dist/mcp-server/tools/definitions/_shared/schemas.d.ts.map +1 -0
  38. package/dist/mcp-server/tools/definitions/_shared/schemas.js +66 -0
  39. package/dist/mcp-server/tools/definitions/_shared/schemas.js.map +1 -0
  40. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts +51 -0
  41. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts.map +1 -0
  42. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js +120 -0
  43. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js.map +1 -0
  44. package/dist/mcp-server/tools/definitions/index.d.ts +582 -0
  45. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
  46. package/dist/mcp-server/tools/definitions/index.js +40 -0
  47. package/dist/mcp-server/tools/definitions/index.js.map +1 -0
  48. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts +42 -0
  49. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts.map +1 -0
  50. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js +58 -0
  51. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js.map +1 -0
  52. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts +46 -0
  53. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts.map +1 -0
  54. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js +66 -0
  55. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js.map +1 -0
  56. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.d.ts +19 -0
  57. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.d.ts.map +1 -0
  58. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.js +43 -0
  59. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.js.map +1 -0
  60. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts +92 -0
  61. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts.map +1 -0
  62. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js +245 -0
  63. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js.map +1 -0
  64. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.d.ts +13 -0
  65. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.d.ts.map +1 -0
  66. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js +38 -0
  67. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js.map +1 -0
  68. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts +59 -0
  69. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts.map +1 -0
  70. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js +273 -0
  71. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js.map +1 -0
  72. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts +13 -0
  73. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts.map +1 -0
  74. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js +38 -0
  75. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js.map +1 -0
  76. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts +68 -0
  77. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts.map +1 -0
  78. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js +178 -0
  79. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js.map +1 -0
  80. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts +77 -0
  81. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts.map +1 -0
  82. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js +172 -0
  83. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js.map +1 -0
  84. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts +22 -0
  85. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts.map +1 -0
  86. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js +88 -0
  87. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js.map +1 -0
  88. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts +81 -0
  89. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts.map +1 -0
  90. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js +83 -0
  91. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js.map +1 -0
  92. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts +59 -0
  93. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts.map +1 -0
  94. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js +167 -0
  95. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js.map +1 -0
  96. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +76 -0
  97. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -0
  98. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +244 -0
  99. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -0
  100. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts +48 -0
  101. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts.map +1 -0
  102. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js +100 -0
  103. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js.map +1 -0
  104. package/dist/services/obsidian/frontmatter-ops.d.ts +34 -0
  105. package/dist/services/obsidian/frontmatter-ops.d.ts.map +1 -0
  106. package/dist/services/obsidian/frontmatter-ops.js +230 -0
  107. package/dist/services/obsidian/frontmatter-ops.js.map +1 -0
  108. package/dist/services/obsidian/obsidian-service.d.ts +83 -0
  109. package/dist/services/obsidian/obsidian-service.d.ts.map +1 -0
  110. package/dist/services/obsidian/obsidian-service.js +435 -0
  111. package/dist/services/obsidian/obsidian-service.js.map +1 -0
  112. package/dist/services/obsidian/section-extractor.d.ts +13 -0
  113. package/dist/services/obsidian/section-extractor.d.ts.map +1 -0
  114. package/dist/services/obsidian/section-extractor.js +124 -0
  115. package/dist/services/obsidian/section-extractor.js.map +1 -0
  116. package/dist/services/obsidian/types.d.ts +91 -0
  117. package/dist/services/obsidian/types.d.ts.map +1 -0
  118. package/dist/services/obsidian/types.js +7 -0
  119. package/dist/services/obsidian/types.js.map +1 -0
  120. package/package.json +63 -69
  121. package/server.json +167 -0
  122. package/CHANGELOG.md +0 -124
  123. package/dist/config/index.d.ts +0 -41
  124. package/dist/config/index.js +0 -191
  125. package/dist/mcp-server/server.d.ts +0 -33
  126. package/dist/mcp-server/server.js +0 -211
  127. package/dist/mcp-server/tools/obsidianDeleteNoteTool/index.d.ts +0 -12
  128. package/dist/mcp-server/tools/obsidianDeleteNoteTool/index.js +0 -12
  129. package/dist/mcp-server/tools/obsidianDeleteNoteTool/logic.d.ts +0 -51
  130. package/dist/mcp-server/tools/obsidianDeleteNoteTool/logic.js +0 -168
  131. package/dist/mcp-server/tools/obsidianDeleteNoteTool/registration.d.ts +0 -19
  132. package/dist/mcp-server/tools/obsidianDeleteNoteTool/registration.js +0 -91
  133. package/dist/mcp-server/tools/obsidianGlobalSearchTool/index.d.ts +0 -12
  134. package/dist/mcp-server/tools/obsidianGlobalSearchTool/index.js +0 -12
  135. package/dist/mcp-server/tools/obsidianGlobalSearchTool/logic.d.ts +0 -77
  136. package/dist/mcp-server/tools/obsidianGlobalSearchTool/logic.js +0 -341
  137. package/dist/mcp-server/tools/obsidianGlobalSearchTool/registration.d.ts +0 -18
  138. package/dist/mcp-server/tools/obsidianGlobalSearchTool/registration.js +0 -69
  139. package/dist/mcp-server/tools/obsidianListNotesTool/index.d.ts +0 -12
  140. package/dist/mcp-server/tools/obsidianListNotesTool/index.js +0 -12
  141. package/dist/mcp-server/tools/obsidianListNotesTool/logic.d.ts +0 -68
  142. package/dist/mcp-server/tools/obsidianListNotesTool/logic.js +0 -215
  143. package/dist/mcp-server/tools/obsidianListNotesTool/registration.d.ts +0 -23
  144. package/dist/mcp-server/tools/obsidianListNotesTool/registration.js +0 -98
  145. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/index.d.ts +0 -3
  146. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/index.js +0 -2
  147. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/logic.d.ts +0 -42
  148. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/logic.js +0 -152
  149. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/registration.d.ts +0 -3
  150. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/registration.js +0 -52
  151. package/dist/mcp-server/tools/obsidianManageTagsTool/index.d.ts +0 -3
  152. package/dist/mcp-server/tools/obsidianManageTagsTool/index.js +0 -2
  153. package/dist/mcp-server/tools/obsidianManageTagsTool/logic.d.ts +0 -28
  154. package/dist/mcp-server/tools/obsidianManageTagsTool/logic.js +0 -161
  155. package/dist/mcp-server/tools/obsidianManageTagsTool/registration.d.ts +0 -3
  156. package/dist/mcp-server/tools/obsidianManageTagsTool/registration.js +0 -52
  157. package/dist/mcp-server/tools/obsidianReadNoteTool/index.d.ts +0 -12
  158. package/dist/mcp-server/tools/obsidianReadNoteTool/index.js +0 -12
  159. package/dist/mcp-server/tools/obsidianReadNoteTool/logic.d.ts +0 -87
  160. package/dist/mcp-server/tools/obsidianReadNoteTool/logic.js +0 -216
  161. package/dist/mcp-server/tools/obsidianReadNoteTool/registration.d.ts +0 -20
  162. package/dist/mcp-server/tools/obsidianReadNoteTool/registration.js +0 -101
  163. package/dist/mcp-server/tools/obsidianSearchReplaceTool/index.d.ts +0 -12
  164. package/dist/mcp-server/tools/obsidianSearchReplaceTool/index.js +0 -12
  165. package/dist/mcp-server/tools/obsidianSearchReplaceTool/logic.d.ts +0 -255
  166. package/dist/mcp-server/tools/obsidianSearchReplaceTool/logic.js +0 -583
  167. package/dist/mcp-server/tools/obsidianSearchReplaceTool/registration.d.ts +0 -22
  168. package/dist/mcp-server/tools/obsidianSearchReplaceTool/registration.js +0 -111
  169. package/dist/mcp-server/tools/obsidianUpdateNoteTool/index.d.ts +0 -12
  170. package/dist/mcp-server/tools/obsidianUpdateNoteTool/index.js +0 -12
  171. package/dist/mcp-server/tools/obsidianUpdateNoteTool/logic.d.ts +0 -183
  172. package/dist/mcp-server/tools/obsidianUpdateNoteTool/logic.js +0 -490
  173. package/dist/mcp-server/tools/obsidianUpdateNoteTool/registration.d.ts +0 -21
  174. package/dist/mcp-server/tools/obsidianUpdateNoteTool/registration.js +0 -108
  175. package/dist/mcp-server/transports/auth/core/authContext.d.ts +0 -33
  176. package/dist/mcp-server/transports/auth/core/authContext.js +0 -24
  177. package/dist/mcp-server/transports/auth/core/authTypes.d.ts +0 -17
  178. package/dist/mcp-server/transports/auth/core/authTypes.js +0 -5
  179. package/dist/mcp-server/transports/auth/core/authUtils.d.ts +0 -18
  180. package/dist/mcp-server/transports/auth/core/authUtils.js +0 -45
  181. package/dist/mcp-server/transports/auth/index.d.ts +0 -10
  182. package/dist/mcp-server/transports/auth/index.js +0 -9
  183. package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.d.ts +0 -27
  184. package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.js +0 -149
  185. package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.d.ts +0 -20
  186. package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.js +0 -124
  187. package/dist/mcp-server/transports/httpErrorHandler.d.ts +0 -26
  188. package/dist/mcp-server/transports/httpErrorHandler.js +0 -73
  189. package/dist/mcp-server/transports/httpTransport.d.ts +0 -21
  190. package/dist/mcp-server/transports/httpTransport.js +0 -208
  191. package/dist/mcp-server/transports/stdioTransport.d.ts +0 -42
  192. package/dist/mcp-server/transports/stdioTransport.js +0 -63
  193. package/dist/services/obsidianRestAPI/index.d.ts +0 -15
  194. package/dist/services/obsidianRestAPI/index.js +0 -17
  195. package/dist/services/obsidianRestAPI/methods/activeFileMethods.d.ts +0 -38
  196. package/dist/services/obsidianRestAPI/methods/activeFileMethods.js +0 -62
  197. package/dist/services/obsidianRestAPI/methods/commandMethods.d.ts +0 -22
  198. package/dist/services/obsidianRestAPI/methods/commandMethods.js +0 -31
  199. package/dist/services/obsidianRestAPI/methods/openMethods.d.ts +0 -16
  200. package/dist/services/obsidianRestAPI/methods/openMethods.js +0 -21
  201. package/dist/services/obsidianRestAPI/methods/patchMethods.d.ts +0 -37
  202. package/dist/services/obsidianRestAPI/methods/patchMethods.js +0 -94
  203. package/dist/services/obsidianRestAPI/methods/periodicNoteMethods.d.ts +0 -42
  204. package/dist/services/obsidianRestAPI/methods/periodicNoteMethods.js +0 -66
  205. package/dist/services/obsidianRestAPI/methods/searchMethods.d.ts +0 -25
  206. package/dist/services/obsidianRestAPI/methods/searchMethods.js +0 -36
  207. package/dist/services/obsidianRestAPI/methods/vaultMethods.d.ts +0 -58
  208. package/dist/services/obsidianRestAPI/methods/vaultMethods.js +0 -144
  209. package/dist/services/obsidianRestAPI/service.d.ts +0 -195
  210. package/dist/services/obsidianRestAPI/service.js +0 -379
  211. package/dist/services/obsidianRestAPI/types.d.ts +0 -127
  212. package/dist/services/obsidianRestAPI/types.js +0 -7
  213. package/dist/services/obsidianRestAPI/vaultCache/index.d.ts +0 -4
  214. package/dist/services/obsidianRestAPI/vaultCache/index.js +0 -4
  215. package/dist/services/obsidianRestAPI/vaultCache/service.d.ts +0 -88
  216. package/dist/services/obsidianRestAPI/vaultCache/service.js +0 -299
  217. package/dist/types-global/errors.d.ts +0 -73
  218. package/dist/types-global/errors.js +0 -71
  219. package/dist/utils/index.d.ts +0 -5
  220. package/dist/utils/index.js +0 -13
  221. package/dist/utils/internal/asyncUtils.d.ts +0 -54
  222. package/dist/utils/internal/asyncUtils.js +0 -101
  223. package/dist/utils/internal/errorHandler.d.ts +0 -176
  224. package/dist/utils/internal/errorHandler.js +0 -351
  225. package/dist/utils/internal/index.d.ts +0 -4
  226. package/dist/utils/internal/index.js +0 -4
  227. package/dist/utils/internal/logger.d.ts +0 -141
  228. package/dist/utils/internal/logger.js +0 -406
  229. package/dist/utils/internal/requestContext.d.ts +0 -83
  230. package/dist/utils/internal/requestContext.js +0 -72
  231. package/dist/utils/metrics/index.d.ts +0 -1
  232. package/dist/utils/metrics/index.js +0 -1
  233. package/dist/utils/metrics/tokenCounter.d.ts +0 -27
  234. package/dist/utils/metrics/tokenCounter.js +0 -128
  235. package/dist/utils/obsidian/index.d.ts +0 -5
  236. package/dist/utils/obsidian/index.js +0 -5
  237. package/dist/utils/obsidian/obsidianApiUtils.d.ts +0 -14
  238. package/dist/utils/obsidian/obsidianApiUtils.js +0 -29
  239. package/dist/utils/obsidian/obsidianStatUtils.d.ts +0 -68
  240. package/dist/utils/obsidian/obsidianStatUtils.js +0 -143
  241. package/dist/utils/parsing/dateParser.d.ts +0 -56
  242. package/dist/utils/parsing/dateParser.js +0 -104
  243. package/dist/utils/parsing/index.d.ts +0 -2
  244. package/dist/utils/parsing/index.js +0 -3
  245. package/dist/utils/parsing/jsonParser.d.ts +0 -80
  246. package/dist/utils/parsing/jsonParser.js +0 -133
  247. package/dist/utils/security/idGenerator.d.ts +0 -140
  248. package/dist/utils/security/idGenerator.js +0 -194
  249. package/dist/utils/security/index.d.ts +0 -3
  250. package/dist/utils/security/index.js +0 -3
  251. package/dist/utils/security/rateLimiter.d.ts +0 -156
  252. package/dist/utils/security/rateLimiter.js +0 -235
  253. package/dist/utils/security/sanitization.d.ts +0 -244
  254. package/dist/utils/security/sanitization.js +0 -599
@@ -1,161 +0,0 @@
1
- import { z } from "zod";
2
- import { dump } from "js-yaml";
3
- import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
4
- import { logger, retryWithDelay, } from "../../../utils/index.js";
5
- import { sanitization } from "../../../utils/security/sanitization.js";
6
- // ====================================================================================
7
- // Schema Definitions
8
- // ====================================================================================
9
- const ManageTagsInputSchemaBase = z.object({
10
- filePath: z
11
- .string()
12
- .min(1)
13
- .describe("The vault-relative path to the target note (e.g., 'Journal/2024-06-12.md')."),
14
- operation: z
15
- .enum(["add", "remove", "list"])
16
- .describe("The tag operation to perform: 'add' to include new tags, 'remove' to delete existing tags, or 'list' to view all current tags."),
17
- tags: z
18
- .array(z.string())
19
- .describe("An array of tag names to be processed. The '#' prefix should be omitted (e.g., use 'project/active', not '#project/active')."),
20
- });
21
- export const ObsidianManageTagsInputSchemaShape = ManageTagsInputSchemaBase.shape;
22
- export const ManageTagsInputSchema = ManageTagsInputSchemaBase;
23
- // ====================================================================================
24
- // Core Logic Function
25
- // ====================================================================================
26
- export const processObsidianManageTags = async (params, context, obsidianService, vaultCacheService) => {
27
- logger.debug(`Processing obsidian_manage_tags request`, {
28
- ...context,
29
- ...params,
30
- });
31
- const { filePath, operation, tags: inputTags } = params;
32
- const sanitizedTags = inputTags.map((t) => sanitization.sanitizeTagName(t));
33
- const shouldRetryNotFound = (err) => err instanceof McpError && err.code === BaseErrorCode.NOT_FOUND;
34
- const getFileWithRetry = async (opContext, format) => {
35
- return await retryWithDelay(() => obsidianService.getFileContent(filePath, format, opContext), {
36
- operationName: `getFileContentForTagManagement`,
37
- context: opContext,
38
- maxRetries: 3,
39
- delayMs: 300,
40
- shouldRetry: shouldRetryNotFound,
41
- });
42
- };
43
- const initialNote = (await getFileWithRetry(context, "json"));
44
- const currentTags = initialNote.tags;
45
- switch (operation) {
46
- case "list": {
47
- return {
48
- success: true,
49
- message: "Successfully listed all tags.",
50
- currentTags: currentTags,
51
- };
52
- }
53
- case "add": {
54
- const tagsToAdd = sanitizedTags.filter((t) => !currentTags.includes(t));
55
- if (tagsToAdd.length === 0) {
56
- return {
57
- success: true,
58
- message: "No new tags to add; all provided tags already exist in the note.",
59
- currentTags: currentTags,
60
- };
61
- }
62
- const frontmatter = initialNote.frontmatter ?? {};
63
- const frontmatterTags = Array.isArray(frontmatter.tags)
64
- ? frontmatter.tags
65
- : [];
66
- const newFrontmatterTags = [
67
- ...new Set([...frontmatterTags, ...tagsToAdd]),
68
- ];
69
- frontmatter.tags = newFrontmatterTags;
70
- const noteContent = (await getFileWithRetry(context, "markdown"));
71
- const frontmatterRegex = /^---\n([\s\S]*?)\n---\n/;
72
- const match = noteContent.match(frontmatterRegex);
73
- const newFrontmatterString = dump(frontmatter);
74
- let newContent;
75
- if (match) {
76
- newContent = noteContent.replace(frontmatterRegex, `---\n${newFrontmatterString}---\n`);
77
- }
78
- else {
79
- newContent = `---\n${newFrontmatterString}---\n\n${noteContent}`;
80
- }
81
- await retryWithDelay(() => obsidianService.updateFileContent(filePath, newContent, context), {
82
- operationName: `updateFileForTagAdd`,
83
- context,
84
- maxRetries: 3,
85
- delayMs: 300,
86
- shouldRetry: shouldRetryNotFound,
87
- });
88
- if (vaultCacheService) {
89
- await vaultCacheService.updateCacheForFile(filePath, context);
90
- }
91
- const finalTags = [...new Set([...currentTags, ...tagsToAdd])];
92
- return {
93
- success: true,
94
- message: `Successfully added tags: ${tagsToAdd.join(", ")}.`,
95
- currentTags: finalTags,
96
- };
97
- }
98
- case "remove": {
99
- const tagsToRemove = sanitizedTags.filter((t) => currentTags.includes(t));
100
- if (tagsToRemove.length === 0) {
101
- return {
102
- success: true,
103
- message: "No tags to remove; none of the provided tags exist in the note.",
104
- currentTags: currentTags,
105
- };
106
- }
107
- let noteContent = (await getFileWithRetry(context, "markdown"));
108
- const frontmatter = initialNote.frontmatter ?? {};
109
- let frontmatterTags = Array.isArray(frontmatter.tags)
110
- ? frontmatter.tags
111
- : [];
112
- const newFrontmatterTags = frontmatterTags.filter((t) => !tagsToRemove.includes(t));
113
- let frontmatterModified = newFrontmatterTags.length !== frontmatterTags.length;
114
- if (frontmatterModified) {
115
- frontmatter.tags = newFrontmatterTags;
116
- if (newFrontmatterTags.length === 0) {
117
- delete frontmatter.tags;
118
- }
119
- }
120
- const frontmatterRegex = /^---\n([\s\S]*?)\n---\n/;
121
- const match = noteContent.match(frontmatterRegex);
122
- if (frontmatterModified && match) {
123
- const newFrontmatterString = Object.keys(frontmatter).length > 0 ? dump(frontmatter) : "";
124
- if (newFrontmatterString) {
125
- noteContent = noteContent.replace(frontmatterRegex, `---\n${newFrontmatterString}---\n`);
126
- }
127
- else {
128
- noteContent = noteContent.replace(frontmatterRegex, "");
129
- }
130
- }
131
- let inlineModified = false;
132
- for (const tag of tagsToRemove) {
133
- const regex = new RegExp(`(^|[^\\w-#])#${tag}\\b`, "g");
134
- if (regex.test(noteContent)) {
135
- noteContent = noteContent.replace(regex, "$1");
136
- inlineModified = true;
137
- }
138
- }
139
- if (frontmatterModified || inlineModified) {
140
- await retryWithDelay(() => obsidianService.updateFileContent(filePath, noteContent, context), {
141
- operationName: `updateFileContentForTagRemove`,
142
- context,
143
- maxRetries: 3,
144
- delayMs: 300,
145
- shouldRetry: shouldRetryNotFound,
146
- });
147
- }
148
- if (vaultCacheService) {
149
- await vaultCacheService.updateCacheForFile(filePath, context);
150
- }
151
- const finalTags = currentTags.filter((t) => !tagsToRemove.includes(t));
152
- return {
153
- success: true,
154
- message: `Successfully removed tags: ${tagsToRemove.join(", ")}.`,
155
- currentTags: finalTags,
156
- };
157
- }
158
- default:
159
- throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Invalid operation: ${operation}`, context);
160
- }
161
- };
@@ -1,3 +0,0 @@
1
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { ObsidianRestApiService, VaultCacheService } from "../../../services/obsidianRestAPI/index.js";
3
- export declare const registerObsidianManageTagsTool: (server: McpServer, obsidianService: ObsidianRestApiService, vaultCacheService: VaultCacheService | undefined) => Promise<void>;
@@ -1,52 +0,0 @@
1
- import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
2
- import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js";
3
- import { ManageTagsInputSchema, ObsidianManageTagsInputSchemaShape, processObsidianManageTags, } from "./logic.js";
4
- export const registerObsidianManageTagsTool = async (server, obsidianService, vaultCacheService) => {
5
- const toolName = "obsidian_manage_tags";
6
- const toolDescription = "Manages tags for a specified note, handling them in both the YAML frontmatter and inline content. Supports adding, removing, and listing tags to provide a comprehensive tag management solution.";
7
- const registrationContext = requestContextService.createRequestContext({
8
- operation: "RegisterObsidianManageTagsTool",
9
- toolName: toolName,
10
- module: "ObsidianManageTagsRegistration",
11
- });
12
- logger.info(`Attempting to register tool: ${toolName}`, registrationContext);
13
- await ErrorHandler.tryCatch(async () => {
14
- server.tool(toolName, toolDescription, ObsidianManageTagsInputSchemaShape, async (params) => {
15
- const handlerContext = requestContextService.createRequestContext({
16
- parentContext: registrationContext,
17
- operation: "HandleObsidianManageTagsRequest",
18
- toolName: toolName,
19
- params: params,
20
- });
21
- logger.debug(`Handling '${toolName}' request`, handlerContext);
22
- return await ErrorHandler.tryCatch(async () => {
23
- const validatedParams = ManageTagsInputSchema.parse(params);
24
- const response = await processObsidianManageTags(validatedParams, handlerContext, obsidianService, vaultCacheService);
25
- logger.debug(`'${toolName}' processed successfully`, handlerContext);
26
- return {
27
- content: [
28
- {
29
- type: "text",
30
- text: JSON.stringify(response, null, 2),
31
- },
32
- ],
33
- isError: false,
34
- };
35
- }, {
36
- operation: `processing ${toolName} handler`,
37
- context: handlerContext,
38
- input: params,
39
- errorMapper: (error) => new McpError(error instanceof McpError
40
- ? error.code
41
- : BaseErrorCode.INTERNAL_ERROR, `Error processing ${toolName} tool: ${error instanceof Error ? error.message : "Unknown error"}`, { ...handlerContext }),
42
- });
43
- });
44
- logger.info(`Tool registered successfully: ${toolName}`, registrationContext);
45
- }, {
46
- operation: `registering tool ${toolName}`,
47
- context: registrationContext,
48
- errorCode: BaseErrorCode.INTERNAL_ERROR,
49
- errorMapper: (error) => new McpError(error instanceof McpError ? error.code : BaseErrorCode.INTERNAL_ERROR, `Failed to register tool '${toolName}': ${error instanceof Error ? error.message : "Unknown error"}`, { ...registrationContext }),
50
- critical: true,
51
- });
52
- };
@@ -1,12 +0,0 @@
1
- /**
2
- * @fileoverview Barrel file for the 'obsidian_read_note' MCP tool.
3
- *
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
- * from the './registration.js' module. This pattern simplifies imports for consumers
7
- * of the tool, allowing them to import necessary components from a single location.
8
- *
9
- * Consumers (like the main server setup) should import the registration function
10
- * from this file to integrate the tool into the MCP server instance.
11
- */
12
- export { registerObsidianReadNoteTool } from "./registration.js";
@@ -1,12 +0,0 @@
1
- /**
2
- * @fileoverview Barrel file for the 'obsidian_read_note' MCP tool.
3
- *
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
- * from the './registration.js' module. This pattern simplifies imports for consumers
7
- * of the tool, allowing them to import necessary components from a single location.
8
- *
9
- * Consumers (like the main server setup) should import the registration function
10
- * from this file to integrate the tool into the MCP server instance.
11
- */
12
- export { registerObsidianReadNoteTool } from "./registration.js";
@@ -1,87 +0,0 @@
1
- import { z } from "zod";
2
- import { NoteJson, ObsidianRestApiService } from "../../../services/obsidianRestAPI/index.js";
3
- import { RequestContext } from "../../../utils/index.js";
4
- /**
5
- * Zod schema for validating the input parameters of the 'obsidian_read_note' tool.
6
- */
7
- export declare const ObsidianReadNoteInputSchema: z.ZodObject<{
8
- /**
9
- * The vault-relative path to the target file (e.g., "Folder/My Note.md").
10
- * Must include the file extension. The tool first attempts a case-sensitive match.
11
- * If not found, it attempts a case-insensitive fallback search within the same directory.
12
- */
13
- filePath: z.ZodString;
14
- /**
15
- * Specifies the desired format for the returned content.
16
- * 'markdown' returns the raw file content as a string.
17
- * 'json' returns a structured NoteJson object containing content, parsed frontmatter, tags, and file metadata (stat).
18
- * Defaults to 'markdown'.
19
- */
20
- format: z.ZodOptional<z.ZodDefault<z.ZodEnum<["markdown", "json"]>>>;
21
- /**
22
- * If true and the requested format is 'markdown', includes formatted file statistics
23
- * (creation time, modification time, token count estimate) in the response's 'stat' field.
24
- * Defaults to false. This flag is ignored if the format is 'json', as stats are always included within the NoteJson object itself (and also added to the top-level 'stat' field in the response).
25
- */
26
- includeStat: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
27
- }, "strip", z.ZodTypeAny, {
28
- filePath: string;
29
- includeStat: boolean;
30
- format?: "markdown" | "json" | undefined;
31
- }, {
32
- filePath: string;
33
- format?: "markdown" | "json" | undefined;
34
- includeStat?: boolean | undefined;
35
- }>;
36
- /**
37
- * TypeScript type inferred from the input schema (`ObsidianReadNoteInputSchema`).
38
- * Represents the validated input parameters used within the core processing logic.
39
- */
40
- export type ObsidianReadNoteInput = z.infer<typeof ObsidianReadNoteInputSchema>;
41
- /**
42
- * Represents the structure of file statistics after formatting, including
43
- * human-readable timestamps and an estimated token count.
44
- */
45
- type FormattedStat = {
46
- /** Creation time formatted as a standard date-time string (e.g., "05:29:00 PM | 05-03-2025"). */
47
- createdTime: string;
48
- /** Last modified time formatted as a standard date-time string (e.g., "05:29:00 PM | 05-03-2025"). */
49
- modifiedTime: string;
50
- /** Estimated token count of the file content (using tiktoken 'gpt-4o'). */
51
- tokenCountEstimate: number;
52
- };
53
- /**
54
- * Defines the structure of the successful response returned by the `processObsidianReadNote` function.
55
- * This object is typically serialized to JSON and sent back to the client.
56
- */
57
- export interface ObsidianReadNoteResponse {
58
- /**
59
- * The content of the file in the requested format.
60
- * If format='markdown', this is a string.
61
- * If format='json', this is a NoteJson object (which also contains the content string and stats).
62
- */
63
- content: string | NoteJson;
64
- /**
65
- * Optional formatted file statistics.
66
- * Included if format='json', or if format='markdown' and includeStat=true.
67
- */
68
- stats?: FormattedStat;
69
- }
70
- /**
71
- * Processes the core logic for reading a file from the Obsidian vault.
72
- *
73
- * It attempts to read the file using the provided path (case-sensitive first,
74
- * then case-insensitive fallback). It always fetches the full NoteJson object
75
- * internally to access file statistics. Finally, it formats the response
76
- * according to the requested format ('markdown' or 'json') and the 'includeStat' flag.
77
- *
78
- * @param {ObsidianReadNoteInput} params - The validated input parameters.
79
- * @param {RequestContext} context - The request context for logging and correlation.
80
- * @param {ObsidianRestApiService} obsidianService - An instance of the Obsidian REST API service.
81
- * @returns {Promise<ObsidianReadNoteResponse>} A promise resolving to the structured success response
82
- * containing the file content and optionally formatted statistics.
83
- * @throws {McpError} Throws an McpError if the file cannot be found (even with fallback),
84
- * if there's an ambiguous fallback match, or if any other API interaction fails.
85
- */
86
- export declare const processObsidianReadNote: (params: ObsidianReadNoteInput, context: RequestContext, obsidianService: ObsidianRestApiService) => Promise<ObsidianReadNoteResponse>;
87
- export {};
@@ -1,216 +0,0 @@
1
- import path from "node:path"; // Using POSIX path functions for vault path manipulation
2
- import { z } from "zod";
3
- import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
4
- import { createFormattedStatWithTokenCount, logger, retryWithDelay, } from "../../../utils/index.js";
5
- // ====================================================================================
6
- // Schema Definitions for Input Validation
7
- // ====================================================================================
8
- /**
9
- * Defines the allowed formats for the returned file content.
10
- * - 'markdown': Returns the raw Markdown content as a string.
11
- * - 'json': Returns a structured NoteJson object including content, frontmatter, tags, and stats.
12
- */
13
- const ReadNoteFormatSchema = z
14
- .enum(["markdown", "json"])
15
- .default("markdown")
16
- .describe("Specifies the format for the returned content ('markdown' or 'json'). Defaults to 'markdown'.");
17
- /**
18
- * Zod schema for validating the input parameters of the 'obsidian_read_note' tool.
19
- */
20
- export const ObsidianReadNoteInputSchema = z
21
- .object({
22
- /**
23
- * The vault-relative path to the target file (e.g., "Folder/My Note.md").
24
- * Must include the file extension. The tool first attempts a case-sensitive match.
25
- * If not found, it attempts a case-insensitive fallback search within the same directory.
26
- */
27
- filePath: z
28
- .string()
29
- .min(1, "filePath cannot be empty")
30
- .describe('The vault-relative path to the target file (e.g., "developer/github/tips.md"). Tries case-sensitive first, then case-insensitive fallback.'),
31
- /**
32
- * Specifies the desired format for the returned content.
33
- * 'markdown' returns the raw file content as a string.
34
- * 'json' returns a structured NoteJson object containing content, parsed frontmatter, tags, and file metadata (stat).
35
- * Defaults to 'markdown'.
36
- */
37
- format: ReadNoteFormatSchema.optional() // Optional, defaults to 'markdown' via ReadNoteFormatSchema
38
- .describe("Format for the returned content ('markdown' or 'json'). Defaults to 'markdown'."),
39
- /**
40
- * If true and the requested format is 'markdown', includes formatted file statistics
41
- * (creation time, modification time, token count estimate) in the response's 'stat' field.
42
- * Defaults to false. This flag is ignored if the format is 'json', as stats are always included within the NoteJson object itself (and also added to the top-level 'stat' field in the response).
43
- */
44
- includeStat: z
45
- .boolean()
46
- .optional()
47
- .default(false)
48
- .describe("If true and format is 'markdown', includes file stats in the response. Defaults to false. Ignored if format is 'json'."),
49
- })
50
- .describe("Retrieves the content and optionally metadata of a specific file within the connected Obsidian vault. Supports case-insensitive path fallback.");
51
- // ====================================================================================
52
- // Core Logic Function
53
- // ====================================================================================
54
- /**
55
- * Processes the core logic for reading a file from the Obsidian vault.
56
- *
57
- * It attempts to read the file using the provided path (case-sensitive first,
58
- * then case-insensitive fallback). It always fetches the full NoteJson object
59
- * internally to access file statistics. Finally, it formats the response
60
- * according to the requested format ('markdown' or 'json') and the 'includeStat' flag.
61
- *
62
- * @param {ObsidianReadNoteInput} params - The validated input parameters.
63
- * @param {RequestContext} context - The request context for logging and correlation.
64
- * @param {ObsidianRestApiService} obsidianService - An instance of the Obsidian REST API service.
65
- * @returns {Promise<ObsidianReadNoteResponse>} A promise resolving to the structured success response
66
- * containing the file content and optionally formatted statistics.
67
- * @throws {McpError} Throws an McpError if the file cannot be found (even with fallback),
68
- * if there's an ambiguous fallback match, or if any other API interaction fails.
69
- */
70
- export const processObsidianReadNote = async (params, context, obsidianService) => {
71
- const { filePath: originalFilePath, format: requestedFormat, includeStat, } = params;
72
- let effectiveFilePath = originalFilePath; // Track the actual path used (might change during fallback)
73
- logger.debug(`Processing obsidian_read_note request for path: ${originalFilePath}`, { ...context, format: requestedFormat, includeStat });
74
- const shouldRetryNotFound = (err) => err instanceof McpError && err.code === BaseErrorCode.NOT_FOUND;
75
- try {
76
- let noteJson;
77
- // --- Step 1: Read File Content (always fetch JSON internally) ---
78
- const readContext = { ...context, operation: "readFileAsJson" };
79
- try {
80
- // Attempt 1: Read using the provided path (case-sensitive)
81
- logger.debug(`Attempting to read file as JSON (case-sensitive): ${originalFilePath}`, readContext);
82
- noteJson = await retryWithDelay(() => obsidianService.getFileContent(originalFilePath, "json", readContext), {
83
- operationName: "readFileWithRetry",
84
- context: readContext,
85
- maxRetries: 3,
86
- delayMs: 300,
87
- shouldRetry: shouldRetryNotFound,
88
- });
89
- effectiveFilePath = originalFilePath; // Confirm exact path worked
90
- logger.debug(`Successfully read file as JSON using exact path: ${originalFilePath}`, readContext);
91
- }
92
- catch (error) {
93
- // Attempt 2: Case-insensitive fallback if initial read failed with NOT_FOUND
94
- if (error instanceof McpError && error.code === BaseErrorCode.NOT_FOUND) {
95
- logger.info(`File not found with exact path: ${originalFilePath}. Attempting case-insensitive fallback.`, readContext);
96
- const fallbackContext = {
97
- ...readContext,
98
- subOperation: "caseInsensitiveFallback",
99
- };
100
- try {
101
- // Use POSIX path functions as vault paths are typically /-separated
102
- const dirname = path.posix.dirname(originalFilePath);
103
- const filenameLower = path.posix
104
- .basename(originalFilePath)
105
- .toLowerCase();
106
- // Handle case where the file is in the vault root (dirname is '.')
107
- const dirToList = dirname === "." ? "/" : dirname;
108
- logger.debug(`Listing directory for fallback: ${dirToList}`, fallbackContext);
109
- const filesInDir = await retryWithDelay(() => obsidianService.listFiles(dirToList, fallbackContext), {
110
- operationName: "listFilesForReadFallback",
111
- context: fallbackContext,
112
- maxRetries: 3,
113
- delayMs: 300,
114
- shouldRetry: shouldRetryNotFound,
115
- });
116
- // Filter directory listing for files matching the lowercase filename
117
- const matches = filesInDir.filter((f) => !f.endsWith("/") && // Ensure it's a file, not a directory entry ending in /
118
- path.posix.basename(f).toLowerCase() === filenameLower);
119
- if (matches.length === 1) {
120
- // Found exactly one case-insensitive match
121
- const correctFilename = path.posix.basename(matches[0]);
122
- effectiveFilePath = path.posix.join(dirname, correctFilename); // Construct the correct path
123
- logger.info(`Found case-insensitive match: ${effectiveFilePath}. Retrying read as JSON.`, fallbackContext);
124
- // Retry reading the file content using the corrected path
125
- noteJson = await retryWithDelay(() => obsidianService.getFileContent(effectiveFilePath, "json", fallbackContext), {
126
- operationName: "readFileWithFallbackRetry",
127
- context: fallbackContext,
128
- maxRetries: 3,
129
- delayMs: 300,
130
- shouldRetry: shouldRetryNotFound,
131
- });
132
- logger.debug(`Successfully read file as JSON using fallback path: ${effectiveFilePath}`, fallbackContext);
133
- }
134
- else if (matches.length > 1) {
135
- // Ambiguous match: Multiple files match case-insensitively
136
- logger.error(`Case-insensitive fallback failed: Multiple matches found for ${filenameLower} in ${dirToList}.`, { ...fallbackContext, matches });
137
- throw new McpError(BaseErrorCode.CONFLICT, // Use CONFLICT for ambiguity
138
- `File read failed: Ambiguous case-insensitive matches for '${originalFilePath}'. Found: [${matches.join(", ")}]`, fallbackContext);
139
- }
140
- else {
141
- // No match found even with fallback
142
- logger.error(`Case-insensitive fallback failed: No match found for ${filenameLower} in ${dirToList}.`, fallbackContext);
143
- throw new McpError(BaseErrorCode.NOT_FOUND, `File not found: '${originalFilePath}' (case-insensitive fallback also failed).`, fallbackContext);
144
- }
145
- }
146
- catch (fallbackError) {
147
- // Catch errors specifically from the fallback logic
148
- if (fallbackError instanceof McpError)
149
- throw fallbackError; // Re-throw known errors
150
- // Wrap unexpected fallback errors
151
- const errorMessage = `Unexpected error during case-insensitive fallback for ${originalFilePath}`;
152
- logger.error(errorMessage, fallbackError instanceof Error ? fallbackError : undefined, fallbackContext);
153
- throw new McpError(BaseErrorCode.INTERNAL_ERROR, `${errorMessage}: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`, fallbackContext);
154
- }
155
- }
156
- else {
157
- // Re-throw errors from the initial read attempt that were not NOT_FOUND
158
- throw error;
159
- }
160
- }
161
- // --- Step 2: Format the Response ---
162
- const formatContext = {
163
- ...context,
164
- operation: "formatResponse",
165
- effectiveFilePath,
166
- };
167
- logger.debug(`Formatting response. Requested format: ${requestedFormat}, Include stat: ${includeStat}`, formatContext);
168
- // Generate formatted statistics using the utility function.
169
- // Provide the content string for token counting. Handle cases where stat might be missing.
170
- const formattedStatResult = noteJson.stat
171
- ? await createFormattedStatWithTokenCount(noteJson.stat, noteJson.content ?? "", formatContext) // Await the async utility
172
- : undefined;
173
- // Ensure stat is undefined if the utility returned null (e.g., token counting failed)
174
- const formattedStat = formattedStatResult === null ? undefined : formattedStatResult;
175
- // Initialize the response object
176
- const response = {
177
- content: "", // Placeholder, will be set based on format
178
- // stat is added conditionally below
179
- };
180
- // Populate response based on requested format
181
- if (requestedFormat === "json") {
182
- // Return the full NoteJson object. Its internal 'stat' will remain numeric.
183
- // The formatted stats are provided in the top-level 'response.stats'.
184
- response.content = noteJson;
185
- response.stats = formattedStat; // Always include formatted stat at top level for JSON format
186
- logger.debug(`Response format set to JSON, including full NoteJson (with original numeric stat) and top-level formatted stat.`, formatContext);
187
- }
188
- else {
189
- // 'markdown' format
190
- response.content = noteJson.content ?? ""; // Extract the markdown content string
191
- if (includeStat && formattedStat) {
192
- response.stats = formattedStat; // Include formatted stats only if requested for markdown
193
- logger.debug(`Response format set to markdown, including formatted stat as requested.`, formatContext);
194
- }
195
- else {
196
- logger.debug(`Response format set to markdown, excluding stat (includeStat=${includeStat}).`, formatContext);
197
- }
198
- }
199
- logger.debug(`Successfully processed read request for ${effectiveFilePath}.`, context);
200
- return response;
201
- }
202
- catch (error) {
203
- // Catch any errors that propagated up (e.g., from initial read, fallback, or unexpected issues)
204
- if (error instanceof McpError) {
205
- // Log known McpErrors that reached this top level
206
- logger.error(`McpError during file read process for ${originalFilePath}: ${error.message}`, error, context);
207
- throw error; // Re-throw McpError
208
- }
209
- else {
210
- // Wrap unexpected errors in a generic McpError
211
- const errorMessage = `Unexpected error processing read request for ${originalFilePath}`;
212
- logger.error(errorMessage, error instanceof Error ? error : undefined, context);
213
- throw new McpError(BaseErrorCode.INTERNAL_ERROR, `${errorMessage}: ${error instanceof Error ? error.message : String(error)}`, context);
214
- }
215
- }
216
- };
@@ -1,20 +0,0 @@
1
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { ObsidianRestApiService } from "../../../services/obsidianRestAPI/index.js";
3
- /**
4
- * Registers the 'obsidian_read_note' tool with the MCP server.
5
- *
6
- * This tool retrieves the content and optionally metadata of a specified file
7
- * within the user's Obsidian vault. It supports specifying the output format
8
- * ('markdown' or 'json') and includes a case-insensitive fallback mechanism
9
- * if the exact file path is not found initially.
10
- *
11
- * The response is a JSON string containing the file content in the requested format
12
- * and optionally formatted file statistics (timestamps, token count).
13
- *
14
- * @param {McpServer} server - The MCP server instance to register the tool with.
15
- * @param {ObsidianRestApiService} obsidianService - An instance of the Obsidian REST API service
16
- * used to interact with the user's Obsidian vault.
17
- * @returns {Promise<void>} A promise that resolves when the tool registration is complete or rejects on error.
18
- * @throws {McpError} Throws an McpError if registration fails critically.
19
- */
20
- export declare const registerObsidianReadNoteTool: (server: McpServer, obsidianService: ObsidianRestApiService) => Promise<void>;