obsidian-mcp-pro 1.4.1 → 1.5.1
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/README.md +169 -12
- package/build/config.d.ts.map +1 -1
- package/build/config.js +31 -12
- package/build/config.js.map +1 -1
- package/build/http-server.d.ts +10 -0
- package/build/http-server.d.ts.map +1 -1
- package/build/http-server.js +137 -12
- package/build/http-server.js.map +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +87 -26
- package/build/index.js.map +1 -1
- package/build/lib/logger.d.ts +19 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +125 -0
- package/build/lib/logger.js.map +1 -0
- package/build/lib/vault.d.ts.map +1 -1
- package/build/lib/vault.js +145 -46
- package/build/lib/vault.js.map +1 -1
- package/build/tools/canvas.d.ts.map +1 -1
- package/build/tools/canvas.js +5 -4
- package/build/tools/canvas.js.map +1 -1
- package/build/tools/links.d.ts.map +1 -1
- package/build/tools/links.js +15 -13
- package/build/tools/links.js.map +1 -1
- package/build/tools/read.d.ts.map +1 -1
- package/build/tools/read.js +23 -20
- package/build/tools/read.js.map +1 -1
- package/build/tools/tags.d.ts.map +1 -1
- package/build/tools/tags.js +5 -4
- package/build/tools/tags.js.map +1 -1
- package/build/tools/write.d.ts.map +1 -1
- package/build/tools/write.js +8 -7
- package/build/tools/write.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
⭐ **Please [star us on GitHub](https://github.com/rps321321/obsidian-mcp-pro) — it helps us reach more users!**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[](https://ko-fi.com/rps321)
|
|
8
|
+
|
|
9
|
+
💙 **Support this project** — obsidian-mcp-pro is free and open-source. If it saves you time, consider [buying me a coffee on Ko-fi](https://ko-fi.com/rps321).
|
|
8
10
|
|
|
9
11
|
[](https://glama.ai/mcp/servers/rps321321/obsidian-mcp-pro)
|
|
10
12
|
|
|
@@ -13,7 +15,7 @@
|
|
|
13
15
|
[](https://github.com/rps321321/obsidian-mcp-pro)
|
|
14
16
|
[](https://opensource.org/licenses/MIT)
|
|
15
17
|
[](https://nodejs.org/)
|
|
16
|
-
[](https://github.com/rps321321/obsidian-mcp-pro)
|
|
17
19
|
[](https://glama.ai/mcp/servers/rps321321/obsidian-mcp-pro)
|
|
18
20
|
|
|
19
21
|
Give AI assistants deep, structured access to your Obsidian knowledge base. Read, write, search, tag, analyze links, traverse graphs, and manipulate canvases — all through the [Model Context Protocol](https://modelcontextprotocol.io/).
|
|
@@ -22,6 +24,25 @@ Every one of the 23 tools ships with rich descriptions, typed schemas, human-rea
|
|
|
22
24
|
|
|
23
25
|
---
|
|
24
26
|
|
|
27
|
+
## Contents
|
|
28
|
+
|
|
29
|
+
- [Features](#features)
|
|
30
|
+
- [Quick Start](#quick-start)
|
|
31
|
+
- [Usage](#usage)
|
|
32
|
+
- [Configuration](#configuration)
|
|
33
|
+
- [Security](#security)
|
|
34
|
+
- [Wikilink Resolution](#wikilink-resolution)
|
|
35
|
+
- [Tool Reference](#tool-reference)
|
|
36
|
+
- [MCP Resources](#mcp-resources)
|
|
37
|
+
- [Troubleshooting](#troubleshooting)
|
|
38
|
+
- [Development](#development)
|
|
39
|
+
- [Testing](#testing)
|
|
40
|
+
- [What's New](#whats-new)
|
|
41
|
+
- [Contributing](#contributing)
|
|
42
|
+
- [License](#license)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
25
46
|
## Features
|
|
26
47
|
|
|
27
48
|
### Read & Search
|
|
@@ -66,7 +87,7 @@ Every one of the 23 tools ships with rich descriptions, typed schemas, human-rea
|
|
|
66
87
|
|
|
67
88
|
> **Using Obsidian?** There's also an [Obsidian plugin](https://github.com/rps321321/obsidian-mcp-pro-plugin) that runs this server inside the app with a ribbon toggle and settings UI — no config-file editing. Recommended for most users.
|
|
68
89
|
|
|
69
|
-
### One-
|
|
90
|
+
### One-Command Install (Claude Desktop / Cursor)
|
|
70
91
|
|
|
71
92
|
```bash
|
|
72
93
|
npx -y obsidian-mcp-pro install
|
|
@@ -80,7 +101,7 @@ Pin a specific vault:
|
|
|
80
101
|
npx -y obsidian-mcp-pro install --vault /path/to/your/vault
|
|
81
102
|
```
|
|
82
103
|
|
|
83
|
-
### Manual Claude Desktop
|
|
104
|
+
### Manual Claude Desktop Config
|
|
84
105
|
|
|
85
106
|
Add this to your Claude Desktop configuration file (`claude_desktop_config.json`):
|
|
86
107
|
|
|
@@ -117,7 +138,7 @@ If you have multiple vaults, specify which one:
|
|
|
117
138
|
claude mcp add obsidian-mcp-pro -- npx -y obsidian-mcp-pro
|
|
118
139
|
```
|
|
119
140
|
|
|
120
|
-
### HTTP
|
|
141
|
+
### HTTP Transport (Remote Clients, Cursor, ChatGPT, Web)
|
|
121
142
|
|
|
122
143
|
```bash
|
|
123
144
|
npx -y obsidian-mcp-pro --transport=http --port=3333
|
|
@@ -130,7 +151,79 @@ npx -y obsidian-mcp-pro --transport=http --token=your-secret
|
|
|
130
151
|
# or: MCP_HTTP_TOKEN=your-secret npx -y obsidian-mcp-pro --transport=http
|
|
131
152
|
```
|
|
132
153
|
|
|
133
|
-
The HTTP server binds to `127.0.0.1` by default with DNS rebinding protection enabled.
|
|
154
|
+
The HTTP server binds to `127.0.0.1` by default with DNS rebinding protection enabled.
|
|
155
|
+
|
|
156
|
+
> [!WARNING]
|
|
157
|
+
> **Never bind `--host=0.0.0.0` directly to the public internet.** Doing so exposes your entire Obsidian vault to anyone who can reach the port. If you need remote access:
|
|
158
|
+
> - Put the server behind a reverse proxy (nginx, Caddy, Cloudflare Tunnel) that terminates TLS, **and**
|
|
159
|
+
> - Require `--token=<secret>` (or `MCP_HTTP_TOKEN`), **and**
|
|
160
|
+
> - Restrict `--allow-origin` to the specific origins you trust, **and**
|
|
161
|
+
> - Set `--rate-limit` to cap request volume per IP.
|
|
162
|
+
>
|
|
163
|
+
> For local-only setups (same machine / VPN / SSH tunnel), keep the default `127.0.0.1` bind.
|
|
164
|
+
|
|
165
|
+
Additional hardening flags:
|
|
166
|
+
|
|
167
|
+
| Flag | Purpose |
|
|
168
|
+
|------|---------|
|
|
169
|
+
| `--allow-origin=<csv>` | Restrict CORS to an allowlist (e.g. `https://claude.ai,https://chat.openai.com`). Default is `*`. |
|
|
170
|
+
| `--rate-limit=<n>` | Cap requests per minute per client IP. `/health` and `/version` are exempt. Default is unlimited. |
|
|
171
|
+
|
|
172
|
+
Operational endpoints (no auth required):
|
|
173
|
+
|
|
174
|
+
| Endpoint | Returns |
|
|
175
|
+
|----------|---------|
|
|
176
|
+
| `GET /health` | `{ status: "ok", sessions: <n>, version: <string> }` — liveness + session count. |
|
|
177
|
+
| `GET /version` | `{ version: <string> }` — package version, for rollout auditing. |
|
|
178
|
+
|
|
179
|
+
Structured logging is controlled by `LOG_LEVEL` (`debug`/`info`/`warn`/`error`/`silent`, default `info`) and `LOG_FORMAT` (`text`/`json`, default `text`). All logs go to stderr so the stdio transport on stdout is never polluted.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Usage
|
|
184
|
+
|
|
185
|
+
Once installed, the server exposes 23 tools and 3 resources to whichever MCP client you configured. Below is a transcript of a Claude Desktop conversation showing what day-to-day use looks like.
|
|
186
|
+
|
|
187
|
+
> **You:** Find notes tagged `#project` I touched this week, then summarize the status of each and append today's date under a "Last reviewed" heading in each one.
|
|
188
|
+
|
|
189
|
+
Claude picks the right tools in order, with no guidance beyond the prompt:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
🔧 search_by_tag(tag="project", includeContent=false)
|
|
193
|
+
→ 7 notes: "Atlas/overview.md", "Atlas/milestones.md", "Beacon/spec.md", ...
|
|
194
|
+
|
|
195
|
+
🔧 list_notes(folder="Atlas", limit=100)
|
|
196
|
+
→ filters to recent modifications via get_note stats
|
|
197
|
+
|
|
198
|
+
🔧 get_note(path="Atlas/overview.md")
|
|
199
|
+
→ reads content + frontmatter + tags
|
|
200
|
+
|
|
201
|
+
🔧 get_note(path="Atlas/milestones.md")
|
|
202
|
+
→ ...
|
|
203
|
+
|
|
204
|
+
🔧 append_to_note(
|
|
205
|
+
path="Atlas/overview.md",
|
|
206
|
+
content="\n## Last reviewed\n2026-04-21 — on track; waiting on design review."
|
|
207
|
+
)
|
|
208
|
+
→ ok
|
|
209
|
+
|
|
210
|
+
🔧 append_to_note(
|
|
211
|
+
path="Atlas/milestones.md",
|
|
212
|
+
content="\n## Last reviewed\n2026-04-21 — Q2 milestone at risk, see spec.md."
|
|
213
|
+
)
|
|
214
|
+
→ ok
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
> **Claude:** I reviewed 7 project notes tagged `#project`. Atlas is on track pending design review; the Q2 milestone is at risk — details in `milestones.md`. Beacon's spec is complete but has 3 open questions in the frontmatter. I appended a "Last reviewed" section to each.
|
|
218
|
+
|
|
219
|
+
Other things the tool set lets agents do without hand-holding:
|
|
220
|
+
|
|
221
|
+
- **Research a topic across the vault.** `search_notes` → `get_outlinks` → `get_graph_neighbors` walks the graph to `depth=2` and surfaces related notes the user may have forgotten.
|
|
222
|
+
- **Clean up dangling references after a rename.** `move_note` → `find_broken_links` returns every wikilink that now points nowhere, with source note and line number.
|
|
223
|
+
- **Maintain a daily log.** `get_daily_note` reads today's note (using the vault's configured date format) and `append_to_note` adds the new entry — daily-note plugin config is honored, no manual date formatting.
|
|
224
|
+
- **Canvas editing.** `read_canvas` → agent reasons about the node graph → `add_canvas_node` + `add_canvas_edge` lays out new ideas on an existing board.
|
|
225
|
+
|
|
226
|
+
Tool descriptions + typed schemas + safety hints (`readOnlyHint`, `destructiveHint`) are what make this work reliably — the agent knows `delete_note` is destructive and asks first, knows `search_notes` is free to call speculatively, and knows the expected shape of every argument.
|
|
134
227
|
|
|
135
228
|
---
|
|
136
229
|
|
|
@@ -146,7 +239,7 @@ The server locates your vault using the following priority:
|
|
|
146
239
|
|
|
147
240
|
Auto-detection works on **macOS**, **Windows**, and **Linux** by reading the platform-specific Obsidian configuration directory.
|
|
148
241
|
|
|
149
|
-
### Daily-
|
|
242
|
+
### Daily-Note Filename Format
|
|
150
243
|
|
|
151
244
|
`get_daily_note`, `create_daily_note`, and the `obsidian://daily` resource render the note path using your vault's `.obsidian/daily-notes.json` `format` string. Moment.js-style tokens are supported:
|
|
152
245
|
|
|
@@ -164,6 +257,12 @@ Auto-detection works on **macOS**, **Windows**, and **Linux** by reading the pla
|
|
|
164
257
|
|
|
165
258
|
Unrecognized tokens pass through unchanged. Local time is used (matching Obsidian's rendering).
|
|
166
259
|
|
|
260
|
+
### Observability
|
|
261
|
+
|
|
262
|
+
Logs stream to stderr as either plain text (default) or single-line JSON — set via `LOG_LEVEL` (`debug`/`info`/`warn`/`error`/`silent`) and `LOG_FORMAT` (`text`/`json`).
|
|
263
|
+
|
|
264
|
+
The server also declares the MCP [`logging` capability](https://modelcontextprotocol.io/specification), so every log line is forwarded to the connected client as a `notifications/message` frame alongside tool responses. Clients that honor `logging/setLevel` can filter server-side logs at runtime without restarting. Claude Desktop surfaces these in its MCP DevTools pane; most other clients currently ignore them, so this is useful primarily for self-hosters and tooling authors.
|
|
265
|
+
|
|
167
266
|
---
|
|
168
267
|
|
|
169
268
|
## Security
|
|
@@ -172,11 +271,14 @@ Unrecognized tokens pass through unchanged. Local time is used (matching Obsidia
|
|
|
172
271
|
- **Excluded directories** — `.obsidian`, `.git`, and `.trash` are pruned at traversal time and at resolution time, so nested occurrences never leak back to clients.
|
|
173
272
|
- **HTTP transport** — binds to `127.0.0.1` by default with DNS rebinding protection (host-header allowlist). Optional `--token=<secret>` requires `Authorization: Bearer <secret>` on every `/mcp` request; compared in constant time.
|
|
174
273
|
- **Error sanitization** — filesystem error messages are stripped of absolute host paths before being returned to MCP clients. Uncaught HTTP errors respond with a generic `Internal server error` body; full detail stays in the server log.
|
|
175
|
-
- **Atomic writes** — `
|
|
274
|
+
- **Atomic writes** — every note write (`create_note`, `append`, `prepend`, `update_frontmatter`, canvas mutations) stages content to a sibling temp file then renames onto the target, so a crash or kill mid-write never leaves a truncated file. Combined with per-path locks for the full read-modify-write cycle, concurrent callers can't lose each other's updates. The `install` subcommand uses the same pattern and keeps a backup of the previous config.
|
|
275
|
+
- **Rate limiting + CORS allowlist** — optional `--rate-limit` caps per-IP request volume; `--allow-origin` restricts browser-facing CORS. `/health` and `/version` stay reachable under load for monitoring.
|
|
276
|
+
- **Request timeout** — HTTP POST requests are capped at 2 minutes of wall-clock time. Long-lived SSE GET streams are exempt so idle clients aren't reaped.
|
|
277
|
+
- **Process supervision** — `uncaughtException` exits cleanly so systemd/Docker/npx supervisors can restart; `unhandledRejection` logs but doesn't kill the process.
|
|
176
278
|
|
|
177
279
|
---
|
|
178
280
|
|
|
179
|
-
## Wikilink
|
|
281
|
+
## Wikilink Resolution
|
|
180
282
|
|
|
181
283
|
`[[Target]]` resolves in the same order Obsidian does:
|
|
182
284
|
|
|
@@ -231,6 +333,48 @@ Resources provide a URI-based way to access vault data:
|
|
|
231
333
|
|
|
232
334
|
---
|
|
233
335
|
|
|
336
|
+
## Troubleshooting
|
|
337
|
+
|
|
338
|
+
### Tools Don't Show Up in Claude Desktop
|
|
339
|
+
|
|
340
|
+
MCP clients only re-read their config on startup. After editing `claude_desktop_config.json` (or running `npx obsidian-mcp-pro install`), fully quit Claude Desktop (⌘Q on macOS, tray → Quit on Windows) and relaunch. Hot-reloading the window is not enough.
|
|
341
|
+
|
|
342
|
+
### "No Obsidian vault configured" on Startup
|
|
343
|
+
|
|
344
|
+
The server couldn't locate a vault. Resolution order is:
|
|
345
|
+
|
|
346
|
+
1. `OBSIDIAN_VAULT_PATH` env var (absolute path) — always wins if set.
|
|
347
|
+
2. `OBSIDIAN_VAULT_NAME` env var — picks a named vault from Obsidian's global config.
|
|
348
|
+
3. Auto-detection — reads `obsidian.json` (platform-specific) and uses the first valid vault found.
|
|
349
|
+
|
|
350
|
+
Fastest fix: set `OBSIDIAN_VAULT_PATH` in the `env` block of your MCP client's config. Auto-detection fails when Obsidian has never been launched, `obsidian.json` is missing/corrupt, or all registered vaults resolve to paths that no longer exist.
|
|
351
|
+
|
|
352
|
+
### "Path traversal detected" Error on Tool Calls
|
|
353
|
+
|
|
354
|
+
All tool paths must be **vault-relative** (e.g. `notes/hello.md`), never absolute (`/Users/me/vault/notes/hello.md`) or containing `..`. The agent normally gets this right — if you see this error, check whether a custom instruction is asking it to use absolute paths.
|
|
355
|
+
|
|
356
|
+
### HTTP Transport Returns `401 Unauthorized`
|
|
357
|
+
|
|
358
|
+
The server was started with `--token=<secret>` (or `MCP_HTTP_TOKEN` is set in the environment) but the client isn't sending a matching `Authorization: Bearer <secret>` header. Verify the token value and that the header is present — comparison is case-sensitive and constant-time.
|
|
359
|
+
|
|
360
|
+
### HTTP Transport Returns `429 Too Many Requests`
|
|
361
|
+
|
|
362
|
+
`--rate-limit=<n>` is set and the client exceeded N requests in the last 60 seconds from that IP. Either raise the limit, drop it, or wait 60 seconds. `/health` and `/version` are exempt if you need to check liveness under load.
|
|
363
|
+
|
|
364
|
+
### Daily-Note Path Is Wrong or Unresolved
|
|
365
|
+
|
|
366
|
+
The server reads `.obsidian/daily-notes.json` from the vault for the filename format and folder. If that file doesn't exist (the Daily Notes core plugin has never been configured), the server falls back to `YYYY-MM-DD.md` in the vault root. Configure the plugin once inside Obsidian and the server picks it up automatically.
|
|
367
|
+
|
|
368
|
+
### `npx obsidian-mcp-pro` Silently Exits With Code 0
|
|
369
|
+
|
|
370
|
+
This was a bug in versions < 1.4.1 where the `npx`-symlinked CLI entry failed to detect itself as the entrypoint. Upgrade: `npx -y obsidian-mcp-pro@latest install`.
|
|
371
|
+
|
|
372
|
+
### Windows: "EPERM: operation not permitted" During Writes
|
|
373
|
+
|
|
374
|
+
The server retries these transparently (Windows holds stricter file-sharing locks than POSIX) — if you still see the error, it usually means antivirus or a sync client (OneDrive, Dropbox) is holding the file. Exclude the vault folder from real-time antivirus scanning, or pause the sync client during heavy agent sessions.
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
234
378
|
## Development
|
|
235
379
|
|
|
236
380
|
```bash
|
|
@@ -267,6 +411,7 @@ src/
|
|
|
267
411
|
dates.ts # Moment-style date format for daily-note filenames
|
|
268
412
|
errors.ts # sanitizeError: strips absolute paths from fs errors
|
|
269
413
|
concurrency.ts # Bounded-concurrency fan-out helper (tag/link scans)
|
|
414
|
+
logger.ts # Leveled stderr logger (text + JSON modes)
|
|
270
415
|
tools/
|
|
271
416
|
read.ts # search_notes, get_note, list_notes, daily, frontmatter
|
|
272
417
|
write.ts # create, append, prepend, update_frontmatter, move, delete
|
|
@@ -276,6 +421,7 @@ src/
|
|
|
276
421
|
__tests__/
|
|
277
422
|
vault.test.ts markdown.test.ts tools.test.ts
|
|
278
423
|
security.test.ts http-server.test.ts semantics.test.ts
|
|
424
|
+
logger.test.ts
|
|
279
425
|
```
|
|
280
426
|
|
|
281
427
|
---
|
|
@@ -286,13 +432,24 @@ src/
|
|
|
286
432
|
npm test
|
|
287
433
|
```
|
|
288
434
|
|
|
289
|
-
|
|
435
|
+
173 tests covering vault operations, atomic writes + concurrent-mutation races, markdown parsing (frontmatter, wikilinks, tags, code-block detection), moment-token date formatting, canvas round-trip fidelity, HTTP transport (Bearer auth, oversize-body, CORS allowlist with `Vary: Origin`, per-IP rate limiting, `/version`), leveled logger (text + JSON output), and security regression guards (symlink escape, case-only rename, path-leak sanitization, cross-process exclusive-create). Runs against Node 20 + 22 on Ubuntu, macOS, and Windows in CI.
|
|
290
436
|
|
|
291
437
|
---
|
|
292
438
|
|
|
293
|
-
##
|
|
439
|
+
## What's New
|
|
440
|
+
|
|
441
|
+
**v1.5.0** — production hardening pass:
|
|
294
442
|
|
|
295
|
-
|
|
443
|
+
- **Atomic writes** on every mutating tool (temp file + rename). Crashes, kills, or OOMs mid-write can no longer leave a truncated note.
|
|
444
|
+
- **`create_note` exclusive mode uses OS-level `wx`** so an out-of-process writer (Obsidian itself, a sync client) can't slip between the check and the write.
|
|
445
|
+
- **Parallel vault scans** — `search_notes` and the `obsidian://tags` resource fan out 8-way. Order-of-magnitude latency drop on 10K+ note vaults.
|
|
446
|
+
- **HTTP hardening** — per-IP `--rate-limit`, `--allow-origin` CORS allowlist (with `Vary: Origin`), POST request timeout, `GET /version` endpoint.
|
|
447
|
+
- **Structured logger** with `LOG_LEVEL` / `LOG_FORMAT` env vars (text or JSON, stderr-only).
|
|
448
|
+
- **Process supervision** — `uncaughtException` exits cleanly for systemd/Docker; `unhandledRejection` logs without killing the process.
|
|
449
|
+
|
|
450
|
+
Full version history in [CHANGELOG.md](./CHANGELOG.md).
|
|
451
|
+
|
|
452
|
+
---
|
|
296
453
|
|
|
297
454
|
## License
|
|
298
455
|
|
package/build/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAsJ/D,wBAAgB,cAAc,IAAI,WAAW,CAsB5C;AAED,wBAAsB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAwCrF"}
|
package/build/config.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as fs from "fs";
|
|
|
2
2
|
import * as fsp from "fs/promises";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import * as os from "os";
|
|
5
|
+
import { log } from "./lib/logger.js";
|
|
5
6
|
function getObsidianConfigPath() {
|
|
6
7
|
const platform = os.platform();
|
|
7
8
|
if (platform === "win32") {
|
|
@@ -37,7 +38,12 @@ function resolveVaultFromEnv() {
|
|
|
37
38
|
}
|
|
38
39
|
const resolved = path.resolve(envPath);
|
|
39
40
|
if (!isValidVaultPath(resolved)) {
|
|
40
|
-
|
|
41
|
+
// Log the configured path (not sanitized) because this is an operator-
|
|
42
|
+
// facing diagnostic — they already know the path, and hiding it would
|
|
43
|
+
// make the error useless. This never goes into a tool response.
|
|
44
|
+
log.warn("OBSIDIAN_VAULT_PATH is not a valid vault (missing .obsidian dir)", {
|
|
45
|
+
vaultPath: resolved,
|
|
46
|
+
});
|
|
41
47
|
return null;
|
|
42
48
|
}
|
|
43
49
|
return resolved;
|
|
@@ -48,11 +54,11 @@ function resolveVaultFromObsidianConfig() {
|
|
|
48
54
|
configPath = getObsidianConfigPath();
|
|
49
55
|
}
|
|
50
56
|
catch (err) {
|
|
51
|
-
|
|
57
|
+
log.warn("Failed to determine Obsidian config path", { err: err });
|
|
52
58
|
return null;
|
|
53
59
|
}
|
|
54
60
|
if (!fs.existsSync(configPath)) {
|
|
55
|
-
|
|
61
|
+
log.warn("Obsidian config not found", { configPath });
|
|
56
62
|
return null;
|
|
57
63
|
}
|
|
58
64
|
let config;
|
|
@@ -61,16 +67,16 @@ function resolveVaultFromObsidianConfig() {
|
|
|
61
67
|
config = JSON.parse(raw);
|
|
62
68
|
}
|
|
63
69
|
catch (err) {
|
|
64
|
-
|
|
70
|
+
log.warn("Failed to parse Obsidian config", { configPath, err: err });
|
|
65
71
|
return null;
|
|
66
72
|
}
|
|
67
73
|
if (!config.vaults || typeof config.vaults !== "object") {
|
|
68
|
-
|
|
74
|
+
log.warn("No vaults found in Obsidian config");
|
|
69
75
|
return null;
|
|
70
76
|
}
|
|
71
77
|
const vaultEntries = Object.values(config.vaults);
|
|
72
78
|
if (vaultEntries.length === 0) {
|
|
73
|
-
|
|
79
|
+
log.warn("Obsidian config contains no vault entries");
|
|
74
80
|
return null;
|
|
75
81
|
}
|
|
76
82
|
const desiredName = process.env.OBSIDIAN_VAULT_NAME;
|
|
@@ -84,10 +90,15 @@ function resolveVaultFromObsidianConfig() {
|
|
|
84
90
|
if (isValidVaultPath(resolved)) {
|
|
85
91
|
return resolved;
|
|
86
92
|
}
|
|
87
|
-
|
|
93
|
+
log.warn("Vault listed in Obsidian config but path is not a valid vault", {
|
|
94
|
+
vaultName: desiredName,
|
|
95
|
+
vaultPath: resolved,
|
|
96
|
+
});
|
|
88
97
|
return null;
|
|
89
98
|
}
|
|
90
|
-
|
|
99
|
+
log.warn("OBSIDIAN_VAULT_NAME has no matching vault in Obsidian config", {
|
|
100
|
+
vaultName: desiredName,
|
|
101
|
+
});
|
|
91
102
|
return null;
|
|
92
103
|
}
|
|
93
104
|
// No name specified — try the first valid vault
|
|
@@ -95,12 +106,14 @@ function resolveVaultFromObsidianConfig() {
|
|
|
95
106
|
const resolved = path.resolve(entry.path);
|
|
96
107
|
if (isValidVaultPath(resolved)) {
|
|
97
108
|
if (vaultEntries.length > 1) {
|
|
98
|
-
|
|
109
|
+
log.info("Multiple vaults found; defaulting to first valid one. Set OBSIDIAN_VAULT_NAME to select a specific vault.", {
|
|
110
|
+
selected: path.basename(resolved),
|
|
111
|
+
});
|
|
99
112
|
}
|
|
100
113
|
return resolved;
|
|
101
114
|
}
|
|
102
115
|
}
|
|
103
|
-
|
|
116
|
+
log.warn("No valid vault paths found in Obsidian config");
|
|
104
117
|
return null;
|
|
105
118
|
}
|
|
106
119
|
export function getVaultConfig() {
|
|
@@ -136,7 +149,10 @@ export async function getDailyNoteConfig(vaultPath) {
|
|
|
136
149
|
catch (err) {
|
|
137
150
|
if (err.code === "ENOENT")
|
|
138
151
|
return defaults;
|
|
139
|
-
|
|
152
|
+
log.warn("Failed to read daily notes config", {
|
|
153
|
+
configPath: dailyNotesConfigPath,
|
|
154
|
+
err: err,
|
|
155
|
+
});
|
|
140
156
|
return defaults;
|
|
141
157
|
}
|
|
142
158
|
try {
|
|
@@ -148,7 +164,10 @@ export async function getDailyNoteConfig(vaultPath) {
|
|
|
148
164
|
};
|
|
149
165
|
}
|
|
150
166
|
catch (err) {
|
|
151
|
-
|
|
167
|
+
log.warn("Failed to parse daily notes config", {
|
|
168
|
+
configPath: dailyNotesConfigPath,
|
|
169
|
+
err: err,
|
|
170
|
+
});
|
|
152
171
|
return defaults;
|
|
153
172
|
}
|
|
154
173
|
}
|
package/build/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AACnC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/build/http-server.d.ts
CHANGED
|
@@ -8,6 +8,16 @@ export interface HttpServerOptions {
|
|
|
8
8
|
* `true` for CLI use. Set `false` when embedding (e.g. inside an Obsidian
|
|
9
9
|
* plugin) so stopping the server doesn't kill the host process. */
|
|
10
10
|
installSignalHandlers?: boolean;
|
|
11
|
+
/** Reported on `/health` and `/version`. Defaults to empty string. */
|
|
12
|
+
version?: string;
|
|
13
|
+
/** Allowed CORS origins. Defaults to `["*"]` to match prior behavior. Use
|
|
14
|
+
* an explicit list (e.g. `["https://claude.ai"]`) to tighten for
|
|
15
|
+
* browser-facing deployments. Requests from other origins still succeed
|
|
16
|
+
* (CORS is a browser-only restriction) but the browser will reject the
|
|
17
|
+
* response. */
|
|
18
|
+
allowedOrigins?: string[];
|
|
19
|
+
/** Max requests per minute per client IP. 0 or undefined disables. */
|
|
20
|
+
rateLimitPerMinute?: number;
|
|
11
21
|
}
|
|
12
22
|
export interface HttpServerHandle {
|
|
13
23
|
host: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,SAAS,CAAC;IAChC;;wEAEoE;IACpE,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;oBAIgB;IAChB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAsJD,wBAAsB,eAAe,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyNxF"}
|