obsidian-mcp-server 3.1.10 → 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.
- package/CLAUDE.md +2 -2
- package/README.md +14 -13
- package/changelog/3.1.x/3.1.11.md +20 -0
- package/changelog/3.2.x/3.2.0.md +49 -0
- package/dist/config/server-config.d.ts +1 -0
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +14 -2
- package/dist/config/server-config.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -10
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/_shared/regex-safety.d.ts +18 -0
- package/dist/mcp-server/tools/definitions/_shared/regex-safety.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/_shared/regex-safety.js +34 -0
- package/dist/mcp-server/tools/definitions/_shared/regex-safety.js.map +1 -0
- package/dist/mcp-server/tools/definitions/_shared/schemas.js +1 -1
- package/dist/mcp-server/tools/definitions/_shared/schemas.js.map +1 -1
- package/dist/mcp-server/tools/definitions/index.d.ts +48 -832
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/index.js +10 -6
- package/dist/mcp-server/tools/definitions/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.d.ts +21 -2
- package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js +59 -6
- package/dist/mcp-server/tools/definitions/obsidian-list-commands.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts +21 -3
- package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js +59 -7
- package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +175 -19
- package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +249 -134
- package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -1
- package/dist/services/obsidian/obsidian-service.d.ts +33 -4
- package/dist/services/obsidian/obsidian-service.d.ts.map +1 -1
- package/dist/services/obsidian/obsidian-service.js +164 -19
- package/dist/services/obsidian/obsidian-service.js.map +1 -1
- package/dist/services/obsidian/path-policy.js +7 -2
- package/dist/services/obsidian/path-policy.js.map +1 -1
- package/dist/services/obsidian/types.d.ts +25 -1
- package/dist/services/obsidian/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/server.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAgBH,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAK/B,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAQhC,CAAC;AAEF,mHAAmH;AACnH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAAiD,CAAC"}
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* when `OBSIDIAN_READ_ONLY=true`. The command-palette pair is exported
|
|
5
5
|
* separately so the entry point wraps it with `disabledTool()` when either
|
|
6
6
|
* `OBSIDIAN_ENABLE_COMMANDS=false` or `OBSIDIAN_READ_ONLY=true` — keeping this
|
|
7
|
-
* module free of eager config reads.
|
|
7
|
+
* module free of eager config reads. `obsidian_search_notes` is exposed as a
|
|
8
|
+
* factory (`buildSearchNotesTool`) because its mode enum is conditional on
|
|
9
|
+
* Omnisearch reachability, which is only known after the startup probe runs.
|
|
8
10
|
* @module mcp-server/tools/definitions/index
|
|
9
11
|
*/
|
|
10
12
|
import { obsidianAppendToNote } from './obsidian-append-to-note.tool.js';
|
|
@@ -19,14 +21,18 @@ import { obsidianManageTags } from './obsidian-manage-tags.tool.js';
|
|
|
19
21
|
import { obsidianOpenInUi } from './obsidian-open-in-ui.tool.js';
|
|
20
22
|
import { obsidianPatchNote } from './obsidian-patch-note.tool.js';
|
|
21
23
|
import { obsidianReplaceInNote } from './obsidian-replace-in-note.tool.js';
|
|
22
|
-
import { obsidianSearchNotes } from './obsidian-search-notes.tool.js';
|
|
23
24
|
import { obsidianWriteNote } from './obsidian-write-note.tool.js';
|
|
24
|
-
|
|
25
|
+
export { buildSearchNotesTool } from './obsidian-search-notes.tool.js';
|
|
26
|
+
/**
|
|
27
|
+
* Read-only tools that don't depend on runtime probes — always registered,
|
|
28
|
+
* even with `OBSIDIAN_READ_ONLY=true`. `obsidian_search_notes` is constructed
|
|
29
|
+
* separately in the entry point via `buildSearchNotesTool` so its mode enum
|
|
30
|
+
* can reflect Omnisearch reachability.
|
|
31
|
+
*/
|
|
25
32
|
export const readToolDefinitions = [
|
|
26
33
|
obsidianGetNote,
|
|
27
34
|
obsidianListNotes,
|
|
28
35
|
obsidianListTags,
|
|
29
|
-
obsidianSearchNotes,
|
|
30
36
|
obsidianOpenInUi,
|
|
31
37
|
];
|
|
32
38
|
/** Write tools — wrapped with `disabledTool()` when `OBSIDIAN_READ_ONLY=true`. */
|
|
@@ -39,8 +45,6 @@ export const writeToolDefinitions = [
|
|
|
39
45
|
obsidianManageTags,
|
|
40
46
|
obsidianDeleteNote,
|
|
41
47
|
];
|
|
42
|
-
/** Combined base set — preserves the previous registration order. */
|
|
43
|
-
export const baseToolDefinitions = [...readToolDefinitions, ...writeToolDefinitions];
|
|
44
48
|
/** Command-palette tools — opt-in via `OBSIDIAN_ENABLE_COMMANDS=true`; suppressed by `OBSIDIAN_READ_ONLY=true`. */
|
|
45
49
|
export const commandToolDefinitions = [obsidianListCommands, obsidianExecuteCommand];
|
|
46
50
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,eAAe;IACf,iBAAiB;IACjB,gBAAgB;IAChB,gBAAgB;CACjB,CAAC;AAEF,kFAAkF;AAClF,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,iBAAiB;IACjB,oBAAoB;IACpB,iBAAiB;IACjB,qBAAqB;IACrB,yBAAyB;IACzB,kBAAkB;IAClB,kBAAkB;CACnB,CAAC;AAEF,mHAAmH;AACnH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,oBAAoB,EAAE,sBAAsB,CAAC,CAAC"}
|
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview obsidian_list_commands — list Obsidian command-palette commands.
|
|
3
3
|
* Gated behind `OBSIDIAN_ENABLE_COMMANDS=true` alongside `obsidian_execute_command`.
|
|
4
|
+
* Optional `nameRegex` post-filters the upstream payload before returning, since
|
|
5
|
+
* vaults with Templater/Dataview/QuickAdd/Excalidraw routinely register 300+
|
|
6
|
+
* commands and the LLM-bound listing is otherwise mostly noise.
|
|
4
7
|
* @module mcp-server/tools/definitions/obsidian-list-commands.tool
|
|
5
8
|
*/
|
|
6
9
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
-
|
|
10
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
11
|
+
export declare const obsidianListCommands: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
12
|
+
nameRegex: z.ZodOptional<z.ZodString>;
|
|
13
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
8
14
|
commands: z.ZodArray<z.ZodObject<{
|
|
9
15
|
id: z.ZodString;
|
|
10
16
|
name: z.ZodString;
|
|
11
17
|
}, z.core.$strip>>;
|
|
12
|
-
|
|
18
|
+
appliedFilters: z.ZodOptional<z.ZodObject<{
|
|
19
|
+
nameRegex: z.ZodOptional<z.ZodString>;
|
|
20
|
+
}, z.core.$strip>>;
|
|
21
|
+
}, z.core.$strip>, readonly [{
|
|
22
|
+
readonly reason: "regex_invalid";
|
|
23
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
24
|
+
readonly when: "The supplied `nameRegex` is not a valid ECMAScript regex.";
|
|
25
|
+
readonly recovery: "Use a valid ECMAScript regex (e.g. `^Templater`), or omit nameRegex to disable filtering.";
|
|
26
|
+
}, {
|
|
27
|
+
readonly reason: "regex_unsafe";
|
|
28
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
29
|
+
readonly when: "The supplied `nameRegex` is well-formed but exceeds the 256-character limit or contains nested quantifiers known to cause catastrophic backtracking.";
|
|
30
|
+
readonly recovery: "Avoid nested quantifiers like `(a+)+` or `(.*)*`. Use a simpler pattern (e.g. `^Templater`), or omit nameRegex to disable filtering.";
|
|
31
|
+
}]>;
|
|
13
32
|
//# sourceMappingURL=obsidian-list-commands.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obsidian-list-commands.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-commands.tool.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"obsidian-list-commands.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-commands.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;GA2F/B,CAAC"}
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview obsidian_list_commands — list Obsidian command-palette commands.
|
|
3
3
|
* Gated behind `OBSIDIAN_ENABLE_COMMANDS=true` alongside `obsidian_execute_command`.
|
|
4
|
+
* Optional `nameRegex` post-filters the upstream payload before returning, since
|
|
5
|
+
* vaults with Templater/Dataview/QuickAdd/Excalidraw routinely register 300+
|
|
6
|
+
* commands and the LLM-bound listing is otherwise mostly noise.
|
|
4
7
|
* @module mcp-server/tools/definitions/obsidian-list-commands.tool
|
|
5
8
|
*/
|
|
6
9
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
10
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
11
|
import { getObsidianService } from '../../../services/obsidian/obsidian-service.js';
|
|
12
|
+
import { nameRegexSafetyIssue } from './_shared/regex-safety.js';
|
|
8
13
|
export const obsidianListCommands = tool('obsidian_list_commands', {
|
|
9
|
-
description: 'List the Obsidian command-palette commands available in the active vault, with their IDs and display names.',
|
|
14
|
+
description: 'List the Obsidian command-palette commands available in the active vault, with their IDs and display names. Filter to a subset with the optional `nameRegex` matched against the display name.',
|
|
10
15
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
11
|
-
input: z.object({
|
|
16
|
+
input: z.object({
|
|
17
|
+
nameRegex: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('Optional ECMAScript regex (no flags, ≤256 chars, no nested quantifiers like `(a+)+`) matched against the command display name (the field agents search by, not the slug-shaped `id`). Use character classes (`[Tt]emplater`) for case-insensitivity.'),
|
|
21
|
+
}),
|
|
12
22
|
output: z.object({
|
|
13
23
|
commands: z
|
|
14
24
|
.array(z
|
|
@@ -18,18 +28,61 @@ export const obsidianListCommands = tool('obsidian_list_commands', {
|
|
|
18
28
|
})
|
|
19
29
|
.describe('An Obsidian command-palette entry.'))
|
|
20
30
|
.describe('All commands registered in the active Obsidian instance.'),
|
|
31
|
+
appliedFilters: z
|
|
32
|
+
.object({
|
|
33
|
+
nameRegex: z.string().optional().describe('nameRegex filter applied to this listing.'),
|
|
34
|
+
})
|
|
35
|
+
.optional()
|
|
36
|
+
.describe('Active filters that produced this listing. Absent when no filter was applied.'),
|
|
21
37
|
}),
|
|
22
38
|
auth: ['tool:obsidian_list_commands:read'],
|
|
23
|
-
|
|
39
|
+
errors: [
|
|
40
|
+
{
|
|
41
|
+
reason: 'regex_invalid',
|
|
42
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
43
|
+
when: 'The supplied `nameRegex` is not a valid ECMAScript regex.',
|
|
44
|
+
recovery: 'Use a valid ECMAScript regex (e.g. `^Templater`), or omit nameRegex to disable filtering.',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
reason: 'regex_unsafe',
|
|
48
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
49
|
+
when: 'The supplied `nameRegex` is well-formed but exceeds the 256-character limit or contains nested quantifiers known to cause catastrophic backtracking.',
|
|
50
|
+
recovery: 'Avoid nested quantifiers like `(a+)+` or `(.*)*`. Use a simpler pattern (e.g. `^Templater`), or omit nameRegex to disable filtering.',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
async handler(input, ctx) {
|
|
54
|
+
let regex;
|
|
55
|
+
if (input.nameRegex) {
|
|
56
|
+
const safetyIssue = nameRegexSafetyIssue(input.nameRegex);
|
|
57
|
+
if (safetyIssue) {
|
|
58
|
+
throw ctx.fail('regex_unsafe', `Unsafe nameRegex: ${safetyIssue}`, {
|
|
59
|
+
nameRegex: input.nameRegex,
|
|
60
|
+
...ctx.recoveryFor('regex_unsafe'),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
regex = new RegExp(input.nameRegex);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
throw ctx.fail('regex_invalid', `Invalid nameRegex: ${err.message}`, { nameRegex: input.nameRegex, ...ctx.recoveryFor('regex_invalid') }, { cause: err });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
24
70
|
const svc = getObsidianService();
|
|
25
71
|
const commands = await svc.listCommands(ctx);
|
|
26
|
-
|
|
72
|
+
const filtered = regex ? commands.filter((c) => regex.test(c.name)) : commands;
|
|
73
|
+
return {
|
|
74
|
+
commands: filtered,
|
|
75
|
+
...(input.nameRegex ? { appliedFilters: { nameRegex: input.nameRegex } } : {}),
|
|
76
|
+
};
|
|
27
77
|
},
|
|
28
78
|
format: (result) => {
|
|
79
|
+
const activeRegex = result.appliedFilters?.nameRegex;
|
|
29
80
|
if (result.commands.length === 0) {
|
|
30
|
-
|
|
81
|
+
const filterNote = activeRegex ? ` matching \`${activeRegex}\`` : '';
|
|
82
|
+
return [{ type: 'text', text: `_No commands available${filterNote}._` }];
|
|
31
83
|
}
|
|
32
|
-
const
|
|
84
|
+
const filterSuffix = activeRegex ? ` · nameRegex=\`${activeRegex}\`` : '';
|
|
85
|
+
const lines = [`**${result.commands.length} commands**${filterSuffix}`, ''];
|
|
33
86
|
for (const c of result.commands)
|
|
34
87
|
lines.push(`- \`${c.id}\` — ${c.name}`);
|
|
35
88
|
return [{ type: 'text', text: lines.join('\n') }];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obsidian-list-commands.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-commands.tool.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"obsidian-list-commands.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-commands.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview obsidian_list_tags — all tags found in the vault, with usage counts.
|
|
3
|
-
* Mirrors the plugin's `/tags/` endpoint; counts are upstream-provided.
|
|
3
|
+
* Mirrors the plugin's `/tags/` endpoint; counts are upstream-provided. Optional
|
|
4
|
+
* `nameRegex` post-filters the upstream payload before returning to keep the
|
|
5
|
+
* LLM-bound response small on vaults with long-tail tag noise.
|
|
4
6
|
* @module mcp-server/tools/definitions/obsidian-list-tags.tool
|
|
5
7
|
*/
|
|
6
8
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
-
|
|
9
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
10
|
+
export declare const obsidianListTags: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
11
|
+
nameRegex: z.ZodOptional<z.ZodString>;
|
|
12
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
8
13
|
tags: z.ZodArray<z.ZodObject<{
|
|
9
14
|
name: z.ZodString;
|
|
10
15
|
count: z.ZodNumber;
|
|
11
16
|
}, z.core.$strip>>;
|
|
12
|
-
|
|
17
|
+
appliedFilters: z.ZodOptional<z.ZodObject<{
|
|
18
|
+
nameRegex: z.ZodOptional<z.ZodString>;
|
|
19
|
+
}, z.core.$strip>>;
|
|
20
|
+
}, z.core.$strip>, readonly [{
|
|
21
|
+
readonly reason: "regex_invalid";
|
|
22
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
23
|
+
readonly when: "The supplied `nameRegex` is not a valid ECMAScript regex.";
|
|
24
|
+
readonly recovery: "Use a valid ECMAScript regex (e.g. `^mcp/.*`), or omit nameRegex to disable filtering.";
|
|
25
|
+
}, {
|
|
26
|
+
readonly reason: "regex_unsafe";
|
|
27
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
28
|
+
readonly when: "The supplied `nameRegex` is well-formed but exceeds the 256-character limit or contains nested quantifiers known to cause catastrophic backtracking.";
|
|
29
|
+
readonly recovery: "Avoid nested quantifiers like `(a+)+` or `(.*)*`. Use a simpler pattern (e.g. `^mcp/.*`), or omit nameRegex to disable filtering.";
|
|
30
|
+
}]>;
|
|
13
31
|
//# sourceMappingURL=obsidian-list-tags.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obsidian-list-tags.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-tags.tool.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"obsidian-list-tags.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-tags.tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;GA2F3B,CAAC"}
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview obsidian_list_tags — all tags found in the vault, with usage counts.
|
|
3
|
-
* Mirrors the plugin's `/tags/` endpoint; counts are upstream-provided.
|
|
3
|
+
* Mirrors the plugin's `/tags/` endpoint; counts are upstream-provided. Optional
|
|
4
|
+
* `nameRegex` post-filters the upstream payload before returning to keep the
|
|
5
|
+
* LLM-bound response small on vaults with long-tail tag noise.
|
|
4
6
|
* @module mcp-server/tools/definitions/obsidian-list-tags.tool
|
|
5
7
|
*/
|
|
6
8
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
9
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
10
|
import { getObsidianService } from '../../../services/obsidian/obsidian-service.js';
|
|
11
|
+
import { nameRegexSafetyIssue } from './_shared/regex-safety.js';
|
|
8
12
|
export const obsidianListTags = tool('obsidian_list_tags', {
|
|
9
|
-
description: 'List every tag found across the vault, with usage counts. Includes hierarchical parents — `work/tasks` contributes to both `work` and `work/tasks`. To find notes by tag, use `obsidian_search_notes` in
|
|
13
|
+
description: 'List every tag found across the vault, with usage counts. Includes hierarchical parents — `work/tasks` contributes to both `work` and `work/tasks`. Filter to a subset with the optional `nameRegex`. To find notes by tag, use `obsidian_search_notes` in jsonlogic mode (e.g. `{"in": ["work", {"var": "tags"}]}`).',
|
|
10
14
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
11
|
-
input: z.object({
|
|
15
|
+
input: z.object({
|
|
16
|
+
nameRegex: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Optional ECMAScript regex (no flags, ≤256 chars, no nested quantifiers like `(a+)+`) matched against the bare tag name (no leading `#`). Hierarchical tags like `work/tasks` are matched as the full string. Use character classes (`[Mm]cp`) for case-insensitivity.'),
|
|
20
|
+
}),
|
|
12
21
|
output: z.object({
|
|
13
22
|
tags: z
|
|
14
23
|
.array(z
|
|
@@ -18,18 +27,61 @@ export const obsidianListTags = tool('obsidian_list_tags', {
|
|
|
18
27
|
})
|
|
19
28
|
.describe('A tag with its usage count.'))
|
|
20
29
|
.describe('All tags in the vault, in upstream-provided order.'),
|
|
30
|
+
appliedFilters: z
|
|
31
|
+
.object({
|
|
32
|
+
nameRegex: z.string().optional().describe('nameRegex filter applied to this listing.'),
|
|
33
|
+
})
|
|
34
|
+
.optional()
|
|
35
|
+
.describe('Active filters that produced this listing. Absent when no filter was applied.'),
|
|
21
36
|
}),
|
|
22
37
|
auth: ['tool:obsidian_list_tags:read'],
|
|
23
|
-
|
|
38
|
+
errors: [
|
|
39
|
+
{
|
|
40
|
+
reason: 'regex_invalid',
|
|
41
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
42
|
+
when: 'The supplied `nameRegex` is not a valid ECMAScript regex.',
|
|
43
|
+
recovery: 'Use a valid ECMAScript regex (e.g. `^mcp/.*`), or omit nameRegex to disable filtering.',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
reason: 'regex_unsafe',
|
|
47
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
48
|
+
when: 'The supplied `nameRegex` is well-formed but exceeds the 256-character limit or contains nested quantifiers known to cause catastrophic backtracking.',
|
|
49
|
+
recovery: 'Avoid nested quantifiers like `(a+)+` or `(.*)*`. Use a simpler pattern (e.g. `^mcp/.*`), or omit nameRegex to disable filtering.',
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
async handler(input, ctx) {
|
|
53
|
+
let regex;
|
|
54
|
+
if (input.nameRegex) {
|
|
55
|
+
const safetyIssue = nameRegexSafetyIssue(input.nameRegex);
|
|
56
|
+
if (safetyIssue) {
|
|
57
|
+
throw ctx.fail('regex_unsafe', `Unsafe nameRegex: ${safetyIssue}`, {
|
|
58
|
+
nameRegex: input.nameRegex,
|
|
59
|
+
...ctx.recoveryFor('regex_unsafe'),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
regex = new RegExp(input.nameRegex);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
throw ctx.fail('regex_invalid', `Invalid nameRegex: ${err.message}`, { nameRegex: input.nameRegex, ...ctx.recoveryFor('regex_invalid') }, { cause: err });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
24
69
|
const svc = getObsidianService();
|
|
25
70
|
const tags = await svc.listTags(ctx);
|
|
26
|
-
|
|
71
|
+
const filtered = regex ? tags.filter((t) => regex.test(t.name)) : tags;
|
|
72
|
+
return {
|
|
73
|
+
tags: filtered.map((t) => ({ name: t.name, count: t.count })),
|
|
74
|
+
...(input.nameRegex ? { appliedFilters: { nameRegex: input.nameRegex } } : {}),
|
|
75
|
+
};
|
|
27
76
|
},
|
|
28
77
|
format: (result) => {
|
|
78
|
+
const activeRegex = result.appliedFilters?.nameRegex;
|
|
29
79
|
if (result.tags.length === 0) {
|
|
30
|
-
|
|
80
|
+
const filterNote = activeRegex ? ` matching \`${activeRegex}\`` : '';
|
|
81
|
+
return [{ type: 'text', text: `_No tags found${filterNote}._` }];
|
|
31
82
|
}
|
|
32
|
-
const
|
|
83
|
+
const filterSuffix = activeRegex ? ` · nameRegex=\`${activeRegex}\`` : '';
|
|
84
|
+
const lines = [`**${result.tags.length} tags**${filterSuffix}`, ''];
|
|
33
85
|
for (const t of result.tags)
|
|
34
86
|
lines.push(`- \`#${t.name}\` (${t.count})`);
|
|
35
87
|
return [{ type: 'text', text: lines.join('\n') }];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obsidian-list-tags.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-tags.tool.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"obsidian-list-tags.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-list-tags.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview obsidian_search_notes — text/
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* response budget — clipped hits
|
|
2
|
+
* @fileoverview obsidian_search_notes — text/jsonlogic/omnisearch search with
|
|
3
|
+
* MCP-spec cursor pagination. The `omnisearch` mode is added conditionally by
|
|
4
|
+
* the entry point only when the Omnisearch plugin's HTTP server is reachable
|
|
5
|
+
* at startup. Text-mode hits additionally clip per file via `maxMatchesPerHit`
|
|
6
|
+
* so a single match-heavy note can't blow the response budget — clipped hits
|
|
7
|
+
* carry `truncated: true` and `totalMatches`.
|
|
7
8
|
* @module mcp-server/tools/definitions/obsidian-search-notes.tool
|
|
8
9
|
*/
|
|
9
10
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
10
11
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
11
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Build the `obsidian_search_notes` tool. The `omnisearch` mode is included
|
|
14
|
+
* in the input/output schemas only when `omnisearchReachable` is true so the
|
|
15
|
+
* LLM never sees it as an option on a deployment where it can't run. Re-probe
|
|
16
|
+
* requires a server restart.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildSearchNotesTool({ omnisearchReachable }: {
|
|
19
|
+
omnisearchReachable: boolean;
|
|
20
|
+
}): import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
12
21
|
mode: z.ZodEnum<{
|
|
13
22
|
text: "text";
|
|
14
|
-
dataview: "dataview";
|
|
15
23
|
jsonlogic: "jsonlogic";
|
|
24
|
+
omnisearch: "omnisearch";
|
|
16
25
|
}>;
|
|
17
26
|
query: z.ZodOptional<z.ZodString>;
|
|
18
27
|
logic: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
19
28
|
contextLength: z.ZodDefault<z.ZodNumber>;
|
|
20
29
|
pathPrefix: z.ZodOptional<z.ZodString>;
|
|
21
30
|
maxMatchesPerHit: z.ZodDefault<z.ZodNumber>;
|
|
31
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
22
32
|
}, z.core.$strip>, z.ZodObject<{
|
|
23
33
|
result: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
24
34
|
mode: z.ZodLiteral<"text">;
|
|
@@ -35,30 +45,170 @@ export declare const obsidianSearchNotes: import("@cyanheads/mcp-ts-core").ToolD
|
|
|
35
45
|
totalMatches: z.ZodOptional<z.ZodNumber>;
|
|
36
46
|
truncated: z.ZodOptional<z.ZodBoolean>;
|
|
37
47
|
}, z.core.$strip>>;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
48
|
+
totalCount: z.ZodNumber;
|
|
49
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
50
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
51
|
+
mode: z.ZodLiteral<"jsonlogic">;
|
|
52
|
+
hits: z.ZodArray<z.ZodObject<{
|
|
53
|
+
filename: z.ZodString;
|
|
54
|
+
result: z.ZodUnknown;
|
|
41
55
|
}, z.core.$strip>>;
|
|
56
|
+
totalCount: z.ZodNumber;
|
|
57
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
42
58
|
}, z.core.$strip>, z.ZodObject<{
|
|
43
|
-
mode: z.ZodLiteral<"
|
|
59
|
+
mode: z.ZodLiteral<"omnisearch">;
|
|
60
|
+
hits: z.ZodArray<z.ZodObject<{
|
|
61
|
+
filename: z.ZodString;
|
|
62
|
+
basename: z.ZodString;
|
|
63
|
+
score: z.ZodNumber;
|
|
64
|
+
foundWords: z.ZodArray<z.ZodString>;
|
|
65
|
+
matches: z.ZodArray<z.ZodObject<{
|
|
66
|
+
match: z.ZodString;
|
|
67
|
+
offset: z.ZodNumber;
|
|
68
|
+
}, z.core.$strip>>;
|
|
69
|
+
excerpt: z.ZodString;
|
|
70
|
+
}, z.core.$strip>>;
|
|
71
|
+
totalCount: z.ZodNumber;
|
|
72
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
73
|
+
truncated: z.ZodBoolean;
|
|
74
|
+
}, z.core.$strip>] | [z.ZodObject<{
|
|
75
|
+
mode: z.ZodLiteral<"text">;
|
|
76
|
+
hits: z.ZodArray<z.ZodObject<{
|
|
77
|
+
filename: z.ZodString;
|
|
78
|
+
score: z.ZodOptional<z.ZodNumber>;
|
|
79
|
+
matches: z.ZodArray<z.ZodObject<{
|
|
80
|
+
context: z.ZodString;
|
|
81
|
+
match: z.ZodObject<{
|
|
82
|
+
start: z.ZodNumber;
|
|
83
|
+
end: z.ZodNumber;
|
|
84
|
+
}, z.core.$strip>;
|
|
85
|
+
}, z.core.$strip>>;
|
|
86
|
+
totalMatches: z.ZodOptional<z.ZodNumber>;
|
|
87
|
+
truncated: z.ZodOptional<z.ZodBoolean>;
|
|
88
|
+
}, z.core.$strip>>;
|
|
89
|
+
totalCount: z.ZodNumber;
|
|
90
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
91
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
92
|
+
mode: z.ZodLiteral<"jsonlogic">;
|
|
44
93
|
hits: z.ZodArray<z.ZodObject<{
|
|
45
94
|
filename: z.ZodString;
|
|
46
95
|
result: z.ZodUnknown;
|
|
47
96
|
}, z.core.$strip>>;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
97
|
+
totalCount: z.ZodNumber;
|
|
98
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
99
|
+
}, z.core.$strip>], "mode">;
|
|
100
|
+
}, z.core.$strip>, readonly [{
|
|
101
|
+
readonly reason: "path_prefix_invalid_mode";
|
|
102
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
103
|
+
readonly when: "`pathPrefix` was provided in a non-text mode (only `text` supports prefix filtering).";
|
|
104
|
+
readonly recovery: "Drop pathPrefix or switch mode to text for prefix filtering.";
|
|
105
|
+
}, {
|
|
106
|
+
readonly reason: "query_required";
|
|
107
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
108
|
+
readonly when: "`query` is missing for `text` or `omnisearch` mode (required for both).";
|
|
109
|
+
readonly recovery: "Pass `query` — substring for text mode, or BM25 query syntax (quoted phrases, `-exclusion`, `path:` / `ext:` filters) for omnisearch.";
|
|
110
|
+
}, {
|
|
111
|
+
readonly reason: "logic_required";
|
|
112
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
113
|
+
readonly when: "`logic` is missing for `jsonlogic` mode.";
|
|
114
|
+
readonly recovery: "Pass a JSONLogic tree as `logic`, e.g. `{\"glob\": [{\"var\": \"path\"}, \"Projects/*.md\"]}`.";
|
|
115
|
+
}, {
|
|
116
|
+
readonly reason: "omnisearch_unreachable";
|
|
117
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
118
|
+
readonly when: "Omnisearch was reachable at startup but is now unreachable (Obsidian quit, plugin disabled, or mobile session).";
|
|
119
|
+
readonly retryable: true;
|
|
120
|
+
readonly recovery: "Restart Obsidian with the Omnisearch plugin enabled, then restart this MCP server so it re-probes the plugin URL.";
|
|
121
|
+
}]>;
|
|
122
|
+
/**
|
|
123
|
+
* Static specimen for the MCP definition linter (which duck-types tool
|
|
124
|
+
* exports out of each `.tool.ts` file) and for existing tests that import
|
|
125
|
+
* the tool directly. Defaults to `omnisearchReachable: false` — the safe
|
|
126
|
+
* baseline that doesn't assume the optional plugin is installed. The entry
|
|
127
|
+
* point (`src/index.ts`) builds the live tool via `buildSearchNotesTool`
|
|
128
|
+
* with the actual probe result; this export is not the registered tool.
|
|
129
|
+
* The omnisearch-enabled variant is exercised by tests rather than the
|
|
130
|
+
* linter (two exports under the same tool name would collide on
|
|
131
|
+
* `name-unique`).
|
|
132
|
+
*/
|
|
133
|
+
export declare const obsidianSearchNotes: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
134
|
+
mode: z.ZodEnum<{
|
|
135
|
+
text: "text";
|
|
136
|
+
jsonlogic: "jsonlogic";
|
|
137
|
+
omnisearch: "omnisearch";
|
|
138
|
+
}>;
|
|
139
|
+
query: z.ZodOptional<z.ZodString>;
|
|
140
|
+
logic: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
141
|
+
contextLength: z.ZodDefault<z.ZodNumber>;
|
|
142
|
+
pathPrefix: z.ZodOptional<z.ZodString>;
|
|
143
|
+
maxMatchesPerHit: z.ZodDefault<z.ZodNumber>;
|
|
144
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
145
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
146
|
+
result: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
147
|
+
mode: z.ZodLiteral<"text">;
|
|
148
|
+
hits: z.ZodArray<z.ZodObject<{
|
|
149
|
+
filename: z.ZodString;
|
|
150
|
+
score: z.ZodOptional<z.ZodNumber>;
|
|
151
|
+
matches: z.ZodArray<z.ZodObject<{
|
|
152
|
+
context: z.ZodString;
|
|
153
|
+
match: z.ZodObject<{
|
|
154
|
+
start: z.ZodNumber;
|
|
155
|
+
end: z.ZodNumber;
|
|
156
|
+
}, z.core.$strip>;
|
|
157
|
+
}, z.core.$strip>>;
|
|
158
|
+
totalMatches: z.ZodOptional<z.ZodNumber>;
|
|
159
|
+
truncated: z.ZodOptional<z.ZodBoolean>;
|
|
51
160
|
}, z.core.$strip>>;
|
|
161
|
+
totalCount: z.ZodNumber;
|
|
162
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
52
163
|
}, z.core.$strip>, z.ZodObject<{
|
|
53
164
|
mode: z.ZodLiteral<"jsonlogic">;
|
|
54
165
|
hits: z.ZodArray<z.ZodObject<{
|
|
55
166
|
filename: z.ZodString;
|
|
56
167
|
result: z.ZodUnknown;
|
|
57
168
|
}, z.core.$strip>>;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
169
|
+
totalCount: z.ZodNumber;
|
|
170
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
171
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
172
|
+
mode: z.ZodLiteral<"omnisearch">;
|
|
173
|
+
hits: z.ZodArray<z.ZodObject<{
|
|
174
|
+
filename: z.ZodString;
|
|
175
|
+
basename: z.ZodString;
|
|
176
|
+
score: z.ZodNumber;
|
|
177
|
+
foundWords: z.ZodArray<z.ZodString>;
|
|
178
|
+
matches: z.ZodArray<z.ZodObject<{
|
|
179
|
+
match: z.ZodString;
|
|
180
|
+
offset: z.ZodNumber;
|
|
181
|
+
}, z.core.$strip>>;
|
|
182
|
+
excerpt: z.ZodString;
|
|
183
|
+
}, z.core.$strip>>;
|
|
184
|
+
totalCount: z.ZodNumber;
|
|
185
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
186
|
+
truncated: z.ZodBoolean;
|
|
187
|
+
}, z.core.$strip>] | [z.ZodObject<{
|
|
188
|
+
mode: z.ZodLiteral<"text">;
|
|
189
|
+
hits: z.ZodArray<z.ZodObject<{
|
|
190
|
+
filename: z.ZodString;
|
|
191
|
+
score: z.ZodOptional<z.ZodNumber>;
|
|
192
|
+
matches: z.ZodArray<z.ZodObject<{
|
|
193
|
+
context: z.ZodString;
|
|
194
|
+
match: z.ZodObject<{
|
|
195
|
+
start: z.ZodNumber;
|
|
196
|
+
end: z.ZodNumber;
|
|
197
|
+
}, z.core.$strip>;
|
|
198
|
+
}, z.core.$strip>>;
|
|
199
|
+
totalMatches: z.ZodOptional<z.ZodNumber>;
|
|
200
|
+
truncated: z.ZodOptional<z.ZodBoolean>;
|
|
201
|
+
}, z.core.$strip>>;
|
|
202
|
+
totalCount: z.ZodNumber;
|
|
203
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
204
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
205
|
+
mode: z.ZodLiteral<"jsonlogic">;
|
|
206
|
+
hits: z.ZodArray<z.ZodObject<{
|
|
207
|
+
filename: z.ZodString;
|
|
208
|
+
result: z.ZodUnknown;
|
|
61
209
|
}, z.core.$strip>>;
|
|
210
|
+
totalCount: z.ZodNumber;
|
|
211
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
62
212
|
}, z.core.$strip>], "mode">;
|
|
63
213
|
}, z.core.$strip>, readonly [{
|
|
64
214
|
readonly reason: "path_prefix_invalid_mode";
|
|
@@ -68,12 +218,18 @@ export declare const obsidianSearchNotes: import("@cyanheads/mcp-ts-core").ToolD
|
|
|
68
218
|
}, {
|
|
69
219
|
readonly reason: "query_required";
|
|
70
220
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
71
|
-
readonly when: "`query` is missing for `text` or `
|
|
72
|
-
readonly recovery: "Pass `query` —
|
|
221
|
+
readonly when: "`query` is missing for `text` or `omnisearch` mode (required for both).";
|
|
222
|
+
readonly recovery: "Pass `query` — substring for text mode, or BM25 query syntax (quoted phrases, `-exclusion`, `path:` / `ext:` filters) for omnisearch.";
|
|
73
223
|
}, {
|
|
74
224
|
readonly reason: "logic_required";
|
|
75
225
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
76
226
|
readonly when: "`logic` is missing for `jsonlogic` mode.";
|
|
77
227
|
readonly recovery: "Pass a JSONLogic tree as `logic`, e.g. `{\"glob\": [{\"var\": \"path\"}, \"Projects/*.md\"]}`.";
|
|
228
|
+
}, {
|
|
229
|
+
readonly reason: "omnisearch_unreachable";
|
|
230
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
231
|
+
readonly when: "Omnisearch was reachable at startup but is now unreachable (Obsidian quit, plugin disabled, or mobile session).";
|
|
232
|
+
readonly retryable: true;
|
|
233
|
+
readonly recovery: "Restart Obsidian with the Omnisearch plugin enabled, then restart this MCP server so it re-probes the plugin URL.";
|
|
78
234
|
}]>;
|
|
79
235
|
//# sourceMappingURL=obsidian-search-notes.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obsidian-search-notes.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-search-notes.tool.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"obsidian-search-notes.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-search-notes.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAsB,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAuFjE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,EAAE;IAAE,mBAAmB,EAAE,OAAO,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAkR7F;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAuD,CAAC"}
|