obsidian-mcp-server 3.3.1 → 3.5.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 (36) hide show
  1. package/AGENTS.md +7 -5
  2. package/CLAUDE.md +7 -5
  3. package/README.md +17 -7
  4. package/changelog/3.4.x/3.4.0.md +25 -0
  5. package/changelog/3.5.x/3.5.0.md +16 -0
  6. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts +8 -2
  7. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts.map +1 -1
  8. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js +10 -4
  9. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js.map +1 -1
  10. package/dist/mcp-server/tools/definitions/index.d.ts +21 -2
  11. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  12. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts +15 -6
  13. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts.map +1 -1
  14. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js +90 -21
  15. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js.map +1 -1
  16. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts +14 -1
  17. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts.map +1 -1
  18. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js +85 -23
  19. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js.map +1 -1
  20. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +30 -2
  21. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -1
  22. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +57 -12
  23. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -1
  24. package/dist/services/obsidian/frontmatter-ops.d.ts +42 -1
  25. package/dist/services/obsidian/frontmatter-ops.d.ts.map +1 -1
  26. package/dist/services/obsidian/frontmatter-ops.js +98 -21
  27. package/dist/services/obsidian/frontmatter-ops.js.map +1 -1
  28. package/dist/services/obsidian/obsidian-service.d.ts +7 -0
  29. package/dist/services/obsidian/obsidian-service.d.ts.map +1 -1
  30. package/dist/services/obsidian/obsidian-service.js +205 -48
  31. package/dist/services/obsidian/obsidian-service.js.map +1 -1
  32. package/dist/services/obsidian/types.d.ts +8 -0
  33. package/dist/services/obsidian/types.d.ts.map +1 -1
  34. package/manifest.json +1 -1
  35. package/package.json +2 -2
  36. package/server.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter-ops.d.ts","sourceRoot":"","sources":["../../../src/services/obsidian/frontmatter-ops.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8CH;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAOzE;AAED,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,CAAC;AAC5C,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,EAAE,YAAY,EACvB,QAAQ,EAAE,WAAW,GACpB,kBAAkB,CAqBpB;AA2JD,yDAAyD;AACzD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC;IACD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAkBA"}
1
+ {"version":3,"file":"frontmatter-ops.d.ts","sourceRoot":"","sources":["../../../src/services/obsidian/frontmatter-ops.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,oFAAoF;AACpF,MAAM,WAAW,MAAM;IACrB,yFAAyF;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,uFAAuF;IACvF,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,gGAAgG;IAChG,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAa9C;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQ1E;AAyBD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAOzE;AAED,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,CAAC;AAC5C,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,EAAE,YAAY,EACvB,QAAQ,EAAE,WAAW,GACpB,kBAAkB,CAqBpB;AA2MD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC;IACD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAkBA"}
@@ -5,17 +5,52 @@
5
5
  * @module services/obsidian/frontmatter-ops
6
6
  */
7
7
  import { isMap, parseDocument } from 'yaml';
8
- const FM_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
9
- function splice(content) {
8
+ const FM_RE = /^(---\r?\n)([\s\S]*?)(\r?\n---\r?\n?)/;
9
+ /**
10
+ * Split a note into its raw frontmatter prefix and its body. `raw + body`
11
+ * reconstructs the input byte for byte, which is what makes this the primitive
12
+ * for body-scoped mutations: rebuild with the original `raw` and the frontmatter
13
+ * block is untouched by construction. Rebuilding through `serializeFrontmatter`
14
+ * would instead re-emit the YAML and can reformat scalars nobody asked to change.
15
+ *
16
+ * A file whose fence is never closed, whose `---` sits below the first line, or
17
+ * whose opening `---` carries trailing whitespace has no frontmatter — the whole
18
+ * thing is body, which is also how Obsidian reads each of those shapes.
19
+ */
20
+ export function splice(content) {
10
21
  const m = FM_RE.exec(content);
11
- if (!m)
12
- return { hasFrontmatter: false, yamlText: '', body: content };
22
+ if (!m) {
23
+ return { hasFrontmatter: false, raw: '', open: '', yamlText: '', close: '', body: content };
24
+ }
13
25
  return {
14
26
  hasFrontmatter: true,
15
- yamlText: m[1] ?? '',
27
+ raw: m[0],
28
+ open: m[1] ?? '',
29
+ yamlText: m[2] ?? '',
30
+ close: m[3] ?? '',
16
31
  body: content.slice(m[0].length),
17
32
  };
18
33
  }
34
+ /**
35
+ * Describe why `yamlText` is not usable as a frontmatter block, or `undefined`
36
+ * when it is. Catches YAML that no longer parses and YAML that parses to
37
+ * something other than a mapping — the two states in which Obsidian reads no
38
+ * properties at all.
39
+ *
40
+ * It cannot catch an edit that stays well-formed while meaning something else:
41
+ * a renamed key, a scalar that re-parses as a different type. Those are valid
42
+ * YAML and pass this check.
43
+ */
44
+ export function frontmatterParseError(yamlText) {
45
+ const doc = parseDocument(yamlText);
46
+ const first = doc.errors[0];
47
+ if (first)
48
+ return first.message;
49
+ if (doc.contents !== null && !isMap(doc.contents)) {
50
+ return 'Frontmatter must be a YAML mapping of properties.';
51
+ }
52
+ return;
53
+ }
19
54
  /**
20
55
  * Re-emit the parsed frontmatter document between `---` fences, preserving the
21
56
  * comments, quoting, and scalar formatting of every untouched node — the reason
@@ -133,8 +168,14 @@ function normalizeTagList(value) {
133
168
  }
134
169
  const FENCED_CODE_BLOCK = /(```[\s\S]*?```|~~~[\s\S]*?~~~)/g;
135
170
  const INLINE_CODE = /(`[^`\n]+`)/g;
171
+ /**
172
+ * Inline `#tag` syntax lives in the body. The frontmatter block is spliced off
173
+ * first and re-attached verbatim, so a `#` inside a YAML scalar is neither read
174
+ * as a tag nor rewritten by a removal.
175
+ */
136
176
  function mutateInlineTags(content, tags, operation, applied, skipped) {
137
- const segments = splitProtectedSegments(content);
177
+ const { raw, body } = splice(content);
178
+ const segments = splitProtectedSegments(body);
138
179
  let updatedNonCode = false;
139
180
  if (operation === 'add') {
140
181
  for (const tag of tags) {
@@ -152,16 +193,23 @@ function mutateInlineTags(content, tags, operation, applied, skipped) {
152
193
  .map((t) => `#${t}`)
153
194
  .join(' ');
154
195
  if (additions.length > 0) {
196
+ /**
197
+ * The separator turns on everything that precedes the insertion point in
198
+ * the finished note — `raw` and every segment — not on any one of them.
199
+ * A note that is nothing but frontmatter has an empty body while `raw`
200
+ * already ends in a newline, and a note whose body ends at a closing code
201
+ * fence ends in a protected segment the tag must not be glued to.
202
+ */
203
+ const preceding = raw + segments.map((s) => s.text).join('');
204
+ const sep = preceding.endsWith('\n') ? '' : '\n';
155
205
  const trailing = segments.length > 0 ? (segments[segments.length - 1] ?? null) : null;
156
206
  if (trailing && !trailing.protected) {
157
- const sep = trailing.text.endsWith('\n') ? '' : '\n';
158
207
  trailing.text = `${trailing.text}${sep}${additions}\n`;
159
- updatedNonCode = true;
160
208
  }
161
209
  else {
162
- segments.push({ protected: false, text: `\n${additions}\n` });
163
- updatedNonCode = true;
210
+ segments.push({ protected: false, text: `${sep}${additions}\n` });
164
211
  }
212
+ updatedNonCode = true;
165
213
  }
166
214
  }
167
215
  else {
@@ -171,23 +219,47 @@ function mutateInlineTags(content, tags, operation, applied, skipped) {
171
219
  for (const s of segments) {
172
220
  if (s.protected)
173
221
  continue;
174
- if (re.test(s.text)) {
175
- s.text = s.text.replace(re, (_full, leading) => leading);
176
- // collapse double spaces left behind
177
- s.text = s.text.replace(/[ \t]{2,}/g, ' ').replace(/ \n/g, '\n');
222
+ /**
223
+ * One pass is not enough: the regex consumes the space after the tag,
224
+ * and that space is the left boundary the next occurrence needs, so a
225
+ * single pass stops at the first of two same tags separated by one
226
+ * space. Repeat until the segment stops changing — every pass drops at
227
+ * least the tag itself, so this terminates.
228
+ */
229
+ for (let next = s.text.replace(re, removeAt); next !== s.text; next = s.text.replace(re, removeAt)) {
230
+ s.text = next;
178
231
  found = true;
179
- updatedNonCode = true;
180
232
  }
181
233
  }
182
- if (found)
234
+ if (found) {
183
235
  applied.add(tag);
184
- else
236
+ updatedNonCode = true;
237
+ }
238
+ else {
185
239
  skipped.add(tag);
240
+ }
186
241
  }
187
242
  }
188
243
  if (!updatedNonCode)
189
244
  return content;
190
- return segments.map((s) => s.text).join('');
245
+ return raw + segments.map((s) => s.text).join('');
246
+ }
247
+ /**
248
+ * Close the gap a removed tag leaves without touching anything else. Exactly one
249
+ * adjacent horizontal space goes with the tag — the one before it when there is
250
+ * one, otherwise the one after — so neighbouring words neither jam together nor
251
+ * end up separated by a widened gap. Everything outside that span survives byte
252
+ * for byte: list and code-block indentation, a trailing two-space hard line
253
+ * break, table cell padding.
254
+ */
255
+ function removeAt(full, leading, trailing, offset, whole) {
256
+ if (!/^[ \t]$/.test(leading))
257
+ return leading;
258
+ // A space is all that marks the start of an immediately following tag —
259
+ // taking it would silently stop that tag being one.
260
+ if (trailing === '' && whole[offset + full.length] === '#')
261
+ return leading;
262
+ return trailing;
191
263
  }
192
264
  function splitProtectedSegments(content) {
193
265
  const segments = [];
@@ -209,16 +281,21 @@ function splitProtectedSegments(content) {
209
281
  }
210
282
  return segments;
211
283
  }
284
+ /** Captures the character before the tag and the single horizontal space after it, if any. */
212
285
  function makeInlineTagRegex(tag) {
213
286
  const escaped = tag.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
214
- return new RegExp(`(^|[^\\w/])#${escaped}(?![\\w/-])`, 'g');
287
+ return new RegExp(`(^|[^\\w/])#${escaped}(?![\\w/-])([ \\t]?)`, 'g');
215
288
  }
216
- /** Read-only helpers for `obsidian_manage_tags list`. */
289
+ /**
290
+ * Read-only helpers for `obsidian_manage_tags list`. Inline tags are read from
291
+ * the body only, matching where a removal can actually reach — a `#` inside a
292
+ * YAML scalar is frontmatter, not a tag.
293
+ */
217
294
  export function listTagsFromContent(content, frontmatter) {
218
295
  const fmTags = normalizeTagList(frontmatter.tags);
219
296
  const inline = [];
220
297
  const seen = new Set();
221
- for (const seg of splitProtectedSegments(content)) {
298
+ for (const seg of splitProtectedSegments(splice(content).body)) {
222
299
  if (seg.protected)
223
300
  continue;
224
301
  const re = /(^|[^\w/])#([a-zA-Z][\w/-]*)/g;
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter-ops.js","sourceRoot":"","sources":["../../../src/services/obsidian/frontmatter-ops.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frontmatter-ops.js","sourceRoot":"","sources":["../../../src/services/obsidian/frontmatter-ops.ts"],"names":[],"mappings":"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"}
@@ -86,6 +86,13 @@ export declare class ObsidianService {
86
86
  listFiles(ctx: Context, dirPath?: string): Promise<FileListing>;
87
87
  listTags(ctx: Context): Promise<ObsidianTag[]>;
88
88
  listCommands(ctx: Context): Promise<ObsidianCommand[]>;
89
+ /**
90
+ * Text search. The upstream materializes one context window per matching
91
+ * note before it responds, so an oversized `contextLength` on a broad query
92
+ * exhausts V8's string capacity and comes back as an opaque 500 — caught
93
+ * here and re-thrown typed, the way `searchOmnisearch` re-throws its own
94
+ * reachability failure.
95
+ */
89
96
  searchText(ctx: Context, query: string, contextLength?: number): Promise<TextSearchHit[]>;
90
97
  searchJsonLogic(ctx: Context, logic: Record<string, unknown>): Promise<StructuredSearchHit[]>;
91
98
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"obsidian-service.d.ts","sourceRoot":"","sources":["../../../src/services/obsidian/obsidian-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"obsidian-service.d.ts","sourceRoot":"","sources":["../../../src/services/obsidian/obsidian-service.ts"],"names":[],"mappings":"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"}
@@ -4,8 +4,8 @@
4
4
  * `target` discriminator, and classifies errors for the framework.
5
5
  * @module services/obsidian/obsidian-service
6
6
  */
7
- import { conflict, forbidden, notFound, serviceUnavailable, unauthorized, validationError, } from '@cyanheads/mcp-ts-core/errors';
8
- import { httpErrorFromResponse, withRetry } from '@cyanheads/mcp-ts-core/utils';
7
+ import { conflict, forbidden, JsonRpcErrorCode, McpError, notFound, serviceUnavailable, unauthorized, validationError, } from '@cyanheads/mcp-ts-core/errors';
8
+ import { httpStatusToErrorCode, withRetry } from '@cyanheads/mcp-ts-core/utils';
9
9
  import { Agent, fetch as undiciFetch } from 'undici';
10
10
  import { getServerConfig } from '../../config/server-config.js';
11
11
  import { PathPolicy } from './path-policy.js';
@@ -301,14 +301,45 @@ export class ObsidianService {
301
301
  return body.commands ?? [];
302
302
  }
303
303
  // ── Search ───────────────────────────────────────────────────────────────
304
+ /**
305
+ * Text search. The upstream materializes one context window per matching
306
+ * note before it responds, so an oversized `contextLength` on a broad query
307
+ * exhausts V8's string capacity and comes back as an opaque 500 — caught
308
+ * here and re-thrown typed, the way `searchOmnisearch` re-throws its own
309
+ * reachability failure.
310
+ */
304
311
  async searchText(ctx, query, contextLength = 100) {
305
312
  const params = new URLSearchParams({ query, contextLength: String(contextLength) });
306
- const res = await this.#request(ctx, `/search/simple/?${params}`, { method: 'POST' });
313
+ let res;
314
+ try {
315
+ res = await this.#request(ctx, `/search/simple/?${params}`, { method: 'POST' });
316
+ }
317
+ catch (err) {
318
+ if (!isStringCapacityOverflow(err))
319
+ throw err;
320
+ /**
321
+ * Built fresh rather than decorated: `contextLength` is the actionable
322
+ * fact and only this frame knows it. `cause` keeps the caught error —
323
+ * and through it the upstream body `#throwForStatus` attached — on the
324
+ * server side for the log record.
325
+ */
326
+ throw validationError(`The Local REST API ran out of string capacity assembling match contexts for this search (contextLength ${contextLength}). It builds a context window for every matching note before responding, so the ceiling tracks contextLength multiplied by the number of matches rather than either alone.`, {
327
+ reason: 'context_length_too_large',
328
+ contextLength,
329
+ ...ctx.recoveryFor('context_length_too_large'),
330
+ }, { cause: err });
331
+ }
307
332
  const raw = (await res.json());
308
333
  // Upstream returns a constant `score` that carries no ranking signal for
309
334
  // text mode — drop it on the way out so consumers don't mistake it for
310
335
  // relevance. Omnisearch is the source of real BM25 ranking.
311
- return raw.map((h) => ({ filename: h.filename, matches: h.matches }));
336
+ return raw.map((h) => ({
337
+ filename: h.filename,
338
+ matches: h.matches.map((m) => ({
339
+ context: m.context,
340
+ match: { ...m.match, ...contextRelativeSpan(m, h.filename, contextLength, query) },
341
+ })),
342
+ }));
312
343
  }
313
344
  async searchJsonLogic(ctx, logic) {
314
345
  const res = await this.#request(ctx, '/search/', {
@@ -613,81 +644,133 @@ export class ObsidianService {
613
644
  ...ctx.recoveryFor('path_is_directory'),
614
645
  });
615
646
  }
647
+ /**
648
+ * Classify an upstream error response and throw.
649
+ *
650
+ * **Containment invariant.** Four things leave this method on the wire and
651
+ * nothing else: a message authored in this file, the request path the caller
652
+ * supplied (`data.path`), the HTTP status (`data.status`, default branch),
653
+ * and the calling tool's own contract `reason` + `recovery`. The upstream's
654
+ * response body never crosses, in any branch, under any key.
655
+ *
656
+ * That is stricter than redaction, deliberately. The Local REST API
657
+ * interleaves genuine diagnostics with vault data in one string: a rejected
658
+ * JSONLogic tree names the note the plugin was evaluating when it gave up
659
+ * (`(while processing <path>)`) and, when `regexp`'s operands are reversed,
660
+ * quotes that note's body back as the pattern it failed to compile; 5xx
661
+ * bodies relay Node `fs` errors carrying the vault's absolute on-disk
662
+ * location. `PathPolicy` gates the success path only, so none of that is
663
+ * scoped to what the caller may read. The two halves cannot be separated
664
+ * reliably — the pattern echo is delimited by characters the note body may
665
+ * itself contain, so any parse that keeps "the diagnostic half" fails open
666
+ * on exactly the input a caller controls, and failing open is the wrong
667
+ * direction for a containment control. So containment wins: the upstream
668
+ * text is read here only to *classify*, and what the caller receives is this
669
+ * file's own account of the failure. A misclassification therefore costs
670
+ * accuracy, never containment.
671
+ *
672
+ * The body is not discarded. It rides as `cause`, which the framework's
673
+ * error handler walks into the log record and neither client surface
674
+ * serializes — `ErrorOptions` makes `cause` non-enumerable, the tool error
675
+ * envelope is built from `code`/`message`/`data` alone, and so is the
676
+ * JSON-RPC error object the SDK emits for resources.
677
+ *
678
+ * Issues #104 and #116.
679
+ */
616
680
  async #throwForStatus(res, path, ctx) {
617
681
  const text = await this.#readBodySafe(res);
618
682
  const body = parseJsonObject(text);
619
683
  const display = displayPath(path);
620
- const upstream = safeUpstream(body, text);
684
+ /** Classification input and log payload only — never a wire value. */
685
+ const upstreamMsg = typeof body?.message === 'string' ? body.message : text.trim();
686
+ const cause = new UpstreamErrorText(upstreamMsg);
621
687
  const data = (reason) => ({
622
688
  path: display,
623
689
  ...(reason !== undefined ? { reason, ...ctx.recoveryFor(reason) } : {}),
624
- ...(upstream ? { upstream } : {}),
625
690
  });
626
691
  switch (res.status) {
627
692
  case 401:
628
- throw unauthorized('Obsidian Local REST API rejected the API key. Verify OBSIDIAN_API_KEY matches the value in Obsidian → Settings → Local REST API.', data());
693
+ throw unauthorized('Obsidian Local REST API rejected the API key. Verify OBSIDIAN_API_KEY matches the value in Obsidian → Settings → Local REST API.', data(), { cause });
629
694
  case 403:
630
- throw forbidden('Obsidian Local REST API forbids this request. Check the plugin permissions.', data());
695
+ throw forbidden('Obsidian Local REST API forbids this request. Check the plugin permissions.', data(), { cause });
631
696
  case 404: {
632
697
  if (path.startsWith('/active/')) {
633
- throw notFound('No file is currently active in Obsidian — open a file in the app first.', data('no_active_file'));
698
+ throw notFound('No file is currently active in Obsidian — open a file in the app first.', data('no_active_file'), { cause });
634
699
  }
635
700
  if (path.startsWith('/periodic/')) {
636
- const periodMatch = /^\/periodic\/(daily|weekly|monthly|quarterly|yearly)\//.exec(path);
637
- const period = periodMatch?.[1] ?? 'periodic';
638
701
  const dateMatch = /\/(\d{4})\/(\d{2})\/(\d{2})\/?$/.exec(path);
639
702
  const suffix = dateMatch ? ` for ${dateMatch[1]}-${dateMatch[2]}-${dateMatch[3]}` : '';
640
- throw notFound(`No ${period} note found${suffix}. Check that the Periodic Notes plugin is enabled and the note exists.`, data('periodic_not_found'));
703
+ throw notFound(`No ${periodOf(path)} note found${suffix}. Check that the Periodic Notes plugin is enabled and the note exists.`, data('periodic_not_found'), { cause });
641
704
  }
642
705
  if (path.startsWith('/commands/')) {
643
- throw notFound(`Unknown Obsidian command: ${display}. Use \`obsidian_list_commands\` to discover valid command IDs.`, data('command_unknown'));
706
+ throw notFound(`Unknown Obsidian command: ${display}. Use \`obsidian_list_commands\` to discover valid command IDs.`, data('command_unknown'), { cause });
644
707
  }
645
- throw notFound(`Not found: ${display}`, data('note_missing'));
708
+ throw notFound(`Not found: ${display}`, data('note_missing'), { cause });
646
709
  }
647
710
  case 405:
648
- throw validationError(`${display} cannot accept this method (often: the path is a directory, not a file).`, data('path_is_directory'));
711
+ throw validationError(`${display} cannot accept this method (often: the path is a directory, not a file).`, data('path_is_directory'), { cause });
649
712
  case 400: {
650
- const upstreamMsg = body?.message ?? `Bad request to ${display}`;
713
+ /**
714
+ * A malformed JSONLogic tree is rejected by the plugin's query parser
715
+ * with a bare 400. Keyed on the exact route rather than the message,
716
+ * because the upstream wording varies with which parse stage failed
717
+ * and `/search/simple/` (text mode) shares the `/search/` prefix
718
+ * without sharing the cause.
719
+ *
720
+ * The uncompilable-`regexp` case is named separately: it is the
721
+ * ordinary failure of a hand-written backlink query, and it is also
722
+ * the one whose upstream text quotes a note body. Classifying it here
723
+ * keeps the diagnostic a caller needs without relaying the pattern
724
+ * that carries it. The `logic_invalid` contract recovery supplies the
725
+ * operand order, and the framework mirrors it onto both surfaces.
726
+ */
727
+ if (routeOf(path) === '/search/') {
728
+ throw validationError(/invalid regular expression/i.test(upstreamMsg)
729
+ ? 'The Local REST API could not compile a `regexp` operand in the JSONLogic tree. `regexp` takes `[PATTERN, VALUE]` — with the operands reversed, the note field is compiled as the pattern.'
730
+ : 'The Local REST API could not evaluate the JSONLogic tree.', data('logic_invalid'), { cause });
731
+ }
651
732
  // Content-preexists is a more specific case nested inside the broader
652
733
  // "could not be applied" family — branch on it first so retries with
653
734
  // identical content surface the right reason and recovery (toggle
654
735
  // `applyIfContentPreexists`) instead of misleading section-miss copy.
655
736
  if (/content-already-preexists-in-target/i.test(upstreamMsg)) {
656
- throw validationError(`The supplied content already appears at the target in ${display}. Pass \`applyIfContentPreexists: true\` to force-apply, or change the content.`, data('content_preexists'));
737
+ throw validationError(`The supplied content already appears at the target in ${display}. Pass \`applyIfContentPreexists: true\` to force-apply, or change the content.`, data('content_preexists'), { cause });
657
738
  }
658
739
  // The Local REST API returns a "could not be applied to the target
659
740
  // content" / "invalid-target" message when a PATCH names a section that
660
741
  // doesn't exist. Translate to actionable guidance.
661
742
  const isTargetMiss = /\bcould not be applied\b|\binvalid-target\b/i.test(upstreamMsg);
662
743
  if (isTargetMiss) {
663
- throw validationError(`Section target not found in ${display}. Use \`obsidian_get_note\` with \`format: "document-map"\` to list available headings, blocks, and frontmatter fields, then retry with one of those locators.`, data('section_target_missing'));
744
+ throw validationError(`Section target not found in ${display}. Use \`obsidian_get_note\` with \`format: "document-map"\` to list available headings, blocks, and frontmatter fields, then retry with one of those locators.`, data('section_target_missing'), { cause });
664
745
  }
665
746
  // Periodic Notes plugin returns 400 with "Specified period is not enabled"
666
747
  // when the requested period (daily/weekly/monthly/...) is disabled in the
667
748
  // user's plugin settings. Distinct from periodic_not_found (404) — caller
668
749
  // can enable it or fall back to an explicit path target.
669
750
  if (path.startsWith('/periodic/') && /\bnot enabled\b/i.test(upstreamMsg)) {
670
- throw validationError(upstreamMsg, data('periodic_disabled'));
751
+ throw validationError(`The ${periodOf(path)} period is not enabled in Obsidian's Periodic Notes plugin settings. Enable it there, or address the note by an explicit vault path instead.`, data('periodic_disabled'), { cause });
671
752
  }
672
- throw validationError(upstreamMsg, data());
753
+ throw validationError(`Obsidian Local REST API rejected the request to ${display} as malformed (HTTP 400).`, data(), { cause });
673
754
  }
674
755
  default: {
675
756
  /**
676
- * Unhandled 4xx and all 5xx — route through the framework helper so we
677
- * get the canonical status→code mapping (500/501→InternalError,
678
- * 502/503→ServiceUnavailable, 504→Timeout) and Retry-After capture.
679
- * Body has already been consumed above, so disable the helper's read
680
- * and pass the truncated body in via `data`.
757
+ * Unhandled 4xx and all 5xx. `httpStatusToErrorCode` supplies the same
758
+ * canonical mapping `httpErrorFromResponse` would (500/501 →
759
+ * InternalError, 502/503 → ServiceUnavailable, 504 → Timeout) without
760
+ * that helper's response-derived extras: it builds its message from
761
+ * the upstream's reason phrase and mirrors the body onto
762
+ * `data.body`/`data.responseBody`, which is the #104 leak.
763
+ *
764
+ * `Retry-After` is re-attached by hand: it is a duration, never vault
765
+ * data, and `withRetry` reads `data.retryAfter` to pace its backoff, so
766
+ * dropping it with the rest would quietly change retry timing.
681
767
  */
682
- const truncated = text ? (text.length > 500 ? `${text.slice(0, 500)}…` : text) : undefined;
683
- throw await httpErrorFromResponse(res, {
684
- service: 'Obsidian Local REST API',
685
- captureBody: false,
686
- data: {
687
- ...data(),
688
- ...(truncated !== undefined ? { body: truncated } : {}),
689
- },
690
- });
768
+ const retryAfter = res.headers.get('retry-after');
769
+ throw new McpError(httpStatusToErrorCode(res.status) ?? JsonRpcErrorCode.InternalError, `Obsidian Local REST API returned HTTP ${res.status}.`, {
770
+ ...data(),
771
+ status: res.status,
772
+ ...(retryAfter !== null ? { retryAfter } : {}),
773
+ }, { cause });
691
774
  }
692
775
  }
693
776
  }
@@ -734,6 +817,93 @@ export function encodeVaultPath(path) {
734
817
  }
735
818
  return segments.map((seg) => encodeURIComponent(seg)).join('/');
736
819
  }
820
+ /**
821
+ * Locate the match span inside the `context` window the upstream ships with it.
822
+ *
823
+ * `start`/`end` are offsets into whichever subject the plugin matched, and
824
+ * there are two. For a **body match** the subject is the note text and the
825
+ * window is `body.slice(max(0, start - contextLength), min(len, end + contextLength))`,
826
+ * so the span sits `min(start, contextLength)` characters into `context`. For a
827
+ * **filename match** the subject is the note's basename and the plugin returns
828
+ * that basename whole as `context`, so the span sits at `start` — which runs
829
+ * past `min(start, contextLength)` as soon as the name is longer than the
830
+ * window. A single hit's `matches[]` can carry both kinds. Verified against
831
+ * Local REST API v5.0.3.
832
+ *
833
+ * `context === basename` is the cheap separator, but it is not decisive: a body
834
+ * window whose left edge is trimmed can coincide with the basename (a note whose
835
+ * own name is quoted in its body, matched so the window lands on that quote),
836
+ * and then the two readings disagree and the filename one slices the wrong text
837
+ * — often past the end of `context` entirely. Where they disagree, settle it on
838
+ * the text rather than the coincidence: the plugin matches whole query tokens,
839
+ * so the correct reading reproduces one. An inconclusive check keeps the
840
+ * filename reading, which is what the coincidence test alone would have picked.
841
+ */
842
+ function contextRelativeSpan(m, filename, contextLength, query) {
843
+ const span = m.match.end - m.match.start;
844
+ const bodyStart = Math.min(m.match.start, contextLength);
845
+ const basename = (filename.split('/').pop() ?? filename).replace(/\.[^./]+$/, '');
846
+ const at = (i) => ({ contextStart: i, contextEnd: i + span });
847
+ if (m.context !== basename || m.match.start === bodyStart)
848
+ return at(bodyStart);
849
+ const reproducesToken = (i) => {
850
+ const slice = m.context.slice(i, i + span);
851
+ return slice.length === span && query.toLowerCase().includes(slice.toLowerCase());
852
+ };
853
+ return reproducesToken(m.match.start) || !reproducesToken(bodyStart)
854
+ ? at(m.match.start)
855
+ : at(bodyStart);
856
+ }
857
+ /**
858
+ * The upstream error body, carried as the `cause` of everything
859
+ * `#throwForStatus` throws.
860
+ *
861
+ * `cause` is the one channel that reaches the server's logs without reaching
862
+ * the client, which is what lets the containment invariant hold while the
863
+ * text stays available for debugging and for the classifiers below. The body
864
+ * is the `Error` message so the framework's cause-chain extractor records it.
865
+ */
866
+ class UpstreamErrorText extends Error {
867
+ constructor(text) {
868
+ super(text);
869
+ this.name = 'UpstreamErrorText';
870
+ }
871
+ }
872
+ /**
873
+ * The upstream body behind an error, when `#throwForStatus` raised it. Walks
874
+ * the `cause` chain rather than reading one level: `withRetry` re-wraps an
875
+ * exhausted error, so on a retry-safe method the carrier sits a level deeper
876
+ * than the throw site left it.
877
+ */
878
+ function upstreamTextOf(err) {
879
+ let current = err;
880
+ for (let depth = 0; depth < 4; depth++) {
881
+ if (current instanceof UpstreamErrorText)
882
+ return current.message;
883
+ if (!(current instanceof Error))
884
+ return;
885
+ current = current.cause;
886
+ }
887
+ return;
888
+ }
889
+ /**
890
+ * True for the V8 `RangeError: Invalid string length` the Local REST API
891
+ * surfaces (as an opaque HTTP 500) when it cannot concatenate the response.
892
+ * Read off the `cause` carrier: since the containment invariant on
893
+ * `#throwForStatus`, the upstream text appears on neither the message nor
894
+ * `data`, and this is the only place it survives.
895
+ */
896
+ function isStringCapacityOverflow(err) {
897
+ return /invalid string length/i.test(upstreamTextOf(err) ?? '');
898
+ }
899
+ /** The period segment of a `/periodic/…` request path, for message copy. */
900
+ function periodOf(urlPath) {
901
+ return /^\/periodic\/(daily|weekly|monthly|quarterly|yearly)\//.exec(urlPath)?.[1] ?? 'periodic';
902
+ }
903
+ /** The request path with its query string dropped — the route alone. */
904
+ function routeOf(urlPath) {
905
+ return urlPath.split('?')[0] ?? urlPath;
906
+ }
737
907
  /**
738
908
  * Convert an internal URL path (e.g. `/vault/Projects/My%20Note.md`) to the
739
909
  * vault-relative form a caller would recognize. Used in error messages so the
@@ -742,7 +912,7 @@ export function encodeVaultPath(path) {
742
912
  function displayPath(urlPath) {
743
913
  if (urlPath.startsWith('/active/'))
744
914
  return '(active file)';
745
- const noQuery = urlPath.split('?')[0] ?? urlPath;
915
+ const noQuery = routeOf(urlPath);
746
916
  let decoded;
747
917
  try {
748
918
  decoded = decodeURIComponent(noQuery);
@@ -764,19 +934,6 @@ function displayPath(urlPath) {
764
934
  }
765
935
  return decoded;
766
936
  }
767
- /**
768
- * Trim the upstream error body down to a safe, user-presentable shape — drops
769
- * `errorCode` and any other plugin-internal fields that would otherwise leak
770
- * into JSON-RPC `error.data`.
771
- */
772
- function safeUpstream(body, text) {
773
- if (body?.message)
774
- return { message: body.message };
775
- const trimmed = text.trim();
776
- if (trimmed)
777
- return { message: trimmed.length > 200 ? `${trimmed.slice(0, 200)}…` : trimmed };
778
- return;
779
- }
780
937
  /**
781
938
  * Read the `Content-Length` header from a HEAD response and parse it as a
782
939
  * non-negative integer byte count. Throws when the upstream omits the header