obsidian-mcp-server 3.6.0 → 3.7.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 (79) hide show
  1. package/AGENTS.md +40 -27
  2. package/CLAUDE.md +40 -27
  3. package/Dockerfile +90 -47
  4. package/README.md +130 -151
  5. package/changelog/3.6.x/3.6.1.md +29 -0
  6. package/changelog/3.7.x/3.7.0.md +34 -0
  7. package/dist/config/server-config.d.ts +1 -0
  8. package/dist/config/server-config.d.ts.map +1 -1
  9. package/dist/config/server-config.js +4 -0
  10. package/dist/config/server-config.js.map +1 -1
  11. package/dist/index.js +30 -10
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts +7 -5
  14. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts.map +1 -1
  15. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js +12 -8
  16. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js.map +1 -1
  17. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts +32 -10
  18. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts.map +1 -1
  19. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js +30 -8
  20. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js.map +1 -1
  21. package/dist/mcp-server/tools/definitions/index.d.ts +230 -294
  22. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  23. package/dist/mcp-server/tools/definitions/index.js +9 -3
  24. package/dist/mcp-server/tools/definitions/index.js.map +1 -1
  25. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js +1 -1
  26. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js.map +1 -1
  27. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts +108 -10
  28. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts.map +1 -1
  29. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js +254 -133
  30. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js.map +1 -1
  31. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts +1 -0
  32. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts.map +1 -1
  33. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js +62 -21
  34. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js.map +1 -1
  35. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.d.ts.map +1 -1
  36. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js +1 -2
  37. package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js.map +1 -1
  38. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts +6 -1
  39. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts.map +1 -1
  40. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js +9 -12
  41. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js.map +1 -1
  42. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts +7 -5
  43. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts.map +1 -1
  44. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js +14 -9
  45. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js.map +1 -1
  46. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts.map +1 -1
  47. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js +1 -2
  48. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js.map +1 -1
  49. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js +2 -2
  50. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js.map +1 -1
  51. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts +4 -1
  52. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts.map +1 -1
  53. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js +15 -4
  54. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js.map +1 -1
  55. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts.map +1 -1
  56. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js +2 -3
  57. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js.map +1 -1
  58. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -1
  59. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +2 -5
  60. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -1
  61. package/dist/services/obsidian/obsidian-service.d.ts +7 -0
  62. package/dist/services/obsidian/obsidian-service.d.ts.map +1 -1
  63. package/dist/services/obsidian/obsidian-service.js +72 -35
  64. package/dist/services/obsidian/obsidian-service.js.map +1 -1
  65. package/dist/services/obsidian/patch-instruction.d.ts +20 -1
  66. package/dist/services/obsidian/patch-instruction.d.ts.map +1 -1
  67. package/dist/services/obsidian/patch-instruction.js +30 -0
  68. package/dist/services/obsidian/patch-instruction.js.map +1 -1
  69. package/dist/services/obsidian/path-policy.d.ts +23 -1
  70. package/dist/services/obsidian/path-policy.d.ts.map +1 -1
  71. package/dist/services/obsidian/path-policy.js +45 -3
  72. package/dist/services/obsidian/path-policy.js.map +1 -1
  73. package/dist/services/obsidian/section-extractor.d.ts +24 -0
  74. package/dist/services/obsidian/section-extractor.d.ts.map +1 -1
  75. package/dist/services/obsidian/section-extractor.js +37 -0
  76. package/dist/services/obsidian/section-extractor.js.map +1 -1
  77. package/manifest.json +9 -1
  78. package/package.json +13 -10
  79. package/server.json +24 -24
@@ -0,0 +1,34 @@
1
+ ---
2
+ summary: "obsidian_delete_note now deletes on the first call unless OBSIDIAN_DELETE_ELICITATION=true, and obsidian_list_tags and obsidian_list_notes no longer expose tag names or folder and note names outside OBSIDIAN_READ_PATHS."
3
+ breaking: false
4
+ security: true
5
+ ---
6
+
7
+ # 3.7.0 — 2026-10-05
8
+
9
+ ## Added
10
+
11
+ - **`OBSIDIAN_DELETE_ELICITATION`** (default `false`) turns the `obsidian_delete_note` confirmation round on ([#153](https://github.com/cyanheads/obsidian-mcp-server/issues/153)). Declared in `server.json`, `manifest.json`, and `.env.example`; the startup log reports the delete mode.
12
+ - **`requestedPath` and a `notice` on `obsidian_get_note` and `obsidian_open_in_ui`** when a path with no exact match reads or opens its single case-insensitive match instead ([#149](https://github.com/cyanheads/obsidian-mcp-server/issues/149)). Write and delete tools still match the exact path.
13
+
14
+ ## Changed
15
+
16
+ - **`obsidian_delete_note` now deletes on the first call, with no confirmation round** ([#153](https://github.com/cyanheads/obsidian-mcp-server/issues/153)). Set `OBSIDIAN_DELETE_ELICITATION=true` to keep the confirmation; the stateful-session requirement over HTTP then applies only in that mode, and not under `OBSIDIAN_READ_ONLY=true` (which disables the tool), so `MCP_SESSION_MODE=stateless` starts otherwise. `OBSIDIAN_WRITE_PATHS` and `OBSIDIAN_READ_ONLY` bound what a delete reaches.
17
+ - **`obsidian_delete_note` checks write scope before it reads the note or builds a prompt**, so a readable note outside `OBSIDIAN_WRITE_PATHS` fails `path_forbidden` without asking ([#153](https://github.com/cyanheads/obsidian-mcp-server/issues/153)).
18
+ - **`obsidian_search_notes` backlink recipe** also matches `[[Target Note\|Alias]]`, the table-safe alias form.
19
+
20
+ ## Fixed
21
+
22
+ - **`obsidian_get_note` `includeLinks` returns the target Obsidian resolves for `[[Note\|Alias]]`**, with no trailing backslash ([#126](https://github.com/cyanheads/obsidian-mcp-server/issues/126)). Wikilink and markdown-link scanning now follows Obsidian's own shapes (`[[Note|see [1]]]`, `Note(1).md`) and stays linear on unclosed brackets.
23
+ - **Heading writes on Local REST API v4.x keep their line breaks** ([#146](https://github.com/cyanheads/obsidian-mcp-server/issues/146)). An append, prepend, or replace no longer runs into the next heading or the line before. CRLF notes still land mid-line, a plugin limitation.
24
+ - **`obsidian_delete_note` no longer deletes a differently-cased note on a case-insensitive filesystem.** A wrong-case path fails `note_missing`, listing near matches in `suggestions`, and sends no DELETE.
25
+
26
+ ## Security
27
+
28
+ - **`obsidian_list_tags` and `obsidian://tags` list only tags from readable notes when `OBSIDIAN_READ_PATHS` is set** ([#154](https://github.com/cyanheads/obsidian-mcp-server/issues/154)). Before, tag names and vault-wide counts from out-of-scope notes were returned. `count` is now the number of readable notes carrying the tag or a nested tag; write paths and read-only alone leave listings vault-wide.
29
+ - **`obsidian_list_notes` returns only readable entries and the folders leading to the read scope** ([#155](https://github.com/cyanheads/obsidian-mcp-server/issues/155)). Before, out-of-scope folder and root-level note names were listed. A nested scope can now be browsed to from the root, and `truncated` marks only depth-limited folders.
30
+
31
+ ## Dependencies
32
+
33
+ - dev: `ignore` ^7.0.11 → ^7.0.12
34
+ - `marked` stays pinned at `17.0.6` (the Local REST API's markdown-patch engine depends on marked 17; marked 18 parses some blocks differently, which would split section targeting from the plugin's)
@@ -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>>, unknown>;
14
14
  writePaths: z.ZodPreprocess<z.ZodPipe<z.ZodOptional<z.ZodArray<z.ZodString>>, z.ZodTransform<string[] | undefined, string[] | undefined>>, unknown>;
15
15
  readOnly: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCodec<z.ZodString, z.ZodBoolean>]>>;
16
+ deleteElicitation: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCodec<z.ZodString, z.ZodBoolean>]>>;
16
17
  omnisearchUrl: z.ZodOptional<z.ZodString>;
17
18
  }, z.core.$strip>;
18
19
  export type ServerConfig = z.infer<typeof ServerConfigSchema>;
@@ -1 +1 @@
1
- {"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAgF3C,QAAA,MAAM,kBAAkB;;;;;;;;;;iBAuDtB,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"}
1
+ {"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAgF3C,QAAA,MAAM,kBAAkB;;;;;;;;;;;iBA4DtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,CAc9C;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
@@ -116,6 +116,9 @@ const ServerConfigSchema = z.object({
116
116
  readOnly: envBoolean
117
117
  .default(false)
118
118
  .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.'),
119
+ deleteElicitation: envBoolean
120
+ .default(false)
121
+ .describe('When true, `obsidian_delete_note` asks the user to confirm each delete through an elicitation round, and HTTP startup requires a stateful session (MCP_SESSION_MODE=stateless is refused) unless OBSIDIAN_READ_ONLY=true, which disables the tool. Defaults to false: the delete runs on the first call, bounded by OBSIDIAN_WRITE_PATHS and OBSIDIAN_READ_ONLY.'),
119
122
  omnisearchUrl: z
120
123
  .string()
121
124
  .url()
@@ -133,6 +136,7 @@ export function getServerConfig() {
133
136
  readPaths: 'OBSIDIAN_READ_PATHS',
134
137
  writePaths: 'OBSIDIAN_WRITE_PATHS',
135
138
  readOnly: 'OBSIDIAN_READ_ONLY',
139
+ deleteElicitation: 'OBSIDIAN_DELETE_ELICITATION',
136
140
  omnisearchUrl: 'OBSIDIAN_OMNISEARCH_URL',
137
141
  });
138
142
  return _config;
@@ -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.js CHANGED
@@ -12,7 +12,7 @@ import { requestContextService } from '@cyanheads/mcp-ts-core/utils';
12
12
  import { getServerConfig } from './config/server-config.js';
13
13
  import { allPromptDefinitions } from './mcp-server/prompts/definitions/index.js';
14
14
  import { allResourceDefinitions } from './mcp-server/resources/definitions/index.js';
15
- import { buildSearchNotesTool, commandToolDefinitions, readToolDefinitions, writeToolDefinitions, } from './mcp-server/tools/definitions/index.js';
15
+ import { buildDeleteNoteTool, buildSearchNotesTool, commandToolDefinitions, readToolDefinitions, writeToolDefinitions, } from './mcp-server/tools/definitions/index.js';
16
16
  import { getObsidianService, initObsidianService } from './services/obsidian/obsidian-service.js';
17
17
  import { PathPolicy } from './services/obsidian/path-policy.js';
18
18
  const config = getServerConfig();
@@ -53,12 +53,22 @@ function buildInstructions() {
53
53
  }
54
54
  return sections.join('\n\n');
55
55
  }
56
+ const writeToolSet = [
57
+ ...writeToolDefinitions,
58
+ buildDeleteNoteTool({ elicitation: config.deleteElicitation }),
59
+ ];
60
+ /**
61
+ * The delete confirmation can run only when `obsidian_delete_note` is
62
+ * registered: `OBSIDIAN_READ_ONLY=true` disables it below, so the gate — and
63
+ * the session it needs — exists only with elicitation on and writes allowed.
64
+ */
65
+ const deleteGateActive = config.deleteElicitation && !config.readOnly;
56
66
  const writeTools = config.readOnly
57
- ? writeToolDefinitions.map((def) => disabledTool(def, {
67
+ ? writeToolSet.map((def) => disabledTool(def, {
58
68
  reason: 'Disabled by OBSIDIAN_READ_ONLY=true.',
59
69
  hint: 'Unset OBSIDIAN_READ_ONLY (or set it to false) to enable write tools.',
60
70
  }))
61
- : writeToolDefinitions;
71
+ : writeToolSet;
62
72
  const commandTools = config.enableCommands && !config.readOnly
63
73
  ? commandToolDefinitions
64
74
  : commandToolDefinitions.map((def) => disabledTool(def, {
@@ -78,27 +88,37 @@ const { services } = await createApp({
78
88
  prompts: allPromptDefinitions,
79
89
  instructions: buildInstructions(),
80
90
  /**
91
+ * With `OBSIDIAN_DELETE_ELICITATION=true` (and writes allowed),
81
92
  * `obsidian_delete_note` confirms through `ctx.requestInput`, which a
82
- * 2025-era HTTP client can only answer on a stateful session. Declared as the
83
- * default, not a requirement — an explicit `MCP_SESSION_MODE=stateless` still
84
- * starts; the delete confirmation is then refused with
85
- * `client_capability_missing` on those clients.
93
+ * 2025-era HTTP client can only answer on a stateful session — under
94
+ * stateless HTTP the tool would be unusable for them. Required, not just
95
+ * defaulted, in that mode: over HTTP, a resolved `stateless` mode (an
96
+ * explicit `MCP_SESSION_MODE=stateless`) fails startup with a
97
+ * `ConfigurationError`. With the confirmation off, or the tool disabled by
98
+ * `OBSIDIAN_READ_ONLY=true`, nothing needs a session and `stateful` is only
99
+ * the default. stdio is never refused; `MCP_SESSION_MODE` has no effect there.
86
100
  */
87
- sessionMode: 'stateful',
101
+ sessionMode: deleteGateActive
102
+ ? { default: 'stateful', require: 'stateful' }
103
+ : { default: 'stateful' },
88
104
  teardown: () => obsidian.close(),
89
105
  });
90
106
  /**
91
107
  * Startup banner — emitted after createApp() returns so the framework's
92
108
  * `logger.initialize()` has run; calls inside `setup()` happen pre-init and
93
109
  * are dropped. Operators check this against their config to verify the active
94
- * path policy. The active scope on `path_forbidden` errors echoes the same
95
- * data so the LLM (or operator) can self-correct without scrolling the log.
110
+ * path policy and whether `obsidian_delete_note` asks before deleting
111
+ * (`deleteElicitation`, false under read-only like `enableCommands`, since
112
+ * the tool is disabled there). The active scope on `path_forbidden` errors echoes
113
+ * the same data so the LLM (or operator) can self-correct without scrolling
114
+ * the log.
96
115
  */
97
116
  const bannerCtx = requestContextService.createRequestContext({
98
117
  operation: 'startup',
99
118
  additionalContext: {
100
119
  ...policy.describe(),
101
120
  enableCommands: config.enableCommands && !config.readOnly,
121
+ deleteElicitation: deleteGateActive,
102
122
  omnisearchUrl: obsidian.omnisearchUrl,
103
123
  omnisearchReachable,
104
124
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -2,11 +2,13 @@
2
2
  * @fileoverview obsidian://tags — vault tag listing with usage counts, for
3
3
  * clients that prefer attaching resources.
4
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.
5
+ * Not a mirror of `obsidian_list_tags`: this is a snapshot of
6
+ * `ObsidianService.listTags`, returned whole and unsorted — the upstream
7
+ * `/tags/` payload in upstream order, or under OBSIDIAN_READ_PATHS the tags of
8
+ * readable notes in order of first appearance. The tool shapes the same
9
+ * payload for an LLM caller — count-descending, capped, filterable — and that
10
+ * shaping deliberately lives in the tool handler rather than the shared
11
+ * service call both make.
10
12
  * @module mcp-server/resources/definitions/obsidian-tags.resource
11
13
  */
12
14
  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;;;;;;;;;;GAUG;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;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGrD,eAAO,MAAM,YAAY;;;;;6BA+BvB,CAAC"}
@@ -2,18 +2,20 @@
2
2
  * @fileoverview obsidian://tags — vault tag listing with usage counts, for
3
3
  * clients that prefer attaching resources.
4
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.
5
+ * Not a mirror of `obsidian_list_tags`: this is a snapshot of
6
+ * `ObsidianService.listTags`, returned whole and unsorted — the upstream
7
+ * `/tags/` payload in upstream order, or under OBSIDIAN_READ_PATHS the tags of
8
+ * readable notes in order of first appearance. The tool shapes the same
9
+ * payload for an LLM caller — count-descending, capped, filterable — and that
10
+ * shaping deliberately lives in the tool handler rather than the shared
11
+ * service call both make.
10
12
  * @module mcp-server/resources/definitions/obsidian-tags.resource
11
13
  */
12
14
  import { resource, z } from '@cyanheads/mcp-ts-core';
13
15
  import { getObsidianService } from '../../../services/obsidian/obsidian-service.js';
14
16
  export const obsidianTags = resource('obsidian://tags', {
15
17
  name: 'obsidian-tags',
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.',
18
+ description: 'All tags found in the Obsidian vault, with usage counts, unsorted and uncapped — a full snapshot. When OBSIDIAN_READ_PATHS is set, only tags carried by readable notes. Includes hierarchical parents (e.g. `work` for `work/tasks`). Use the `obsidian_list_tags` tool for a count-ranked, capped, filterable view.',
17
19
  mimeType: 'application/json',
18
20
  params: z.object({}),
19
21
  output: z.object({
@@ -21,10 +23,12 @@ export const obsidianTags = resource('obsidian://tags', {
21
23
  .array(z
22
24
  .object({
23
25
  name: z.string().describe('Tag name without the leading `#`.'),
24
- count: z.number().describe('Usage count across the vault.'),
26
+ count: z
27
+ .number()
28
+ .describe('Times the tag, or a tag nested under it, occurs across the vault. When OBSIDIAN_READ_PATHS is set: the number of readable notes carrying the tag or a tag nested under it.'),
25
29
  })
26
30
  .describe('A tag with its usage count.'))
27
- .describe('Every tag in the vault, in upstream-provided order.'),
31
+ .describe('Every tag in the vault, in the order the Local REST API reports them. When OBSIDIAN_READ_PATHS is set: every tag carried by a readable note, in order of first appearance.'),
28
32
  }),
29
33
  auth: ['resource:obsidian-tags:read'],
30
34
  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;;;;;;;;;;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"}
1
+ {"version":3,"file":"obsidian-tags.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/obsidian-tags.resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAC,iBAAiB,EAAE;IACtD,IAAI,EAAE,eAAe;IACrB,WAAW,EACT,sTAAsT;IACxT,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACpB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC;aACJ,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;YAC9D,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,CACP,4KAA4K,CAC7K;SACJ,CAAC;aACD,QAAQ,CAAC,6BAA6B,CAAC,CAC3C;aACA,QAAQ,CACP,4KAA4K,CAC7K;KACJ,CAAC;IACF,IAAI,EAAE,CAAC,6BAA6B,CAAC;IAErC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG;QACxB,MAAM,GAAG,GAAG,kBAAkB,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;IACvE,CAAC;CACF,CAAC,CAAC"}
@@ -4,20 +4,35 @@
4
4
  * 1. **Case-insensitive fallback.** If a path lookup 404s, list the parent
5
5
  * directory and look for a single case-insensitive filename match. If
6
6
  * found, retry against the canonical filesystem path (matches v2.x
7
- * behavior). This silently fixes "Readme.md" vs "README.md" on Linux; on
8
- * Mac/Windows the OS already case-folds and the fallback is a no-op.
7
+ * behavior) and report the path that was asked for as `requestedPath`, so
8
+ * the caller can disclose the substitution. The fallback is reachable on
9
+ * every host: the plugin's `note+json` and document-map reads resolve
10
+ * through Obsidian's case-sensitive vault index even on a case-insensitive
11
+ * filesystem (macOS, Windows). Only the raw-markdown read case-folds there,
12
+ * answering 200 for a wrong-case path before any fallback runs.
9
13
  *
10
14
  * 2. **"Did you mean" suggestions.** When no case match exists but the parent
11
15
  * directory has near-matches (e.g., extension-stripped variants), re-throw
12
16
  * NotFound enriched with the candidates in the message and
13
17
  * `error.data.suggestions[]`.
14
18
  *
15
- * Read/open/delete tools wrap their service calls with `withCaseFallback`.
19
+ * `obsidian_get_note` and `obsidian_open_in_ui` wrap their service calls with
20
+ * `withCaseFallback`; writes and deletes match the exact path.
16
21
  * @module mcp-server/tools/definitions/_shared/suggest-paths
17
22
  */
18
23
  import type { Context } from '@cyanheads/mcp-ts-core';
19
24
  import type { ObsidianService } from '../../../../services/obsidian/obsidian-service.js';
20
25
  import type { NoteTarget } from '../../../../services/obsidian/types.js';
26
+ /** Outcome of {@link withCaseFallback}; `requestedPath` is present only when another path was read. */
27
+ export type CaseFallback<T> = {
28
+ result: T;
29
+ resolvedPath: string | undefined;
30
+ requestedPath?: never;
31
+ } | {
32
+ result: T;
33
+ resolvedPath: string;
34
+ requestedPath: string;
35
+ };
21
36
  /**
22
37
  * Wrap a service call with case-insensitive path fallback and "did you mean"
23
38
  * enrichment. Non-path targets pass through — their paths are resolved
@@ -26,7 +41,7 @@ import type { NoteTarget } from '../../../../services/obsidian/types.js';
26
41
  * For path targets:
27
42
  * - **Exact match** → returns `{ result, resolvedPath: target.path }`.
28
43
  * - **Single case match** → retries with the canonical path and returns
29
- * `{ result, resolvedPath: <canonical> }`.
44
+ * `{ result, resolvedPath: <canonical>, requestedPath: target.path }`.
30
45
  * - **Multiple case matches** → throws `Conflict` with the candidates so the
31
46
  * agent can disambiguate.
32
47
  * - **No case match, extension-stripped near-matches** → throws `NotFound`
@@ -35,17 +50,24 @@ import type { NoteTarget } from '../../../../services/obsidian/types.js';
35
50
  *
36
51
  * `resolvedPath` is `undefined` for non-path targets — callers derive the
37
52
  * canonical path from the result itself (typically `NoteJson.path`).
53
+ * `requestedPath` is present only on the single-case-match branch.
38
54
  */
39
- export declare function withCaseFallback<T>(ctx: Context, svc: ObsidianService, target: NoteTarget, fn: (target: NoteTarget) => Promise<T>): Promise<{
40
- result: T;
41
- resolvedPath: string | undefined;
42
- }>;
55
+ export declare function withCaseFallback<T>(ctx: Context, svc: ObsidianService, target: NoteTarget, fn: (target: NoteTarget) => Promise<T>): Promise<CaseFallback<T>>;
56
+ /**
57
+ * Disclose a `withCaseFallback` substitution on the caller's enrichment: the
58
+ * `requestedPath` field plus a one-line notice naming both paths. `action` is
59
+ * what the tool did with the canonical file. Returns the notice — `notice` is
60
+ * last-wins, so a caller that sets another one must fold this text into it —
61
+ * or `undefined` when nothing was substituted.
62
+ */
63
+ export declare function discloseCaseSubstitution(ctx: Context, fallback: CaseFallback<unknown>, action: 'read' | 'opened'): string | undefined;
43
64
  /**
44
65
  * List the parent directory of `path` and return up to {@link MAX_SUGGESTIONS}
45
66
  * close-match candidates. Match order: case-insensitive equality first, then
46
67
  * extension-stripped equality. Returns `[]` on listing failure or empty
47
- * basename. Used by callers that need suggestions without performing the
48
- * underlying operation (e.g., `obsidian_open_in_ui`'s explicit messaging).
68
+ * basename. Used by callers that need suggestions without substituting a
69
+ * match (e.g., `obsidian_delete_note`'s exact-case miss, which names the
70
+ * candidates but never deletes one in place of the requested path).
49
71
  */
50
72
  export declare function findSimilarPaths(ctx: Context, svc: ObsidianService, path: string): Promise<string[]>;
51
73
  //# sourceMappingURL=suggest-paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"suggest-paths.d.ts","sourceRoot":"","sources":["../../../../../src/mcp-server/tools/definitions/_shared/suggest-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAW/D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,UAAU,EAClB,EAAE,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GACrC,OAAO,CAAC;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC,CAuC1D;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,EAAE,CAAC,CAGnB"}
1
+ {"version":3,"file":"suggest-paths.d.ts","sourceRoot":"","sources":["../../../../../src/mcp-server/tools/definitions/_shared/suggest-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAW/D,uGAAuG;AACvG,MAAM,MAAM,YAAY,CAAC,CAAC,IACtB;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,aAAa,CAAC,EAAE,KAAK,CAAA;CAAE,GACtE;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,UAAU,EAClB,EAAE,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GACrC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAsC1B;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,YAAY,CAAC,OAAO,CAAC,EAC/B,MAAM,EAAE,MAAM,GAAG,QAAQ,GACxB,MAAM,GAAG,SAAS,CAOpB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,EAAE,CAAC,CAGnB"}
@@ -4,15 +4,20 @@
4
4
  * 1. **Case-insensitive fallback.** If a path lookup 404s, list the parent
5
5
  * directory and look for a single case-insensitive filename match. If
6
6
  * found, retry against the canonical filesystem path (matches v2.x
7
- * behavior). This silently fixes "Readme.md" vs "README.md" on Linux; on
8
- * Mac/Windows the OS already case-folds and the fallback is a no-op.
7
+ * behavior) and report the path that was asked for as `requestedPath`, so
8
+ * the caller can disclose the substitution. The fallback is reachable on
9
+ * every host: the plugin's `note+json` and document-map reads resolve
10
+ * through Obsidian's case-sensitive vault index even on a case-insensitive
11
+ * filesystem (macOS, Windows). Only the raw-markdown read case-folds there,
12
+ * answering 200 for a wrong-case path before any fallback runs.
9
13
  *
10
14
  * 2. **"Did you mean" suggestions.** When no case match exists but the parent
11
15
  * directory has near-matches (e.g., extension-stripped variants), re-throw
12
16
  * NotFound enriched with the candidates in the message and
13
17
  * `error.data.suggestions[]`.
14
18
  *
15
- * Read/open/delete tools wrap their service calls with `withCaseFallback`.
19
+ * `obsidian_get_note` and `obsidian_open_in_ui` wrap their service calls with
20
+ * `withCaseFallback`; writes and deletes match the exact path.
16
21
  * @module mcp-server/tools/definitions/_shared/suggest-paths
17
22
  */
18
23
  import { conflict, JsonRpcErrorCode, McpError, notFound } from '@cyanheads/mcp-ts-core/errors';
@@ -25,7 +30,7 @@ const MAX_SUGGESTIONS = 5;
25
30
  * For path targets:
26
31
  * - **Exact match** → returns `{ result, resolvedPath: target.path }`.
27
32
  * - **Single case match** → retries with the canonical path and returns
28
- * `{ result, resolvedPath: <canonical> }`.
33
+ * `{ result, resolvedPath: <canonical>, requestedPath: target.path }`.
29
34
  * - **Multiple case matches** → throws `Conflict` with the candidates so the
30
35
  * agent can disambiguate.
31
36
  * - **No case match, extension-stripped near-matches** → throws `NotFound`
@@ -34,6 +39,7 @@ const MAX_SUGGESTIONS = 5;
34
39
  *
35
40
  * `resolvedPath` is `undefined` for non-path targets — callers derive the
36
41
  * canonical path from the result itself (typically `NoteJson.path`).
42
+ * `requestedPath` is present only on the single-case-match branch.
37
43
  */
38
44
  export async function withCaseFallback(ctx, svc, target, fn) {
39
45
  if (target.type !== 'path') {
@@ -50,7 +56,7 @@ export async function withCaseFallback(ctx, svc, target, fn) {
50
56
  const sole = probe.caseMatches.length === 1 ? probe.caseMatches[0] : undefined;
51
57
  if (sole !== undefined) {
52
58
  const result = await fn({ type: 'path', path: sole });
53
- return { result, resolvedPath: sole };
59
+ return { result, resolvedPath: sole, requestedPath: target.path };
54
60
  }
55
61
  if (probe.caseMatches.length > 1) {
56
62
  const list = probe.caseMatches.map((m) => `"${m}"`).join(', ');
@@ -58,7 +64,6 @@ export async function withCaseFallback(ctx, svc, target, fn) {
58
64
  path: target.path,
59
65
  reason: 'ambiguous_path',
60
66
  matches: probe.caseMatches,
61
- ...ctx.recoveryFor('ambiguous_path'),
62
67
  }, { cause: err });
63
68
  }
64
69
  if (probe.extInsensitive.length === 0)
@@ -69,12 +74,29 @@ export async function withCaseFallback(ctx, svc, target, fn) {
69
74
  throw notFound(`${prefix}. Did you mean: ${list}?`, { ...(err.data ?? {}), suggestions }, { cause: err });
70
75
  }
71
76
  }
77
+ /**
78
+ * Disclose a `withCaseFallback` substitution on the caller's enrichment: the
79
+ * `requestedPath` field plus a one-line notice naming both paths. `action` is
80
+ * what the tool did with the canonical file. Returns the notice — `notice` is
81
+ * last-wins, so a caller that sets another one must fold this text into it —
82
+ * or `undefined` when nothing was substituted.
83
+ */
84
+ export function discloseCaseSubstitution(ctx, fallback, action) {
85
+ if (fallback.requestedPath === undefined)
86
+ return;
87
+ const { requestedPath, resolvedPath } = fallback;
88
+ const notice = `\`${requestedPath}\` has no exact match; ${action} \`${resolvedPath}\`, the one file in that folder whose name matches it ignoring case. Write and delete tools match paths exactly — pass them \`${resolvedPath}\`.`;
89
+ ctx.enrich({ requestedPath });
90
+ ctx.enrich.notice(notice);
91
+ return notice;
92
+ }
72
93
  /**
73
94
  * List the parent directory of `path` and return up to {@link MAX_SUGGESTIONS}
74
95
  * close-match candidates. Match order: case-insensitive equality first, then
75
96
  * extension-stripped equality. Returns `[]` on listing failure or empty
76
- * basename. Used by callers that need suggestions without performing the
77
- * underlying operation (e.g., `obsidian_open_in_ui`'s explicit messaging).
97
+ * basename. Used by callers that need suggestions without substituting a
98
+ * match (e.g., `obsidian_delete_note`'s exact-case miss, which names the
99
+ * candidates but never deletes one in place of the requested path).
78
100
  */
79
101
  export async function findSimilarPaths(ctx, svc, path) {
80
102
  const probe = await probeParentDir(ctx, svc, path);
@@ -1 +1 @@
1
- {"version":3,"file":"suggest-paths.js","sourceRoot":"","sources":["../../../../../src/mcp-server/tools/definitions/_shared/suggest-paths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"suggest-paths.js","sourceRoot":"","sources":["../../../../../src/mcp-server/tools/definitions/_shared/suggest-paths.ts"],"names":[],"mappings":"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"}