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
@@ -0,0 +1,244 @@
1
+ /**
2
+ * @fileoverview obsidian_search_notes — text/dataview/jsonlogic search.
3
+ * Caps results at 100 hits and surfaces an `excluded` indicator when more
4
+ * were returned upstream. Text-mode hits are additionally capped per file
5
+ * via `maxMatchesPerHit` so a single match-heavy note can't blow the
6
+ * response budget — clipped hits carry `truncated: true` and `totalMatches`.
7
+ * @module mcp-server/tools/definitions/obsidian-search-notes.tool
8
+ */
9
+ import { tool, z } from '@cyanheads/mcp-ts-core';
10
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
11
+ import { getObsidianService } from '../../../services/obsidian/obsidian-service.js';
12
+ const HIT_CAP = 100;
13
+ const DEFAULT_MATCHES_PER_HIT = 10;
14
+ const EXCLUSION_HINT = 'Narrow your query (add filters or more specific terms) to surface the rest.';
15
+ const TextHitSchema = z
16
+ .object({
17
+ filename: z.string().describe('Vault-relative path of the matching note.'),
18
+ score: z.number().optional().describe('Relevance score from the search index, when available.'),
19
+ matches: z
20
+ .array(z
21
+ .object({
22
+ context: z.string().describe('Surrounding text around the match.'),
23
+ match: z
24
+ .object({
25
+ start: z.number().describe('Match start offset in the surrounding context.'),
26
+ end: z.number().describe('Match end offset in the surrounding context.'),
27
+ })
28
+ .describe('Match offsets within the context window.'),
29
+ })
30
+ .describe('A single match within a file.'))
31
+ .describe('Per-match context windows. Capped per file by `maxMatchesPerHit`.'),
32
+ totalMatches: z
33
+ .number()
34
+ .optional()
35
+ .describe('Total matches in this file. Present only when `matches` was clipped to `maxMatchesPerHit`.'),
36
+ truncated: z
37
+ .boolean()
38
+ .optional()
39
+ .describe('True when `matches` was clipped to `maxMatchesPerHit`. Use `obsidian_get_note` to read the full file when more context is needed.'),
40
+ })
41
+ .describe('A file with one or more text-search matches.');
42
+ const StructuredHitSchema = z
43
+ .object({
44
+ filename: z.string().describe('Vault-relative path of the matching note.'),
45
+ result: z.unknown().describe('The query result for this file — shape determined by the query.'),
46
+ })
47
+ .describe('A file with a structured (Dataview/JSONLogic) result value.');
48
+ const ExcludedSchema = z
49
+ .object({
50
+ count: z.number().describe('Number of additional hits the upstream returned beyond the cap.'),
51
+ hint: z.string().describe('Suggestion for narrowing the query.'),
52
+ })
53
+ .optional();
54
+ export const obsidianSearchNotes = tool('obsidian_search_notes', {
55
+ description: `Search the vault. Modes:
56
+ - \`text\`: substring match with context windows. Pass \`query\` as a string and optionally \`pathPrefix\` to filter the returned filenames.
57
+ - \`dataview\`: a Dataview DQL query (\`TABLE …\`). Pass \`query\` as the DQL string. Use this for path/date/metadata filters; \`file.mtime\`, \`file.path\`, etc. are queryable.
58
+ - \`jsonlogic\`: a JSONLogic tree evaluated over each note's NoteJson. Pass \`logic\` as a JSON object. Available \`var\` paths: \`path\` (string), \`content\` (string), \`frontmatter.<key>\` (any), \`tags\` (string[]), \`stat.ctime\` / \`stat.mtime\` / \`stat.size\` (number). Custom operators include \`glob\` and \`regexp\`.
59
+
60
+ Results are capped at ${HIT_CAP} hits; an \`excluded\` indicator reports the overflow. Text-mode hits are additionally clipped to \`maxMatchesPerHit\` matches per file (default ${DEFAULT_MATCHES_PER_HIT}); when clipped, the hit carries \`truncated: true\` and \`totalMatches\`.`,
61
+ annotations: { readOnlyHint: true, idempotentHint: true },
62
+ input: z.object({
63
+ mode: z
64
+ .enum(['text', 'dataview', 'jsonlogic'])
65
+ .describe('Search algorithm and request body shape.'),
66
+ query: z
67
+ .string()
68
+ .optional()
69
+ .describe('For `text` mode: substring to match. For `dataview` mode: the DQL query string. Required for those modes.'),
70
+ logic: z
71
+ .record(z.string(), z.unknown())
72
+ .optional()
73
+ .describe('JSONLogic tree. Required and only used when `mode` is `"jsonlogic"`.'),
74
+ contextLength: z
75
+ .number()
76
+ .int()
77
+ .positive()
78
+ .optional()
79
+ .describe('Characters of context on each side of the match (text mode only). Default 100.'),
80
+ pathPrefix: z
81
+ .string()
82
+ .optional()
83
+ .describe('Filter returned filenames by prefix (text mode only, applied client-side).'),
84
+ maxMatchesPerHit: z
85
+ .number()
86
+ .int()
87
+ .positive()
88
+ .optional()
89
+ .describe(`Cap on match contexts returned per file in text mode. When clipped, the hit carries \`truncated: true\` and \`totalMatches\`. Default ${DEFAULT_MATCHES_PER_HIT}.`),
90
+ }),
91
+ output: z.object({
92
+ result: z
93
+ .discriminatedUnion('mode', [
94
+ z
95
+ .object({
96
+ mode: z.literal('text').describe('Echoed mode.'),
97
+ hits: z.array(TextHitSchema).describe('Matching files with per-match context.'),
98
+ excluded: ExcludedSchema.describe('Present when results were truncated to the cap.'),
99
+ })
100
+ .describe('Text-search results.'),
101
+ z
102
+ .object({
103
+ mode: z.literal('dataview').describe('Echoed mode.'),
104
+ hits: z
105
+ .array(StructuredHitSchema)
106
+ .describe('Matching files with the query result per file.'),
107
+ excluded: ExcludedSchema.describe('Present when results were truncated to the cap.'),
108
+ })
109
+ .describe('Dataview DQL results.'),
110
+ z
111
+ .object({
112
+ mode: z.literal('jsonlogic').describe('Echoed mode.'),
113
+ hits: z
114
+ .array(StructuredHitSchema)
115
+ .describe('Matching files with the JSONLogic result per file.'),
116
+ excluded: ExcludedSchema.describe('Present when results were truncated to the cap.'),
117
+ })
118
+ .describe('JSONLogic results.'),
119
+ ])
120
+ .describe('Mode-discriminated search payload.'),
121
+ }),
122
+ auth: ['tool:obsidian_search_notes:read'],
123
+ errors: [
124
+ {
125
+ reason: 'path_prefix_invalid_mode',
126
+ code: JsonRpcErrorCode.ValidationError,
127
+ when: '`pathPrefix` was provided in a non-text mode (only `text` supports prefix filtering).',
128
+ },
129
+ {
130
+ reason: 'query_required',
131
+ code: JsonRpcErrorCode.ValidationError,
132
+ when: '`query` is missing for `text` or `dataview` mode (required for both).',
133
+ },
134
+ {
135
+ reason: 'logic_required',
136
+ code: JsonRpcErrorCode.ValidationError,
137
+ when: '`logic` is missing for `jsonlogic` mode.',
138
+ },
139
+ ],
140
+ async handler(input, ctx) {
141
+ const svc = getObsidianService();
142
+ if (input.pathPrefix && input.mode !== 'text') {
143
+ throw ctx.fail('path_prefix_invalid_mode', '`pathPrefix` is only valid in text mode.', {
144
+ mode: input.mode,
145
+ });
146
+ }
147
+ if (input.mode === 'text') {
148
+ if (!input.query) {
149
+ throw ctx.fail('query_required', '`query` is required for text mode.', {
150
+ mode: input.mode,
151
+ });
152
+ }
153
+ const all = await svc.searchText(ctx, input.query, input.contextLength);
154
+ const prefix = input.pathPrefix;
155
+ const filtered = prefix ? all.filter((h) => h.filename.startsWith(prefix)) : all;
156
+ const matchCap = input.maxMatchesPerHit ?? DEFAULT_MATCHES_PER_HIT;
157
+ const clipped = filtered.map((h) => clipMatches(h, matchCap));
158
+ const capped = applyCap(clipped);
159
+ return { result: { mode: 'text', ...capped } };
160
+ }
161
+ if (input.mode === 'dataview') {
162
+ if (!input.query) {
163
+ throw ctx.fail('query_required', '`query` (DQL string) is required for dataview mode.', {
164
+ mode: input.mode,
165
+ });
166
+ }
167
+ const all = await svc.searchDataview(ctx, input.query);
168
+ const capped = applyCap(all);
169
+ return { result: { mode: 'dataview', ...capped } };
170
+ }
171
+ if (!input.logic) {
172
+ throw ctx.fail('logic_required', '`logic` (JSONLogic tree) is required for jsonlogic mode.', {
173
+ mode: input.mode,
174
+ });
175
+ }
176
+ const all = await svc.searchJsonLogic(ctx, input.logic);
177
+ const capped = applyCap(all);
178
+ return { result: { mode: 'jsonlogic', ...capped } };
179
+ },
180
+ format: ({ result }) => {
181
+ const lines = [`**Search (${result.mode}) — ${result.hits.length} hits**`];
182
+ if (result.excluded) {
183
+ lines.push(`_Excluded ${result.excluded.count} additional hits — ${result.excluded.hint}_`);
184
+ }
185
+ if (result.hits.length === 0) {
186
+ lines.push('', '_No matches. Try broader terms, a different mode, or check that the path/filter is correct._');
187
+ return [{ type: 'text', text: lines.join('\n') }];
188
+ }
189
+ lines.push('');
190
+ if (result.mode === 'text') {
191
+ for (const h of result.hits) {
192
+ const score = h.score !== undefined ? ` (score: ${h.score})` : '';
193
+ const trunc = h.truncated
194
+ ? ` — truncated, showing first ${h.matches.length} of ${h.totalMatches} matches`
195
+ : '';
196
+ lines.push(`### ${h.filename}${score}${trunc}`);
197
+ for (const m of h.matches) {
198
+ lines.push(`- match[${m.match.start}–${m.match.end}]: ${truncate(m.context, 240)}`);
199
+ }
200
+ }
201
+ }
202
+ else {
203
+ for (const h of result.hits) {
204
+ lines.push(`### ${h.filename}`);
205
+ lines.push('```json');
206
+ lines.push(safeJsonStringify(h.result));
207
+ lines.push('```');
208
+ }
209
+ }
210
+ return [{ type: 'text', text: lines.join('\n') }];
211
+ },
212
+ });
213
+ function applyCap(all) {
214
+ if (all.length <= HIT_CAP)
215
+ return { hits: all, excluded: undefined };
216
+ return {
217
+ hits: all.slice(0, HIT_CAP),
218
+ excluded: { count: all.length - HIT_CAP, hint: EXCLUSION_HINT },
219
+ };
220
+ }
221
+ function clipMatches(hit, cap) {
222
+ if (hit.matches.length <= cap)
223
+ return hit;
224
+ return {
225
+ ...hit,
226
+ matches: hit.matches.slice(0, cap),
227
+ truncated: true,
228
+ totalMatches: hit.matches.length,
229
+ };
230
+ }
231
+ function truncate(s, n) {
232
+ if (s.length <= n)
233
+ return s;
234
+ return `${s.slice(0, n)}…`;
235
+ }
236
+ function safeJsonStringify(v) {
237
+ try {
238
+ return JSON.stringify(v, null, 2);
239
+ }
240
+ catch {
241
+ return String(v);
242
+ }
243
+ }
244
+ //# sourceMappingURL=obsidian-search-notes.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"obsidian-search-notes.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-search-notes.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @fileoverview obsidian_write_note — create or overwrite a note (whole file)
3
+ * or replace a single section in place via PATCH-with-replace. Idempotent.
4
+ * @module mcp-server/tools/definitions/obsidian-write-note.tool
5
+ */
6
+ import { z } from '@cyanheads/mcp-ts-core';
7
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
8
+ export declare const obsidianWriteNote: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
9
+ target: z.ZodDiscriminatedUnion<[z.ZodObject<{
10
+ type: z.ZodLiteral<"path">;
11
+ path: z.ZodString;
12
+ }, z.core.$strip>, z.ZodObject<{
13
+ type: z.ZodLiteral<"active">;
14
+ }, z.core.$strip>, z.ZodObject<{
15
+ type: z.ZodLiteral<"periodic">;
16
+ period: z.ZodEnum<{
17
+ daily: "daily";
18
+ weekly: "weekly";
19
+ monthly: "monthly";
20
+ quarterly: "quarterly";
21
+ yearly: "yearly";
22
+ }>;
23
+ date: z.ZodOptional<z.ZodString>;
24
+ }, z.core.$strip>], "type">;
25
+ content: z.ZodString;
26
+ section: z.ZodOptional<z.ZodObject<{
27
+ type: z.ZodEnum<{
28
+ heading: "heading";
29
+ block: "block";
30
+ frontmatter: "frontmatter";
31
+ }>;
32
+ target: z.ZodString;
33
+ }, z.core.$strip>>;
34
+ contentType: z.ZodDefault<z.ZodEnum<{
35
+ markdown: "markdown";
36
+ json: "json";
37
+ }>>;
38
+ overwrite: z.ZodDefault<z.ZodBoolean>;
39
+ }, z.core.$strip>, z.ZodObject<{
40
+ path: z.ZodString;
41
+ sectionTargeted: z.ZodBoolean;
42
+ created: z.ZodBoolean;
43
+ }, z.core.$strip>, readonly [{
44
+ readonly reason: "file_exists";
45
+ readonly code: JsonRpcErrorCode.Conflict;
46
+ readonly when: "Whole-file write was attempted against an existing note and `overwrite` was not set to `true`.";
47
+ }]>;
48
+ //# sourceMappingURL=obsidian-write-note.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"obsidian-write-note.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-write-note.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwF5B,CAAC"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @fileoverview obsidian_write_note — create or overwrite a note (whole file)
3
+ * or replace a single section in place via PATCH-with-replace. Idempotent.
4
+ * @module mcp-server/tools/definitions/obsidian-write-note.tool
5
+ */
6
+ import { tool, z } from '@cyanheads/mcp-ts-core';
7
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
8
+ import { getObsidianService } from '../../../services/obsidian/obsidian-service.js';
9
+ import { ContentTypeSchema, SectionSchema, TargetSchema } from './_shared/schemas.js';
10
+ export const obsidianWriteNote = tool('obsidian_write_note', {
11
+ description: 'Create or overwrite a note. With `section` provided, replaces just that heading/block/frontmatter section in place; otherwise writes the whole file. Whole-file writes refuse to clobber an existing note unless `overwrite: true` is set — read the note first and prefer `obsidian_patch_note` / `obsidian_append_to_note` / `obsidian_replace_in_note` for in-place edits. For heading sections, `content` is the new body; the heading line itself is preserved automatically and a leading duplicate heading is stripped.',
12
+ annotations: { idempotentHint: true, destructiveHint: true },
13
+ input: z.object({
14
+ target: TargetSchema.describe('Where the note lives.'),
15
+ content: z
16
+ .string()
17
+ .describe('Body to write. For heading sections, the new section body — do not repeat the heading line (it stays in place). Markdown unless `contentType` is `json`.'),
18
+ section: SectionSchema.optional().describe('Optional sub-document target. When set, only this section is replaced; rest of the note is untouched.'),
19
+ contentType: ContentTypeSchema,
20
+ overwrite: z
21
+ .boolean()
22
+ .default(false)
23
+ .describe('Whole-file mode only (ignored when `section` is set). When `false` (default), the call fails with `file_exists` if the target note already exists — read it first and use `obsidian_patch_note` / `obsidian_append_to_note` / `obsidian_replace_in_note` for in-place edits, or retry with `overwrite: true` for a deliberate full replacement.'),
24
+ }),
25
+ output: z.object({
26
+ path: z.string().describe('Resolved vault-relative path of the note that was written.'),
27
+ sectionTargeted: z
28
+ .boolean()
29
+ .describe('True when only a section was replaced; false for full-file writes.'),
30
+ created: z
31
+ .boolean()
32
+ .describe('True when the write created a new file. False when it replaced an existing one or targeted a section.'),
33
+ }),
34
+ auth: ['tool:obsidian_write_note:write'],
35
+ errors: [
36
+ {
37
+ reason: 'file_exists',
38
+ code: JsonRpcErrorCode.Conflict,
39
+ when: 'Whole-file write was attempted against an existing note and `overwrite` was not set to `true`.',
40
+ },
41
+ ],
42
+ async handler(input, ctx) {
43
+ const svc = getObsidianService();
44
+ const { target } = input;
45
+ if (input.section) {
46
+ const body = input.section.type === 'heading'
47
+ ? stripLeadingHeading(input.content, input.section.target)
48
+ : input.content;
49
+ await svc.patchNote(ctx, target, body, {
50
+ operation: 'replace',
51
+ targetType: input.section.type,
52
+ target: input.section.target,
53
+ targetDelimiter: input.section.type === 'heading' ? '::' : undefined,
54
+ contentType: input.contentType,
55
+ applyIfContentPreexists: true,
56
+ });
57
+ const path = await svc.resolvePath(ctx, target);
58
+ return { path, sectionTargeted: true, created: false };
59
+ }
60
+ const exists = await svc.noteExists(ctx, target);
61
+ if (exists && !input.overwrite) {
62
+ const path = await svc.resolvePath(ctx, target);
63
+ throw ctx.fail('file_exists', `Note '${path}' already exists. To modify it in place, use \`obsidian_patch_note\` (surgical section edits), \`obsidian_append_to_note\` (append content), or \`obsidian_replace_in_note\` (search-and-replace). To replace the entire file, retry with \`overwrite: true\`.`, { path });
64
+ }
65
+ await svc.writeNote(ctx, target, input.content, input.contentType);
66
+ const path = await svc.resolvePath(ctx, target);
67
+ return { path, sectionTargeted: false, created: !exists };
68
+ },
69
+ format: (result) => [
70
+ {
71
+ type: 'text',
72
+ text: [
73
+ `**${result.created ? 'Created' : 'Wrote'} ${result.path}**`,
74
+ `*Section targeted:* ${result.sectionTargeted}`,
75
+ `*Created:* ${result.created}`,
76
+ ].join('\n'),
77
+ },
78
+ ],
79
+ });
80
+ /**
81
+ * If `content` opens with a markdown heading whose text matches the leaf of
82
+ * `headingTarget` (delimited by `::`), drop that heading line plus a single
83
+ * blank line. Upstream PATCH-replace operates on the section *body*, so a
84
+ * caller-supplied heading line would otherwise be embedded as a duplicate.
85
+ */
86
+ function stripLeadingHeading(content, headingTarget) {
87
+ const leaf = headingTarget.split('::').pop()?.trim();
88
+ if (!leaf)
89
+ return content;
90
+ const lines = content.split('\n');
91
+ const first = lines[0]?.trimEnd() ?? '';
92
+ const m = /^(#{1,6})\s+(.+)$/.exec(first);
93
+ if (!m || m[2]?.trim() !== leaf)
94
+ return content;
95
+ lines.shift();
96
+ if (lines[0]?.trim() === '')
97
+ lines.shift();
98
+ return lines.join('\n');
99
+ }
100
+ //# sourceMappingURL=obsidian-write-note.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"obsidian-write-note.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-write-note.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @fileoverview Read-modify-write helpers for the YAML frontmatter block of a
3
+ * note's raw content. Used by the composed manage-frontmatter / manage-tags
4
+ * tools when the upstream Local REST API has no single-call equivalent.
5
+ * @module services/obsidian/frontmatter-ops
6
+ */
7
+ /**
8
+ * Returns the full file content with `key` removed from the frontmatter.
9
+ * If the file has no frontmatter or the key isn't present, returns content
10
+ * unchanged.
11
+ */
12
+ export declare function deleteFrontmatterKey(content: string, key: string): string;
13
+ export interface TagReconcileResult {
14
+ /** Tags actually changed (added/removed) at one or more locations. */
15
+ applied: string[];
16
+ /** Updated content with the requested tag mutations applied. */
17
+ content: string;
18
+ /** Tags that were already in the desired state at the targeted location(s). */
19
+ skipped: string[];
20
+ }
21
+ export type TagOperation = 'add' | 'remove';
22
+ export type TagLocation = 'frontmatter' | 'inline' | 'both';
23
+ /**
24
+ * Add or remove tags across frontmatter (`tags:` array) and inline `#tag`
25
+ * syntax. Inline occurrences inside fenced code blocks are left alone — they
26
+ * are code, not tags.
27
+ */
28
+ export declare function reconcileTags(content: string, tags: string[], operation: TagOperation, location: TagLocation): TagReconcileResult;
29
+ /** Read-only helpers for `obsidian_manage_tags list`. */
30
+ export declare function listTagsFromContent(content: string, frontmatter: Record<string, unknown>): {
31
+ frontmatter: string[];
32
+ inline: string[];
33
+ };
34
+ //# sourceMappingURL=frontmatter-ops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter-ops.d.ts","sourceRoot":"","sources":["../../../src/services/obsidian/frontmatter-ops.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqCH;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAOzE;AAED,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,CAAC;AAC5C,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,EAAE,YAAY,EACvB,QAAQ,EAAE,WAAW,GACpB,kBAAkB,CAqBpB;AA6JD,yDAAyD;AACzD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC;IACD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAkBA"}