obsidian-mcp-server 3.3.1 → 3.4.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 (27) hide show
  1. package/AGENTS.md +7 -5
  2. package/CLAUDE.md +7 -5
  3. package/README.md +4 -4
  4. package/changelog/3.4.x/3.4.0.md +25 -0
  5. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts +8 -2
  6. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts.map +1 -1
  7. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js +10 -4
  8. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js.map +1 -1
  9. package/dist/mcp-server/tools/definitions/index.d.ts +9 -2
  10. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  11. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts +15 -6
  12. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts.map +1 -1
  13. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js +90 -21
  14. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js.map +1 -1
  15. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +30 -2
  16. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -1
  17. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +57 -12
  18. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -1
  19. package/dist/services/obsidian/obsidian-service.d.ts +7 -0
  20. package/dist/services/obsidian/obsidian-service.d.ts.map +1 -1
  21. package/dist/services/obsidian/obsidian-service.js +205 -48
  22. package/dist/services/obsidian/obsidian-service.js.map +1 -1
  23. package/dist/services/obsidian/types.d.ts +8 -0
  24. package/dist/services/obsidian/types.d.ts.map +1 -1
  25. package/manifest.json +1 -1
  26. package/package.json +2 -2
  27. package/server.json +3 -3
package/AGENTS.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Agent Protocol
2
2
 
3
3
  **Server:** obsidian-mcp-server
4
- **Version:** 3.3.1
4
+ **Version:** 3.4.0
5
5
  **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.12.3`
6
6
  **Engines:** Bun ≥1.3.0, Node ≥24.0.0
7
7
  **MCP SDK:** `@modelcontextprotocol/server` ^2.0.0
@@ -47,7 +47,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
47
47
 
48
48
  ### Tool — `obsidian_list_tags`
49
49
 
50
- 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()`.
50
+ 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()`. Reduced for illustration — the live definition also carries `nameRegex` / `minCount` / `limit` inputs, the count-descending sort and cap they feed, an `errors[]` contract, and an `enrichment` block.
51
51
 
52
52
  ```ts
53
53
  import { tool, z } from '@cyanheads/mcp-ts-core';
@@ -66,7 +66,7 @@ export const obsidianListTags = tool('obsidian_list_tags', {
66
66
  count: z.number().describe('Usage count across the vault.'),
67
67
  }).describe('A tag with its usage count.'),
68
68
  )
69
- .describe('All tags in the vault, in upstream-provided order.'),
69
+ .describe('Matching tags ordered by `count` descending.'),
70
70
  }),
71
71
  auth: ['tool:obsidian_list_tags:read'],
72
72
 
@@ -216,8 +216,10 @@ Services that accept `ctx` use the same resolver for parity. The Obsidian servic
216
216
 
217
217
  ```ts
218
218
  // inside obsidian-service.ts
219
- throw notFound(`Not found: ${display}`, data('note_missing'));
220
- // where data(reason) does: { path, reason, ...ctx.recoveryFor(reason), upstream? }
219
+ throw notFound(`Not found: ${display}`, data('note_missing'), { cause });
220
+ // where data(reason) does: { path, reason, ...ctx.recoveryFor(reason) }
221
+ // The upstream body is never spread into `data` — it rides as `cause`, which
222
+ // is non-enumerable and so reaches the log without reaching the client.
221
223
  ```
222
224
 
223
225
  **Fallback for ad-hoc throws** (no contract entry fits, prototype tools, service-layer code without a contract): use error factories.
package/CLAUDE.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Agent Protocol
2
2
 
3
3
  **Server:** obsidian-mcp-server
4
- **Version:** 3.3.1
4
+ **Version:** 3.4.0
5
5
  **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.12.3`
6
6
  **Engines:** Bun ≥1.3.0, Node ≥24.0.0
7
7
  **MCP SDK:** `@modelcontextprotocol/server` ^2.0.0
@@ -47,7 +47,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
47
47
 
48
48
  ### Tool — `obsidian_list_tags`
49
49
 
50
- 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()`.
50
+ 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()`. Reduced for illustration — the live definition also carries `nameRegex` / `minCount` / `limit` inputs, the count-descending sort and cap they feed, an `errors[]` contract, and an `enrichment` block.
51
51
 
52
52
  ```ts
53
53
  import { tool, z } from '@cyanheads/mcp-ts-core';
@@ -66,7 +66,7 @@ export const obsidianListTags = tool('obsidian_list_tags', {
66
66
  count: z.number().describe('Usage count across the vault.'),
67
67
  }).describe('A tag with its usage count.'),
68
68
  )
69
- .describe('All tags in the vault, in upstream-provided order.'),
69
+ .describe('Matching tags ordered by `count` descending.'),
70
70
  }),
71
71
  auth: ['tool:obsidian_list_tags:read'],
72
72
 
@@ -216,8 +216,10 @@ Services that accept `ctx` use the same resolver for parity. The Obsidian servic
216
216
 
217
217
  ```ts
218
218
  // inside obsidian-service.ts
219
- throw notFound(`Not found: ${display}`, data('note_missing'));
220
- // where data(reason) does: { path, reason, ...ctx.recoveryFor(reason), upstream? }
219
+ throw notFound(`Not found: ${display}`, data('note_missing'), { cause });
220
+ // where data(reason) does: { path, reason, ...ctx.recoveryFor(reason) }
221
+ // The upstream body is never spread into `data` — it rides as `cause`, which
222
+ // is non-enumerable and so reaches the log without reaching the client.
221
223
  ```
222
224
 
223
225
  **Fallback for ad-hoc throws** (no contract entry fits, prototype tools, service-layer code without a contract): use error factories.
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  <div align="center">
9
9
 
10
- [![Version](https://img.shields.io/badge/Version-3.3.1-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/obsidian-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/obsidian-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/obsidian-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3.0-blueviolet.svg?style=flat-square)](https://bun.sh/)
10
+ [![Version](https://img.shields.io/badge/Version-3.4.0-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/obsidian-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/obsidian-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/obsidian-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3.0-blueviolet.svg?style=flat-square)](https://bun.sh/)
11
11
 
12
12
  </div>
13
13
 
@@ -29,7 +29,7 @@ Fourteen tools grouped by shape — readers fetch notes and metadata, writers cr
29
29
  |:----------|:------------|
30
30
  | `obsidian_get_note` | Read a note as raw content, full structured form (content + frontmatter + tags + stat, with optional outgoing links), structural document map, or a single section. |
31
31
  | `obsidian_list_notes` | List notes and subdirectories under a vault path. Recursive walk (default depth 2, max depth 20; 1000-entry cap) with optional `extension` and `nameRegex` filters. |
32
- | `obsidian_list_tags` | List every tag found across the vault with usage counts, including hierarchical parents. Optional `nameRegex` post-filters the result set. |
32
+ | `obsidian_list_tags` | List vault tags with usage counts, including hierarchical parents. Ordered by count descending and capped at `limit` (default 200, max 10000), with the withheld remainder disclosed. Optional `nameRegex` and `minCount` narrow the set first. |
33
33
  | `obsidian_list_commands` | List Obsidian command-palette commands, optionally filtered by `nameRegex` on display name. **Opt-in via `OBSIDIAN_ENABLE_COMMANDS=true`** (paired with `obsidian_execute_command`). |
34
34
  | `obsidian_search_notes` | Search the vault by text, JSONLogic, or BM25-ranked Omnisearch (when the plugin is reachable). Results paginate via opaque cursors. |
35
35
  | `obsidian_write_note` | Create a note, replace a single section in place, or — with `overwrite: true` — clobber an existing file. Refuses whole-file writes against an existing path by default. |
@@ -60,7 +60,7 @@ Pair the document-map projection with `obsidian_patch_note` to discover edit tar
60
60
  Up to three search modes selected by `mode`:
61
61
 
62
62
  - `text` — substring match with surrounding context windows. `contextLength` controls characters of context per side of each match (default 100; bump it for more context per hit). Optional `pathPrefix` filter (text mode only — passing `pathPrefix` in any other mode is rejected with `path_prefix_invalid_mode`).
63
- - `jsonlogic` — JSONLogic tree evaluated against `path`, `content`, `frontmatter.<key>`, `tags`, and `stat.{ctime,mtime,size}`; custom `glob` and `regexp` operators
63
+ - `jsonlogic` — JSONLogic tree evaluated against `path`, `content`, `frontmatter.<key>`, `tags`, and `stat.{ctime,mtime,size}`; custom `glob` and `regexp` operators, both taking `[PATTERN, VALUE]` — pattern first, then the field reference: `{"glob": ["Projects/*.md", {"var": "path"}]}`. The reverse order compiles the note's own field as the pattern: `glob` then matches nothing, and `regexp` fails outright on whatever the field parses as. This is also how backlinks are expressed, since there is no dedicated tool or upstream endpoint for them: `{"regexp": ["\\[\\[Target Note(\\||#|\\]\\])", {"var": "content"}]}` returns every note whose body wikilinks `Target Note`.
64
64
  - `omnisearch` — BM25-ranked search via the community [Omnisearch](https://github.com/scambier/obsidian-omnisearch) plugin. Supports quoted phrases, `-exclusion`, `path:` / `ext:` filters, typo tolerance, and PDF + OCR coverage (via [Text Extractor](https://github.com/scambier/obsidian-text-extractor)). Only present in the mode enum when the plugin's HTTP server is reachable at startup; the upstream hard-caps results at 50 — narrow the query to surface more (the response carries `truncated: true` when the cap was likely hit).
65
65
 
66
66
  Results paginate via opaque cursors per the [MCP 2025-11-25 spec](https://modelcontextprotocol.io/specification/2025-11-25/utils/pagination): omit `cursor` for the first page, then pass `nextCursor` from the prior response. Every result carries `totalCount` (post-path-policy, pre-pagination); `nextCursor` is omitted on the last page. Text-mode hits are additionally clipped per file at `maxMatchesPerHit` (default 10) so a single match-heavy note can't blow the response budget — clipped hits carry `truncated: true` and `totalMatches`.
@@ -181,7 +181,7 @@ The startup banner logs the active scope so operators can verify their config at
181
181
  | Resource | `obsidian://tags` | All tags found across the vault, with usage counts. |
182
182
  | Resource | `obsidian://status` | Server reachability, auth status, plugin/Obsidian version info, and the plugin manifest. |
183
183
 
184
- All resource data is also reachable via tools — `obsidian_get_note` for `obsidian://vault/{+path}`, `obsidian_list_tags` for `obsidian://tags`. Resources exist for clients that prefer attaching a specific note or vault snapshot to a conversation.
184
+ All resource data is also reachable via tools — `obsidian_get_note` for `obsidian://vault/{+path}`, `obsidian_list_tags` for `obsidian://tags`. Resources exist for clients that prefer attaching a specific note or vault snapshot to a conversation. The tag pair is not a mirror: `obsidian://tags` keeps snapshot semantics and returns the upstream payload whole and unsorted, while `obsidian_list_tags` orders by count and caps.
185
185
 
186
186
  ## Features
187
187
 
@@ -0,0 +1,25 @@
1
+ ---
2
+ summary: "obsidian_list_tags now sorts by count and caps at limit by default; JSONLogic glob/regexp docs and text-search offsets are fixed; upstream error text no longer reaches clients."
3
+ breaking: true
4
+ security: true
5
+ ---
6
+
7
+ # 3.4.0 — 2026-08-22
8
+
9
+ ## Changed
10
+
11
+ - **`obsidian_list_tags` now orders by usage count (descending, ties by name) and caps the response at `limit`** (default 200, max 10000), disclosing how many tags were withheld ([#110](https://github.com/cyanheads/obsidian-mcp-server/issues/110)). A zero-argument call previously returned the vault's entire tag list in upstream order; existing callers now see at most 200, most-used first. New `minCount` drops the single-use tail. `obsidian://tags` is unchanged — still an unsorted, uncapped snapshot.
12
+
13
+ ### Dependency bumps
14
+
15
+ - `vitest` ^4.1.10 → ^4.1.11
16
+
17
+ ## Fixed
18
+
19
+ - **`obsidian_search_notes`'s `glob`/`regexp` JSONLogic operators were documented backwards everywhere they appear** — the `logic` field, both `mode` descriptions, and the `logic_required` recovery hint now state the actual `[PATTERN, VALUE]` order, and a rejected tree classifies as `logic_invalid` instead of a generic 400 ([#113](https://github.com/cyanheads/obsidian-mcp-server/issues/113)).
20
+ - **Text-search hit offsets were documented and computed as `context`-relative but are actually relative to the matched subject** (the note body, or its basename for a filename match) — new `contextStart`/`contextEnd` index `context` directly, and `format()` now fences rendered note excerpts, Omnisearch excerpts, and JSONLogic results wide enough that backticks in vault text can't break out of the code block ([#114](https://github.com/cyanheads/obsidian-mcp-server/issues/114)).
21
+ - **An oversized `contextLength` on a broad `obsidian_search_notes` query failed with an untyped internal error** — it now throws a typed `context_length_too_large` `ValidationError` naming `contextLength` and the query itself as the two levers to narrow ([#115](https://github.com/cyanheads/obsidian-mcp-server/issues/115)).
22
+
23
+ ## Security
24
+
25
+ - **Upstream error text no longer reaches clients.** `ObsidianService#throwForStatus` dropped `data.upstream` and `data.body` from every branch — Local REST API error bodies can carry vault note paths, note body content, and absolute filesystem paths regardless of `OBSIDIAN_READ_PATHS` scoping. Errors now carry only server-authored messages plus `path`, `status`, and the calling tool's contract `reason` ([#116](https://github.com/cyanheads/obsidian-mcp-server/issues/116), [#104](https://github.com/cyanheads/obsidian-mcp-server/issues/104)).
@@ -1,6 +1,12 @@
1
1
  /**
2
- * @fileoverview obsidian://tags — vault tag listing with usage counts.
3
- * Mirrors `obsidian_list_tags` for clients that prefer attaching resources.
2
+ * @fileoverview obsidian://tags — vault tag listing with usage counts, for
3
+ * clients that prefer attaching resources.
4
+ *
5
+ * Not a mirror of `obsidian_list_tags`: this is a snapshot of the upstream
6
+ * `/tags/` payload, returned whole and in upstream order. The tool shapes the
7
+ * same payload for an LLM caller — count-descending, capped, filterable — and
8
+ * that shaping deliberately lives in the tool handler rather than the shared
9
+ * `ObsidianService.listTags` both call.
4
10
  * @module mcp-server/resources/definitions/obsidian-tags.resource
5
11
  */
6
12
  import { z } from '@cyanheads/mcp-ts-core';
@@ -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;;;;GAIG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGrD,eAAO,MAAM,YAAY;;;;;6BAyBvB,CAAC"}
1
+ {"version":3,"file":"obsidian-tags.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/obsidian-tags.resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGrD,eAAO,MAAM,YAAY;;;;;6BAyBvB,CAAC"}
@@ -1,13 +1,19 @@
1
1
  /**
2
- * @fileoverview obsidian://tags — vault tag listing with usage counts.
3
- * Mirrors `obsidian_list_tags` for clients that prefer attaching resources.
2
+ * @fileoverview obsidian://tags — vault tag listing with usage counts, for
3
+ * clients that prefer attaching resources.
4
+ *
5
+ * Not a mirror of `obsidian_list_tags`: this is a snapshot of the upstream
6
+ * `/tags/` payload, returned whole and in upstream order. The tool shapes the
7
+ * same payload for an LLM caller — count-descending, capped, filterable — and
8
+ * that shaping deliberately lives in the tool handler rather than the shared
9
+ * `ObsidianService.listTags` both call.
4
10
  * @module mcp-server/resources/definitions/obsidian-tags.resource
5
11
  */
6
12
  import { resource, z } from '@cyanheads/mcp-ts-core';
7
13
  import { getObsidianService } from '../../../services/obsidian/obsidian-service.js';
8
14
  export const obsidianTags = resource('obsidian://tags', {
9
15
  name: 'obsidian-tags',
10
- description: 'All tags found in the Obsidian vault, with usage counts. Includes hierarchical parents (e.g. `work` for `work/tasks`).',
16
+ description: 'All tags found in the Obsidian vault, with usage counts, in upstream order and uncapped — a full snapshot. Includes hierarchical parents (e.g. `work` for `work/tasks`). Use the `obsidian_list_tags` tool for a count-ranked, capped, filterable view.',
11
17
  mimeType: 'application/json',
12
18
  params: z.object({}),
13
19
  output: z.object({
@@ -18,7 +24,7 @@ export const obsidianTags = resource('obsidian://tags', {
18
24
  count: z.number().describe('Usage count across the vault.'),
19
25
  })
20
26
  .describe('A tag with its usage count.'))
21
- .describe('All tags in the vault.'),
27
+ .describe('Every tag in the vault, in upstream-provided order.'),
22
28
  }),
23
29
  auth: ['resource:obsidian-tags:read'],
24
30
  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;;;;GAIG;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,wHAAwH;IAC1H,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,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;SAC5D,CAAC;aACD,QAAQ,CAAC,6BAA6B,CAAC,CAC3C;aACA,QAAQ,CAAC,wBAAwB,CAAC;KACtC,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;;;;;;;;;;GAUG;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,yPAAyP;IAC3P,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,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;SAC5D,CAAC;aACD,QAAQ,CAAC,6BAA6B,CAAC,CAC3C;aACA,QAAQ,CAAC,qDAAqD,CAAC;KACnE,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"}
@@ -202,14 +202,18 @@ export declare const readToolDefinitions: (import("@cyanheads/mcp-ts-core").Tool
202
202
  readonly notice: import("zod").ZodOptional<import("zod").ZodString>;
203
203
  }> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
204
204
  nameRegex: import("zod").ZodOptional<import("zod").ZodString>;
205
+ minCount: import("zod").ZodOptional<import("zod").ZodNumber>;
206
+ limit: import("zod").ZodDefault<import("zod").ZodNumber>;
205
207
  }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
206
208
  tags: import("zod").ZodArray<import("zod").ZodObject<{
207
209
  name: import("zod").ZodString;
208
210
  count: import("zod").ZodNumber;
209
211
  }, import("zod/v4/core").$strip>>;
210
- appliedFilters: import("zod").ZodOptional<import("zod").ZodObject<{
212
+ appliedFilters: import("zod").ZodObject<{
211
213
  nameRegex: import("zod").ZodOptional<import("zod").ZodString>;
212
- }, import("zod/v4/core").$strip>>;
214
+ minCount: import("zod").ZodOptional<import("zod").ZodNumber>;
215
+ limit: import("zod").ZodNumber;
216
+ }, import("zod/v4/core").$strip>;
213
217
  }, import("zod/v4/core").$strip>, readonly [{
214
218
  readonly reason: "regex_invalid";
215
219
  readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
@@ -222,6 +226,9 @@ export declare const readToolDefinitions: (import("@cyanheads/mcp-ts-core").Tool
222
226
  readonly recovery: "Avoid nested quantifiers like `(a+)+` or `(.*)*`. Use a simpler pattern (e.g. `^mcp/.*`), or omit nameRegex to disable filtering.";
223
227
  }], {
224
228
  readonly notice: import("zod").ZodOptional<import("zod").ZodString>;
229
+ readonly truncated: import("zod").ZodOptional<import("zod").ZodBoolean>;
230
+ readonly shown: import("zod").ZodOptional<import("zod").ZodNumber>;
231
+ readonly cap: import("zod").ZodOptional<import("zod").ZodNumber>;
225
232
  }> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
226
233
  path: import("zod").ZodString;
227
234
  failIfMissing: import("zod").ZodDefault<import("zod").ZodBoolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAgBH,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAK/B,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAQhC,CAAC;AAEF,mHAAmH;AACnH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAiD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAgBH,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAK/B,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAQhC,CAAC;AAEF,mHAAmH;AACnH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAiD,CAAC"}
@@ -1,22 +1,28 @@
1
1
  /**
2
- * @fileoverview obsidian_list_tags — all tags found in the vault, with usage counts.
3
- * Mirrors the plugin's `/tags/` endpoint; counts are upstream-provided. Optional
4
- * `nameRegex` post-filters the upstream payload before returning to keep the
5
- * LLM-bound response small on vaults with long-tail tag noise.
2
+ * @fileoverview obsidian_list_tags — the most-used tags in the vault, with usage counts.
3
+ * Wraps the plugin's `/tags/` endpoint, then shapes it for an LLM caller: `nameRegex`
4
+ * and `minCount` narrow the candidate set, the survivors are ordered by usage, and
5
+ * `limit` keeps the exploratory zero-argument call bounded on a vault with a long
6
+ * single-use tail. The `obsidian://tags` resource wraps the same endpoint but keeps
7
+ * snapshot semantics — unsorted, uncapped — so the two surfaces differ by design.
6
8
  * @module mcp-server/tools/definitions/obsidian-list-tags.tool
7
9
  */
8
10
  import { z } from '@cyanheads/mcp-ts-core';
9
11
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
10
12
  export declare const obsidianListTags: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
11
13
  nameRegex: z.ZodOptional<z.ZodString>;
14
+ minCount: z.ZodOptional<z.ZodNumber>;
15
+ limit: z.ZodDefault<z.ZodNumber>;
12
16
  }, z.core.$strip>, z.ZodObject<{
13
17
  tags: z.ZodArray<z.ZodObject<{
14
18
  name: z.ZodString;
15
19
  count: z.ZodNumber;
16
20
  }, z.core.$strip>>;
17
- appliedFilters: z.ZodOptional<z.ZodObject<{
21
+ appliedFilters: z.ZodObject<{
18
22
  nameRegex: z.ZodOptional<z.ZodString>;
19
- }, z.core.$strip>>;
23
+ minCount: z.ZodOptional<z.ZodNumber>;
24
+ limit: z.ZodNumber;
25
+ }, z.core.$strip>;
20
26
  }, z.core.$strip>, readonly [{
21
27
  readonly reason: "regex_invalid";
22
28
  readonly code: JsonRpcErrorCode.ValidationError;
@@ -29,5 +35,8 @@ export declare const obsidianListTags: import("@cyanheads/mcp-ts-core").ToolDefi
29
35
  readonly recovery: "Avoid nested quantifiers like `(a+)+` or `(.*)*`. Use a simpler pattern (e.g. `^mcp/.*`), or omit nameRegex to disable filtering.";
30
36
  }], {
31
37
  readonly notice: z.ZodOptional<z.ZodString>;
38
+ readonly truncated: z.ZodOptional<z.ZodBoolean>;
39
+ readonly shown: z.ZodOptional<z.ZodNumber>;
40
+ readonly cap: z.ZodOptional<z.ZodNumber>;
32
41
  }>;
33
42
  //# sourceMappingURL=obsidian-list-tags.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"obsidian-list-tags.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-tags.tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;EAuG3B,CAAC"}
1
+ {"version":3,"file":"obsidian-list-tags.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-tags.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAajE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgK3B,CAAC"}
@@ -1,22 +1,45 @@
1
1
  /**
2
- * @fileoverview obsidian_list_tags — all tags found in the vault, with usage counts.
3
- * Mirrors the plugin's `/tags/` endpoint; counts are upstream-provided. Optional
4
- * `nameRegex` post-filters the upstream payload before returning to keep the
5
- * LLM-bound response small on vaults with long-tail tag noise.
2
+ * @fileoverview obsidian_list_tags — the most-used tags in the vault, with usage counts.
3
+ * Wraps the plugin's `/tags/` endpoint, then shapes it for an LLM caller: `nameRegex`
4
+ * and `minCount` narrow the candidate set, the survivors are ordered by usage, and
5
+ * `limit` keeps the exploratory zero-argument call bounded on a vault with a long
6
+ * single-use tail. The `obsidian://tags` resource wraps the same endpoint but keeps
7
+ * snapshot semantics — unsorted, uncapped — so the two surfaces differ by design.
6
8
  * @module mcp-server/tools/definitions/obsidian-list-tags.tool
7
9
  */
8
10
  import { tool, z } from '@cyanheads/mcp-ts-core';
9
11
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
10
12
  import { getObsidianService } from '../../../services/obsidian/obsidian-service.js';
11
13
  import { nameRegexSafetyIssue } from './_shared/regex-safety.js';
14
+ /** Bounded so the first exploratory call cannot return the whole tag distribution. */
15
+ const DEFAULT_TAG_LIMIT = 200;
16
+ /**
17
+ * Set far above any plausible vault's tag cardinality so "give me everything" is
18
+ * reachable by asking for a number, with no `0`-means-uncapped sentinel — to a
19
+ * model reading the schema, `0` reads as "return none".
20
+ */
21
+ const MAX_TAG_LIMIT = 10_000;
12
22
  export const obsidianListTags = tool('obsidian_list_tags', {
13
- description: 'List every tag found across the vault, with usage counts. Includes hierarchical parents — `work/tasks` contributes to both `work` and `work/tasks`. Filter to a subset with the optional `nameRegex`. To find notes by tag, use `obsidian_search_notes` in jsonlogic mode (e.g. `{"in": ["work", {"var": "tags"}]}`).',
23
+ description: `List the vault's tags with usage counts, ordered by count descending and capped at \`limit\` (default ${DEFAULT_TAG_LIMIT}) — the response says so when it withheld any. Includes hierarchical parents: \`work/tasks\` contributes to both \`work\` and \`work/tasks\`. Narrow with \`nameRegex\` for a known prefix or \`minCount\` to drop the single-use tail. To find notes by tag, use \`obsidian_search_notes\` in jsonlogic mode (e.g. \`{"in": ["work", {"var": "tags"}]}\`).`,
14
24
  annotations: { readOnlyHint: true, idempotentHint: true },
15
25
  input: z.object({
16
26
  nameRegex: z
17
27
  .string()
18
28
  .optional()
19
29
  .describe('Optional ECMAScript regex (no flags, ≤256 chars, no nested quantifiers like `(a+)+`) matched against the bare tag name (no leading `#`). Hierarchical tags like `work/tasks` are matched as the full string. Use character classes (`[Mm]cp`) for case-insensitivity.'),
30
+ minCount: z
31
+ .number()
32
+ .int()
33
+ .min(0)
34
+ .optional()
35
+ .describe('Keep only tags used at least this many times. Omit (or pass 0) for no filter. On a vault with a long single-use tail this drops it in one argument.'),
36
+ limit: z
37
+ .number()
38
+ .int()
39
+ .min(1)
40
+ .max(MAX_TAG_LIMIT)
41
+ .default(DEFAULT_TAG_LIMIT)
42
+ .describe(`Maximum tags to return, applied after \`nameRegex\` and \`minCount\` and after ordering by count descending, so the cap keeps the most-used. Max ${MAX_TAG_LIMIT} — high enough to return any real vault whole. When the cap bites, the response reports \`truncated\`, \`shown\`, and \`cap\`.`),
20
43
  }),
21
44
  output: z.object({
22
45
  tags: z
@@ -26,19 +49,29 @@ export const obsidianListTags = tool('obsidian_list_tags', {
26
49
  count: z.number().describe('Usage count across the vault.'),
27
50
  })
28
51
  .describe('A tag with its usage count.'))
29
- .describe('All tags in the vault, in upstream-provided order.'),
52
+ .describe('Matching tags ordered by `count` descending, ties broken by name ascending, truncated to `appliedFilters.limit`.'),
30
53
  appliedFilters: z
31
54
  .object({
32
55
  nameRegex: z.string().optional().describe('nameRegex filter applied to this listing.'),
56
+ minCount: z
57
+ .number()
58
+ .optional()
59
+ .describe('minCount filter applied to this listing. Absent when none was supplied.'),
60
+ limit: z.number().describe('Cap applied to this listing.'),
33
61
  })
34
- .optional()
35
- .describe('Active filters that produced this listing. Absent when no filter was applied.'),
62
+ .describe('Filters and cap that produced this listing.'),
36
63
  }),
37
64
  enrichment: {
38
65
  notice: z
39
66
  .string()
40
67
  .optional()
41
- .describe('Guidance when no tags matched the applied filter, or the vault has no tags.'),
68
+ .describe('Guidance when no tags matched the applied filters, when the vault has no tags, or — since `ctx.enrich.truncated` routes its guidance here — when the cap withheld some.'),
69
+ truncated: z
70
+ .boolean()
71
+ .optional()
72
+ .describe('True when more tags matched the filters than `limit` allowed through.'),
73
+ shown: z.number().optional().describe('Number of tags returned.'),
74
+ cap: z.number().optional().describe('The `limit` that was applied.'),
42
75
  },
43
76
  auth: ['tool:obsidian_list_tags:read'],
44
77
  errors: [
@@ -73,21 +106,46 @@ export const obsidianListTags = tool('obsidian_list_tags', {
73
106
  }
74
107
  }
75
108
  const svc = getObsidianService();
76
- const tags = await svc.listTags(ctx);
77
- const filtered = regex ? tags.filter((t) => regex.test(t.name)) : tags;
78
- if (filtered.length === 0) {
79
- const filterNote = input.nameRegex ? ` matching \`${input.nameRegex}\`` : '';
80
- ctx.enrich.notice(`No tags found${filterNote}. ${input.nameRegex ? 'Try a broader nameRegex or omit it to list all tags.' : 'The vault may have no tagged notes.'}`);
81
- }
82
- return {
83
- tags: filtered.map((t) => ({ name: t.name, count: t.count })),
84
- ...(input.nameRegex ? { appliedFilters: { nameRegex: input.nameRegex } } : {}),
109
+ const minCount = input.minCount ?? 0;
110
+ /**
111
+ * Order is load-bearing: narrow, then rank, then cap. Truncation is
112
+ * measured against the post-filter candidate count reporting the raw
113
+ * vault total would describe tags `minCount` had already excluded as
114
+ * things the cap withheld.
115
+ */
116
+ const candidates = (await svc.listTags(ctx))
117
+ .filter((t) => (regex ? regex.test(t.name) : true))
118
+ .filter((t) => t.count >= minCount)
119
+ .sort((a, b) => b.count - a.count || a.name.localeCompare(b.name));
120
+ const tags = candidates.slice(0, input.limit).map((t) => ({ name: t.name, count: t.count }));
121
+ const appliedFilters = {
122
+ ...(input.nameRegex ? { nameRegex: input.nameRegex } : {}),
123
+ ...(minCount > 0 ? { minCount } : {}),
124
+ limit: input.limit,
85
125
  };
126
+ if (candidates.length === 0) {
127
+ /**
128
+ * Keyed on the narrowing filters only. `limit` is always present and
129
+ * never causes an empty result, so folding it in here would make the
130
+ * "this vault has no tags at all" case unreachable.
131
+ */
132
+ const narrowing = describeFilters({ ...appliedFilters, limit: undefined });
133
+ ctx.enrich.notice(narrowing
134
+ ? `No tags matched ${narrowing}. Loosen or drop the filters to widen the listing.`
135
+ : 'No tags found. The vault may have no tagged notes.');
136
+ }
137
+ else if (candidates.length > input.limit) {
138
+ ctx.enrich.truncated({
139
+ shown: tags.length,
140
+ cap: input.limit,
141
+ guidance: `Showing the ${tags.length} most-used of ${candidates.length} matching tags. Raise \`limit\` (max ${MAX_TAG_LIMIT}) for more, or narrow with \`nameRegex\` / \`minCount\`.`,
142
+ });
143
+ }
144
+ return { tags, appliedFilters };
86
145
  },
87
146
  format: (result) => {
88
- const activeRegex = result.appliedFilters?.nameRegex;
89
- const filterSuffix = activeRegex ? ` · nameRegex=\`${activeRegex}\`` : '';
90
- const lines = [`**${result.tags.length} tags**${filterSuffix}`];
147
+ const suffix = describeFilters(result.appliedFilters);
148
+ const lines = [`**${result.tags.length} tags**${suffix ? ` · ${suffix}` : ''}`];
91
149
  if (result.tags.length > 0) {
92
150
  lines.push('');
93
151
  for (const t of result.tags)
@@ -96,4 +154,15 @@ export const obsidianListTags = tool('obsidian_list_tags', {
96
154
  return [{ type: 'text', text: lines.join('\n') }];
97
155
  },
98
156
  });
157
+ /** Human-readable echo of the filters and cap behind a listing. */
158
+ function describeFilters(filters) {
159
+ const parts = [];
160
+ if (filters.nameRegex)
161
+ parts.push(`nameRegex=\`${filters.nameRegex}\``);
162
+ if (filters.minCount !== undefined)
163
+ parts.push(`minCount=${filters.minCount}`);
164
+ if (filters.limit !== undefined)
165
+ parts.push(`limit=${filters.limit}`);
166
+ return parts.join(' · ');
167
+ }
99
168
  //# sourceMappingURL=obsidian-list-tags.tool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"obsidian-list-tags.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-tags.tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"obsidian-list-tags.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-tags.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,sFAAsF;AACtF,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAC9B;;;;GAIG;AACH,MAAM,aAAa,GAAG,MAAM,CAAC;AAE7B,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,oBAAoB,EAAE;IACzD,WAAW,EAAE,yGAAyG,iBAAiB,6VAA6V;IACpe,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE;IACzD,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,uQAAuQ,CACxQ;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,EAAE;aACV,QAAQ,CACP,qJAAqJ,CACtJ;QACH,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,aAAa,CAAC;aAClB,OAAO,CAAC,iBAAiB,CAAC;aAC1B,QAAQ,CACP,oJAAoJ,aAAa,gIAAgI,CAClS;KACJ,CAAC;IACF,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,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;SAC5D,CAAC;aACD,QAAQ,CAAC,6BAA6B,CAAC,CAC3C;aACA,QAAQ,CACP,kHAAkH,CACnH;QACH,cAAc,EAAE,CAAC;aACd,MAAM,CAAC;YACN,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;YACtF,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,yEAAyE,CAAC;YACtF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;SAC3D,CAAC;aACD,QAAQ,CAAC,6CAA6C,CAAC;KAC3D,CAAC;IACF,UAAU,EAAE;QACV,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,yKAAyK,CAC1K;QACH,SAAS,EAAE,CAAC;aACT,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,uEAAuE,CAAC;QACpF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;QACjE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;KACrE;IACD,IAAI,EAAE,CAAC,8BAA8B,CAAC;IACtC,MAAM,EAAE;QACN;YACE,MAAM,EAAE,eAAe;YACvB,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,2DAA2D;YACjE,QAAQ,EACN,wFAAwF;SAC3F;QACD;YACE,MAAM,EAAE,cAAc;YACtB,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,sJAAsJ;YAC5J,QAAQ,EACN,mIAAmI;SACtI;KACF;IAED,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,IAAI,KAAyB,CAAC;QAC9B,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,oBAAoB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC1D,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,qBAAqB,WAAW,EAAE,EAAE;oBACjE,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,GAAG,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC;iBACnC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,CAAC;gBACH,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACtC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,GAAG,CAAC,IAAI,CACZ,eAAe,EACf,sBAAuB,GAAa,CAAC,OAAO,EAAE,EAC9C,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,EAAE,EACnE,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;YACJ,CAAC;QACH,CAAC;QAED,MAAM,GAAG,GAAG,kBAAkB,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;QAErC;;;;;WAKG;QACH,MAAM,UAAU,GAAG,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;aACzC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;aAClD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,QAAQ,CAAC;aAClC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAErE,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAE7F,MAAM,cAAc,GAAG;YACrB,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrC,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC;QAEF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B;;;;eAIG;YACH,MAAM,SAAS,GAAG,eAAe,CAAC,EAAE,GAAG,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YAC3E,GAAG,CAAC,MAAM,CAAC,MAAM,CACf,SAAS;gBACP,CAAC,CAAC,mBAAmB,SAAS,oDAAoD;gBAClF,CAAC,CAAC,oDAAoD,CACzD,CAAC;QACJ,CAAC;aAAM,IAAI,UAAU,CAAC,MAAM,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;YAC3C,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,IAAI,CAAC,MAAM;gBAClB,GAAG,EAAE,KAAK,CAAC,KAAK;gBAChB,QAAQ,EAAE,eAAe,IAAI,CAAC,MAAM,iBAAiB,UAAU,CAAC,MAAM,wCAAwC,aAAa,0DAA0D;aACtL,CAAC,CAAC;QACL,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAClC,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,MAAM,UAAU,MAAM,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC,CAAC;AAEH,mEAAmE;AACnE,SAAS,eAAe,CAAC,OAIxB;IACC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,OAAO,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,eAAe,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC;IACxE,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC/E,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACtE,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC"}
@@ -39,6 +39,8 @@ export declare function buildSearchNotesTool({ omnisearchReachable }: {
39
39
  match: z.ZodObject<{
40
40
  start: z.ZodNumber;
41
41
  end: z.ZodNumber;
42
+ contextStart: z.ZodNumber;
43
+ contextEnd: z.ZodNumber;
42
44
  }, z.core.$strip>;
43
45
  }, z.core.$strip>>;
44
46
  totalMatches: z.ZodOptional<z.ZodNumber>;
@@ -63,6 +65,8 @@ export declare function buildSearchNotesTool({ omnisearchReachable }: {
63
65
  match: z.ZodObject<{
64
66
  start: z.ZodNumber;
65
67
  end: z.ZodNumber;
68
+ contextStart: z.ZodNumber;
69
+ contextEnd: z.ZodNumber;
66
70
  }, z.core.$strip>;
67
71
  }, z.core.$strip>>;
68
72
  totalMatches: z.ZodOptional<z.ZodNumber>;
@@ -105,11 +109,21 @@ export declare function buildSearchNotesTool({ omnisearchReachable }: {
105
109
  readonly code: JsonRpcErrorCode.ValidationError;
106
110
  readonly when: '`query` is missing for `text` or `omnisearch` mode (required for both).';
107
111
  readonly recovery: 'Pass `query` — substring for text mode, or BM25 query syntax (quoted phrases, `-exclusion`, `path:` / `ext:` filters) for omnisearch.';
112
+ }, {
113
+ readonly reason: 'context_length_too_large';
114
+ readonly code: JsonRpcErrorCode.ValidationError;
115
+ readonly when: 'The Local REST API exhausted its string capacity building one context window per match, so the whole text search failed.';
116
+ readonly recovery: 'Lower `contextLength`, or narrow the query so fewer notes match. The ceiling is the product of the two, so a broad query fails at a much smaller window than a narrow one does.';
108
117
  }, {
109
118
  readonly reason: 'logic_required';
110
119
  readonly code: JsonRpcErrorCode.ValidationError;
111
120
  readonly when: '`logic` is missing for `jsonlogic` mode.';
112
- readonly recovery: 'Pass a JSONLogic tree as `logic`, e.g. `{"glob": [{"var": "path"}, "Projects/*.md"]}`.';
121
+ readonly recovery: 'Pass a JSONLogic tree as `logic`. `glob` and `regexp` take `[PATTERN, VALUE]` — pattern first, e.g. `{"glob": ["Projects/*.md", {"var": "path"}]}`.';
122
+ }, {
123
+ readonly reason: 'logic_invalid';
124
+ readonly code: JsonRpcErrorCode.ValidationError;
125
+ readonly when: 'The Local REST API rejected the JSONLogic tree — an unrecognized operator, or an operand it could not evaluate (an uncompilable `regexp` pattern). A mis-arity operator is not rejected: it evaluates to false and the search returns zero hits.';
126
+ readonly recovery: 'Check the operator names and arity. `glob` and `regexp` take `[PATTERN, VALUE]` — pattern first, e.g. `{"regexp": ["^Inbox/", {"var": "path"}]}`; the reverse order compiles the note field as the pattern.';
113
127
  }, {
114
128
  readonly reason: 'omnisearch_unreachable';
115
129
  readonly code: JsonRpcErrorCode.ServiceUnavailable;
@@ -153,6 +167,8 @@ export declare const obsidianSearchNotes: import("@cyanheads/mcp-ts-core").ToolD
153
167
  match: z.ZodObject<{
154
168
  start: z.ZodNumber;
155
169
  end: z.ZodNumber;
170
+ contextStart: z.ZodNumber;
171
+ contextEnd: z.ZodNumber;
156
172
  }, z.core.$strip>;
157
173
  }, z.core.$strip>>;
158
174
  totalMatches: z.ZodOptional<z.ZodNumber>;
@@ -177,6 +193,8 @@ export declare const obsidianSearchNotes: import("@cyanheads/mcp-ts-core").ToolD
177
193
  match: z.ZodObject<{
178
194
  start: z.ZodNumber;
179
195
  end: z.ZodNumber;
196
+ contextStart: z.ZodNumber;
197
+ contextEnd: z.ZodNumber;
180
198
  }, z.core.$strip>;
181
199
  }, z.core.$strip>>;
182
200
  totalMatches: z.ZodOptional<z.ZodNumber>;
@@ -219,11 +237,21 @@ export declare const obsidianSearchNotes: import("@cyanheads/mcp-ts-core").ToolD
219
237
  readonly code: JsonRpcErrorCode.ValidationError;
220
238
  readonly when: '`query` is missing for `text` or `omnisearch` mode (required for both).';
221
239
  readonly recovery: 'Pass `query` — substring for text mode, or BM25 query syntax (quoted phrases, `-exclusion`, `path:` / `ext:` filters) for omnisearch.';
240
+ }, {
241
+ readonly reason: 'context_length_too_large';
242
+ readonly code: JsonRpcErrorCode.ValidationError;
243
+ readonly when: 'The Local REST API exhausted its string capacity building one context window per match, so the whole text search failed.';
244
+ readonly recovery: 'Lower `contextLength`, or narrow the query so fewer notes match. The ceiling is the product of the two, so a broad query fails at a much smaller window than a narrow one does.';
222
245
  }, {
223
246
  readonly reason: 'logic_required';
224
247
  readonly code: JsonRpcErrorCode.ValidationError;
225
248
  readonly when: '`logic` is missing for `jsonlogic` mode.';
226
- readonly recovery: 'Pass a JSONLogic tree as `logic`, e.g. `{"glob": [{"var": "path"}, "Projects/*.md"]}`.';
249
+ readonly recovery: 'Pass a JSONLogic tree as `logic`. `glob` and `regexp` take `[PATTERN, VALUE]` — pattern first, e.g. `{"glob": ["Projects/*.md", {"var": "path"}]}`.';
250
+ }, {
251
+ readonly reason: 'logic_invalid';
252
+ readonly code: JsonRpcErrorCode.ValidationError;
253
+ readonly when: 'The Local REST API rejected the JSONLogic tree — an unrecognized operator, or an operand it could not evaluate (an uncompilable `regexp` pattern). A mis-arity operator is not rejected: it evaluates to false and the search returns zero hits.';
254
+ readonly recovery: 'Check the operator names and arity. `glob` and `regexp` take `[PATTERN, VALUE]` — pattern first, e.g. `{"regexp": ["^Inbox/", {"var": "path"}]}`; the reverse order compiles the note field as the pattern.';
227
255
  }, {
228
256
  readonly reason: 'omnisearch_unreachable';
229
257
  readonly code: JsonRpcErrorCode.ServiceUnavailable;
@@ -1 +1 @@
1
- {"version":3,"file":"obsidian-search-notes.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-search-notes.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAsB,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAsFjE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,EAAE;IAAE,mBAAmB,EAAE,OAAO,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkIhF,0BAA0B;;mBAE5B,uFAAuF;uBACnF,8DAA8D;;qBAGhE,gBAAgB;;mBAElB,yEAAyE;uBAE7E,uIAAuI;;qBAGjI,gBAAgB;;mBAElB,0CAA0C;uBAE9C,wFAAwF;;qBAGlF,wBAAwB;;mBAE1B,iHAAiH;;uBAGrH,mHAAmH;;;;GAqJ1H;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA3LlB,0BAA0B;;mBAE5B,uFAAuF;uBACnF,8DAA8D;;qBAGhE,gBAAgB;;mBAElB,yEAAyE;uBAE7E,uIAAuI;;qBAGjI,gBAAgB;;mBAElB,0CAA0C;uBAE9C,wFAAwF;;qBAGlF,wBAAwB;;mBAE1B,iHAAiH;;uBAGrH,mHAAmH;;;;EAkKpC,CAAC"}
1
+ {"version":3,"file":"obsidian-search-notes.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-search-notes.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAsB,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAoGjE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,EAAE;IAAE,mBAAmB,EAAE,OAAO,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkIhF,0BAA0B;;mBAE5B,uFAAuF;uBACnF,8DAA8D;;qBAGhE,gBAAgB;;mBAElB,yEAAyE;uBAE7E,uIAAuI;;qBAGjI,0BAA0B;;mBAE5B,0HAA0H;uBAE9H,iLAAiL;;qBAG3K,gBAAgB;;mBAElB,0CAA0C;uBAE9C,qJAAqJ;;qBAG/I,eAAe;;mBAEjB,kPAAkP;uBAEtP,6MAA6M;;qBAGvM,wBAAwB;;mBAE1B,iHAAiH;;uBAGrH,mHAAmH;;;;GA2J1H;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA/MlB,0BAA0B;;mBAE5B,uFAAuF;uBACnF,8DAA8D;;qBAGhE,gBAAgB;;mBAElB,yEAAyE;uBAE7E,uIAAuI;;qBAGjI,0BAA0B;;mBAE5B,0HAA0H;uBAE9H,iLAAiL;;qBAG3K,gBAAgB;;mBAElB,0CAA0C;uBAE9C,qJAAqJ;;qBAG/I,eAAe;;mBAEjB,kPAAkP;uBAEtP,6MAA6M;;qBAGvM,wBAAwB;;mBAE1B,iHAAiH;;uBAGrH,mHAAmH;;;;EAwKpC,CAAC"}