obsidian-mcp-server 3.7.2 → 3.9.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 (110) hide show
  1. package/AGENTS.md +20 -15
  2. package/CLAUDE.md +20 -15
  3. package/README.md +31 -19
  4. package/changelog/3.8.x/3.8.0.md +38 -0
  5. package/changelog/3.9.x/3.9.0.md +43 -0
  6. package/changelog/template.md +10 -3
  7. package/dist/config/server-config.d.ts +1 -0
  8. package/dist/config/server-config.d.ts.map +1 -1
  9. package/dist/config/server-config.js +30 -19
  10. package/dist/config/server-config.js.map +1 -1
  11. package/dist/index.d.ts +3 -3
  12. package/dist/index.js +27 -15
  13. package/dist/index.js.map +1 -1
  14. package/dist/instructions.d.ts +4 -3
  15. package/dist/instructions.d.ts.map +1 -1
  16. package/dist/instructions.js +23 -12
  17. package/dist/instructions.js.map +1 -1
  18. package/dist/mcp-server/resources/definitions/index.d.ts +2 -2
  19. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts +3 -2
  20. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts.map +1 -1
  21. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js +6 -5
  22. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js.map +1 -1
  23. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.d.ts +2 -2
  24. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.js +2 -2
  25. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.js.map +1 -1
  26. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts +15 -6
  27. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts.map +1 -1
  28. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js +24 -12
  29. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js.map +1 -1
  30. package/dist/mcp-server/tools/definitions/index.d.ts +250 -230
  31. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  32. package/dist/mcp-server/tools/definitions/index.js +6 -4
  33. package/dist/mcp-server/tools/definitions/index.js.map +1 -1
  34. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts +8 -2
  35. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts.map +1 -1
  36. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js +10 -3
  37. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js.map +1 -1
  38. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts +7 -6
  39. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts.map +1 -1
  40. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js +7 -7
  41. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js.map +1 -1
  42. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts +2 -2
  43. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts.map +1 -1
  44. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js +8 -5
  45. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js.map +1 -1
  46. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts +6 -6
  47. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts.map +1 -1
  48. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js +8 -8
  49. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js.map +1 -1
  50. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts +4 -4
  51. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js +7 -7
  52. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js.map +1 -1
  53. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts +2 -2
  54. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts.map +1 -1
  55. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js +2 -2
  56. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js.map +1 -1
  57. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts +2 -2
  58. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts.map +1 -1
  59. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js +2 -2
  60. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js.map +1 -1
  61. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts +2 -2
  62. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js +3 -3
  63. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js.map +1 -1
  64. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts +8 -2
  65. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts.map +1 -1
  66. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js +10 -3
  67. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js.map +1 -1
  68. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts +2 -2
  69. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js +2 -2
  70. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js.map +1 -1
  71. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +185 -35
  72. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -1
  73. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +145 -82
  74. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -1
  75. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts +8 -2
  76. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts.map +1 -1
  77. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js +12 -5
  78. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js.map +1 -1
  79. package/dist/services/obsidian/jsonlogic-evaluator.d.ts +33 -8
  80. package/dist/services/obsidian/jsonlogic-evaluator.d.ts.map +1 -1
  81. package/dist/services/obsidian/jsonlogic-evaluator.js +171 -32
  82. package/dist/services/obsidian/jsonlogic-evaluator.js.map +1 -1
  83. package/dist/services/obsidian/jsonlogic-worker.d.ts +6 -5
  84. package/dist/services/obsidian/jsonlogic-worker.d.ts.map +1 -1
  85. package/dist/services/obsidian/jsonlogic-worker.js +7 -5
  86. package/dist/services/obsidian/jsonlogic-worker.js.map +1 -1
  87. package/dist/services/obsidian/obsidian-service.d.ts +90 -36
  88. package/dist/services/obsidian/obsidian-service.d.ts.map +1 -1
  89. package/dist/services/obsidian/obsidian-service.js +748 -248
  90. package/dist/services/obsidian/obsidian-service.js.map +1 -1
  91. package/dist/services/obsidian/patch-instruction.d.ts +4 -1
  92. package/dist/services/obsidian/patch-instruction.d.ts.map +1 -1
  93. package/dist/services/obsidian/patch-instruction.js +5 -2
  94. package/dist/services/obsidian/patch-instruction.js.map +1 -1
  95. package/dist/services/obsidian/path-policy.d.ts +67 -23
  96. package/dist/services/obsidian/path-policy.d.ts.map +1 -1
  97. package/dist/services/obsidian/path-policy.js +183 -80
  98. package/dist/services/obsidian/path-policy.js.map +1 -1
  99. package/dist/services/obsidian/section-extractor.d.ts +62 -1
  100. package/dist/services/obsidian/section-extractor.d.ts.map +1 -1
  101. package/dist/services/obsidian/section-extractor.js +387 -51
  102. package/dist/services/obsidian/section-extractor.js.map +1 -1
  103. package/dist/services/obsidian/simple-search.d.ts +62 -0
  104. package/dist/services/obsidian/simple-search.d.ts.map +1 -0
  105. package/dist/services/obsidian/simple-search.js +264 -0
  106. package/dist/services/obsidian/simple-search.js.map +1 -0
  107. package/manifest.json +12 -4
  108. package/package.json +9 -9
  109. package/server.json +23 -11
  110. package/skills/obsidian-guide/SKILL.md +61 -0
@@ -0,0 +1,43 @@
1
+ ---
2
+ summary: "Request timeouts are enforced on Bun and Node, Omnisearch is withheld under a read scope, and heading writes below a repeated link definition are refused before any PATCH. Scoped text searches evaluate once per walk, and the server publishes its first skill, obsidian-guide."
3
+ breaking: true
4
+ security: true
5
+ ---
6
+
7
+ # 3.9.0 — 2026-11-11
8
+
9
+ ## Added
10
+
11
+ - **The `obsidian-guide` skill**, the server's first published skill, served as `skill://obsidian-guide/SKILL.md` through `createApp({ skills: 'skills' })`. The server `instructions` point at it.
12
+
13
+ ## Changed
14
+
15
+ - **`obsidian_search_notes` with `mode: "omnisearch"` under `OBSIDIAN_READ_PATHS` or `OBSIDIAN_DENY_PATHS` is rejected as invalid params (-32602)** before any Omnisearch request, the startup probe included. The mode is withheld from the `mode` enum and the tool description, and the output enum `truncatedReason` no longer has `read_scope`. Scoped callers search with `text` or `jsonlogic`. ([#173](https://github.com/cyanheads/obsidian-mcp-server/issues/173))
16
+ - **Heading writes below a repeated link definition fail `repeated_link_definition` before any PATCH**, from `obsidian_patch_note` and from `obsidian_append_to_note` and `obsidian_write_note` with `section`. For a section that runs to the end of the note, the repeat must sit above the target heading itself; a repeat inside that last section is not refused. ([#175](https://github.com/cyanheads/obsidian-mcp-server/issues/175))
17
+ - **The refusal also covers writes no plugin engine would have misplaced**: a prepend whose repeat sits inside the target section; an append to a section that runs to the end of the note, with the repeat above its heading; a heading created under an ancestor heading path that occurs more than once in the note, which the check places at the farther of the two engines' candidate positions, so it can refuse a create only the other wire format would misplace; a write that would have left the note unchanged; and labels the check folds more coarsely than the parser does, a lazy blockquote continuation included. On plugin 5.x a heading write now reads the note before the PATCH, so a read of it that fails persistently or with a 4xx fails a write 3.8.0 sent. ([#175](https://github.com/cyanheads/obsidian-mcp-server/issues/175))
18
+ - **A request attempt that runs past `OBSIDIAN_REQUEST_TIMEOUT_MS`, headers or body, fails `obsidian_timeout` on Bun and Node.** On Bun an Omnisearch query past it now fails `omnisearch_unreachable`, where 3.8.0 had no bound and let it finish. ([#176](https://github.com/cyanheads/obsidian-mcp-server/issues/176))
19
+ - **A call whose requests together pass max(45 s, `OBSIDIAN_REQUEST_TIMEOUT_MS`) fails `obsidian_timeout`.** ([#176](https://github.com/cyanheads/obsidian-mcp-server/issues/176))
20
+ - **`OBSIDIAN_REQUEST_TIMEOUT_MS` above 2147483647 fails at startup.**
21
+ - **A connection dropped mid-body fails `obsidian_unreachable` and is retried on GET, PUT, and DELETE.** ([#176](https://github.com/cyanheads/obsidian-mcp-server/issues/176))
22
+ - **A scoped `text` search is searched once.** Later pages come from the stored hit list, kept up to 5 minutes past the last page read and 32 Mi characters across walks, and show the first page's snapshot. A walk is stored only when the hits run past the page being served. ([#177](https://github.com/cyanheads/obsidian-mcp-server/issues/177))
23
+ - **The Omnisearch-mode `matches`, `excerpt`, and `score` descriptions are corrected**, and `tools/list` declares `omnisearch_unreachable` only where the mode is offered. ([#173](https://github.com/cyanheads/obsidian-mcp-server/issues/173))
24
+ - **The `obsidian_list_tags` description gains JSONLogic tag-matching examples**, and the server `instructions` point at the `obsidian-guide` skill.
25
+
26
+ ## Fixed
27
+
28
+ - **A call waiting on the plugin-version read another call started no longer fails when that other call is cancelled**; it reads the version itself.
29
+ - **The did-you-mean, ambiguous-path, and case-variant path suggestions in `content[]` render as code spans.**
30
+ - **Creating a heading under an existing ancestor finds that ancestor in time linear in the note.**
31
+
32
+ ## Security
33
+
34
+ - **Under `OBSIDIAN_READ_PATHS` or `OBSIDIAN_DENY_PATHS`, Omnisearch ranked and selected its results over the whole vault**, so notes outside the scope changed what a scoped caller saw. The mode is now withheld under either. ([#173](https://github.com/cyanheads/obsidian-mcp-server/issues/173))
35
+
36
+ ## Dependencies
37
+
38
+ - `@cyanheads/mcp-ts-core` ^0.13.18 → ^0.13.22
39
+ - `engines.bun` >=1.4.0 → >=1.4.4
40
+ - `undici` ^8.12.3 → ^8.12.4
41
+ - `@biomejs/biome` ^2.6.4 → ^2.6.6 (dev)
42
+ - `vitest`, `@vitest/coverage-istanbul` ^5.0.5 → ^5.1.0 (dev)
43
+ - `tsc-alias` ^1.9.9 → ^1.9.10 (dev)
@@ -116,14 +116,21 @@ security: false
116
116
  resolves to whatever real item already owns 42, and timeline previews pull
117
117
  in that unrelated item's metadata.
118
118
 
119
+ Outside reporters: when the issue or PR came from outside the project
120
+ (`git-wrapup` step 5 says how to tell), thank its author in the same
121
+ parenthetical, profile linked by full URL for the same reason:
122
+
123
+ ([#38](https://github.com/cyanheads/mcp-ts-core/issues/38), thanks [@octocat](https://github.com/octocat)!)
124
+
119
125
  TAG ANNOTATIONS — the annotated tag body renders as the GitHub Release body
120
126
  via `gh release create --notes-from-tag`. It is a condensed digest of this
121
127
  entry, never a copy, and its format is owned by the `release-and-publish`
122
128
  skill (step 4, "Create the annotated tag"): a short subject line without the
123
129
  version, flat headline bullets — no Keep-a-Changelog section headers, no
124
- gates line — at most one deps line, issue backlinks, and the changelog link
125
- last. In release-PR mode the `git-wrapup` skill authors those bullets as the
126
- PR body's `## Changes` and the tag copies them.
130
+ gates line — at most one deps line, issue backlinks with any outside-reporter
131
+ thanks, and the changelog link last. In release-PR mode the `git-wrapup`
132
+ skill authors those bullets as the PR body's `## Changes` and the tag copies
133
+ them.
127
134
  -->
128
135
 
129
136
  ## Added
@@ -12,6 +12,7 @@ declare const ServerConfigSchema: z.ZodObject<{
12
12
  enableCommands: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCodec<z.ZodString, z.ZodBoolean>]>>;
13
13
  readPaths: z.ZodPreprocess<z.ZodPipe<z.ZodOptional<z.ZodArray<z.ZodString>>, z.ZodTransform<string[] | undefined, string[] | undefined>>, unknown>;
14
14
  writePaths: z.ZodPreprocess<z.ZodPipe<z.ZodOptional<z.ZodArray<z.ZodString>>, z.ZodTransform<string[] | undefined, string[] | undefined>>, unknown>;
15
+ denyPaths: z.ZodPreprocess<z.ZodPipe<z.ZodOptional<z.ZodArray<z.ZodString>>, z.ZodTransform<string[] | undefined, string[] | undefined>>, unknown>;
15
16
  readOnly: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCodec<z.ZodString, z.ZodBoolean>]>>;
16
17
  deleteElicitation: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCodec<z.ZodString, z.ZodBoolean>]>>;
17
18
  omnisearchUrl: z.ZodOptional<z.ZodString>;
@@ -1 +1 @@
1
- {"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAgF3C,QAAA,MAAM,kBAAkB;;;;;;;;;;;iBA4DtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,CAc9C;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
1
+ {"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAwF3C,QAAA,MAAM,kBAAkB;;;;;;;;;;;;iBAmEtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,CAe9C;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
@@ -12,18 +12,20 @@ import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
12
12
  */
13
13
  const envBoolean = z.union([z.boolean(), z.stringbool()]);
14
14
  /**
15
- * Comma-separated path-list preprocessor. Semantics (see issue #40):
16
- * - undefined / `''` / whitespace-only → undefined (treat as unset; default = full vault)
15
+ * Comma-separated path-list preprocessor, shared by OBSIDIAN_READ_PATHS,
16
+ * OBSIDIAN_WRITE_PATHS, and OBSIDIAN_DENY_PATHS. Semantics (see issues #40, #76):
17
+ * - undefined / `''` / whitespace-only → undefined (treat as unset)
17
18
  * - `,` / `,,,` (separators only, no path content) → throw ZodError → ConfigurationError
18
19
  * - mixed empties (`a,,b`) → drop empties → `['a', 'b']`
19
- * - absolute path / `..` traversal → throw
20
- * - valid: `\` → `/` + lower-case + trim trailing slash + dedupe (preserves first occurrence order)
20
+ * - absolute path / `..` traversal / an entry naming the vault root (`.`, `./`) → throw
21
+ * - valid: `\` → `/`, empty and `.` segments dropped, lower-case, NFC, dedupe
22
+ * (preserves first occurrence order)
21
23
  *
22
- * Separator normalization is required for parity with `PathPolicy.normalize()`,
23
- * which also collapses `\` → `/` on candidate paths. Without matching
24
- * normalization here, a prefix like `Foo\Bar` would never match a candidate
25
- * `Foo\Bar\note.md` (candidate becomes `foo/bar/note.md`, prefix stays as
26
- * `foo\bar`).
24
+ * The stored form is `PathPolicy.normalize()`'s — the form a vault path
25
+ * reaches the plugin in — so a prefix and a candidate compare directly. A
26
+ * prefix kept as written (`foo\bar`, `./private`, `journal//therapy`) would
27
+ * match no vault path: a refusal for an allowlist, and a deny entry that
28
+ * silently denies nothing.
27
29
  */
28
30
  const envPathList = z
29
31
  .preprocess((val) => {
@@ -63,7 +65,7 @@ const envPathList = z
63
65
  });
64
66
  return z.NEVER;
65
67
  }
66
- const segments = raw.split(/[\\/]/);
68
+ const segments = raw.split(/[\\/]/).filter((s) => s !== '' && s !== '.');
67
69
  if (segments.includes('..')) {
68
70
  ctx.addIssue({
69
71
  code: 'custom',
@@ -71,9 +73,14 @@ const envPathList = z
71
73
  });
72
74
  return z.NEVER;
73
75
  }
74
- const normalized = raw.replace(/\\/g, '/').toLowerCase().replace(/\/+$/, '');
75
- if (normalized.length === 0)
76
- continue;
76
+ if (segments.length === 0) {
77
+ ctx.addIssue({
78
+ code: 'custom',
79
+ message: `must name a folder or note, not the vault root; got '${raw}'`,
80
+ });
81
+ return z.NEVER;
82
+ }
83
+ const normalized = segments.join('/').toLowerCase().normalize('NFC');
77
84
  if (seen.has(normalized))
78
85
  continue;
79
86
  seen.add(normalized);
@@ -95,8 +102,8 @@ const ServerConfigSchema = z.object({
95
102
  /**
96
103
  * Normalized here rather than at each `${baseUrl}${path}` join: the schema
97
104
  * is the one place that runs before anything reads the value, so a single
98
- * transform covers `#request`, the HEAD size probe, the capability probe,
99
- * and `deriveOmnisearchUrl` alike (issue #121).
105
+ * transform covers `#request` (the HEAD size probe included), the
106
+ * capability probe, and `deriveOmnisearchUrl` alike (issue #121).
100
107
  */
101
108
  .transform((url) => url.replace(/\/+$/, '')),
102
109
  verifySsl: envBoolean
@@ -106,13 +113,16 @@ const ServerConfigSchema = z.object({
106
113
  .number()
107
114
  .int()
108
115
  .positive()
116
+ // The longest delay a timer takes; past it both runtimes fire after 1 ms.
117
+ .max(2_147_483_647)
109
118
  .default(30_000)
110
- .describe('Per-request timeout in milliseconds.'),
119
+ .describe('Milliseconds (at most 2147483647) one attempt at a Local REST API request — headers and body — may take before it fails with `obsidian_timeout`; an Omnisearch query past it fails with `omnisearch_unreachable`. GET, PUT, and DELETE retry a timed-out attempt, and every Local REST API request one tool or resource call makes shares a budget of 45 s, or of this value when it is longer.'),
111
120
  enableCommands: envBoolean
112
121
  .default(false)
113
122
  .describe('Opt-in flag for the command-palette pair (`obsidian_list_commands` + `obsidian_execute_command`). Off by default — Obsidian commands are opaque and can be destructive.'),
114
- readPaths: envPathList.describe('Optional vault-relative folder allowlist for read operations. Comma-separated; prefix-based with implicit recursion; case-insensitive; trailing slashes normalized. Unset = full vault.'),
115
- writePaths: envPathList.describe('Optional vault-relative folder allowlist for write operations. Same syntax as OBSIDIAN_READ_PATHS. Write paths are implicitly readable. Unset = full vault, or the read scope when reads are restricted.'),
123
+ readPaths: envPathList.describe('Optional vault-relative folder allowlist for read operations. Comma-separated; prefix-based with implicit recursion; case-insensitive; backslashes read as slashes, repeated and trailing slashes and `.` segments dropped, and names normalized to Unicode NFC; an entry naming the vault root (`.`) is rejected at startup. Unset = full vault.'),
124
+ writePaths: envPathList.describe('Optional vault-relative folder allowlist for write operations. Same syntax as OBSIDIAN_READ_PATHS. Write paths are implicitly readable. Unset = full vault, or the read scope when reads are restricted; paths in OBSIDIAN_DENY_PATHS stay denied.'),
125
+ denyPaths: envPathList.describe('Optional vault-relative blocklist for reads and writes alike. Same syntax as OBSIDIAN_READ_PATHS. Wins over both allowlists: a denied path is unreadable and unwritable, and absent from listings, search results, and tag counts. Unset = nothing denied.'),
116
126
  readOnly: envBoolean
117
127
  .default(false)
118
128
  .describe('Global kill switch. When true, denies every write regardless of OBSIDIAN_WRITE_PATHS, and suppresses the OBSIDIAN_ENABLE_COMMANDS pair (commands can mutate). Defaults to false.'),
@@ -123,7 +133,7 @@ const ServerConfigSchema = z.object({
123
133
  .string()
124
134
  .url()
125
135
  .optional()
126
- .describe('Override URL for the Omnisearch plugin HTTP server. When unset, derives from OBSIDIAN_BASE_URL host with port 51361 (falling back to http://localhost:51361). Used to enable the optional `omnisearch` mode on `obsidian_search_notes`; if the URL is unreachable at startup, the mode is omitted from the tool schema.'),
136
+ .describe('Override URL for the Omnisearch plugin HTTP server. When unset, derives from OBSIDIAN_BASE_URL host with port 51361 (falling back to http://localhost:51361). Used to enable the optional `omnisearch` mode on `obsidian_search_notes`; if the URL is unreachable at startup, the mode is omitted from the tool schema. Under OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS the mode is withheld and the URL is never called: Omnisearch ranks and selects its results over the whole vault, so they depend on notes outside the scope.'),
127
137
  });
128
138
  let _config;
129
139
  export function getServerConfig() {
@@ -135,6 +145,7 @@ export function getServerConfig() {
135
145
  enableCommands: 'OBSIDIAN_ENABLE_COMMANDS',
136
146
  readPaths: 'OBSIDIAN_READ_PATHS',
137
147
  writePaths: 'OBSIDIAN_WRITE_PATHS',
148
+ denyPaths: 'OBSIDIAN_DENY_PATHS',
138
149
  readOnly: 'OBSIDIAN_READ_ONLY',
139
150
  deleteElicitation: 'OBSIDIAN_DELETE_ELICITATION',
140
151
  omnisearchUrl: 'OBSIDIAN_OMNISEARCH_URL',
@@ -1 +1 @@
1
- {"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * @fileoverview obsidian-mcp-server entry point. Initializes the Obsidian
4
- * Local REST API service at module load so the Omnisearch probe can run
4
+ * Local REST API service at module load so Omnisearch availability is decided
5
5
  * before tools are constructed — `obsidian_search_notes` is built via a
6
- * factory that takes Omnisearch reachability as input, so the `omnisearch`
7
- * mode appears in the tool schema only when the plugin is actually reachable.
6
+ * factory that takes it as input, so the `omnisearch` mode appears in the tool
7
+ * schema only with reads unscoped and the plugin actually reachable.
8
8
  * @module index
9
9
  */
10
10
  export {};
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * @fileoverview obsidian-mcp-server entry point. Initializes the Obsidian
4
- * Local REST API service at module load so the Omnisearch probe can run
4
+ * Local REST API service at module load so Omnisearch availability is decided
5
5
  * before tools are constructed — `obsidian_search_notes` is built via a
6
- * factory that takes Omnisearch reachability as input, so the `omnisearch`
7
- * mode appears in the tool schema only when the plugin is actually reachable.
6
+ * factory that takes it as input, so the `omnisearch` mode appears in the tool
7
+ * schema only with reads unscoped and the plugin actually reachable.
8
8
  * @module index
9
9
  */
10
10
  import { createApp, disabledTool } from '@cyanheads/mcp-ts-core';
@@ -13,21 +13,22 @@ import { getServerConfig } from './config/server-config.js';
13
13
  import { buildInstructions } from './instructions.js';
14
14
  import { allPromptDefinitions } from './mcp-server/prompts/definitions/index.js';
15
15
  import { allResourceDefinitions } from './mcp-server/resources/definitions/index.js';
16
- import { buildDeleteNoteTool, buildSearchNotesTool, commandToolDefinitions, readToolDefinitions, writeToolDefinitions, } from './mcp-server/tools/definitions/index.js';
16
+ import { buildDeleteNoteTool, buildSearchNotesTool, commandToolDefinitions, omnisearchAvailability, readToolDefinitions, writeToolDefinitions, } from './mcp-server/tools/definitions/index.js';
17
17
  import { getObsidianService, initObsidianService } from './services/obsidian/obsidian-service.js';
18
18
  import { PathPolicy } from './services/obsidian/path-policy.js';
19
19
  const config = getServerConfig();
20
20
  const policy = new PathPolicy(config);
21
21
  /**
22
- * Init the service at module load (rather than inside `setup()`) so the
23
- * Omnisearch probe can run before tool construction. `setup()` runs after
24
- * tools are passed into `createApp()`, which is too late to influence the
22
+ * Init the service at module load (rather than inside `setup()`) so
23
+ * Omnisearch availability — the probe, or `withheld` under a read scope with
24
+ * no probe — is known before tool construction. `setup()` runs after tools
25
+ * are passed into `createApp()`, which is too late to influence the
25
26
  * search-notes schema.
26
27
  */
27
28
  initObsidianService(config);
28
29
  const obsidian = getObsidianService();
29
- const omnisearchReachable = await obsidian.probeOmnisearch();
30
- const searchNotesTool = buildSearchNotesTool({ omnisearchReachable });
30
+ const omnisearch = await omnisearchAvailability(obsidian);
31
+ const searchNotesTool = buildSearchNotesTool({ omnisearch });
31
32
  const writeToolSet = [
32
33
  ...writeToolDefinitions,
33
34
  buildDeleteNoteTool({ elicitation: config.deleteElicitation }),
@@ -63,10 +64,12 @@ const { services } = await createApp({
63
64
  prompts: allPromptDefinitions,
64
65
  instructions: buildInstructions({
65
66
  enableCommands: config.enableCommands,
66
- omnisearchReachable,
67
+ omnisearch,
67
68
  policy,
68
69
  readOnly: config.readOnly,
69
70
  }),
71
+ /** Root `skills/`, served as `skill://<name>/SKILL.md` to clients without the plugin. */
72
+ skills: 'skills',
70
73
  /**
71
74
  * With `OBSIDIAN_DELETE_ELICITATION=true` (and writes allowed),
72
75
  * `obsidian_delete_note` confirms through `ctx.requestInput`, which a
@@ -92,7 +95,11 @@ const { services } = await createApp({
92
95
  * the tool is disabled there). The server `instructions` and the active scope
93
96
  * on `path_forbidden` errors state the effective scope instead (write paths
94
97
  * are readable; a write needs read access), so the LLM (or operator) can
95
- * self-correct without scrolling the log.
98
+ * self-correct without scrolling the log. The deny list (`denyPaths`, present
99
+ * when set) appears only here: the agent-facing surfaces say paths are
100
+ * withheld without naming them. `omnisearch` is the startup
101
+ * `omnisearchAvailability`; under a read scope it is `withheld` and the
102
+ * plugin was never probed.
96
103
  */
97
104
  const bannerCtx = requestContextService.createRequestContext({
98
105
  operation: 'startup',
@@ -101,14 +108,19 @@ const bannerCtx = requestContextService.createRequestContext({
101
108
  enableCommands: config.enableCommands && !config.readOnly,
102
109
  deleteElicitation: deleteGateActive,
103
110
  omnisearchUrl: obsidian.omnisearchUrl,
104
- omnisearchReachable,
111
+ omnisearch,
105
112
  },
106
113
  });
107
114
  services.logger.info('Path policy', bannerCtx);
108
- services.logger.info(omnisearchReachable
109
- ? `Omnisearch reachable at ${obsidian.omnisearchUrl} — \`omnisearch\` mode enabled on \`obsidian_search_notes\`.`
110
- : `Omnisearch not reachable at ${obsidian.omnisearchUrl} — \`omnisearch\` mode omitted from \`obsidian_search_notes\`. Set OBSIDIAN_OMNISEARCH_URL or enable the Omnisearch plugin's HTTP server to use it.`, bannerCtx);
115
+ services.logger.info({
116
+ offered: `Omnisearch reachable at ${obsidian.omnisearchUrl} — \`omnisearch\` mode enabled on \`obsidian_search_notes\`.`,
117
+ unreachable: `Omnisearch not reachable at ${obsidian.omnisearchUrl} — \`omnisearch\` mode omitted from \`obsidian_search_notes\`. Set OBSIDIAN_OMNISEARCH_URL or enable the Omnisearch plugin's HTTP server to use it.`,
118
+ withheld: 'Omnisearch not probed — `omnisearch` mode withheld from `obsidian_search_notes` because OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS scopes reads. Omnisearch ranks and selects its results over the whole vault, so they depend on notes outside the scope; `text` and `jsonlogic` modes search the readable notes alone.',
119
+ }[omnisearch], bannerCtx);
111
120
  if (policy.readOnlyShadowsWritePaths) {
112
121
  services.logger.warning('OBSIDIAN_WRITE_PATHS is set but ignored because OBSIDIAN_READ_ONLY=true. Unset one of the two to remove the conflict.', bannerCtx);
113
122
  }
123
+ for (const { variable, prefix } of policy.denyShadowedPaths) {
124
+ services.logger.warning(`${variable} entry '${prefix}' lies inside OBSIDIAN_DENY_PATHS and grants nothing. Remove it, or narrow the deny entry that covers it.`, bannerCtx);
125
+ }
114
126
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -2,18 +2,19 @@
2
2
  * @fileoverview The server-level `instructions` string sent on every
3
3
  * `initialize`: baseline orientation, then deployment-specific lines for
4
4
  * read-only mode, the effective path scope, the command-palette toggle, and
5
- * Omnisearch availability.
5
+ * the `omnisearch` mode when it is offered.
6
6
  * @module instructions
7
7
  */
8
+ import type { OmnisearchAvailability } from './mcp-server/tools/definitions/obsidian-search-notes.tool.js';
8
9
  import type { PathPolicy } from './services/obsidian/path-policy.js';
9
10
  /**
10
11
  * Build the instructions. The scope lines state what `path_forbidden`
11
12
  * enforces (`PathPolicy.effectiveScope`), not the configured lists the
12
- * startup banner reports.
13
+ * startup banner reports. Omnisearch appears only when the mode is `offered`.
13
14
  */
14
15
  export declare function buildInstructions(opts: {
15
16
  enableCommands: boolean;
16
- omnisearchReachable: boolean;
17
+ omnisearch: OmnisearchAvailability;
17
18
  policy: PathPolicy;
18
19
  readOnly: boolean;
19
20
  }): string;
@@ -1 +1 @@
1
- {"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAarE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,MAAM,CA6BT"}
1
+ {"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8DAA8D,CAAC;AAC3G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAsBrE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,MAAM,CA+BT"}
@@ -2,38 +2,49 @@
2
2
  * @fileoverview The server-level `instructions` string sent on every
3
3
  * `initialize`: baseline orientation, then deployment-specific lines for
4
4
  * read-only mode, the effective path scope, the command-palette toggle, and
5
- * Omnisearch availability.
5
+ * the `omnisearch` mode when it is offered.
6
6
  * @module instructions
7
7
  */
8
- const BASELINE = 'Use the `obsidian_*` tools to access the Obsidian vault via the Local REST API plugin: search, read, write, and patch notes, including targeted edits to headings, blocks, and YAML frontmatter. Notes are addressed by vault-relative path including the file extension (e.g. `Folder/Note.md`); tags support hierarchical `parent/child` notation, and counts roll up to parents.';
8
+ const BASELINE = 'Use the `obsidian_*` tools to access the Obsidian vault via the Local REST API plugin: search, read, write, and patch notes, including targeted edits to headings, blocks, and YAML frontmatter. Notes are addressed by vault-relative path including the file extension (e.g. `Folder/Note.md`); tags support hierarchical `parent/child` notation, and counts roll up to parents. The obsidian-guide skill (`skill://obsidian-guide/SKILL.md`) carries the gates for edits that span calls: pinning `active` and `periodic` targets, round-tripping heading sections, paging a search before editing its hits, matching tags, and repeating a write after a timeout or a dropped connection.';
9
9
  const SCOPE_RECOVERY = 'Paths outside scope reject with `path_forbidden` — error data carries the active scope so you can self-correct.';
10
- /** Prefixes as the instructions quote them; `undefined` is an unrestricted op. */
11
- function renderScope(scope) {
12
- return scope === undefined ? 'full vault' : scope.map((p) => `'${p}'`).join(', ');
10
+ const WITHHELD_RECOVERY = 'Withheld paths reject with subreason `denied_path` and carry no scope.';
11
+ /**
12
+ * Prefixes as the instructions quote them; `undefined` is an unrestricted op,
13
+ * `[]` an op that reaches nothing. `withheld` notes that OBSIDIAN_DENY_PATHS
14
+ * carves paths out of the scope, without naming them: the deny prefixes name
15
+ * exactly what the list hides.
16
+ */
17
+ function renderScope(scope, withheld) {
18
+ if (scope?.length === 0)
19
+ return 'none';
20
+ const reach = scope === undefined ? 'full vault' : scope.map((p) => `'${p}'`).join(', ');
21
+ return withheld ? `${reach}, except paths the operator withholds` : reach;
13
22
  }
14
23
  /**
15
24
  * Build the instructions. The scope lines state what `path_forbidden`
16
25
  * enforces (`PathPolicy.effectiveScope`), not the configured lists the
17
- * startup banner reports.
26
+ * startup banner reports. Omnisearch appears only when the mode is `offered`.
18
27
  */
19
28
  export function buildInstructions(opts) {
20
- const { enableCommands, omnisearchReachable, policy, readOnly } = opts;
29
+ const { enableCommands, omnisearch, policy, readOnly } = opts;
21
30
  const { readable, writable } = policy.effectiveScope();
31
+ const withheld = policy.withholdsPaths;
32
+ const recovery = withheld ? `${SCOPE_RECOVERY} ${WITHHELD_RECOVERY}` : SCOPE_RECOVERY;
22
33
  const sections = [BASELINE];
23
34
  if (readOnly) {
24
35
  sections.push('Read-only mode is active (OBSIDIAN_READ_ONLY=true): write tools are unavailable. `obsidian_open_in_ui` still opens notes that exist, but rejects an open against a missing path — Obsidian would create the file.');
25
- if (readable !== undefined) {
26
- sections.push(`Vault path policy is enforced. Readable: ${renderScope(readable)}. ${SCOPE_RECOVERY}`);
36
+ if (readable !== undefined || withheld) {
37
+ sections.push(`Vault path policy is enforced. Readable: ${renderScope(readable, withheld)}. ${recovery}`);
27
38
  }
28
39
  }
29
40
  else if (!policy.isUnrestricted) {
30
- sections.push(`Vault path policy is enforced. Readable: ${renderScope(readable)}. Writable: ${renderScope(writable)}. ${SCOPE_RECOVERY}`);
41
+ sections.push(`Vault path policy is enforced. Readable: ${renderScope(readable, withheld)}. Writable: ${renderScope(writable, withheld)}. ${recovery}`);
31
42
  }
32
43
  if (enableCommands && !readOnly) {
33
44
  sections.push('Command-palette tools (`obsidian_list_commands`, `obsidian_execute_command`) are enabled and can fire any Obsidian command. Commands are opaque and may be destructive — prefer dedicated tools when one fits.');
34
45
  }
35
- if (omnisearchReachable) {
36
- sections.push('`obsidian_search_notes` includes an `omnisearch` mode: BM25-ranked, typo-tolerant, with PDF/OCR coverage (via the Text Extractor plugin). Results cap at 50 upstream — narrow the query (quoted phrases, `-exclusion`, `path:` / `ext:` filters) to surface more.');
46
+ if (omnisearch === 'offered') {
47
+ sections.push('`obsidian_search_notes` includes an `omnisearch` mode: BM25-ranked, typo-tolerant, with PDF/OCR coverage (via the Text Extractor plugin). Omnisearch keeps only its top 50 matches: narrow with `path:` / `ext:` filters or more plain terms, which apply before that cap. Quoted phrases and `-exclusion` filter only those 50, so a result using them is marked `truncated`.');
37
48
  }
38
49
  return sections.join('\n\n');
39
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"instructions.js","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,QAAQ,GACZ,qXAAqX,CAAC;AAExX,MAAM,cAAc,GAClB,iHAAiH,CAAC;AAEpH,kFAAkF;AAClF,SAAS,WAAW,CAAC,KAAoC;IACvD,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAKjC;IACC,MAAM,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IACvE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;IACvD,MAAM,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC5B,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,IAAI,CACX,mNAAmN,CACpN,CAAC;QACF,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CACX,4CAA4C,WAAW,CAAC,QAAQ,CAAC,KAAK,cAAc,EAAE,CACvF,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAClC,QAAQ,CAAC,IAAI,CACX,4CAA4C,WAAW,CAAC,QAAQ,CAAC,eAAe,WAAW,CAAC,QAAQ,CAAC,KAAK,cAAc,EAAE,CAC3H,CAAC;IACJ,CAAC;IACD,IAAI,cAAc,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChC,QAAQ,CAAC,IAAI,CACX,gNAAgN,CACjN,CAAC;IACJ,CAAC;IACD,IAAI,mBAAmB,EAAE,CAAC;QACxB,QAAQ,CAAC,IAAI,CACX,mQAAmQ,CACpQ,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC"}
1
+ {"version":3,"file":"instructions.js","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,MAAM,QAAQ,GACZ,gqBAAgqB,CAAC;AAEnqB,MAAM,cAAc,GAClB,iHAAiH,CAAC;AAEpH,MAAM,iBAAiB,GAAG,wEAAwE,CAAC;AAEnG;;;;;GAKG;AACH,SAAS,WAAW,CAAC,KAAoC,EAAE,QAAiB;IAC1E,IAAI,KAAK,EAAE,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACvC,MAAM,KAAK,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzF,OAAO,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,uCAAuC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAKjC;IACC,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAC9D,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;IACvD,MAAM,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAC;IACvC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,cAAc,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC;IACtF,MAAM,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC5B,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,IAAI,CACX,mNAAmN,CACpN,CAAC;QACF,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,EAAE,CAAC;YACvC,QAAQ,CAAC,IAAI,CACX,4CAA4C,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,QAAQ,EAAE,CAC3F,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAClC,QAAQ,CAAC,IAAI,CACX,4CAA4C,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,eAAe,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,QAAQ,EAAE,CACzI,CAAC;IACJ,CAAC;IACD,IAAI,cAAc,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChC,QAAQ,CAAC,IAAI,CACX,gNAAgN,CACjN,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CACX,gXAAgX,CACjX,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC"}
@@ -17,8 +17,8 @@ export declare const allResourceDefinitions: (import("@cyanheads/mcp-ts-core").R
17
17
  }, import("zod/v4/core").$strip>, readonly [{
18
18
  readonly reason: "path_forbidden";
19
19
  readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.Forbidden;
20
- readonly when: "The requested path is outside OBSIDIAN_READ_PATHS (and OBSIDIAN_WRITE_PATHS, since write paths imply read access).";
21
- readonly recovery: "Use a path inside the configured read scope. The error data echoes the active scope.";
20
+ readonly when: "The requested path is outside OBSIDIAN_READ_PATHS (and OBSIDIAN_WRITE_PATHS, since write paths imply read access), or inside OBSIDIAN_DENY_PATHS.";
21
+ readonly recovery: "Use a path inside the configured read scope. The error data echoes the active scope; a `denied_path` denial carries none, since the operator withholds that path.";
22
22
  }, {
23
23
  readonly reason: "note_missing";
24
24
  readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
@@ -4,8 +4,9 @@
4
4
  *
5
5
  * Not a mirror of `obsidian_list_tags`: this is a snapshot of
6
6
  * `ObsidianService.listTags`, returned whole and unsorted — the upstream
7
- * `/tags/` payload in upstream order, or under OBSIDIAN_READ_PATHS the tags of
8
- * readable notes in order of first appearance. The tool shapes the same
7
+ * `/tags/` payload in upstream order, or under OBSIDIAN_READ_PATHS or
8
+ * OBSIDIAN_DENY_PATHS the tags of readable notes in order of first
9
+ * appearance. The tool shapes the same
9
10
  * payload for an LLM caller — count-descending, capped, filterable — and that
10
11
  * shaping deliberately lives in the tool handler rather than the shared
11
12
  * service call both make.
@@ -1 +1 @@
1
- {"version":3,"file":"obsidian-tags.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/obsidian-tags.resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGrD,eAAO,MAAM,YAAY;;;;;6BA+BvB,CAAC"}
1
+ {"version":3,"file":"obsidian-tags.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/obsidian-tags.resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGrD,eAAO,MAAM,YAAY;;;;;6BA+BvB,CAAC"}
@@ -4,8 +4,9 @@
4
4
  *
5
5
  * Not a mirror of `obsidian_list_tags`: this is a snapshot of
6
6
  * `ObsidianService.listTags`, returned whole and unsorted — the upstream
7
- * `/tags/` payload in upstream order, or under OBSIDIAN_READ_PATHS the tags of
8
- * readable notes in order of first appearance. The tool shapes the same
7
+ * `/tags/` payload in upstream order, or under OBSIDIAN_READ_PATHS or
8
+ * OBSIDIAN_DENY_PATHS the tags of readable notes in order of first
9
+ * appearance. The tool shapes the same
9
10
  * payload for an LLM caller — count-descending, capped, filterable — and that
10
11
  * shaping deliberately lives in the tool handler rather than the shared
11
12
  * service call both make.
@@ -15,7 +16,7 @@ import { resource, z } from '@cyanheads/mcp-ts-core';
15
16
  import { getObsidianService } from '../../../services/obsidian/obsidian-service.js';
16
17
  export const obsidianTags = resource('obsidian://tags', {
17
18
  name: 'obsidian-tags',
18
- description: 'All tags found in the Obsidian vault, with usage counts, unsorted and uncapped — a full snapshot. When OBSIDIAN_READ_PATHS is set, only tags carried by readable notes. Includes hierarchical parents (e.g. `work` for `work/tasks`). Use the `obsidian_list_tags` tool for a count-ranked, capped, filterable view.',
19
+ description: 'All tags found in the Obsidian vault, with usage counts, unsorted and uncapped — a full snapshot. When OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS is set, only tags carried by readable notes. Includes hierarchical parents (e.g. `work` for `work/tasks`). Use the `obsidian_list_tags` tool for a count-ranked, capped, filterable view.',
19
20
  mimeType: 'application/json',
20
21
  params: z.object({}),
21
22
  output: z.object({
@@ -25,10 +26,10 @@ export const obsidianTags = resource('obsidian://tags', {
25
26
  name: z.string().describe('Tag name without the leading `#`.'),
26
27
  count: z
27
28
  .number()
28
- .describe('Times the tag, or a tag nested under it, occurs across the vault. When OBSIDIAN_READ_PATHS is set: the number of readable notes carrying the tag or a tag nested under it.'),
29
+ .describe('Times the tag, or a tag nested under it, occurs across the vault. When OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS is set: the number of readable notes carrying the tag or a tag nested under it.'),
29
30
  })
30
31
  .describe('A tag with its usage count.'))
31
- .describe('Every tag in the vault, in the order the Local REST API reports them. When OBSIDIAN_READ_PATHS is set: every tag carried by a readable note, in order of first appearance.'),
32
+ .describe('Every tag in the vault, in the order the Local REST API reports them. When OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS is set: every tag carried by a readable note, in order of first appearance.'),
32
33
  }),
33
34
  auth: ['resource:obsidian-tags:read'],
34
35
  async handler(_params, ctx) {
@@ -1 +1 @@
1
- {"version":3,"file":"obsidian-tags.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/obsidian-tags.resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAC,iBAAiB,EAAE;IACtD,IAAI,EAAE,eAAe;IACrB,WAAW,EACT,sTAAsT;IACxT,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACpB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC;aACJ,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;YAC9D,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,CACP,4KAA4K,CAC7K;SACJ,CAAC;aACD,QAAQ,CAAC,6BAA6B,CAAC,CAC3C;aACA,QAAQ,CACP,4KAA4K,CAC7K;KACJ,CAAC;IACF,IAAI,EAAE,CAAC,6BAA6B,CAAC;IAErC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG;QACxB,MAAM,GAAG,GAAG,kBAAkB,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;IACvE,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"obsidian-tags.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/obsidian-tags.resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAC,iBAAiB,EAAE;IACtD,IAAI,EAAE,eAAe;IACrB,WAAW,EACT,6UAA6U;IAC/U,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACpB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC;aACJ,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;YAC9D,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,CACP,mMAAmM,CACpM;SACJ,CAAC;aACD,QAAQ,CAAC,6BAA6B,CAAC,CAC3C;aACA,QAAQ,CACP,mMAAmM,CACpM;KACJ,CAAC;IACF,IAAI,EAAE,CAAC,6BAA6B,CAAC;IAErC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG;QACxB,MAAM,GAAG,GAAG,kBAAkB,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;IACvE,CAAC;CACF,CAAC,CAAC"}
@@ -21,8 +21,8 @@ export declare const obsidianVaultNote: import("@cyanheads/mcp-ts-core").Resourc
21
21
  }, z.core.$strip>, readonly [{
22
22
  readonly reason: "path_forbidden";
23
23
  readonly code: JsonRpcErrorCode.Forbidden;
24
- readonly when: "The requested path is outside OBSIDIAN_READ_PATHS (and OBSIDIAN_WRITE_PATHS, since write paths imply read access).";
25
- readonly recovery: "Use a path inside the configured read scope. The error data echoes the active scope.";
24
+ readonly when: "The requested path is outside OBSIDIAN_READ_PATHS (and OBSIDIAN_WRITE_PATHS, since write paths imply read access), or inside OBSIDIAN_DENY_PATHS.";
25
+ readonly recovery: "Use a path inside the configured read scope. The error data echoes the active scope; a `denied_path` denial carries none, since the operator withholds that path.";
26
26
  }, {
27
27
  readonly reason: "note_missing";
28
28
  readonly code: JsonRpcErrorCode.NotFound;
@@ -34,8 +34,8 @@ export const obsidianVaultNote = resource('obsidian://vault/{+path}', {
34
34
  {
35
35
  reason: 'path_forbidden',
36
36
  code: JsonRpcErrorCode.Forbidden,
37
- when: 'The requested path is outside OBSIDIAN_READ_PATHS (and OBSIDIAN_WRITE_PATHS, since write paths imply read access).',
38
- recovery: 'Use a path inside the configured read scope. The error data echoes the active scope.',
37
+ when: 'The requested path is outside OBSIDIAN_READ_PATHS (and OBSIDIAN_WRITE_PATHS, since write paths imply read access), or inside OBSIDIAN_DENY_PATHS.',
38
+ recovery: 'Use a path inside the configured read scope. The error data echoes the active scope; a `denied_path` denial carries none, since the operator withholds that path.',
39
39
  },
40
40
  {
41
41
  reason: 'note_missing',
@@ -1 +1 @@
1
- {"version":3,"file":"obsidian-vault-note.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/obsidian-vault-note.resource.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,0BAA0B,EAAE;IACpE,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EACT,yJAAyJ;IAC3J,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,uDAAuD,CAAC;KAC1F,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QAC7D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QAClD,WAAW,EAAE,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;aAC/B,QAAQ,CACP,4FAA4F,CAC7F;QACH,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QACnF,IAAI,EAAE,CAAC;aACJ,MAAM,CAAC;YACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAC3D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;YAC5D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;SACjD,CAAC;aACD,QAAQ,CAAC,gBAAgB,CAAC;KAC9B,CAAC;IACF,IAAI,EAAE,CAAC,mCAAmC,CAAC;IAC3C,MAAM,EAAE;QACN;YACE,MAAM,EAAE,gBAAgB;YACxB,IAAI,EAAE,gBAAgB,CAAC,SAAS;YAChC,IAAI,EAAE,oHAAoH;YAC1H,QAAQ,EACN,sFAAsF;SACzF;QACD;YACE,MAAM,EAAE,cAAc;YACtB,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,sDAAsD;YAC5D,QAAQ,EACN,2FAA2F;SAC9F;QACD;YACE,MAAM,EAAE,mBAAmB;YAC3B,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,4DAA4D;YAClE,QAAQ,EACN,kHAAkH;SACrH;KACF;IAED,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG;QACvB,MAAM,GAAG,GAAG,kBAAkB,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,OAAO,QAAQ,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAAC,GAAG,EAAE,EAAE;QACvD,IAAI,CAAC;YACH,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"obsidian-vault-note.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/obsidian-vault-note.resource.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,0BAA0B,EAAE;IACpE,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EACT,yJAAyJ;IAC3J,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,uDAAuD,CAAC;KAC1F,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QAC7D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QAClD,WAAW,EAAE,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;aAC/B,QAAQ,CACP,4FAA4F,CAC7F;QACH,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QACnF,IAAI,EAAE,CAAC;aACJ,MAAM,CAAC;YACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAC3D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;YAC5D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;SACjD,CAAC;aACD,QAAQ,CAAC,gBAAgB,CAAC;KAC9B,CAAC;IACF,IAAI,EAAE,CAAC,mCAAmC,CAAC;IAC3C,MAAM,EAAE;QACN;YACE,MAAM,EAAE,gBAAgB;YACxB,IAAI,EAAE,gBAAgB,CAAC,SAAS;YAChC,IAAI,EAAE,mJAAmJ;YACzJ,QAAQ,EACN,mKAAmK;SACtK;QACD;YACE,MAAM,EAAE,cAAc;YACtB,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,sDAAsD;YAC5D,QAAQ,EACN,2FAA2F;SAC9F;QACD;YACE,MAAM,EAAE,mBAAmB;YAC3B,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,4DAA4D;YAClE,QAAQ,EACN,kHAAkH;SACrH;KACF;IAED,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG;QACvB,MAAM,GAAG,GAAG,kBAAkB,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,OAAO,QAAQ,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAAC,GAAG,EAAE,EAAE;QACvD,IAAI,CAAC;YACH,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}