obsidian-mcp-server 3.1.11 → 3.2.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 (40) hide show
  1. package/CLAUDE.md +2 -2
  2. package/README.md +14 -13
  3. package/changelog/3.2.x/3.2.0.md +49 -0
  4. package/dist/config/server-config.d.ts +1 -0
  5. package/dist/config/server-config.d.ts.map +1 -1
  6. package/dist/config/server-config.js +6 -0
  7. package/dist/config/server-config.js.map +1 -1
  8. package/dist/index.d.ts +4 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +26 -9
  11. package/dist/index.js.map +1 -1
  12. package/dist/mcp-server/tools/definitions/_shared/regex-safety.d.ts +18 -0
  13. package/dist/mcp-server/tools/definitions/_shared/regex-safety.d.ts.map +1 -0
  14. package/dist/mcp-server/tools/definitions/_shared/regex-safety.js +34 -0
  15. package/dist/mcp-server/tools/definitions/_shared/regex-safety.js.map +1 -0
  16. package/dist/mcp-server/tools/definitions/_shared/schemas.js +1 -1
  17. package/dist/mcp-server/tools/definitions/_shared/schemas.js.map +1 -1
  18. package/dist/mcp-server/tools/definitions/index.d.ts +30 -844
  19. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  20. package/dist/mcp-server/tools/definitions/index.js +10 -6
  21. package/dist/mcp-server/tools/definitions/index.js.map +1 -1
  22. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.d.ts +21 -2
  23. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.d.ts.map +1 -1
  24. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js +59 -6
  25. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js.map +1 -1
  26. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts.map +1 -1
  27. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js +2 -22
  28. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js.map +1 -1
  29. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +175 -19
  30. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -1
  31. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +249 -134
  32. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -1
  33. package/dist/services/obsidian/obsidian-service.d.ts +22 -2
  34. package/dist/services/obsidian/obsidian-service.d.ts.map +1 -1
  35. package/dist/services/obsidian/obsidian-service.js +143 -12
  36. package/dist/services/obsidian/obsidian-service.js.map +1 -1
  37. package/dist/services/obsidian/types.d.ts +25 -1
  38. package/dist/services/obsidian/types.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/server.json +3 -3
package/CLAUDE.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Agent Protocol
2
2
 
3
3
  **Server:** obsidian-mcp-server
4
- **Version:** 3.1.10
4
+ **Version:** 3.2.0
5
5
  **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.9.1`
6
6
  **Engines:** Bun ≥1.3.11, Node ≥24.0.0
7
7
 
@@ -247,7 +247,7 @@ src/
247
247
  mcp-server/
248
248
  tools/definitions/
249
249
  _shared/schemas.ts # Shared TargetSchema + SectionSchema reused across tools
250
- index.ts # baseToolDefinitions[] + conditional commandToolDefinitions[]
250
+ index.ts # read/write/command tool sets + buildSearchNotesTool factory (Omnisearch-aware)
251
251
  obsidian-*.tool.ts # 14 tool definitions (12 base + 2 opt-in command-palette pair)
252
252
  resources/definitions/
253
253
  index.ts # allResourceDefinitions[]
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  <div align="center">
9
9
 
10
- [![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) [![Version](https://img.shields.io/badge/Version-3.1.11-blue.svg?style=flat-square)](./CHANGELOG.md) [![Framework](https://img.shields.io/badge/Built%20on-@cyanheads/mcp--ts--core-259?style=flat-square)](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.29.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/)
10
+ [![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) [![Version](https://img.shields.io/badge/Version-3.2.0-blue.svg?style=flat-square)](./CHANGELOG.md) [![Framework](https://img.shields.io/badge/Built%20on-@cyanheads/mcp--ts--core-259?style=flat-square)](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.29.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/)
11
11
 
12
12
  [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![TypeScript](https://img.shields.io/badge/TypeScript-^6.0.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3.11-blueviolet.svg?style=flat-square)](https://bun.sh/)
13
13
 
@@ -22,14 +22,14 @@ Fourteen tools grouped by shape — readers fetch notes and metadata, writers cr
22
22
  | Tool Name | Description |
23
23
  |:----------|:------------|
24
24
  | `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. |
25
- | `obsidian_list_notes` | List notes and subdirectories at a vault path with a recursive walk (default depth 2 structural overview; max 20) bounded by a 1000-entry cap. Optional `extension` and `nameRegex` filters apply across the tree; regex-filtered directories are skipped without recursing into them. Returns flat `entries[]` plus a box-drawing tree in the rendered output; per-directory `truncated: true` flags where the depth limit cut off recursion. |
26
- | `obsidian_list_tags` | List every tag found across the vault with usage counts, including hierarchical parents. Optional `nameRegex` post-filters the result set (length-capped, nested-quantifier-guarded). |
27
- | `obsidian_list_commands` | List Obsidian command-palette commands available for execution. **Opt-in via `OBSIDIAN_ENABLE_COMMANDS=true`** (paired with `obsidian_execute_command`). |
28
- | `obsidian_search_notes` | Search the vault by text, Dataview DQL, or JSONLogic. Text-mode matches return surrounding context windows (`contextLength`) capped at 100 hits with overflow indicator. |
25
+ | `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. |
26
+ | `obsidian_list_tags` | List every tag found across the vault with usage counts, including hierarchical parents. Optional `nameRegex` post-filters the result set. |
27
+ | `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`). |
28
+ | `obsidian_search_notes` | Search the vault by text, JSONLogic, or BM25-ranked Omnisearch (when the plugin is reachable). Results paginate via opaque cursors. |
29
29
  | `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. |
30
- | `obsidian_append_to_note` | Append content to a note. Without `section` it creates the file if missing — your content becomes the entire file. With `section`, appends to that heading/block/frontmatter (PATCH; the file must exist). |
30
+ | `obsidian_append_to_note` | Append content to a note. Without `section`, creates the file if missing. With `section`, appends to a specific heading, block, or frontmatter field (file must exist). |
31
31
  | `obsidian_patch_note` | Surgical `append` / `prepend` / `replace` against a heading, block reference, or frontmatter field. |
32
- | `obsidian_replace_in_note` | Body-wide search-replace inside a single note. Literal or regex matching, with `wholeWord`, `flexibleWhitespace`, `caseSensitive`, `replaceAll`, and `$1`/`$&` capture groups. |
32
+ | `obsidian_replace_in_note` | Body-wide search-replace inside a single note. Literal or regex matching with whole-word, whitespace-flexible, and case-sensitivity options; supports capture-group replacement. |
33
33
  | `obsidian_manage_frontmatter` | Atomic `get` / `set` / `delete` on a single frontmatter key. |
34
34
  | `obsidian_manage_tags` | Add, remove, or list tags — reconciles frontmatter `tags:` and inline `#tag` syntax. |
35
35
  | `obsidian_delete_note` | Permanently delete a note. Elicits human confirmation when the client supports it. |
@@ -51,13 +51,13 @@ Pair the document-map projection with `obsidian_patch_note` to discover edit tar
51
51
 
52
52
  ### `obsidian_search_notes`
53
53
 
54
- Three search modes selected by `mode`:
54
+ Up to three search modes selected by `mode`:
55
55
 
56
- - `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 `dataview` or `jsonlogic` mode is rejected with `path_prefix_invalid_mode`).
57
- - `dataview` — Dataview DQL (`TABLE …`) for path/date/metadata queries; `file.mtime`, `file.path`, etc. are queryable
56
+ - `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`).
58
57
  - `jsonlogic` — JSONLogic tree evaluated against `path`, `content`, `frontmatter.<key>`, `tags`, and `stat.{ctime,mtime,size}`; custom `glob` and `regexp` operators
58
+ - `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).
59
59
 
60
- Results are capped at 100 hits. When the upstream returns more, an `excluded` indicator surfaces the overflow count and a hint to narrow the query. 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`.
60
+ Results paginate via opaque cursors per the [MCP 2025-06-18 spec](https://modelcontextprotocol.io/specification/2025-06-18/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`.
61
61
 
62
62
  ---
63
63
 
@@ -188,7 +188,7 @@ Obsidian-specific:
188
188
  - Wraps the [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api) plugin — typed client, deterministic error mapping
189
189
  - Section-aware editing across headings, block references, and frontmatter fields via `PATCH`-with-target operations
190
190
  - Tag reconciliation across both representations: frontmatter `tags:` array and inline `#tag` syntax (skipping fenced code blocks)
191
- - Search across three modes: text, Dataview DQL, JSONLogic with overflow indicator when results exceed the 100-hit cap
191
+ - Search across up to three modes: text, JSONLogic, and (when the plugin is reachable) BM25-ranked Omnisearch — cursor-paginated per the MCP 2025-06-18 spec, with per-file match clipping in text mode
192
192
  - Optional human-in-the-loop confirmation for destructive deletes via `ctx.elicit`
193
193
  - Folder-scoped read/write permissions via `OBSIDIAN_READ_PATHS` / `OBSIDIAN_WRITE_PATHS` and a global `OBSIDIAN_READ_ONLY` kill switch — denies are typed `path_forbidden` with the active scope echoed back in the error data
194
194
  - Opt-in command-palette pair (`obsidian_list_commands` + `obsidian_execute_command`) — registered only when `OBSIDIAN_ENABLE_COMMANDS=true`
@@ -244,7 +244,7 @@ MCP_TRANSPORT_TYPE=http OBSIDIAN_API_KEY=... bun run start:http
244
244
  ### Prerequisites
245
245
 
246
246
  - [Bun v1.3.11](https://bun.sh/) or higher (or Node.js v24+).
247
- - The [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api) plugin installed and enabled in your vault. Generate an API key in **Settings → Community Plugins → Local REST API** and copy it into `OBSIDIAN_API_KEY`.
247
+ - The [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api) plugin **v4.0.0 or later** installed and enabled in your vault. Generate an API key in **Settings → Community Plugins → Local REST API** and copy it into `OBSIDIAN_API_KEY`.
248
248
  - This server defaults to `http://127.0.0.1:27123` for simplicity. Enable **"Non-encrypted (HTTP) Server"** in the plugin settings to use it. To use the always-on HTTPS port instead, set `OBSIDIAN_BASE_URL=https://127.0.0.1:27124`; the plugin's self-signed cert is handled by `OBSIDIAN_VERIFY_SSL=false` (the default).
249
249
 
250
250
  ### Installation
@@ -286,6 +286,7 @@ MCP_TRANSPORT_TYPE=http OBSIDIAN_API_KEY=... bun run start:http
286
286
  | `OBSIDIAN_READ_PATHS` | Comma-separated vault-relative folder allowlist for read operations. Prefix-based with implicit recursion; case-insensitive; trailing slashes normalized. Unset = full vault. Write paths are implicitly readable. | unset |
287
287
  | `OBSIDIAN_WRITE_PATHS` | Comma-separated vault-relative folder allowlist for write operations. Same syntax as `OBSIDIAN_READ_PATHS`. Unset = full vault. | unset |
288
288
  | `OBSIDIAN_READ_ONLY` | Global kill switch. When `true`, denies every write regardless of `OBSIDIAN_WRITE_PATHS`, and suppresses the `OBSIDIAN_ENABLE_COMMANDS` pair (commands can mutate). | `false` |
289
+ | `OBSIDIAN_OMNISEARCH_URL` | Override URL for the [Omnisearch](https://github.com/scambier/obsidian-omnisearch) plugin's HTTP server. When unset, derives from `OBSIDIAN_BASE_URL` host with port `51361` (falling back to `http://localhost:51361`). Probed once at startup — if reachable, the `omnisearch` mode is added to `obsidian_search_notes`; otherwise it's omitted from the tool schema. Restart the server to re-probe. | derived |
289
290
  | `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
290
291
  | `MCP_HTTP_HOST` | Host for the HTTP server. | `127.0.0.1` |
291
292
  | `MCP_HTTP_PORT` | Port for the HTTP server. | `3010` |
@@ -0,0 +1,49 @@
1
+ ---
2
+ summary: "`obsidian_search_notes` gains BM25-ranked Omnisearch mode (auto-detected) and MCP-spec cursor pagination across all branches; `obsidian_list_commands` gains a `nameRegex` filter; PATCH headers track markdown-patch 1.0 from Local REST API v4.0.0+."
3
+ breaking: true
4
+ security: false
5
+ ---
6
+
7
+ # 3.2.0 — 2026-05-17
8
+
9
+ Two new agent-facing affordances on `obsidian_search_notes` ranked search and proper pagination; one quality-of-life filter on `obsidian_list_commands`; and a wire-format catch-up for the Local REST API v4.0.0 markdown-patch 1.0 header rename. Minimum supported plugin floor is now v4.0.0.
10
+
11
+ ## Added
12
+
13
+ - **`obsidian_search_notes` `omnisearch` mode** — 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)). Auto-detected: probed once at startup against `/search?q=` (200 + `application/json` + JSON-array body — unrouted paths return 200 with empty body, so status alone is insufficient); if reachable, the mode appears in the input enum, otherwise it's omitted so the LLM never sees it as an option. Upstream hard-caps results at 50 — the omnisearch branch carries `truncated: true` when that cap was likely hit. Resolves [#51](https://github.com/cyanheads/obsidian-mcp-server/issues/51).
14
+ - **`OBSIDIAN_OMNISEARCH_URL`** — override the derived Omnisearch URL (default: `OBSIDIAN_BASE_URL` host + port `51361`, with `127.0.0.1` mapped to `localhost`). Restart to re-probe.
15
+ - **`obsidian_list_commands` `nameRegex` filter** — optional ECMAScript regex matched against the command display name. Reuses the ReDoS guards from `obsidian_list_tags` (≤256 chars, static rejection of nested-quantifier shapes) via the new shared helper. Response echoes `appliedFilters: { nameRegex }`. Resolves [#53](https://github.com/cyanheads/obsidian-mcp-server/issues/53).
16
+ - **`src/mcp-server/tools/definitions/_shared/regex-safety.ts`** — `nameRegexSafetyIssue(pattern)` + `NAME_REGEX_MAX_LENGTH` lifted out of `obsidian-list-tags.tool.ts` so both filter tools share one implementation. Mirrors the existing `_shared/schemas.ts` pattern.
17
+ - **`ObsidianService.probeOmnisearch(signal?)`** — one-shot 500ms startup probe. Validates status + content-type + array body.
18
+ - **`ObsidianService.searchOmnisearch(ctx, query)`** — normalizes the upstream payload: renames `path` → `filename` (so `PathPolicy.filterReadable` composes), decodes HTML entities + converts `<br>` → `\n` in `excerpt`, drops `vault`. Throws `omnisearch_unreachable` (ServiceUnavailable, retryable) on mid-session failures.
19
+ - **`buildSearchNotesTool({ omnisearchReachable })`** factory replaces the static `obsidianSearchNotes` export — entry point passes the live probe result so the schema reflects what's actually callable. The module still exports a static specimen with `omnisearchReachable: false` for the MCP definition linter and existing tests.
20
+
21
+ ## Changed
22
+
23
+ - **`obsidian_search_notes` switched from cap+overflow to MCP-spec cursor pagination** (per spec [2025-06-18](https://modelcontextprotocol.io/specification/2025-06-18/utils/pagination)) via the framework's `paginateArray` helper. Output now carries `totalCount: number` (post-path-policy, pre-pagination) on every mode and `nextCursor?: string` when a successor page exists. Invalid cursors throw `InvalidParams` per spec. Path-policy denial count stays hidden.
24
+ - **PATCH header rename** — `Apply-If-Content-Preexists` → `Reject-If-Content-Preexists` with sense inversion, tracking [coddingtonbear/obsidian-local-rest-api v4.0.0](https://github.com/coddingtonbear/obsidian-local-rest-api/releases/tag/4.0.0) (markdown-patch 1.0). The public `applyIfContentPreexists` flag stays on the schema for caller stability and `ObsidianService.#buildPatchHeaders` inverts on the way out so the public default (`false`) sends `Reject-If-Content-Preexists: true` and preserves the historical idempotent-by-default behavior. Replace operations are plugin-exempt regardless. **Minimum supported Local REST API: v4.0.0.**
25
+ - **Startup banner** — adds `omnisearchUrl` and `omnisearchReachable` to the structured request context, plus a follow-up info line that reports the resolved URL and which way the mode toggled. The reachability message tells the operator to set `OBSIDIAN_OMNISEARCH_URL` or enable the plugin's HTTP server when the probe fails.
26
+ - **`initObsidianService(config)` moved from `createApp.setup()` to module-load order** in `src/index.ts`. Required because `setup()` runs after tools are passed into `createApp()`, which is too late for the Omnisearch probe to influence `obsidian_search_notes`' mode enum.
27
+ - **`tools/definitions/index.ts`** — `obsidianSearchNotes` no longer included in `readToolDefinitions`; entry point injects `buildSearchNotesTool(...)` directly. `baseToolDefinitions` removed (one stale caller).
28
+ - **`obsidian_list_tags` description** — pointer to discover notes by tag now references `jsonlogic` (`{"in": ["work", {"var": "tags"}]}`) instead of the removed `dataview` mode.
29
+ - **CLAUDE.md** — `tools/definitions/index.ts` description updated for the new factory; `src/` file map mentions `_shared/regex-safety.ts` and the Omnisearch-aware factory.
30
+ - **README** — `obsidian_search_notes` row and dedicated section rewritten for the new mode set, cursor pagination, and Omnisearch caveats. `OBSIDIAN_OMNISEARCH_URL` row added to the env-var table. Prerequisite raised to **Local REST API v4.0.0+**.
31
+
32
+ ## Removed
33
+
34
+ - **`obsidian_search_notes` `dataview` mode** — [Local REST API v4.0.0 removed Dataview DQL search support](https://github.com/coddingtonbear/obsidian-local-rest-api/releases/tag/4.0.0); the mode is gone with it. Use `jsonlogic` for path/frontmatter/stat filtering, or `omnisearch` for ranked relevance.
35
+ - **`ObsidianService.searchDataview(ctx, dql)`** — sole caller removed with the mode. The `application/vnd.olrapi.dataview.dql+txt` content type constant also goes.
36
+ - **`obsidian_search_notes` `excluded` overflow indicator** — replaced by `totalCount` + `nextCursor`. The `EXCLUSION_HINT` constant is removed.
37
+
38
+ ## Fixed
39
+
40
+ - **`safeCodePoint` (excerpt entity decoder)** — drops a dead `try/catch` around `String.fromCodePoint`; the preceding range guard already covers every `RangeError` condition per spec.
41
+
42
+ ## Migration
43
+
44
+ | Before | After |
45
+ |:--|:--|
46
+ | `obsidian_search_notes` with `mode: 'dataview'` | Removed upstream in Local REST API v4.0.0 (Dataview DQL search). Switch to `mode: 'jsonlogic'` (path / frontmatter / stat filters) or `mode: 'omnisearch'` (ranked relevance, when reachable). |
47
+ | Reading `result.excluded.count` | Read `result.totalCount` and check whether `result.nextCursor` is set. |
48
+ | Paging through > 100 hits | Pass `cursor: result.nextCursor` on the next call; the page size is server-determined (50 default, 200 max). |
49
+ | Sending `Apply-If-Content-Preexists` against Local REST API < 4.0.0 | Upgrade the plugin to v4.0.0 or later. The header was renamed upstream; the wire format is incompatible with older builds. |
@@ -13,6 +13,7 @@ declare const ServerConfigSchema: z.ZodObject<{
13
13
  readPaths: z.ZodPreprocess<z.ZodPipe<z.ZodOptional<z.ZodArray<z.ZodString>>, z.ZodTransform<string[] | undefined, string[] | undefined>>>;
14
14
  writePaths: z.ZodPreprocess<z.ZodPipe<z.ZodOptional<z.ZodArray<z.ZodString>>, z.ZodTransform<string[] | undefined, string[] | undefined>>>;
15
15
  readOnly: z.ZodDefault<z.ZodPreprocess<z.ZodBoolean>>;
16
+ omnisearchUrl: z.ZodOptional<z.ZodString>;
16
17
  }, z.core.$strip>;
17
18
  export type ServerConfig = z.infer<typeof ServerConfigSchema>;
18
19
  export declare function getServerConfig(): ServerConfig;
@@ -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;AAkF3C,QAAA,MAAM,kBAAkB;;;;;;;;;iBAyCtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,CAY9C;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;AAkF3C,QAAA,MAAM,kBAAkB;;;;;;;;;;iBAgDtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,CAa9C;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
@@ -112,6 +112,11 @@ const ServerConfigSchema = z.object({
112
112
  readOnly: envBoolean
113
113
  .default(false)
114
114
  .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.'),
115
+ omnisearchUrl: z
116
+ .string()
117
+ .url()
118
+ .optional()
119
+ .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.'),
115
120
  });
116
121
  let _config;
117
122
  export function getServerConfig() {
@@ -124,6 +129,7 @@ export function getServerConfig() {
124
129
  readPaths: 'OBSIDIAN_READ_PATHS',
125
130
  writePaths: 'OBSIDIAN_WRITE_PATHS',
126
131
  readOnly: 'OBSIDIAN_READ_ONLY',
132
+ omnisearchUrl: 'OBSIDIAN_OMNISEARCH_URL',
127
133
  });
128
134
  return _config;
129
135
  }
@@ -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,8 +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 in `setup()` so handlers can reach it via
5
- * `getObsidianService()`.
4
+ * Local REST API service at module load so the Omnisearch probe can run
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
8
  * @module index
7
9
  */
8
10
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
package/dist/index.js CHANGED
@@ -1,8 +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 in `setup()` so handlers can reach it via
5
- * `getObsidianService()`.
4
+ * Local REST API service at module load so the Omnisearch probe can run
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
8
  * @module index
7
9
  */
8
10
  import { createApp, disabledTool } from '@cyanheads/mcp-ts-core';
@@ -10,16 +12,26 @@ import { requestContextService } from '@cyanheads/mcp-ts-core/utils';
10
12
  import { getServerConfig } from './config/server-config.js';
11
13
  import { allPromptDefinitions } from './mcp-server/prompts/definitions/index.js';
12
14
  import { allResourceDefinitions } from './mcp-server/resources/definitions/index.js';
13
- import { commandToolDefinitions, readToolDefinitions, writeToolDefinitions, } from './mcp-server/tools/definitions/index.js';
14
- import { initObsidianService } from './services/obsidian/obsidian-service.js';
15
+ import { buildSearchNotesTool, commandToolDefinitions, readToolDefinitions, writeToolDefinitions, } from './mcp-server/tools/definitions/index.js';
16
+ import { getObsidianService, initObsidianService } from './services/obsidian/obsidian-service.js';
15
17
  import { PathPolicy } from './services/obsidian/path-policy.js';
16
18
  const config = getServerConfig();
17
19
  const policy = new PathPolicy(config);
20
+ /**
21
+ * Init the service at module load (rather than inside `setup()`) so the
22
+ * Omnisearch probe can run before tool construction. `setup()` runs after
23
+ * tools are passed into `createApp()`, which is too late to influence the
24
+ * search-notes schema.
25
+ */
26
+ initObsidianService(config);
27
+ const obsidian = getObsidianService();
28
+ const omnisearchReachable = await obsidian.probeOmnisearch();
29
+ const searchNotesTool = buildSearchNotesTool({ omnisearchReachable });
18
30
  /**
19
31
  * Build the server-level `instructions` string sent on every `initialize`.
20
32
  * Provides baseline orientation about the server and then layers in
21
33
  * deployment-specific lines (read-only mode, scoped paths, command-palette
22
- * toggle) when those flags are active.
34
+ * toggle, Omnisearch availability) when those flags are active.
23
35
  */
24
36
  function buildInstructions() {
25
37
  const sections = [
@@ -36,6 +48,9 @@ function buildInstructions() {
36
48
  if (config.enableCommands && !config.readOnly) {
37
49
  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.');
38
50
  }
51
+ if (omnisearchReachable) {
52
+ 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.');
53
+ }
39
54
  return sections.join('\n\n');
40
55
  }
41
56
  const writeTools = config.readOnly
@@ -54,15 +69,12 @@ const commandTools = config.enableCommands && !config.readOnly
54
69
  ? 'Unset OBSIDIAN_READ_ONLY to allow commands; OBSIDIAN_ENABLE_COMMANDS=true is also required.'
55
70
  : 'Set OBSIDIAN_ENABLE_COMMANDS=true to enable obsidian_list_commands and obsidian_execute_command.',
56
71
  }));
57
- const tools = [...readToolDefinitions, ...writeTools, ...commandTools];
72
+ const tools = [...readToolDefinitions, searchNotesTool, ...writeTools, ...commandTools];
58
73
  const { services } = await createApp({
59
74
  tools,
60
75
  resources: allResourceDefinitions,
61
76
  prompts: allPromptDefinitions,
62
77
  instructions: buildInstructions(),
63
- setup() {
64
- initObsidianService(config);
65
- },
66
78
  });
67
79
  /**
68
80
  * Startup banner — emitted after createApp() returns so the framework's
@@ -75,8 +87,13 @@ const bannerCtx = requestContextService.createRequestContext({
75
87
  operation: 'startup',
76
88
  ...policy.describe(),
77
89
  enableCommands: config.enableCommands && !config.readOnly,
90
+ omnisearchUrl: obsidian.omnisearchUrl,
91
+ omnisearchReachable,
78
92
  });
79
93
  services.logger.info('Path policy', bannerCtx);
94
+ services.logger.info(omnisearchReachable
95
+ ? `Omnisearch reachable at ${obsidian.omnisearchUrl} — \`omnisearch\` mode enabled on \`obsidian_search_notes\`.`
96
+ : `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);
80
97
  if (policy.readOnlyShadowsWritePaths) {
81
98
  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);
82
99
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AACrF,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAEhE,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;AACjC,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;AAEtC;;;;;GAKG;AACH,SAAS,iBAAiB;IACxB,MAAM,QAAQ,GAAa;QACzB,qXAAqX;KACtX,CAAC;IACF,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CACX,mIAAmI,CACpI,CAAC;IACJ,CAAC;SAAM,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAClC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,CAAC,KAAiC,EAAU,EAAE,CAC3D,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5E,QAAQ,CAAC,IAAI,CACX,4CAA4C,MAAM,CAAC,SAAS,CAAC,eAAe,MAAM,CAAC,UAAU,CAAC,qHAAqH,CACpN,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,cAAc,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC9C,QAAQ,CAAC,IAAI,CACX,gNAAgN,CACjN,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ;IAChC,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAC/B,YAAY,CAAC,GAAG,EAAE;QAChB,MAAM,EAAE,sCAAsC;QAC9C,IAAI,EAAE,sEAAsE;KAC7E,CAAC,CACH;IACH,CAAC,CAAC,oBAAoB,CAAC;AAEzB,MAAM,YAAY,GAChB,MAAM,CAAC,cAAc,IAAI,CAAC,MAAM,CAAC,QAAQ;IACvC,CAAC,CAAC,sBAAsB;IACxB,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACjC,YAAY,CAAC,GAAG,EAAE;QAChB,MAAM,EAAE,MAAM,CAAC,QAAQ;YACrB,CAAC,CAAC,4DAA4D;YAC9D,CAAC,CAAC,4EAA4E;QAChF,IAAI,EAAE,MAAM,CAAC,QAAQ;YACnB,CAAC,CAAC,6FAA6F;YAC/F,CAAC,CAAC,kGAAkG;KACvG,CAAC,CACH,CAAC;AAER,MAAM,KAAK,GAAG,CAAC,GAAG,mBAAmB,EAAE,GAAG,UAAU,EAAE,GAAG,YAAY,CAAC,CAAC;AAEvE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,SAAS,CAAC;IACnC,KAAK;IACL,SAAS,EAAE,sBAAsB;IACjC,OAAO,EAAE,oBAAoB;IAC7B,YAAY,EAAE,iBAAiB,EAAE;IACjC,KAAK;QACH,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;CACF,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,SAAS,GAAG,qBAAqB,CAAC,oBAAoB,CAAC;IAC3D,SAAS,EAAE,SAAS;IACpB,GAAG,MAAM,CAAC,QAAQ,EAAE;IACpB,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,CAAC,MAAM,CAAC,QAAQ;CAC1D,CAAC,CAAC;AACH,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;AAC/C,IAAI,MAAM,CAAC,yBAAyB,EAAE,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,OAAO,CACrB,uHAAuH,EACvH,SAAS,CACV,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @fileoverview Static safety guards for user-supplied `nameRegex` filters.
3
+ * JavaScript's RegExp engine has no native execution timeout, so we statically
4
+ * reject the textbook catastrophic-backtracking shapes before calling
5
+ * `new RegExp(...)`. Shared by tools that post-filter upstream listings by
6
+ * name (`obsidian_list_tags`, `obsidian_list_commands`).
7
+ * @module mcp-server/tools/definitions/_shared/regex-safety
8
+ */
9
+ /** Maximum allowed pattern length — bounds compile cost and AST surface. */
10
+ export declare const NAME_REGEX_MAX_LENGTH = 256;
11
+ /**
12
+ * Returns a human-readable reason string when the pattern is unsafe, or
13
+ * `undefined` when it passes the static guards. Callers compile with
14
+ * `new RegExp(pattern)` after this returns `undefined` and surface the
15
+ * returned reason via the tool's `regex_unsafe` error.
16
+ */
17
+ export declare function nameRegexSafetyIssue(pattern: string): string | undefined;
18
+ //# sourceMappingURL=regex-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex-safety.d.ts","sourceRoot":"","sources":["../../../../../src/mcp-server/tools/definitions/_shared/regex-safety.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,4EAA4E;AAC5E,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAWzC;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQxE"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @fileoverview Static safety guards for user-supplied `nameRegex` filters.
3
+ * JavaScript's RegExp engine has no native execution timeout, so we statically
4
+ * reject the textbook catastrophic-backtracking shapes before calling
5
+ * `new RegExp(...)`. Shared by tools that post-filter upstream listings by
6
+ * name (`obsidian_list_tags`, `obsidian_list_commands`).
7
+ * @module mcp-server/tools/definitions/_shared/regex-safety
8
+ */
9
+ /** Maximum allowed pattern length — bounds compile cost and AST surface. */
10
+ export const NAME_REGEX_MAX_LENGTH = 256;
11
+ /**
12
+ * Detects the canonical catastrophic-backtracking shape: a `+`/`*`/`{N,}`
13
+ * quantifier immediately following a `)` whose interior already ends in a
14
+ * `+`/`*`/`}` quantifier (e.g. `(a+)+`, `(.*)*`, `(a{2,})*`). Not exhaustive —
15
+ * patterns with overlapping alternation like `(a|a)*` still slip through —
16
+ * but eliminates the textbook ReDoS vector at zero runtime cost.
17
+ */
18
+ const NESTED_QUANTIFIER = /[+*}]\)[*+{]/;
19
+ /**
20
+ * Returns a human-readable reason string when the pattern is unsafe, or
21
+ * `undefined` when it passes the static guards. Callers compile with
22
+ * `new RegExp(pattern)` after this returns `undefined` and surface the
23
+ * returned reason via the tool's `regex_unsafe` error.
24
+ */
25
+ export function nameRegexSafetyIssue(pattern) {
26
+ if (pattern.length > NAME_REGEX_MAX_LENGTH) {
27
+ return `pattern exceeds ${NAME_REGEX_MAX_LENGTH}-character limit`;
28
+ }
29
+ if (NESTED_QUANTIFIER.test(pattern)) {
30
+ return 'pattern contains nested quantifiers (catastrophic-backtracking risk)';
31
+ }
32
+ return;
33
+ }
34
+ //# sourceMappingURL=regex-safety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex-safety.js","sourceRoot":"","sources":["../../../../../src/mcp-server/tools/definitions/_shared/regex-safety.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,4EAA4E;AAC5E,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,IAAI,OAAO,CAAC,MAAM,GAAG,qBAAqB,EAAE,CAAC;QAC3C,OAAO,mBAAmB,qBAAqB,kBAAkB,CAAC;IACpE,CAAC;IACD,IAAI,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,sEAAsE,CAAC;IAChF,CAAC;IACD,OAAO;AACT,CAAC"}
@@ -54,7 +54,7 @@ export const PatchOptionsSchema = z
54
54
  applyIfContentPreexists: z
55
55
  .boolean()
56
56
  .default(false)
57
- .describe('Apply the patch even if matching content already exists in the target. Guards against double-applying.'),
57
+ .describe('When false (default), the patch is rejected if the supplied content already appears in the target idempotent against agent retries. Set to true to force-apply even when it would duplicate. Replace operations are unaffected (the plugin exempts them).'),
58
58
  trimTargetWhitespace: z
59
59
  .boolean()
60
60
  .default(false)
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../../../src/mcp-server/tools/definitions/_shared/schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAE3C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IACvD,CAAC;SACE,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC;QACnE,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CAAC,kEAAkE,CAAC;KAChF,CAAC;SACD,QAAQ,CAAC,4CAA4C,CAAC;IACzD,CAAC;SACE,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,8CAA8C,CAAC;KACnF,CAAC;SACD,QAAQ,CAAC,gEAAgE,CAAC;IAC7E,CAAC;SACE,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,oDAAoD,CAAC;QAC1F,MAAM,EAAE,CAAC;aACN,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;aAC3D,QAAQ,CAAC,4BAA4B,CAAC;QACzC,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,KAAK,CAAC,qBAAqB,CAAC;aAC5B,QAAQ,EAAE;aACV,QAAQ,CAAC,mDAAmD,CAAC;KACjE,CAAC;SACD,QAAQ,CAAC,6CAA6C,CAAC;CAC3D,CAAC,CAAC;AAEH,yCAAyC;AACzC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;SACzC,QAAQ,CAAC,mEAAmE,CAAC;IAChF,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,+IAA+I,CAChJ;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,CAAC;IACN,qBAAqB,EAAE,CAAC;SACrB,OAAO,EAAE;SACT,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,yEAAyE,CAAC;IACtF,uBAAuB,EAAE,CAAC;SACvB,OAAO,EAAE;SACT,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CACP,wGAAwG,CACzG;IACH,oBAAoB,EAAE,CAAC;SACpB,OAAO,EAAE;SACT,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,wEAAwE,CAAC;CACtF,CAAC;KACD,QAAQ,EAAE,CAAC;AAEd,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;KAC1B,OAAO,CAAC,UAAU,CAAC;KACnB,QAAQ,CACP,qPAAqP,CACtP,CAAC"}
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../../../src/mcp-server/tools/definitions/_shared/schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAE3C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IACvD,CAAC;SACE,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC;QACnE,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CAAC,kEAAkE,CAAC;KAChF,CAAC;SACD,QAAQ,CAAC,4CAA4C,CAAC;IACzD,CAAC;SACE,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,8CAA8C,CAAC;KACnF,CAAC;SACD,QAAQ,CAAC,gEAAgE,CAAC;IAC7E,CAAC;SACE,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,oDAAoD,CAAC;QAC1F,MAAM,EAAE,CAAC;aACN,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;aAC3D,QAAQ,CAAC,4BAA4B,CAAC;QACzC,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,KAAK,CAAC,qBAAqB,CAAC;aAC5B,QAAQ,EAAE;aACV,QAAQ,CAAC,mDAAmD,CAAC;KACjE,CAAC;SACD,QAAQ,CAAC,6CAA6C,CAAC;CAC3D,CAAC,CAAC;AAEH,yCAAyC;AACzC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;SACzC,QAAQ,CAAC,mEAAmE,CAAC;IAChF,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,+IAA+I,CAChJ;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,CAAC;IACN,qBAAqB,EAAE,CAAC;SACrB,OAAO,EAAE;SACT,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,yEAAyE,CAAC;IACtF,uBAAuB,EAAE,CAAC;SACvB,OAAO,EAAE;SACT,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CACP,6PAA6P,CAC9P;IACH,oBAAoB,EAAE,CAAC;SACpB,OAAO,EAAE;SACT,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,wEAAwE,CAAC;CACtF,CAAC;KACD,QAAQ,EAAE,CAAC;AAEd,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;KAC1B,OAAO,CAAC,UAAU,CAAC;KACnB,QAAQ,CACP,qPAAqP,CACtP,CAAC"}