obsidian-mcp-server 2.0.6 → 3.0.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 (253) 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/template.md +51 -0
  7. package/dist/config/server-config.d.ts +19 -0
  8. package/dist/config/server-config.d.ts.map +1 -0
  9. package/dist/config/server-config.js +55 -0
  10. package/dist/config/server-config.js.map +1 -0
  11. package/dist/index.d.ts +7 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +23 -295
  14. package/dist/index.js.map +1 -0
  15. package/dist/mcp-server/prompts/definitions/index.d.ts +8 -0
  16. package/dist/mcp-server/prompts/definitions/index.d.ts.map +1 -0
  17. package/dist/mcp-server/prompts/definitions/index.js +8 -0
  18. package/dist/mcp-server/prompts/definitions/index.js.map +1 -0
  19. package/dist/mcp-server/resources/definitions/index.d.ts +36 -0
  20. package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -0
  21. package/dist/mcp-server/resources/definitions/index.js +9 -0
  22. package/dist/mcp-server/resources/definitions/index.js.map +1 -0
  23. package/dist/mcp-server/resources/definitions/obsidian-status.resource.d.ts +23 -0
  24. package/dist/mcp-server/resources/definitions/obsidian-status.resource.d.ts.map +1 -0
  25. package/dist/mcp-server/resources/definitions/obsidian-status.resource.js +47 -0
  26. package/dist/mcp-server/resources/definitions/obsidian-status.resource.js.map +1 -0
  27. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts +13 -0
  28. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts.map +1 -0
  29. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js +30 -0
  30. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js.map +1 -0
  31. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.d.ts +21 -0
  32. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.d.ts.map +1 -0
  33. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.js +38 -0
  34. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.js.map +1 -0
  35. package/dist/mcp-server/tools/definitions/_shared/schemas.d.ts +45 -0
  36. package/dist/mcp-server/tools/definitions/_shared/schemas.d.ts.map +1 -0
  37. package/dist/mcp-server/tools/definitions/_shared/schemas.js +66 -0
  38. package/dist/mcp-server/tools/definitions/_shared/schemas.js.map +1 -0
  39. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts +51 -0
  40. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts.map +1 -0
  41. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js +120 -0
  42. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js.map +1 -0
  43. package/dist/mcp-server/tools/definitions/index.d.ts +531 -0
  44. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
  45. package/dist/mcp-server/tools/definitions/index.js +38 -0
  46. package/dist/mcp-server/tools/definitions/index.js.map +1 -0
  47. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts +42 -0
  48. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts.map +1 -0
  49. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js +58 -0
  50. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js.map +1 -0
  51. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts +46 -0
  52. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts.map +1 -0
  53. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js +66 -0
  54. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js.map +1 -0
  55. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.d.ts +19 -0
  56. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.d.ts.map +1 -0
  57. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.js +43 -0
  58. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.js.map +1 -0
  59. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts +92 -0
  60. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts.map +1 -0
  61. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js +245 -0
  62. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js.map +1 -0
  63. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.d.ts +13 -0
  64. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.d.ts.map +1 -0
  65. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js +38 -0
  66. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js.map +1 -0
  67. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts +59 -0
  68. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts.map +1 -0
  69. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js +273 -0
  70. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js.map +1 -0
  71. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts +13 -0
  72. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts.map +1 -0
  73. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js +38 -0
  74. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js.map +1 -0
  75. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts +68 -0
  76. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts.map +1 -0
  77. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js +178 -0
  78. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js.map +1 -0
  79. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts +77 -0
  80. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts.map +1 -0
  81. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js +172 -0
  82. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js.map +1 -0
  83. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts +22 -0
  84. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts.map +1 -0
  85. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js +88 -0
  86. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js.map +1 -0
  87. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts +81 -0
  88. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts.map +1 -0
  89. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js +83 -0
  90. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js.map +1 -0
  91. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts +59 -0
  92. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts.map +1 -0
  93. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js +167 -0
  94. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js.map +1 -0
  95. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +76 -0
  96. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -0
  97. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +244 -0
  98. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -0
  99. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts +41 -0
  100. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts.map +1 -0
  101. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js +76 -0
  102. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js.map +1 -0
  103. package/dist/services/obsidian/frontmatter-ops.d.ts +34 -0
  104. package/dist/services/obsidian/frontmatter-ops.d.ts.map +1 -0
  105. package/dist/services/obsidian/frontmatter-ops.js +230 -0
  106. package/dist/services/obsidian/frontmatter-ops.js.map +1 -0
  107. package/dist/services/obsidian/obsidian-service.d.ts +73 -0
  108. package/dist/services/obsidian/obsidian-service.d.ts.map +1 -0
  109. package/dist/services/obsidian/obsidian-service.js +399 -0
  110. package/dist/services/obsidian/obsidian-service.js.map +1 -0
  111. package/dist/services/obsidian/section-extractor.d.ts +13 -0
  112. package/dist/services/obsidian/section-extractor.d.ts.map +1 -0
  113. package/dist/services/obsidian/section-extractor.js +124 -0
  114. package/dist/services/obsidian/section-extractor.js.map +1 -0
  115. package/dist/services/obsidian/types.d.ts +91 -0
  116. package/dist/services/obsidian/types.d.ts.map +1 -0
  117. package/dist/services/obsidian/types.js +7 -0
  118. package/dist/services/obsidian/types.js.map +1 -0
  119. package/package.json +63 -69
  120. package/server.json +167 -0
  121. package/CHANGELOG.md +0 -118
  122. package/dist/config/index.d.ts +0 -41
  123. package/dist/config/index.js +0 -191
  124. package/dist/mcp-server/server.d.ts +0 -33
  125. package/dist/mcp-server/server.js +0 -211
  126. package/dist/mcp-server/tools/obsidianDeleteNoteTool/index.d.ts +0 -12
  127. package/dist/mcp-server/tools/obsidianDeleteNoteTool/index.js +0 -12
  128. package/dist/mcp-server/tools/obsidianDeleteNoteTool/logic.d.ts +0 -51
  129. package/dist/mcp-server/tools/obsidianDeleteNoteTool/logic.js +0 -168
  130. package/dist/mcp-server/tools/obsidianDeleteNoteTool/registration.d.ts +0 -19
  131. package/dist/mcp-server/tools/obsidianDeleteNoteTool/registration.js +0 -91
  132. package/dist/mcp-server/tools/obsidianGlobalSearchTool/index.d.ts +0 -12
  133. package/dist/mcp-server/tools/obsidianGlobalSearchTool/index.js +0 -12
  134. package/dist/mcp-server/tools/obsidianGlobalSearchTool/logic.d.ts +0 -77
  135. package/dist/mcp-server/tools/obsidianGlobalSearchTool/logic.js +0 -341
  136. package/dist/mcp-server/tools/obsidianGlobalSearchTool/registration.d.ts +0 -18
  137. package/dist/mcp-server/tools/obsidianGlobalSearchTool/registration.js +0 -69
  138. package/dist/mcp-server/tools/obsidianListNotesTool/index.d.ts +0 -12
  139. package/dist/mcp-server/tools/obsidianListNotesTool/index.js +0 -12
  140. package/dist/mcp-server/tools/obsidianListNotesTool/logic.d.ts +0 -68
  141. package/dist/mcp-server/tools/obsidianListNotesTool/logic.js +0 -215
  142. package/dist/mcp-server/tools/obsidianListNotesTool/registration.d.ts +0 -23
  143. package/dist/mcp-server/tools/obsidianListNotesTool/registration.js +0 -98
  144. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/index.d.ts +0 -3
  145. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/index.js +0 -2
  146. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/logic.d.ts +0 -42
  147. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/logic.js +0 -152
  148. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/registration.d.ts +0 -3
  149. package/dist/mcp-server/tools/obsidianManageFrontmatterTool/registration.js +0 -52
  150. package/dist/mcp-server/tools/obsidianManageTagsTool/index.d.ts +0 -3
  151. package/dist/mcp-server/tools/obsidianManageTagsTool/index.js +0 -2
  152. package/dist/mcp-server/tools/obsidianManageTagsTool/logic.d.ts +0 -28
  153. package/dist/mcp-server/tools/obsidianManageTagsTool/logic.js +0 -161
  154. package/dist/mcp-server/tools/obsidianManageTagsTool/registration.d.ts +0 -3
  155. package/dist/mcp-server/tools/obsidianManageTagsTool/registration.js +0 -52
  156. package/dist/mcp-server/tools/obsidianReadNoteTool/index.d.ts +0 -12
  157. package/dist/mcp-server/tools/obsidianReadNoteTool/index.js +0 -12
  158. package/dist/mcp-server/tools/obsidianReadNoteTool/logic.d.ts +0 -87
  159. package/dist/mcp-server/tools/obsidianReadNoteTool/logic.js +0 -216
  160. package/dist/mcp-server/tools/obsidianReadNoteTool/registration.d.ts +0 -20
  161. package/dist/mcp-server/tools/obsidianReadNoteTool/registration.js +0 -101
  162. package/dist/mcp-server/tools/obsidianSearchReplaceTool/index.d.ts +0 -12
  163. package/dist/mcp-server/tools/obsidianSearchReplaceTool/index.js +0 -12
  164. package/dist/mcp-server/tools/obsidianSearchReplaceTool/logic.d.ts +0 -255
  165. package/dist/mcp-server/tools/obsidianSearchReplaceTool/logic.js +0 -583
  166. package/dist/mcp-server/tools/obsidianSearchReplaceTool/registration.d.ts +0 -22
  167. package/dist/mcp-server/tools/obsidianSearchReplaceTool/registration.js +0 -111
  168. package/dist/mcp-server/tools/obsidianUpdateNoteTool/index.d.ts +0 -12
  169. package/dist/mcp-server/tools/obsidianUpdateNoteTool/index.js +0 -12
  170. package/dist/mcp-server/tools/obsidianUpdateNoteTool/logic.d.ts +0 -183
  171. package/dist/mcp-server/tools/obsidianUpdateNoteTool/logic.js +0 -490
  172. package/dist/mcp-server/tools/obsidianUpdateNoteTool/registration.d.ts +0 -21
  173. package/dist/mcp-server/tools/obsidianUpdateNoteTool/registration.js +0 -108
  174. package/dist/mcp-server/transports/auth/core/authContext.d.ts +0 -33
  175. package/dist/mcp-server/transports/auth/core/authContext.js +0 -24
  176. package/dist/mcp-server/transports/auth/core/authTypes.d.ts +0 -17
  177. package/dist/mcp-server/transports/auth/core/authTypes.js +0 -5
  178. package/dist/mcp-server/transports/auth/core/authUtils.d.ts +0 -18
  179. package/dist/mcp-server/transports/auth/core/authUtils.js +0 -45
  180. package/dist/mcp-server/transports/auth/index.d.ts +0 -10
  181. package/dist/mcp-server/transports/auth/index.js +0 -9
  182. package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.d.ts +0 -27
  183. package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.js +0 -149
  184. package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.d.ts +0 -20
  185. package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.js +0 -124
  186. package/dist/mcp-server/transports/httpErrorHandler.d.ts +0 -26
  187. package/dist/mcp-server/transports/httpErrorHandler.js +0 -73
  188. package/dist/mcp-server/transports/httpTransport.d.ts +0 -21
  189. package/dist/mcp-server/transports/httpTransport.js +0 -208
  190. package/dist/mcp-server/transports/stdioTransport.d.ts +0 -42
  191. package/dist/mcp-server/transports/stdioTransport.js +0 -63
  192. package/dist/services/obsidianRestAPI/index.d.ts +0 -15
  193. package/dist/services/obsidianRestAPI/index.js +0 -17
  194. package/dist/services/obsidianRestAPI/methods/activeFileMethods.d.ts +0 -38
  195. package/dist/services/obsidianRestAPI/methods/activeFileMethods.js +0 -62
  196. package/dist/services/obsidianRestAPI/methods/commandMethods.d.ts +0 -22
  197. package/dist/services/obsidianRestAPI/methods/commandMethods.js +0 -31
  198. package/dist/services/obsidianRestAPI/methods/openMethods.d.ts +0 -16
  199. package/dist/services/obsidianRestAPI/methods/openMethods.js +0 -21
  200. package/dist/services/obsidianRestAPI/methods/patchMethods.d.ts +0 -37
  201. package/dist/services/obsidianRestAPI/methods/patchMethods.js +0 -94
  202. package/dist/services/obsidianRestAPI/methods/periodicNoteMethods.d.ts +0 -42
  203. package/dist/services/obsidianRestAPI/methods/periodicNoteMethods.js +0 -66
  204. package/dist/services/obsidianRestAPI/methods/searchMethods.d.ts +0 -25
  205. package/dist/services/obsidianRestAPI/methods/searchMethods.js +0 -36
  206. package/dist/services/obsidianRestAPI/methods/vaultMethods.d.ts +0 -58
  207. package/dist/services/obsidianRestAPI/methods/vaultMethods.js +0 -144
  208. package/dist/services/obsidianRestAPI/service.d.ts +0 -195
  209. package/dist/services/obsidianRestAPI/service.js +0 -379
  210. package/dist/services/obsidianRestAPI/types.d.ts +0 -127
  211. package/dist/services/obsidianRestAPI/types.js +0 -7
  212. package/dist/services/obsidianRestAPI/vaultCache/index.d.ts +0 -4
  213. package/dist/services/obsidianRestAPI/vaultCache/index.js +0 -4
  214. package/dist/services/obsidianRestAPI/vaultCache/service.d.ts +0 -88
  215. package/dist/services/obsidianRestAPI/vaultCache/service.js +0 -299
  216. package/dist/types-global/errors.d.ts +0 -73
  217. package/dist/types-global/errors.js +0 -71
  218. package/dist/utils/index.d.ts +0 -5
  219. package/dist/utils/index.js +0 -13
  220. package/dist/utils/internal/asyncUtils.d.ts +0 -54
  221. package/dist/utils/internal/asyncUtils.js +0 -101
  222. package/dist/utils/internal/errorHandler.d.ts +0 -176
  223. package/dist/utils/internal/errorHandler.js +0 -351
  224. package/dist/utils/internal/index.d.ts +0 -4
  225. package/dist/utils/internal/index.js +0 -4
  226. package/dist/utils/internal/logger.d.ts +0 -141
  227. package/dist/utils/internal/logger.js +0 -406
  228. package/dist/utils/internal/requestContext.d.ts +0 -83
  229. package/dist/utils/internal/requestContext.js +0 -72
  230. package/dist/utils/metrics/index.d.ts +0 -1
  231. package/dist/utils/metrics/index.js +0 -1
  232. package/dist/utils/metrics/tokenCounter.d.ts +0 -27
  233. package/dist/utils/metrics/tokenCounter.js +0 -128
  234. package/dist/utils/obsidian/index.d.ts +0 -5
  235. package/dist/utils/obsidian/index.js +0 -5
  236. package/dist/utils/obsidian/obsidianApiUtils.d.ts +0 -14
  237. package/dist/utils/obsidian/obsidianApiUtils.js +0 -29
  238. package/dist/utils/obsidian/obsidianStatUtils.d.ts +0 -68
  239. package/dist/utils/obsidian/obsidianStatUtils.js +0 -143
  240. package/dist/utils/parsing/dateParser.d.ts +0 -56
  241. package/dist/utils/parsing/dateParser.js +0 -104
  242. package/dist/utils/parsing/index.d.ts +0 -2
  243. package/dist/utils/parsing/index.js +0 -3
  244. package/dist/utils/parsing/jsonParser.d.ts +0 -80
  245. package/dist/utils/parsing/jsonParser.js +0 -133
  246. package/dist/utils/security/idGenerator.d.ts +0 -140
  247. package/dist/utils/security/idGenerator.js +0 -194
  248. package/dist/utils/security/index.d.ts +0 -3
  249. package/dist/utils/security/index.js +0 -3
  250. package/dist/utils/security/rateLimiter.d.ts +0 -156
  251. package/dist/utils/security/rateLimiter.js +0 -235
  252. package/dist/utils/security/sanitization.d.ts +0 -244
  253. package/dist/utils/security/sanitization.js +0 -599
package/CLAUDE.md ADDED
@@ -0,0 +1,364 @@
1
+ # Agent Protocol
2
+
3
+ **Server:** obsidian-mcp-server
4
+ **Version:** 3.0.0
5
+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)
6
+
7
+ > **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
8
+
9
+ ---
10
+
11
+ ## What's Next?
12
+
13
+ When the user asks what to do next, what's left, or needs direction, suggest relevant options based on the current project state:
14
+
15
+ 1. **Re-run the `setup` skill** — ensures CLAUDE.md, skills, structure, and metadata are populated and up to date with the current codebase
16
+ 2. **Run the `design-mcp-server` skill** — if the tool/resource surface hasn't been mapped yet, work through domain design
17
+ 3. **Add tools/resources/prompts** — scaffold new definitions using the `add-tool`, `add-app-tool`, `add-resource`, `add-prompt` skills
18
+ 4. **Add services** — scaffold domain service integrations using the `add-service` skill
19
+ 5. **Add tests** — scaffold tests for existing definitions using the `add-test` skill
20
+ 6. **Field-test definitions** — exercise tools/resources/prompts with real inputs using the `field-test` skill, get a report of issues and pain points
21
+ 7. **Run `devcheck`** — lint, format, typecheck, and security audit
22
+ 8. **Run the `security-pass` skill** — audit handlers for MCP-specific security gaps: output injection, scope blast radius, input sinks, tenant isolation
23
+ 9. **Run the `polish-docs-meta` skill** — finalize README, CHANGELOG, metadata, and agent protocol for shipping
24
+ 10. **Run the `maintenance` skill** — investigate changelogs, adopt upstream changes, and sync skills after `bun update --latest`
25
+
26
+ Tailor suggestions to what's actually missing or stale — don't recite the full list every time.
27
+
28
+ ---
29
+
30
+ ## Core Rules
31
+
32
+ - **Logic throws, framework catches.** Tool/resource handlers are pure — throw on failure, no `try/catch`. Plain `Error` is fine; the framework catches, classifies, and formats. Use error factories (`notFound()`, `validationError()`, etc.) when the error code matters.
33
+ - **Use `ctx.log`** for request-scoped logging. No `console` calls.
34
+ - **Check `ctx.elicit`** for presence before calling — used by `obsidian_delete_note` to confirm destructive ops.
35
+ - **All Obsidian access goes through `getObsidianService()`.** No direct `fetch()` calls to the Local REST API in tools/resources — the service centralizes auth, TLS, timeouts, and `ctx.signal` propagation.
36
+ - **Secrets in env vars only.** `OBSIDIAN_API_KEY` is required; never hardcoded.
37
+ - **`obsidian_execute_command` is opt-in.** Registered only when `OBSIDIAN_ENABLE_COMMANDS=true` — Obsidian commands are opaque and can be destructive.
38
+
39
+ ---
40
+
41
+ ## Patterns
42
+
43
+ ### Tool — `obsidian_list_tags`
44
+
45
+ A small read-only tool that wraps a single upstream endpoint, normalizes the response into the output schema, and renders a markdown twin in `format()`.
46
+
47
+ ```ts
48
+ import { tool, z } from '@cyanheads/mcp-ts-core';
49
+ import { getObsidianService } from '@/services/obsidian/obsidian-service.js';
50
+
51
+ export const obsidianListTags = tool('obsidian_list_tags', {
52
+ description:
53
+ 'List every tag found across the vault, with usage counts. Includes hierarchical parents — `work/tasks` contributes to both `work` and `work/tasks`.',
54
+ annotations: { readOnlyHint: true, idempotentHint: true },
55
+ input: z.object({}),
56
+ output: z.object({
57
+ tags: z
58
+ .array(
59
+ z.object({
60
+ name: z.string().describe('Tag name without the leading `#`.'),
61
+ count: z.number().describe('Usage count across the vault.'),
62
+ }).describe('A tag with its usage count.'),
63
+ )
64
+ .describe('All tags in the vault, in upstream-provided order.'),
65
+ }),
66
+ auth: ['tool:obsidian_list_tags:read'],
67
+
68
+ async handler(_input, ctx) {
69
+ const svc = getObsidianService();
70
+ const tags = await svc.listTags(ctx);
71
+ return { tags: tags.map((t) => ({ name: t.name, count: t.count })) };
72
+ },
73
+
74
+ // format() populates content[] — the markdown twin of structuredContent.
75
+ // Different clients read different surfaces (Claude Code → structuredContent,
76
+ // Claude Desktop → content[]); both must carry the same data.
77
+ // Enforced at lint time: every field in `output` must appear in the rendered text.
78
+ format: (result) => {
79
+ if (result.tags.length === 0) {
80
+ return [{ type: 'text', text: '_No tags found in the vault._' }];
81
+ }
82
+ const lines = [`**${result.tags.length} tags**`, ''];
83
+ for (const t of result.tags) lines.push(`- \`#${t.name}\` (${t.count})`);
84
+ return [{ type: 'text', text: lines.join('\n') }];
85
+ },
86
+ });
87
+ ```
88
+
89
+ For a destructive tool with optional human-in-the-loop confirmation, see `obsidian-delete-note.tool.ts` — it uses `ctx.elicit` when present and falls back to the `destructiveHint` annotation otherwise.
90
+
91
+ ### Resource — `obsidian://status`
92
+
93
+ ```ts
94
+ import { resource, z } from '@cyanheads/mcp-ts-core';
95
+ import { getObsidianService } from '@/services/obsidian/obsidian-service.js';
96
+
97
+ export const obsidianStatus = resource('obsidian://status', {
98
+ name: 'obsidian-status',
99
+ description:
100
+ 'Server reachability, plugin version, and auth status of the Obsidian Local REST API.',
101
+ mimeType: 'application/json',
102
+ params: z.object({}),
103
+ output: z.object({
104
+ status: z.string().describe('Upstream reported status string.'),
105
+ service: z.string().describe('Service identifier returned by the plugin.'),
106
+ authenticated: z.boolean().describe('Whether the configured OBSIDIAN_API_KEY is recognized.'),
107
+ }),
108
+ auth: ['resource:obsidian-status:read'],
109
+ async handler(_params, ctx) {
110
+ const svc = getObsidianService();
111
+ return await svc.getStatus(ctx);
112
+ },
113
+ });
114
+ ```
115
+
116
+ For a parameterized resource, see `obsidian-vault-note.resource.ts` (`obsidian://vault/{+path}`) — the `{+path}` segment captures everything after `/vault/` including slashes.
117
+
118
+ ### Prompt
119
+
120
+ This server exposes a CRUD/search surface; no recurring multi-turn pattern benefits from a structured prompt template, so `allPromptDefinitions` is intentionally empty. Add one with `prompt('name', { ... })` if a workflow emerges.
121
+
122
+ ### Server config — `OBSIDIAN_*` env vars
123
+
124
+ ```ts
125
+ // src/config/server-config.ts — lazy-parsed, separate from framework config
126
+ import { z } from '@cyanheads/mcp-ts-core';
127
+ import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
128
+
129
+ const envBoolean = z.preprocess((val) => {
130
+ if (val === undefined || val === null || val === '') return;
131
+ if (typeof val === 'boolean') return val;
132
+ return String(val).toLowerCase().trim() === 'true' || val === '1';
133
+ }, z.boolean());
134
+
135
+ const ServerConfigSchema = z.object({
136
+ apiKey: z.string().min(1).describe('Bearer token for the Obsidian Local REST API plugin.'),
137
+ baseUrl: z.string().url().default('http://127.0.0.1:27123'),
138
+ verifySsl: envBoolean.default(false),
139
+ requestTimeoutMs: z.coerce.number().int().positive().default(30_000),
140
+ enableCommands: envBoolean.default(false),
141
+ });
142
+
143
+ let _config: z.infer<typeof ServerConfigSchema> | undefined;
144
+ export function getServerConfig() {
145
+ _config ??= parseEnvConfig(ServerConfigSchema, {
146
+ apiKey: 'OBSIDIAN_API_KEY',
147
+ baseUrl: 'OBSIDIAN_BASE_URL',
148
+ verifySsl: 'OBSIDIAN_VERIFY_SSL',
149
+ requestTimeoutMs: 'OBSIDIAN_REQUEST_TIMEOUT_MS',
150
+ enableCommands: 'OBSIDIAN_ENABLE_COMMANDS',
151
+ });
152
+ return _config;
153
+ }
154
+ ```
155
+
156
+ `parseEnvConfig` maps Zod schema paths → env var names so validation errors name the actual variable (`OBSIDIAN_API_KEY`) rather than the internal path (`apiKey`). It throws a `ConfigurationError` the framework catches and prints as a clean startup banner.
157
+
158
+ ---
159
+
160
+ ## Context
161
+
162
+ Handlers receive a unified `ctx` object. Properties this server actually uses:
163
+
164
+ | Property | Description |
165
+ |:---------|:------------|
166
+ | `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. |
167
+ | `ctx.elicit` | Optional human-in-the-loop confirmation. **Check for presence first** — used by `obsidian_delete_note` to confirm destructive operations when the client supports elicitation. |
168
+ | `ctx.signal` | `AbortSignal` propagated to the Local REST API client so per-request timeouts and client cancellations cut off in-flight HTTP. |
169
+ | `ctx.requestId` | Unique request ID — surfaces in log lines for correlation. |
170
+ | `ctx.tenantId` | Tenant ID from JWT or `'default'` for stdio. |
171
+
172
+ The framework also provides `ctx.state`, `ctx.sample`, and `ctx.progress`. They aren't used by this server — Obsidian is single-vault and stateless from the server's perspective, so per-tenant KV and progress streams aren't needed. See the framework `CLAUDE.md` for the full surface.
173
+
174
+ ---
175
+
176
+ ## Errors
177
+
178
+ Handlers throw — the framework catches, classifies, and formats.
179
+
180
+ **Recommended: typed error contract.** Declare `errors: [{ reason, code, when, retryable? }]` on `tool()` / `resource()` to advertise the failure surface in `tools/list` (under `_meta['mcp-ts-core/errors']`) and receive a typed `ctx.fail(reason, …)` keyed by the declared reason union. TypeScript catches `ctx.fail('typo')` at compile time, `data.reason` is auto-populated for observability, and the linter enforces conformance against the handler body. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`) bubble freely and don't need declaring.
181
+
182
+ ```ts
183
+ errors: [
184
+ { reason: 'note_missing', code: JsonRpcErrorCode.NotFound, when: 'No note matched the path' },
185
+ { reason: 'plugin_unreachable', code: JsonRpcErrorCode.ServiceUnavailable, when: 'Local REST API plugin is offline', retryable: true },
186
+ ],
187
+ async handler(input, ctx) {
188
+ const note = await svc.getNote(input.path, ctx);
189
+ if (!note) throw ctx.fail('note_missing', `Note ${input.path} not found`);
190
+ return note;
191
+ }
192
+ ```
193
+
194
+ Services don't have `ctx.fail` — they pass `data: { reason: 'note_missing' }` to a factory so the wire shape matches what `ctx.fail` produces:
195
+
196
+ ```ts
197
+ // inside obsidian-service.ts
198
+ throw notFound('Note not found', { reason: 'note_missing', path });
199
+ ```
200
+
201
+ **Fallback for ad-hoc throws** (no contract entry fits, prototype tools, service-layer code without a contract): use error factories.
202
+
203
+ ```ts
204
+ import { notFound, validationError, serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
205
+ throw notFound('Note not found', { path });
206
+ throw serviceUnavailable('Local REST API unavailable', { url }, { cause: err });
207
+ ```
208
+
209
+ For HTTP responses from the Local REST API, use `httpErrorFromResponse(response, { service: 'obsidian-rest' })` from `/utils` — maps the full status table (401/403/408/422/429/5xx) and captures body + `Retry-After`.
210
+
211
+ Available factories: `notFound`, `validationError`, `forbidden`, `unauthorized`, `invalidParams`, `invalidRequest`, `conflict`, `rateLimited`, `timeout`, `serviceUnavailable`, `configurationError`, `internalError`, `serializationError`, `databaseError`. Plain `Error` is also auto-classified from message patterns (`'not found'` → `NotFound`, etc.). See framework CLAUDE.md and the `api-errors` skill for the full pattern table.
212
+
213
+ ---
214
+
215
+ ## Structure
216
+
217
+ ```text
218
+ src/
219
+ index.ts # createApp() entry point — registers tools/resources, inits Obsidian service
220
+ config/
221
+ server-config.ts # OBSIDIAN_* env vars (Zod schema)
222
+ services/
223
+ obsidian/
224
+ obsidian-service.ts # Local REST API client (init/accessor pattern)
225
+ frontmatter-ops.ts # YAML frontmatter parse/serialize/edit helpers
226
+ section-extractor.ts # Heading/block/frontmatter section extraction
227
+ types.ts # Domain types (NoteJson, NoteTarget, etc.)
228
+ mcp-server/
229
+ tools/definitions/
230
+ _shared/schemas.ts # Shared TargetSchema + SectionSchema reused across tools
231
+ index.ts # baseToolDefinitions[] + conditional obsidianExecuteCommand
232
+ obsidian-*.tool.ts # 14 tool definitions (13 base + 1 opt-in)
233
+ resources/definitions/
234
+ index.ts # allResourceDefinitions[]
235
+ obsidian-vault-note.resource.ts # obsidian://vault/{+path}
236
+ obsidian-tags.resource.ts # obsidian://tags
237
+ obsidian-status.resource.ts # obsidian://status
238
+ prompts/definitions/
239
+ index.ts # allPromptDefinitions = [] (intentionally empty)
240
+ ```
241
+
242
+ ---
243
+
244
+ ## Naming
245
+
246
+ | What | Convention | Example |
247
+ |:-----|:-----------|:--------|
248
+ | Files | kebab-case with suffix | `search-docs.tool.ts` |
249
+ | Tool/resource/prompt names | snake_case | `search_docs` |
250
+ | Directories | kebab-case | `src/services/doc-search/` |
251
+ | Descriptions | Single string or template literal, no `+` concatenation | `'Search items by query and filter.'` |
252
+
253
+ ---
254
+
255
+ ## Skills
256
+
257
+ Skills are modular instructions in `skills/` at the project root. Read them directly when a task matches — e.g., `skills/add-tool/SKILL.md` when adding a tool.
258
+
259
+ **Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). This makes skills available as context without needing to reference `skills/` paths manually. After framework updates, run the `maintenance` skill — it re-syncs the agent directory automatically (Phase B).
260
+
261
+ Available skills:
262
+
263
+ | Skill | Purpose |
264
+ |:------|:--------|
265
+ | `setup` | Post-init project orientation |
266
+ | `design-mcp-server` | Design tool surface, resources, and services for a new server |
267
+ | `add-tool` | Scaffold a new tool definition |
268
+ | `add-app-tool` | Scaffold an MCP App tool + paired UI resource |
269
+ | `add-resource` | Scaffold a new resource definition |
270
+ | `add-prompt` | Scaffold a new prompt definition |
271
+ | `add-service` | Scaffold a new service integration |
272
+ | `add-test` | Scaffold test file for a tool, resource, or service |
273
+ | `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
274
+ | `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
275
+ | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
276
+ | `release-and-publish` | Ship a release end-to-end across npm, MCP Registry, and GHCR |
277
+ | `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
278
+ | `migrate-mcp-ts-template` | Migrate a `mcp-ts-template` fork to depend on `@cyanheads/mcp-ts-core` as a package |
279
+ | `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
280
+ | `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
281
+ | `api-auth` | Auth modes, scopes, JWT/OAuth |
282
+ | `api-config` | AppConfig, parseConfig, env vars |
283
+ | `api-context` | Context interface, logger, state, progress |
284
+ | `api-errors` | McpError, JsonRpcErrorCode, error patterns |
285
+ | `api-linter` | MCP definition linter rule reference (`bun run lint:mcp` failures) |
286
+ | `api-services` | LLM, Speech, Graph services |
287
+ | `api-testing` | createMockContext, test patterns |
288
+ | `api-utils` | Formatting, parsing, security, pagination, scheduling |
289
+ | `api-workers` | Cloudflare Workers runtime |
290
+
291
+ When you complete a skill's checklist, check the boxes and add a completion timestamp at the end (e.g., `Completed: 2026-03-11`).
292
+
293
+ ---
294
+
295
+ ## Commands
296
+
297
+ **Runtime:** Scripts use `tsx` — both `bun run <cmd>` and `npm run <cmd>` work. `bun` is preferred (faster startup, native TS).
298
+
299
+ | Command | Purpose |
300
+ |:--------|:--------|
301
+ | `bun run build` | Compile TypeScript |
302
+ | `bun run rebuild` | Clean + build |
303
+ | `bun run clean` | Remove build artifacts |
304
+ | `bun run devcheck` | Lint + format + typecheck + security + changelog sync |
305
+ | `bun run tree` | Generate `docs/tree.md` |
306
+ | `bun run format` | Auto-fix formatting (Biome) |
307
+ | `bun run lint:mcp` | Validate MCP definitions against the linter rules |
308
+ | `bun run test` | Run Vitest tests |
309
+ | `bun run dev:stdio` | Dev mode (stdio, watch) |
310
+ | `bun run dev:http` | Dev mode (HTTP, watch) |
311
+ | `bun run start:stdio` | Production mode (stdio) — requires `bun run build` first |
312
+ | `bun run start:http` | Production mode (HTTP) — requires `bun run build` first |
313
+ | `bun run changelog:build` | Regenerate `CHANGELOG.md` rollup from `changelog/<minor>.x/*.md` |
314
+ | `bun run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
315
+
316
+ ---
317
+
318
+ ## Changelog
319
+
320
+ Directory-based, grouped by minor series using the `.x` semver-wildcard convention. Source of truth is `changelog/<major.minor>.x/<version>.md` (e.g. `changelog/0.1.x/0.1.0.md`) — one file per released version, shipped in the npm package. At release time, author the per-version file with a concrete version and date, then run `npm run changelog:build` to regenerate the rollup. `changelog/template.md` is a **pristine format reference** — never edited, never renamed, never moved. Read it to remember the frontmatter + section layout when scaffolding a new per-version file. `CHANGELOG.md` is a **navigation index** (header + link + one-line summary per version), regenerated by `npm run changelog:build`. Devcheck hard-fails on drift. Never hand-edit `CHANGELOG.md`.
321
+
322
+ Each per-version file opens with YAML frontmatter:
323
+
324
+ ```markdown
325
+ ---
326
+ summary: One-line headline, ≤250 chars # required — powers the rollup index
327
+ breaking: false # optional — true flags breaking changes
328
+ ---
329
+
330
+ # 0.1.0 — YYYY-MM-DD
331
+ ...
332
+ ```
333
+
334
+ `breaking: true` renders a `· ⚠️ Breaking` badge in the rollup — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames).
335
+
336
+ ---
337
+
338
+ ## Imports
339
+
340
+ ```ts
341
+ // Framework — z is re-exported, no separate zod import needed
342
+ import { tool, z } from '@cyanheads/mcp-ts-core';
343
+ import { McpError, JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
344
+
345
+ // Server's own code — via path alias
346
+ import { getMyService } from '@/services/my-domain/my-service.js';
347
+ ```
348
+
349
+ ---
350
+
351
+ ## Checklist
352
+
353
+ - [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types (no `z.custom()`, `z.date()`, `z.transform()`, `z.bigint()`, `z.symbol()`, `z.void()`, `z.map()`, `z.set()`, `z.function()`, `z.nan()`)
354
+ - [ ] Optional nested objects: handler guards for empty inner values from form-based clients (`if (input.obj?.field && ...)`, not just `if (input.obj)`). When regex/length constraints matter, use `z.union([z.literal(''), z.string().regex(...).describe(...)])` — literal variants are exempt from `describe-on-fields`.
355
+ - [ ] JSDoc `@fileoverview` + `@module` on every file
356
+ - [ ] `ctx.log` for logging, `ctx.state` for storage
357
+ - [ ] Handlers throw on failure — error factories or plain `Error`, no try/catch
358
+ - [ ] `format()` renders all data the LLM needs — different clients forward different surfaces (Claude Code → `structuredContent`, Claude Desktop → `content[]`); both must carry the same data
359
+ - [ ] If wrapping external API: raw/domain/output schemas reviewed against real upstream sparsity/nullability before finalizing required vs optional fields
360
+ - [ ] If wrapping external API: normalization and `format()` preserve uncertainty; do not fabricate facts from missing upstream data
361
+ - [ ] If wrapping external API: tests include at least one sparse payload case with omitted upstream fields
362
+ - [ ] Registered in `createApp()` arrays (directly or via barrel exports). Conditional registration (e.g. `obsidianExecuteCommand` behind `OBSIDIAN_ENABLE_COMMANDS`) happens in `src/index.ts`, not in the barrel
363
+ - [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
364
+ - [ ] `bun run devcheck` passes
package/Dockerfile ADDED
@@ -0,0 +1,99 @@
1
+ # ==============================================================================
2
+ # Build Stage
3
+ #
4
+ # This stage installs all dependencies (including dev), builds the TypeScript
5
+ # source code into JavaScript, and prepares the production assets.
6
+ # ==============================================================================
7
+ FROM oven/bun:1 AS build
8
+
9
+ WORKDIR /usr/src/app
10
+
11
+ # Copy dependency manifests for optimized layer caching
12
+ COPY package.json bun.lock ./
13
+
14
+ # Install all dependencies (including dev dependencies for building)
15
+ RUN bun install --frozen-lockfile
16
+
17
+ # Copy the rest of the source code
18
+ COPY . .
19
+
20
+ # Build the application
21
+ RUN bun run build
22
+
23
+
24
+ # ==============================================================================
25
+ # Production Stage
26
+ #
27
+ # This stage creates a minimal, optimized, and secure image for running the
28
+ # application. It uses a slim base image and only includes production
29
+ # dependencies and build artifacts.
30
+ # ==============================================================================
31
+ FROM oven/bun:1-slim AS production
32
+
33
+ WORKDIR /usr/src/app
34
+
35
+ # Set the environment to production for performance and to ensure only
36
+ # production dependencies are installed.
37
+ ENV NODE_ENV=production
38
+
39
+ # OCI image metadata (https://github.com/opencontainers/image-spec/blob/main/annotations.md)
40
+ LABEL org.opencontainers.image.title="obsidian-mcp-server"
41
+ LABEL org.opencontainers.image.description="MCP server for Obsidian vaults — read, write, search, and surgically edit notes, tags, and frontmatter via the Local REST API plugin. STDIO or Streamable HTTP."
42
+ LABEL org.opencontainers.image.source="https://github.com/cyanheads/obsidian-mcp-server"
43
+ LABEL org.opencontainers.image.licenses="Apache-2.0"
44
+
45
+ # Copy dependency manifests
46
+ COPY package.json bun.lock ./
47
+
48
+ # Install only production dependencies, ignoring any lifecycle scripts (like 'prepare')
49
+ # that are not needed in the final production image.
50
+ RUN bun install --production --frozen-lockfile --ignore-scripts
51
+
52
+ # Conditionally install OpenTelemetry optional peer dependencies (Tier 3).
53
+ # These are not bundled by default to keep the base image lean. Enable at build time
54
+ # with: docker build --build-arg OTEL_ENABLED=true
55
+ ARG OTEL_ENABLED=true
56
+ RUN if [ "$OTEL_ENABLED" = "true" ]; then \
57
+ bun add @hono/otel \
58
+ @opentelemetry/instrumentation-http \
59
+ @opentelemetry/exporter-metrics-otlp-http \
60
+ @opentelemetry/exporter-trace-otlp-http \
61
+ @opentelemetry/instrumentation-pino \
62
+ @opentelemetry/resources \
63
+ @opentelemetry/sdk-metrics \
64
+ @opentelemetry/sdk-node \
65
+ @opentelemetry/sdk-trace-node \
66
+ @opentelemetry/semantic-conventions; \
67
+ fi
68
+
69
+ # Copy the compiled application code from the build stage
70
+ COPY --from=build /usr/src/app/dist ./dist
71
+
72
+ # The 'oven/bun' image already provides a non-root user named 'bun'.
73
+ # We will use this existing user for enhanced security.
74
+
75
+ # Create and set permissions for the log directory, assigning ownership to the 'bun' user.
76
+ RUN mkdir -p /var/log/obsidian-mcp-server && chown -R bun:bun /var/log/obsidian-mcp-server
77
+
78
+ # Switch to the non-root user
79
+ USER bun
80
+
81
+ # Define an argument for the port, allowing it to be overridden at build time.
82
+ # The `PORT` variable is often injected by cloud environments at runtime.
83
+ ARG PORT
84
+
85
+ # Set runtime environment variables
86
+ # Note: PORT is an automatic variable in many cloud environments (e.g., Cloud Run)
87
+ ENV MCP_HTTP_PORT=${PORT:-3010}
88
+ ENV MCP_HTTP_HOST="0.0.0.0"
89
+ ENV MCP_TRANSPORT_TYPE="http"
90
+ ENV MCP_SESSION_MODE="stateless"
91
+ ENV MCP_LOG_LEVEL="info"
92
+ ENV LOGS_DIR="/var/log/obsidian-mcp-server"
93
+ ENV MCP_FORCE_CONSOLE_LOGGING="true"
94
+
95
+ # Expose the port the server listens on
96
+ EXPOSE ${MCP_HTTP_PORT}
97
+
98
+ # The command to start the server
99
+ CMD ["bun", "run", "dist/index.js"]
package/LICENSE CHANGED
@@ -1,8 +1,6 @@
1
-
2
- Apache License
1
+ Apache License
3
2
  Version 2.0, January 2004
4
- Copyright 2025 Casey Hand @cyanheads
5
- http://www.apache.org/licenses/
3
+ http://www.apache.org/licenses/
6
4
 
7
5
  TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8
6
 
@@ -188,7 +186,7 @@
188
186
  same "printed page" as the copyright notice for easier
189
187
  identification within third-party archives.
190
188
 
191
- Copyright [yyyy] [name of copyright owner]
189
+ Copyright 2026 Casey Hand @cyanheads
192
190
 
193
191
  Licensed under the Apache License, Version 2.0 (the "License");
194
192
  you may not use this file except in compliance with the License.
@@ -200,4 +198,4 @@
200
198
  distributed under the License is distributed on an "AS IS" BASIS,
201
199
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202
200
  See the License for the specific language governing permissions and
203
- limitations under the License.
201
+ limitations under the License.