feat(vault): multi-vault discovery + selection — v0.3.0#18
Merged
Conversation
Adds four new tools — vault.list, vault.current, vault.select,
vault.reset — that let an LLM enumerate the user's known Obsidian
vaults and switch between them for the session, without restarting
the server or threading vaultPath through every call.
Tool surface: 62 → 66 across 15 → 16 namespaces.
Fully backwards compatible:
- OBSIDIAN_VAULT_PATH behaves identically to v0.2.5.
- No existing tool signatures change.
- requireVaultPath precedence gains a middle slot —
arg > session > env > error — that collapses to v0.2.5's
arg > env > error when vault.select is never called.
- All 56 pre-existing tests pass unmodified; 55 new tests added.
Vault discovery:
- OBSIDIAN_VAULT_PATH — the default (documented, stable)
- OBSIDIAN_VAULT_<NAME>=path env vars — additional named vaults (new,
documented, stable)
- obsidian.json parsing — opt-out via
KOBSIDIAN_VAULT_DISCOVERY=off
(EXPERIMENTAL — Obsidian's
undocumented registry format,
stable since 1.0 but could
change without notice; parse
failures never crash the
server, just surface via
vault.list.obsidianConfigError)
Platform-path resolution anchored on os.homedir() with escape hatch
env var KOBSIDIAN_OBSIDIAN_CONFIG for portable installs / WSL:
- darwin ~/Library/Application Support/obsidian/obsidian.json
- win32 %APPDATA%\obsidian\obsidian.json (with home fallback)
- linux $XDG_CONFIG_HOME/obsidian/... → ~/.config/... → flatpak → snap
Security gating:
- KOBSIDIAN_VAULT_ALLOW=name1,name2,/abs/path — allowlist
- KOBSIDIAN_VAULT_DENY=... — denylist (applied after allowlist)
- OBSIDIAN_VAULT_PATH is NEVER filtered by allow/deny to prevent
operator self-lockout.
Error UX: vault.select distinguishes "vault doesn't exist" (not_found)
from "vault exists but is blocked by operator gating" (unauthorized)
by resolving against the ungated pool, then applying allow/deny.
Other:
- vault.select on workspace.* / commands.* tools: surfaced as a note
on every tool description via buildDescription() in create-server.ts,
so LLMs know workspace/commands bridge to the live Obsidian instance
(OBSIDIAN_API_URL) and are not affected by the filesystem selection.
- New pick-vault server prompt for slash-command discoverability.
- Fixed stale ingest-source prompt references to removed v0.2.5 tools
(notes.insertAfterHeading / notes.append → notes.edit modes).
Cross-platform testing:
- 4 new test files: vault-paths, vault-discovery, vault-precedence,
vault-tools (49 assertions across platform mocks, fixtures,
precedence, real integration).
- 7 fixture obsidian.json files (macOS / Windows escaped backslashes /
Linux / malformed / no-vaults / empty-vaults / with-unknown-keys).
- Platform-path tests feed mocked {platform, home, env} so they pass
on every CI runner without needing the real OS.
Docs: README, AGENTS.md, docs/tools.md, docs/ENVIRONMENT.md,
docs/MIGRATION.md, CHANGELOG.md all updated. Version bumped to 0.3.0
across package.json, server.json, manifest.json.
Verification:
- bun run typecheck — clean
- bun run lint (biome) — clean
- bun run test — 111/111 passing (+55 vs v0.2.5)
- bun run build — stdio + http bundles built
- docs/tool-inventory.json regenerated — 66 tools
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Highlight v0.3.0's multi-vault support as the differentiator: no other Obsidian MCP lets an LLM list and switch between vaults in-session. - New docs/WORKSPACES.md — focused feature page: 60-second tour, all three discovery sources (with the EXPERIMENTAL label on obsidian.json parsing), precedence chain, operator gating, HTTP caveat, cross-links to ENVIRONMENT.md / MIGRATION.md / CHANGELOG.md / tools.md. - README top-of-page callout linking to docs/WORKSPACES.md so the feature is visible to anyone scanning the hero block. - Link WORKSPACES.md from docs/README.md (the docs landing page) with its own section above Architecture. - Fixed stale MCP_tools=90 badge in the hero — now reflects the actual 66 tools. No code changes — typecheck + lint + test + inventory all still green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
f5f8be1 to
d2209ce
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The 4 new tools
Discovery sources (in priority order)
`obsidian.json` paths per OS
Security / gating
Changes outside `vault.*`
HTTP transport caveat
Multi-client HTTP deployments share the `DomainContext` across requests, so `vault.select` is process-global today. `vault.select`'s description warns about this; concurrent HTTP clients should pass `vaultPath` per call. Per-`Mcp-Session-Id` scoping is deferred to a future v0.3.x.
Test plan
After merge
Tag `v0.3.0` on the merge commit — `release.yml` handles mcpb bundles + npm publish via OIDC Trusted Publishing.
🤖 Generated with Claude Code