obsidian-mcp-server 3.1.0 → 3.1.2
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 +24 -9
- package/README.md +28 -1
- package/changelog/3.1.x/3.1.1.md +21 -0
- package/changelog/3.1.x/3.1.2.md +23 -0
- package/dist/config/server-config.d.ts +5 -2
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +73 -0
- package/dist/config/server-config.js.map +1 -1
- package/dist/index.js +39 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/index.d.ts +793 -10
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/index.js +15 -9
- package/dist/mcp-server/tools/definitions/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts +7 -1
- package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js +9 -0
- package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts +14 -0
- package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js +20 -1
- package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.js +1 -0
- package/dist/mcp-server/tools/definitions/obsidian-execute-command.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts +14 -0
- package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js +17 -0
- package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts +7 -0
- package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js +18 -3
- package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts +14 -0
- package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js +17 -0
- package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts +14 -0
- package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js +17 -1
- package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts +6 -0
- package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js +14 -4
- package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts +16 -2
- package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js +16 -0
- package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts +14 -0
- package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js +17 -1
- package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +3 -0
- 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 +21 -4
- package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts +6 -0
- package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js +13 -1
- package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js.map +1 -1
- package/dist/services/obsidian/obsidian-service.d.ts +7 -0
- package/dist/services/obsidian/obsidian-service.d.ts.map +1 -1
- package/dist/services/obsidian/obsidian-service.js +132 -28
- package/dist/services/obsidian/obsidian-service.js.map +1 -1
- package/dist/services/obsidian/path-policy.d.ts +56 -0
- package/dist/services/obsidian/path-policy.d.ts.map +1 -0
- package/dist/services/obsidian/path-policy.js +154 -0
- package/dist/services/obsidian/path-policy.js.map +1 -0
- package/package.json +7 -8
- package/server.json +41 -3
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Path-policy enforcement for the Obsidian Local REST API service.
|
|
3
|
+
* Single chokepoint for OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS / OBSIDIAN_READ_ONLY —
|
|
4
|
+
* tools and resources call into the service, the service consults this policy
|
|
5
|
+
* before every upstream HTTP call. See issue #40 for the spec.
|
|
6
|
+
*
|
|
7
|
+
* The policy carries the active scope so error data echoes back which paths
|
|
8
|
+
* are allowed; the LLM (or operator) can self-correct without poking at logs.
|
|
9
|
+
*
|
|
10
|
+
* @module services/obsidian/path-policy
|
|
11
|
+
*/
|
|
12
|
+
import type { ServerConfig } from '../../config/server-config.js';
|
|
13
|
+
export type PathOp = 'read' | 'write';
|
|
14
|
+
export type PathForbiddenSubreason = 'outside_read_paths' | 'outside_write_paths' | 'read_only_mode';
|
|
15
|
+
/** Wire data shape thrown with `path_forbidden`. */
|
|
16
|
+
export interface PathForbiddenData {
|
|
17
|
+
activeScope: string[];
|
|
18
|
+
op: PathOp;
|
|
19
|
+
path: string;
|
|
20
|
+
reason: 'path_forbidden';
|
|
21
|
+
recovery: {
|
|
22
|
+
hint: string;
|
|
23
|
+
};
|
|
24
|
+
subreason: PathForbiddenSubreason;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Enforces folder-scoped read/write permissions on vault-relative paths.
|
|
28
|
+
* Constructed once from validated `ServerConfig`; read paths and write paths
|
|
29
|
+
* arrive already lower-cased, trimmed of trailing slashes, and deduplicated by
|
|
30
|
+
* the config parser, so matching is a straight prefix-or-equal compare.
|
|
31
|
+
*/
|
|
32
|
+
export declare class PathPolicy {
|
|
33
|
+
#private;
|
|
34
|
+
constructor(config: ServerConfig);
|
|
35
|
+
/** True when no path policy is active — every op falls through to the upstream. */
|
|
36
|
+
get isUnrestricted(): boolean;
|
|
37
|
+
/** Snapshot for startup-banner logging. */
|
|
38
|
+
describe(): {
|
|
39
|
+
readPaths: readonly string[] | 'full vault';
|
|
40
|
+
writePaths: readonly string[] | 'full vault' | 'denied (read-only)';
|
|
41
|
+
readOnly: boolean;
|
|
42
|
+
};
|
|
43
|
+
/** True when both READ_ONLY=true and WRITE_PATHS is non-empty (operator should know WRITE_PATHS is ignored). */
|
|
44
|
+
get readOnlyShadowsWritePaths(): boolean;
|
|
45
|
+
isReadable(path: string): boolean;
|
|
46
|
+
isWritable(path: string): boolean;
|
|
47
|
+
/** Throws `path_forbidden` if the path is not readable. */
|
|
48
|
+
assertReadable(path: string): void;
|
|
49
|
+
/** Throws `path_forbidden` if the path is not writable (write tools also implicitly need read access). */
|
|
50
|
+
assertWritable(path: string): void;
|
|
51
|
+
/** Drop reads outside scope. Used by `obsidian_search_notes` to silently filter. */
|
|
52
|
+
filterReadable<T extends {
|
|
53
|
+
filename: string;
|
|
54
|
+
}>(hits: readonly T[]): T[];
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=path-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-policy.d.ts","sourceRoot":"","sources":["../../../src/services/obsidian/path-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtC,MAAM,MAAM,sBAAsB,GAC9B,oBAAoB,GACpB,qBAAqB,GACrB,gBAAgB,CAAC;AAErB,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3B,SAAS,EAAE,sBAAsB,CAAC;CACnC;AAED;;;;;GAKG;AACH,qBAAa,UAAU;;gBAKT,MAAM,EAAE,YAAY;IAMhC,mFAAmF;IACnF,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,2CAA2C;IAC3C,QAAQ,IAAI;QACV,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,CAAC;QAC5C,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,GAAG,oBAAoB,CAAC;QACpE,QAAQ,EAAE,OAAO,CAAC;KACnB;IAQD,gHAAgH;IAChH,IAAI,yBAAyB,IAAI,OAAO,CAEvC;IAED,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAejC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAOjC,2DAA2D;IAC3D,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKlC,0GAA0G;IAC1G,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQlC,oFAAoF;IACpF,cAAc,CAAC,CAAC,SAAS;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE;CA8BxE"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Path-policy enforcement for the Obsidian Local REST API service.
|
|
3
|
+
* Single chokepoint for OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS / OBSIDIAN_READ_ONLY —
|
|
4
|
+
* tools and resources call into the service, the service consults this policy
|
|
5
|
+
* before every upstream HTTP call. See issue #40 for the spec.
|
|
6
|
+
*
|
|
7
|
+
* The policy carries the active scope so error data echoes back which paths
|
|
8
|
+
* are allowed; the LLM (or operator) can self-correct without poking at logs.
|
|
9
|
+
*
|
|
10
|
+
* @module services/obsidian/path-policy
|
|
11
|
+
*/
|
|
12
|
+
import { forbidden } from '@cyanheads/mcp-ts-core/errors';
|
|
13
|
+
/**
|
|
14
|
+
* Enforces folder-scoped read/write permissions on vault-relative paths.
|
|
15
|
+
* Constructed once from validated `ServerConfig`; read paths and write paths
|
|
16
|
+
* arrive already lower-cased, trimmed of trailing slashes, and deduplicated by
|
|
17
|
+
* the config parser, so matching is a straight prefix-or-equal compare.
|
|
18
|
+
*/
|
|
19
|
+
export class PathPolicy {
|
|
20
|
+
#readPaths;
|
|
21
|
+
#writePaths;
|
|
22
|
+
#readOnly;
|
|
23
|
+
constructor(config) {
|
|
24
|
+
this.#readPaths = config.readPaths;
|
|
25
|
+
this.#writePaths = config.writePaths;
|
|
26
|
+
this.#readOnly = config.readOnly;
|
|
27
|
+
}
|
|
28
|
+
/** True when no path policy is active — every op falls through to the upstream. */
|
|
29
|
+
get isUnrestricted() {
|
|
30
|
+
return !this.#readOnly && this.#readPaths === undefined && this.#writePaths === undefined;
|
|
31
|
+
}
|
|
32
|
+
/** Snapshot for startup-banner logging. */
|
|
33
|
+
describe() {
|
|
34
|
+
return {
|
|
35
|
+
readPaths: this.#readPaths ?? 'full vault',
|
|
36
|
+
writePaths: this.#readOnly ? 'denied (read-only)' : (this.#writePaths ?? 'full vault'),
|
|
37
|
+
readOnly: this.#readOnly,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** True when both READ_ONLY=true and WRITE_PATHS is non-empty (operator should know WRITE_PATHS is ignored). */
|
|
41
|
+
get readOnlyShadowsWritePaths() {
|
|
42
|
+
return this.#readOnly && this.#writePaths !== undefined && this.#writePaths.length > 0;
|
|
43
|
+
}
|
|
44
|
+
isReadable(path) {
|
|
45
|
+
const candidate = normalize(path);
|
|
46
|
+
if (this.#readPaths === undefined)
|
|
47
|
+
return true;
|
|
48
|
+
if (matchesAny(candidate, this.#readPaths))
|
|
49
|
+
return true;
|
|
50
|
+
/** Write paths are implicitly readable — you can't sanely edit what you can't see. */
|
|
51
|
+
if (!this.#readOnly &&
|
|
52
|
+
this.#writePaths !== undefined &&
|
|
53
|
+
matchesAny(candidate, this.#writePaths)) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
isWritable(path) {
|
|
59
|
+
if (this.#readOnly)
|
|
60
|
+
return false;
|
|
61
|
+
const candidate = normalize(path);
|
|
62
|
+
if (this.#writePaths === undefined)
|
|
63
|
+
return true;
|
|
64
|
+
return matchesAny(candidate, this.#writePaths);
|
|
65
|
+
}
|
|
66
|
+
/** Throws `path_forbidden` if the path is not readable. */
|
|
67
|
+
assertReadable(path) {
|
|
68
|
+
if (this.isReadable(path))
|
|
69
|
+
return;
|
|
70
|
+
throw this.#deny(path, 'read', 'outside_read_paths');
|
|
71
|
+
}
|
|
72
|
+
/** Throws `path_forbidden` if the path is not writable (write tools also implicitly need read access). */
|
|
73
|
+
assertWritable(path) {
|
|
74
|
+
if (this.#readOnly) {
|
|
75
|
+
throw this.#deny(path, 'write', 'read_only_mode');
|
|
76
|
+
}
|
|
77
|
+
if (this.isWritable(path))
|
|
78
|
+
return;
|
|
79
|
+
throw this.#deny(path, 'write', 'outside_write_paths');
|
|
80
|
+
}
|
|
81
|
+
/** Drop reads outside scope. Used by `obsidian_search_notes` to silently filter. */
|
|
82
|
+
filterReadable(hits) {
|
|
83
|
+
/** Reads unrestricted when readPaths is unset — `isReadable` short-circuits to true. */
|
|
84
|
+
if (this.#readPaths === undefined)
|
|
85
|
+
return [...hits];
|
|
86
|
+
return hits.filter((h) => this.isReadable(h.filename));
|
|
87
|
+
}
|
|
88
|
+
#deny(path, op, subreason) {
|
|
89
|
+
const activeScope = this.#scopeFor(op);
|
|
90
|
+
const { message, recovery } = renderDenial(path, op, subreason, activeScope);
|
|
91
|
+
const data = {
|
|
92
|
+
reason: 'path_forbidden',
|
|
93
|
+
path,
|
|
94
|
+
op,
|
|
95
|
+
subreason,
|
|
96
|
+
activeScope,
|
|
97
|
+
recovery: { hint: recovery },
|
|
98
|
+
};
|
|
99
|
+
return forbidden(message, { ...data });
|
|
100
|
+
}
|
|
101
|
+
#scopeFor(op) {
|
|
102
|
+
if (op === 'write') {
|
|
103
|
+
if (this.#readOnly)
|
|
104
|
+
return [];
|
|
105
|
+
return [...(this.#writePaths ?? [])];
|
|
106
|
+
}
|
|
107
|
+
const set = new Set();
|
|
108
|
+
if (this.#readPaths)
|
|
109
|
+
for (const p of this.#readPaths)
|
|
110
|
+
set.add(p);
|
|
111
|
+
if (!this.#readOnly && this.#writePaths)
|
|
112
|
+
for (const p of this.#writePaths)
|
|
113
|
+
set.add(p);
|
|
114
|
+
return [...set];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function normalize(path) {
|
|
118
|
+
/**
|
|
119
|
+
* Match the parser's normalization rules so the candidate compares apples to
|
|
120
|
+
* apples against the configured prefixes.
|
|
121
|
+
*/
|
|
122
|
+
return path.replace(/^[\\/]+|[\\/]+$/g, '').toLowerCase();
|
|
123
|
+
}
|
|
124
|
+
function matchesAny(candidate, prefixes) {
|
|
125
|
+
for (const prefix of prefixes) {
|
|
126
|
+
if (candidate === prefix)
|
|
127
|
+
return true;
|
|
128
|
+
/** Prefix match only at a path boundary so `pub` doesn't match `public/`. */
|
|
129
|
+
if (candidate.startsWith(`${prefix}/`))
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Split into `message` (the "what") and `recovery` (the "how to fix"). The
|
|
136
|
+
* framework renders both in `content[]` as `Error: <message>` then
|
|
137
|
+
* `Recovery: <recovery>`, so they need to carry distinct information.
|
|
138
|
+
*/
|
|
139
|
+
function renderDenial(path, op, subreason, activeScope) {
|
|
140
|
+
if (subreason === 'read_only_mode') {
|
|
141
|
+
return {
|
|
142
|
+
message: `Path '${path}' is not writable: server is in read-only mode (OBSIDIAN_READ_ONLY=true).`,
|
|
143
|
+
recovery: 'Unset OBSIDIAN_READ_ONLY (or set it to false) to enable writes.',
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const envVar = subreason === 'outside_write_paths' ? 'OBSIDIAN_WRITE_PATHS' : 'OBSIDIAN_READ_PATHS';
|
|
147
|
+
const opLabel = op === 'write' ? 'writable' : 'readable';
|
|
148
|
+
const scopeRender = activeScope.length > 0 ? activeScope.map((p) => `'${p}'`).join(', ') : '(empty)';
|
|
149
|
+
return {
|
|
150
|
+
message: `Path '${path}' is not ${opLabel}: outside ${envVar}.`,
|
|
151
|
+
recovery: `Allowed prefixes: [${scopeRender}]. Use a path within scope, or update ${envVar} to include this path.`,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=path-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-policy.js","sourceRoot":"","sources":["../../../src/services/obsidian/path-policy.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "obsidian-mcp-server",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.2",
|
|
4
4
|
"mcpName": "io.github.cyanheads/obsidian-mcp-server",
|
|
5
5
|
"description": "MCP server for Obsidian vaults — read, write, search, and surgically edit notes, tags, and frontmatter via the Local REST API plugin. STDIO or Streamable HTTP.",
|
|
6
6
|
"type": "module",
|
|
@@ -29,11 +29,10 @@
|
|
|
29
29
|
"changelog:build": "bun run scripts/build-changelog.ts",
|
|
30
30
|
"changelog:check": "bun run scripts/build-changelog.ts --check",
|
|
31
31
|
"test": "bunx vitest run",
|
|
32
|
-
"dev:stdio": "MCP_TRANSPORT_TYPE=stdio bun --watch src/index.ts",
|
|
33
|
-
"dev:http": "MCP_TRANSPORT_TYPE=http bun --watch src/index.ts",
|
|
34
32
|
"start": "node dist/index.js",
|
|
35
33
|
"start:stdio": "MCP_TRANSPORT_TYPE=stdio bun ./dist/index.js",
|
|
36
|
-
"start:http": "MCP_TRANSPORT_TYPE=http bun ./dist/index.js"
|
|
34
|
+
"start:http": "MCP_TRANSPORT_TYPE=http bun ./dist/index.js",
|
|
35
|
+
"publish-mcp": "mcp-publisher login github -token \"$(security find-generic-password -a \"$USER\" -s mcp-publisher-github-pat -w)\" && mcp-publisher publish"
|
|
37
36
|
},
|
|
38
37
|
"keywords": [
|
|
39
38
|
"mcp",
|
|
@@ -67,18 +66,18 @@
|
|
|
67
66
|
"access": "public"
|
|
68
67
|
},
|
|
69
68
|
"dependencies": {
|
|
70
|
-
"@cyanheads/mcp-ts-core": "^0.8.
|
|
69
|
+
"@cyanheads/mcp-ts-core": "^0.8.13",
|
|
71
70
|
"@types/js-yaml": "^4.0.9",
|
|
72
71
|
"js-yaml": "^4.1.1",
|
|
73
72
|
"pino-pretty": "^13.1.3",
|
|
74
|
-
"undici": "^8.
|
|
73
|
+
"undici": "^8.2.0"
|
|
75
74
|
},
|
|
76
75
|
"devDependencies": {
|
|
77
|
-
"@biomejs/biome": "^2.4.
|
|
76
|
+
"@biomejs/biome": "^2.4.14",
|
|
78
77
|
"@types/node": "^25.6.0",
|
|
79
78
|
"depcheck": "^1.4.7",
|
|
80
79
|
"ignore": "^7.0.5",
|
|
81
|
-
"tsc-alias": "^1.8.
|
|
80
|
+
"tsc-alias": "^1.8.17",
|
|
82
81
|
"typescript": "^6.0.3",
|
|
83
82
|
"vitest": "^4.1.5"
|
|
84
83
|
}
|
package/server.json
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
"url": "https://github.com/cyanheads/obsidian-mcp-server",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "3.1.
|
|
9
|
+
"version": "3.1.2",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
14
14
|
"identifier": "obsidian-mcp-server",
|
|
15
15
|
"runtimeHint": "node",
|
|
16
|
-
"version": "3.1.
|
|
16
|
+
"version": "3.1.2",
|
|
17
17
|
"packageArguments": [
|
|
18
18
|
{
|
|
19
19
|
"type": "positional",
|
|
@@ -59,6 +59,25 @@
|
|
|
59
59
|
"isRequired": false,
|
|
60
60
|
"default": "false"
|
|
61
61
|
},
|
|
62
|
+
{
|
|
63
|
+
"name": "OBSIDIAN_READ_PATHS",
|
|
64
|
+
"description": "Optional comma-separated vault-relative folder allowlist for reads. Prefix-based with implicit recursion; case-insensitive; trailing slashes normalized. Unset = full vault. Write paths are implicitly readable. Example: 'public/,projects/'.",
|
|
65
|
+
"format": "string",
|
|
66
|
+
"isRequired": false
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "OBSIDIAN_WRITE_PATHS",
|
|
70
|
+
"description": "Optional comma-separated vault-relative folder allowlist for writes. Same syntax as OBSIDIAN_READ_PATHS. Unset = full vault. Example: 'projects/,scratch/'.",
|
|
71
|
+
"format": "string",
|
|
72
|
+
"isRequired": false
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "OBSIDIAN_READ_ONLY",
|
|
76
|
+
"description": "Global read-only kill switch. When true, every write is denied regardless of OBSIDIAN_WRITE_PATHS, and the command-palette pair is suppressed (commands can mutate). Useful for shared or public-facing deployments.",
|
|
77
|
+
"format": "string",
|
|
78
|
+
"isRequired": false,
|
|
79
|
+
"default": "false"
|
|
80
|
+
},
|
|
62
81
|
{
|
|
63
82
|
"name": "MCP_LOG_LEVEL",
|
|
64
83
|
"description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').",
|
|
@@ -76,7 +95,7 @@
|
|
|
76
95
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
77
96
|
"identifier": "obsidian-mcp-server",
|
|
78
97
|
"runtimeHint": "node",
|
|
79
|
-
"version": "3.1.
|
|
98
|
+
"version": "3.1.2",
|
|
80
99
|
"packageArguments": [
|
|
81
100
|
{
|
|
82
101
|
"type": "positional",
|
|
@@ -122,6 +141,25 @@
|
|
|
122
141
|
"isRequired": false,
|
|
123
142
|
"default": "false"
|
|
124
143
|
},
|
|
144
|
+
{
|
|
145
|
+
"name": "OBSIDIAN_READ_PATHS",
|
|
146
|
+
"description": "Optional comma-separated vault-relative folder allowlist for reads. Prefix-based with implicit recursion; case-insensitive; trailing slashes normalized. Unset = full vault. Write paths are implicitly readable. Example: 'public/,projects/'.",
|
|
147
|
+
"format": "string",
|
|
148
|
+
"isRequired": false
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "OBSIDIAN_WRITE_PATHS",
|
|
152
|
+
"description": "Optional comma-separated vault-relative folder allowlist for writes. Same syntax as OBSIDIAN_READ_PATHS. Unset = full vault. Example: 'projects/,scratch/'.",
|
|
153
|
+
"format": "string",
|
|
154
|
+
"isRequired": false
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"name": "OBSIDIAN_READ_ONLY",
|
|
158
|
+
"description": "Global read-only kill switch. When true, every write is denied regardless of OBSIDIAN_WRITE_PATHS, and the command-palette pair is suppressed (commands can mutate). Useful for shared or public-facing deployments.",
|
|
159
|
+
"format": "string",
|
|
160
|
+
"isRequired": false,
|
|
161
|
+
"default": "false"
|
|
162
|
+
},
|
|
125
163
|
{
|
|
126
164
|
"name": "MCP_HTTP_HOST",
|
|
127
165
|
"description": "The hostname for the HTTP server.",
|