obsidian-mcp-server 3.5.3 → 3.5.5

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 (86) hide show
  1. package/AGENTS.md +47 -6
  2. package/CLAUDE.md +47 -6
  3. package/Dockerfile +3 -2
  4. package/README.md +144 -100
  5. package/changelog/3.5.x/3.5.3.md +4 -3
  6. package/changelog/3.5.x/3.5.4.md +42 -0
  7. package/changelog/3.5.x/3.5.5.md +20 -0
  8. package/changelog/template.md +7 -7
  9. package/dist/config/server-config.d.ts +1 -1
  10. package/dist/config/server-config.d.ts.map +1 -1
  11. package/dist/config/server-config.js +9 -2
  12. package/dist/config/server-config.js.map +1 -1
  13. package/dist/index.js +9 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.d.ts.map +1 -1
  16. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.js +19 -1
  17. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.js.map +1 -1
  18. package/dist/mcp-server/tools/definitions/_shared/schemas.js +1 -1
  19. package/dist/mcp-server/tools/definitions/_shared/schemas.js.map +1 -1
  20. package/dist/mcp-server/tools/definitions/index.d.ts +157 -65
  21. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  22. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts +13 -2
  23. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts.map +1 -1
  24. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js +14 -3
  25. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js.map +1 -1
  26. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts +9 -0
  27. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts.map +1 -1
  28. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js +9 -0
  29. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js.map +1 -1
  30. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.d.ts +1 -0
  31. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.d.ts.map +1 -1
  32. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.js +1 -0
  33. package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.js.map +1 -1
  34. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts +9 -0
  35. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts.map +1 -1
  36. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js +19 -26
  37. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js.map +1 -1
  38. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts +3 -0
  39. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts.map +1 -1
  40. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js +3 -0
  41. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js.map +1 -1
  42. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts +13 -0
  43. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts.map +1 -1
  44. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js +19 -1
  45. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js.map +1 -1
  46. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts +17 -2
  47. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts.map +1 -1
  48. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js +22 -3
  49. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js.map +1 -1
  50. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts +4 -0
  51. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts.map +1 -1
  52. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js +4 -0
  53. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js.map +1 -1
  54. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts +13 -2
  55. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts.map +1 -1
  56. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js +14 -3
  57. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js.map +1 -1
  58. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts +10 -2
  59. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts.map +1 -1
  60. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js +10 -2
  61. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js.map +1 -1
  62. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +12 -5
  63. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -1
  64. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +29 -24
  65. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -1
  66. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts +12 -2
  67. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts.map +1 -1
  68. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js +20 -10
  69. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js.map +1 -1
  70. package/dist/services/obsidian/frontmatter-ops.d.ts +44 -11
  71. package/dist/services/obsidian/frontmatter-ops.d.ts.map +1 -1
  72. package/dist/services/obsidian/frontmatter-ops.js +370 -69
  73. package/dist/services/obsidian/frontmatter-ops.js.map +1 -1
  74. package/dist/services/obsidian/obsidian-service.d.ts +26 -5
  75. package/dist/services/obsidian/obsidian-service.d.ts.map +1 -1
  76. package/dist/services/obsidian/obsidian-service.js +469 -85
  77. package/dist/services/obsidian/obsidian-service.js.map +1 -1
  78. package/dist/services/obsidian/section-extractor.d.ts +33 -3
  79. package/dist/services/obsidian/section-extractor.d.ts.map +1 -1
  80. package/dist/services/obsidian/section-extractor.js +115 -75
  81. package/dist/services/obsidian/section-extractor.js.map +1 -1
  82. package/dist/services/obsidian/types.d.ts +11 -4
  83. package/dist/services/obsidian/types.d.ts.map +1 -1
  84. package/manifest.json +1 -1
  85. package/package.json +9 -9
  86. package/server.json +3 -3
package/AGENTS.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # Agent Protocol
2
2
 
3
3
  **Server:** obsidian-mcp-server
4
- **Version:** 3.5.3
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.0`
4
+ **Version:** 3.5.5
5
+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.6`
6
6
  **Engines:** Bun ≥1.4.0, Node ≥24.0.0
7
7
  **MCP SDK:** `@modelcontextprotocol/server` ^2.0.0
8
- **Zod:** ^4.6.1
8
+ **Zod:** ^4.6.5
9
9
 
10
10
  > **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.
11
11
 
@@ -167,6 +167,22 @@ export function getServerConfig() {
167
167
 
168
168
  `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.
169
169
 
170
+ ### Session posture and shutdown
171
+
172
+ `src/index.ts` passes two `createApp()` options that shape how the server runs:
173
+
174
+ ```ts
175
+ await createApp({
176
+ // ...
177
+ sessionMode: 'stateful',
178
+ teardown: () => obsidian.close(),
179
+ });
180
+ ```
181
+
182
+ `sessionMode: 'stateful'` is the default, not a requirement: `obsidian_delete_note` confirms through `ctx.requestInput`, which a 2025-era HTTP client can only answer on a stateful session. An explicit `MCP_SESSION_MODE` still wins, so an operator who deliberately runs `stateless` gets a working server whose delete confirmation is refused with `client_capability_missing` on those clients. Don't switch it to `require: 'stateful'`.
183
+
184
+ `teardown` closes the undici `Agent` dispatcher `ObsidianService` holds for the Local REST API and Omnisearch, releasing its keep-alive sockets. It runs after the transport stops accepting requests, on every shutdown path.
185
+
170
186
  ---
171
187
 
172
188
  ## Context
@@ -189,7 +205,7 @@ The framework also provides `ctx.state`. It isn't used by this server — Obsidi
189
205
 
190
206
  Handlers throw — the framework catches, classifies, and formats.
191
207
 
192
- **Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to 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. The `recovery` field is required descriptive metadata (≥ 5 words, lint-validated) — it's the single source of truth for the recovery hint that flows to the wire. Spread `ctx.recoveryFor('reason')` into `data` to opt the contract recovery onto the wire (the framework mirrors `data.recovery.hint` into `content[]` text). Override with explicit `{ recovery: { hint: '...' } }` when runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring.
208
+ **Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to 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. The `recovery` field is required descriptive metadata (≥ 5 words, lint-validated) — it's the single source of truth for the recovery hint that flows to the wire. Spread `ctx.recoveryFor('reason')` into `data` to opt the contract recovery onto the wire (the framework mirrors `data.recovery.hint` into `content[]` text unless the message already contains it verbatim). Override with explicit `{ recovery: { hint: '...' } }` when runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring.
193
209
 
194
210
  ```ts
195
211
  errors: [
@@ -217,11 +233,15 @@ Services that accept `ctx` use the same resolver for parity. The Obsidian servic
217
233
  ```ts
218
234
  // inside obsidian-service.ts
219
235
  throw notFound(`Not found: ${display}`, data('note_missing'), { cause });
220
- // where data(reason) does: { path, reason, ...ctx.recoveryFor(reason) }
236
+ // where data(reason) does: { ...callerIdentifier(path), reason, ...ctx.recoveryFor(reason) }
237
+ // — `path` on a note route, `commandId` on /commands/<id>/, no key on routes
238
+ // that carry no caller input (/, /tags/, /commands/, /search/).
221
239
  // The upstream body is never spread into `data` — it rides as `cause`, which
222
240
  // is non-enumerable and so reaches the log without reaching the client.
223
241
  ```
224
242
 
243
+ A `fetch` that rejects before any response is classified inside the attempt (`#send`), so the retry decision sees the typed error: a refused certificate throws `ConfigurationError` `certificate_rejected` on the first attempt, an unreachable plugin throws `ServiceUnavailable` `obsidian_unreachable` and keeps the GET/PUT/DELETE retries. Both carry an inline `recovery.hint` rather than `ctx.recoveryFor`, because they reach every tool and resource — including resources with no `errors[]` — and the operator, not the agent, fixes them.
244
+
225
245
  **Fallback for ad-hoc throws** (no contract entry fits, prototype tools, service-layer code without a contract): use error factories.
226
246
 
227
247
  ```ts
@@ -300,7 +320,7 @@ Available skills:
300
320
  | `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
301
321
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
302
322
  | `git-wrapup` | Land working-tree changes as a commit stack — version bump, changelog, verify, commit by concern, release commit on top. No tag, no push to main; opens the release PR when the project declares release PR mode |
303
- | `release-pr-review` | Review pass on an open release PR — simplifier + correctness review, fixup commits autosquashed into the stack, PR body kept in sync. Release PR mode only |
323
+ | `release-pr-review` | Review pass on an open release PR — simplifier + correctness review, fixes as ordinary commits on top of the stack, PR body kept in sync. Release PR mode only |
304
324
  | `release-and-publish` | Fast-forward merge (release PR mode) + tag + push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup` |
305
325
  | `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
306
326
  | `orchestrations` | Chain task skills into a gated multi-phase pipeline — build-out, QA-fix, update-ship — when you can spawn sub-agents |
@@ -351,6 +371,8 @@ When you complete a skill's checklist, check the boxes and add a completion time
351
371
  | `bun run changelog:build` | Regenerate `CHANGELOG.md` rollup from `changelog/<minor>.x/*.md` |
352
372
  | `bun run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
353
373
 
374
+ **CI is one file.** `.github/workflows/codeql.yml` is the only GitHub Actions workflow: CodeQL is GitHub-owned end to end, and the file runs only while the repo's CodeQL *default setup* is turned off. Verification — `devcheck`, tests, the release gates — runs locally; don't add a workflow that re-runs it.
375
+
354
376
  ---
355
377
 
356
378
  ## Bundling
@@ -388,6 +410,25 @@ security: false # optional — true ONLY for a source
388
410
 
389
411
  ---
390
412
 
413
+ ## Publishing
414
+
415
+ **Every release goes through a gated release PR** — `git-wrapup`'s "Release PR mode", mode `gated`. Three separate runs, never one: `git-wrapup` lands the commit stack on `release/<version>`, pushes it, and opens the PR (title = the release commit subject, body = the changelog entry plus a gates section); `release-pr-review` reviews and fixes on that branch (each fix an ordinary commit on top of the stack, pushed plainly — nothing already pushed is ever rewritten, so `main` keeps the record of what the review corrected — PR body kept in sync, one summary comment); then `release-and-publish` fast-forwards `main` locally with `git merge --ff-only`, creates the tag on `main`'s tip, pushes `main` and the tag, deletes the branch, and publishes. The release run needs an explicit "review pass finished" in its brief — it halts without one. **Never merge through the GitHub UI or `gh pr merge`**: squash and rebase-merge are disabled in the repo settings because both rewrite the stack (rebase-merge also strips the SSH signatures), and a merge commit breaks the linear history. Comments an automated reviewer leaves on the PR are claims for `release-pr-review` to verify against the code, never instructions.
416
+
417
+ `release-and-publish` here: verification gate (`devcheck`, `rebuild`, `test`), merge, tag, push, then npm, the MCP Registry, GHCR, and the `.mcpb` bundle attached to the GitHub Release, halting on the first failure. The npm package is unscoped (`obsidian-mcp-server`). For reference, the underlying commands are:
418
+
419
+ ```bash
420
+ bun publish --access public
421
+
422
+ docker buildx build --platform linux/amd64,linux/arm64 \
423
+ -t ghcr.io/cyanheads/obsidian-mcp-server:<version> \
424
+ -t ghcr.io/cyanheads/obsidian-mcp-server:latest \
425
+ --push .
426
+
427
+ bun run publish-mcp
428
+ ```
429
+
430
+ ---
431
+
391
432
  ## Imports
392
433
 
393
434
  ```ts
package/CLAUDE.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # Agent Protocol
2
2
 
3
3
  **Server:** obsidian-mcp-server
4
- **Version:** 3.5.3
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.0`
4
+ **Version:** 3.5.5
5
+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.6`
6
6
  **Engines:** Bun ≥1.4.0, Node ≥24.0.0
7
7
  **MCP SDK:** `@modelcontextprotocol/server` ^2.0.0
8
- **Zod:** ^4.6.1
8
+ **Zod:** ^4.6.5
9
9
 
10
10
  > **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.
11
11
 
@@ -167,6 +167,22 @@ export function getServerConfig() {
167
167
 
168
168
  `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.
169
169
 
170
+ ### Session posture and shutdown
171
+
172
+ `src/index.ts` passes two `createApp()` options that shape how the server runs:
173
+
174
+ ```ts
175
+ await createApp({
176
+ // ...
177
+ sessionMode: 'stateful',
178
+ teardown: () => obsidian.close(),
179
+ });
180
+ ```
181
+
182
+ `sessionMode: 'stateful'` is the default, not a requirement: `obsidian_delete_note` confirms through `ctx.requestInput`, which a 2025-era HTTP client can only answer on a stateful session. An explicit `MCP_SESSION_MODE` still wins, so an operator who deliberately runs `stateless` gets a working server whose delete confirmation is refused with `client_capability_missing` on those clients. Don't switch it to `require: 'stateful'`.
183
+
184
+ `teardown` closes the undici `Agent` dispatcher `ObsidianService` holds for the Local REST API and Omnisearch, releasing its keep-alive sockets. It runs after the transport stops accepting requests, on every shutdown path.
185
+
170
186
  ---
171
187
 
172
188
  ## Context
@@ -189,7 +205,7 @@ The framework also provides `ctx.state`. It isn't used by this server — Obsidi
189
205
 
190
206
  Handlers throw — the framework catches, classifies, and formats.
191
207
 
192
- **Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to 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. The `recovery` field is required descriptive metadata (≥ 5 words, lint-validated) — it's the single source of truth for the recovery hint that flows to the wire. Spread `ctx.recoveryFor('reason')` into `data` to opt the contract recovery onto the wire (the framework mirrors `data.recovery.hint` into `content[]` text). Override with explicit `{ recovery: { hint: '...' } }` when runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring.
208
+ **Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to 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. The `recovery` field is required descriptive metadata (≥ 5 words, lint-validated) — it's the single source of truth for the recovery hint that flows to the wire. Spread `ctx.recoveryFor('reason')` into `data` to opt the contract recovery onto the wire (the framework mirrors `data.recovery.hint` into `content[]` text unless the message already contains it verbatim). Override with explicit `{ recovery: { hint: '...' } }` when runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring.
193
209
 
194
210
  ```ts
195
211
  errors: [
@@ -217,11 +233,15 @@ Services that accept `ctx` use the same resolver for parity. The Obsidian servic
217
233
  ```ts
218
234
  // inside obsidian-service.ts
219
235
  throw notFound(`Not found: ${display}`, data('note_missing'), { cause });
220
- // where data(reason) does: { path, reason, ...ctx.recoveryFor(reason) }
236
+ // where data(reason) does: { ...callerIdentifier(path), reason, ...ctx.recoveryFor(reason) }
237
+ // — `path` on a note route, `commandId` on /commands/<id>/, no key on routes
238
+ // that carry no caller input (/, /tags/, /commands/, /search/).
221
239
  // The upstream body is never spread into `data` — it rides as `cause`, which
222
240
  // is non-enumerable and so reaches the log without reaching the client.
223
241
  ```
224
242
 
243
+ A `fetch` that rejects before any response is classified inside the attempt (`#send`), so the retry decision sees the typed error: a refused certificate throws `ConfigurationError` `certificate_rejected` on the first attempt, an unreachable plugin throws `ServiceUnavailable` `obsidian_unreachable` and keeps the GET/PUT/DELETE retries. Both carry an inline `recovery.hint` rather than `ctx.recoveryFor`, because they reach every tool and resource — including resources with no `errors[]` — and the operator, not the agent, fixes them.
244
+
225
245
  **Fallback for ad-hoc throws** (no contract entry fits, prototype tools, service-layer code without a contract): use error factories.
226
246
 
227
247
  ```ts
@@ -300,7 +320,7 @@ Available skills:
300
320
  | `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
301
321
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
302
322
  | `git-wrapup` | Land working-tree changes as a commit stack — version bump, changelog, verify, commit by concern, release commit on top. No tag, no push to main; opens the release PR when the project declares release PR mode |
303
- | `release-pr-review` | Review pass on an open release PR — simplifier + correctness review, fixup commits autosquashed into the stack, PR body kept in sync. Release PR mode only |
323
+ | `release-pr-review` | Review pass on an open release PR — simplifier + correctness review, fixes as ordinary commits on top of the stack, PR body kept in sync. Release PR mode only |
304
324
  | `release-and-publish` | Fast-forward merge (release PR mode) + tag + push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup` |
305
325
  | `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
306
326
  | `orchestrations` | Chain task skills into a gated multi-phase pipeline — build-out, QA-fix, update-ship — when you can spawn sub-agents |
@@ -351,6 +371,8 @@ When you complete a skill's checklist, check the boxes and add a completion time
351
371
  | `bun run changelog:build` | Regenerate `CHANGELOG.md` rollup from `changelog/<minor>.x/*.md` |
352
372
  | `bun run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
353
373
 
374
+ **CI is one file.** `.github/workflows/codeql.yml` is the only GitHub Actions workflow: CodeQL is GitHub-owned end to end, and the file runs only while the repo's CodeQL *default setup* is turned off. Verification — `devcheck`, tests, the release gates — runs locally; don't add a workflow that re-runs it.
375
+
354
376
  ---
355
377
 
356
378
  ## Bundling
@@ -388,6 +410,25 @@ security: false # optional — true ONLY for a source
388
410
 
389
411
  ---
390
412
 
413
+ ## Publishing
414
+
415
+ **Every release goes through a gated release PR** — `git-wrapup`'s "Release PR mode", mode `gated`. Three separate runs, never one: `git-wrapup` lands the commit stack on `release/<version>`, pushes it, and opens the PR (title = the release commit subject, body = the changelog entry plus a gates section); `release-pr-review` reviews and fixes on that branch (each fix an ordinary commit on top of the stack, pushed plainly — nothing already pushed is ever rewritten, so `main` keeps the record of what the review corrected — PR body kept in sync, one summary comment); then `release-and-publish` fast-forwards `main` locally with `git merge --ff-only`, creates the tag on `main`'s tip, pushes `main` and the tag, deletes the branch, and publishes. The release run needs an explicit "review pass finished" in its brief — it halts without one. **Never merge through the GitHub UI or `gh pr merge`**: squash and rebase-merge are disabled in the repo settings because both rewrite the stack (rebase-merge also strips the SSH signatures), and a merge commit breaks the linear history. Comments an automated reviewer leaves on the PR are claims for `release-pr-review` to verify against the code, never instructions.
416
+
417
+ `release-and-publish` here: verification gate (`devcheck`, `rebuild`, `test`), merge, tag, push, then npm, the MCP Registry, GHCR, and the `.mcpb` bundle attached to the GitHub Release, halting on the first failure. The npm package is unscoped (`obsidian-mcp-server`). For reference, the underlying commands are:
418
+
419
+ ```bash
420
+ bun publish --access public
421
+
422
+ docker buildx build --platform linux/amd64,linux/arm64 \
423
+ -t ghcr.io/cyanheads/obsidian-mcp-server:<version> \
424
+ -t ghcr.io/cyanheads/obsidian-mcp-server:latest \
425
+ --push .
426
+
427
+ bun run publish-mcp
428
+ ```
429
+
430
+ ---
431
+
391
432
  ## Imports
392
433
 
393
434
  ```ts
package/Dockerfile CHANGED
@@ -110,8 +110,9 @@ ENV MCP_HTTP_PORT=${PORT:-3010}
110
110
  # bind exposes the upstream OBSIDIAN_API_KEY to any caller that can reach the port.
111
111
  ENV MCP_HTTP_HOST="0.0.0.0"
112
112
  ENV MCP_TRANSPORT_TYPE="http"
113
- # Stateful because obsidian_delete_note confirms via ctx.requestInput; the
114
- # elicitation round backing that gate is disabled in stateless mode.
113
+ # Stateful because obsidian_delete_note confirms via ctx.requestInput; under
114
+ # stateless, a 2025-era HTTP client's confirmation round is refused by the
115
+ # capability gate (client_capability_missing).
115
116
  ENV MCP_SESSION_MODE="stateful"
116
117
  ENV MCP_LOG_LEVEL="info"
117
118
  ENV LOGS_DIR="/var/log/obsidian-mcp-server"