Obsidian Vault logo

Obsidian Vault

Community
cyanheads

Read, write, search, and surgically edit Obsidian vault notes, tags, and frontmatter via MCP. STDIO or Streamable HTTP.

Publishercyanheads
Repositoryobsidian-mcp-server
LanguageTypeScript
Forks
104
Stars
683
Available tools
0
Transport typestdio
Categories
LicenseApache-2.0
Links
  • Connect tools to AI workflows

    Obsidian Vault exposes MCP capabilities that can be used by compatible AI clients and agents.

  • 0 available tools

    Browse the callable actions below, including names and descriptions when provided by the server.

  • Ready-to-copy setup

    Use the installation snippets to configure this server in your preferred MCP client.

  • Open source signals

    683 stars and 104 forks from the linked repository.

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework


Overview

Read, write, search, and surgically edit Obsidian vault notes — sections, frontmatter, tags — over the Local REST API plugin, with folder-scoped read/write permissions built in. Runs as a stdio process or a local Streamable HTTP server.

Tools

ToolDescription
obsidian_get_noteRead a note as raw content, full structured form (content + frontmatter + tags + stat, with optional outgoing links), structural document map, or a single section.
obsidian_list_notesList notes and subdirectories under a vault path. Recursive walk (default depth 2, max depth 20; 1000-entry cap) with optional extension and nameRegex filters.
obsidian_list_tagsList vault tags with usage counts, including hierarchical parents. Ordered by count descending and capped at limit (default 200, max 10000), with the withheld remainder disclosed. Optional nameRegex and minCount narrow the set first.
obsidian_list_commandsList Obsidian command-palette commands, optionally filtered by nameRegex on display name. Opt-in via OBSIDIAN_ENABLE_COMMANDS=true (paired with obsidian_execute_command).
obsidian_search_notesSearch the vault by text, JSONLogic, or BM25-ranked Omnisearch (when the plugin is reachable). Results paginate via opaque cursors.
obsidian_write_noteCreate a note, replace a single section in place, or — with overwrite: true — clobber an existing file. Refuses whole-file writes against an existing path by default.
obsidian_append_to_noteAppend content to a note. Without section, creates the file if missing. With section, appends to a specific heading, block, or frontmatter field (file must exist).
obsidian_patch_noteSurgical append / prepend / replace against a heading, block reference, or frontmatter field.
obsidian_replace_in_noteSearch-replace inside a single note, scoped to the body by default. Literal or regex matching with whole-word, whitespace-flexible, and case-sensitivity options; supports capture-group replacement.
obsidian_manage_frontmatterAtomic get / set / delete on a single frontmatter key.
obsidian_manage_tagsAdd, remove, or list tags. Defaults to the frontmatter tags: array; location: 'inline' or 'both' opts into mutating the note body.
obsidian_delete_notePermanently delete a note. Always asks the user to confirm first — the call is answered with a confirmation request and retried with the answer.
obsidian_open_in_uiOpen a file in the Obsidian app UI, with failIfMissing and newLeaf toggles.
obsidian_execute_commandExecute an Obsidian command-palette command by ID. Opt-in via OBSIDIAN_ENABLE_COMMANDS=true.

Resources

ResourceDescription
obsidian://vault/{+path}A note in the vault — content, frontmatter, tags, and file metadata.
obsidian://tagsAll tags found across the vault, with usage counts (full snapshot).
obsidian://statusServer reachability, auth status, plugin/Obsidian version info, and registered API extensions.

Vault-note and tag data are also reachable via tools — obsidian_get_note for obsidian://vault/{+path}, obsidian_list_tags for obsidian://tags (count-ranked and capped, unlike the resource's raw snapshot). obsidian://status has no tool equivalent. Resources exist for clients that prefer attaching a note or vault snapshot to a conversation.

Capability reference

obsidian_get_note tool

  • format: "content" | "full" | "document-map" | "section" selects the projection; full accepts includeLinks: true for outgoing wiki/markdown links (vault-internal only — external URLs are filtered)
  • Addressed by vault path, the active file, or a periodic note (daily / weekly / monthly / quarterly / yearly)
  • Heading sections use Parent::Child syntax; a bare leaf name matching several headings returns the first match and lists every colliding path in candidates
  • Forgiving path resolution: a case-mismatched path retries against the canonical filename, an ambiguous case match fails with Conflict, and a NotFound carries Did you mean: …? suggestions when near-matches exist
  • Typed errors include note_missing, path_forbidden, no_active_file, periodic_unsupported / periodic_disabled, and path_traversal

obsidian_list_notes tool

  • Recursive walk from path (default vault root); depth 1–20 (default 2 = target plus immediate children)
  • Optional extension and nameRegex (≤256 chars, no nested quantifiers) filters; a directory failing nameRegex is skipped without recursing into it
  • Hard cap of 1000 entries per call — excluded.reason: "entry_cap" signals a truncated walk; narrow path or the filters to see the rest
  • Per-directory truncated: true marks entries cut off by the depth limit or by path policy

obsidian_list_tags tool

  • Vault-wide tag counts, including hierarchical parents (work/tasks contributes to both work and work/tasks)
  • Ordered by count descending, capped at limit (default 200, max 10000); optional nameRegex and minCount narrow the candidate set before ranking
  • Reports truncated / shown / cap when the limit withheld results
  • Not narrowed by OBSIDIAN_READ_PATHS — tag names (never note contents) can surface from outside the read scope

obsidian_list_commands tool

  • Lists Obsidian command-palette IDs and display names; optional nameRegex filters on display name
  • Opt-in via OBSIDIAN_ENABLE_COMMANDS=true — absent from tools/list when unset
  • Discovery partner for obsidian_execute_command

obsidian_search_notes tool

  • mode: "text" | "jsonlogic" always; "omnisearch" is added to the schema only when the Omnisearch plugin's HTTP server is reachable at startup (restart to re-probe)
  • text — substring match with contextLength-sized context windows (default 100) and an optional pathPrefix; jsonlogic — a JSONLogic tree with var paths into path / content / frontmatter.<key> / tags / stat.{ctime,mtime,size}, plus glob / regexp operators taking [PATTERN, VALUE]; omnisearch — BM25-ranked, quoted phrases, -exclusion, path: / ext: filters, typo tolerance, PDF/OCR via Text Extractor, hard-capped at 50 upstream hits (truncated: true when likely hit)
  • Cursor pagination — omit cursor for page one, pass nextCursor from the prior response; text-mode hits additionally clip to maxMatchesPerHit (default 10), flagged with truncated / totalMatches
  • No dedicated backlinks tool — express "what links here" via jsonlogic: {"regexp": ["\\[\\[Target Note(\\||#|\\]\\])", {"var": "content"}]}

obsidian_write_note tool

  • Without section — full-file write; refuses to clobber an existing note unless overwrite: true (file_exists conflict otherwise, naming the surgical-edit tools as the alternative)
  • With section — PATCH-with-replace against a heading/block/frontmatter target, leaving the rest of the file untouched (overwrite is ignored); a bare heading leaf shared by several headings fails with ambiguous_section
  • Output reports created, plus previousSizeInBytes / currentSizeInBytes on every call to spot an accidental clobber or a mistyped path

obsidian_append_to_note tool

  • Without section — appends to an existing file, or creates it with the given content as the whole body (created: true flags the second case)
  • With section — appends to a heading/block/frontmatter target; the file must already exist, and createTargetIfMissing: true brings the section itself into existence
  • Block-reference targets concatenate with no separator — include a leading newline in content for one
  • previousSizeInBytes / currentSizeInBytes bracket every call for drift detection

obsidian_patch_note tool

  • operation: "append" | "prepend" | "replace" against one heading, block reference, or frontmatter field per call
  • Heading targets accept the full Parent::Child path or an unambiguous bare leaf name; a leaf matching several headings fails with ambiguous_section and lists the candidates
  • patchOptions: createTargetIfMissing, applyIfContentPreexists (idempotency guard — otherwise content_preexists), trimTargetWhitespace

obsidian_replace_in_note tool

  • One or more replacements, applied in array order, each over the previous one's output
  • scope: "body" (default, frontmatter left byte-identical) | "frontmatter" | "both"; frontmatter/both re-parse the rewritten YAML afterward and write nothing if it breaks (frontmatter_invalid)
  • Per-replacement options: useRegex (≤1024 chars, no nested quantifiers), caseSensitive, wholeWord (\b…\b in both modes), flexibleWhitespace (literal mode only), replaceAll (default true)
  • perReplacement[] reports bodyCount / frontmatterCount per entry; totalReplacements sums them

obsidian_manage_frontmatter tool

  • operation: "get" | "set" | "delete" on a single frontmatter key; set requires a JSON-typed value (string, number, boolean, array, or object)
  • get needs read access; set / delete need the path inside OBSIDIAN_WRITE_PATHS with OBSIDIAN_READ_ONLY=false
  • set / delete return the full frontmatter after the change plus previousSizeInBytes / currentSizeInBytes

obsidian_manage_tags tool

  • operation: "add" | "remove" | "list"; location: "frontmatter" (default, canonical tags: array) | "inline" (body #tag, add appends at end-of-file) | "both" (reconciles both)
  • Inline detection skips fenced/inline code spans, link spans ([[...]], [text](...), [text][ref]), and \#-escaped hashes, so a heading anchor or wikilink alias is never mistaken for a tag
  • add / remove report applied vs. skipped tags plus the full tags set after the change; list ignores the input tags array

obsidian_delete_note tool

  • Always asks for confirmation first — the initial call returns an elicitation request naming the file's byte size, and is retried with the answer; declining fails with cancelled and issues no DELETE
  • No API-level undo — recovery requires Obsidian's local trash
  • Requires an MCP client that can serve an elicitation round-trip; every other tool works without one

obsidian_open_in_ui tool

  • failIfMissing (default true) controls open-vs-create: opening an existing file needs read access, opening a missing one (with failIfMissing: false) creates it and needs write access
  • newLeaf opens in a split pane instead of the active one
  • Same forgiving path resolution as obsidian_get_note (case fallback, Did you mean suggestions); obsidian_delete_note deliberately doesn't get it — a destructive op never silently rewrites its target
  • Output reports createdIfMissing so the caller can tell which branch ran

obsidian_execute_command tool

  • Dispatches an Obsidian command-palette command by commandId (discover via obsidian_list_commands); runs with the same authority as a keyboard invocation
  • Opt-in via OBSIDIAN_ENABLE_COMMANDS=true — absent from tools/list when unset
  • Behavior is command-dependent — some are destructive (delete file, close vault), some open UI

obsidian://vault/{+path} resource

  • The {+path} segment captures everything after /vault/, including slashes
  • Paths may be sent literally or percent-encoded — Folder/Test Note.md and Folder/Test%20Note.md resolve to the same note, as do non-ASCII names and a bare %
  • Returns the same shape as obsidian_get_note with format: "full" — content, frontmatter, tags, stat
  • Gated by OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS like the tool equivalent

obsidian://tags resource

  • Full snapshot of the upstream /tags/ payload — unsorted, uncapped, includes hierarchical parents
  • Not a mirror of obsidian_list_tags: no count-descending order, no limit / nameRegex / minCount

obsidian://status resource

  • Reachability, plugin version, authenticated (whether the configured OBSIDIAN_API_KEY was accepted), and plugin manifest info
  • apiExtensions[] lists registered plugin extensions — check for local-rest-api-periodic-notes before relying on periodic targets on plugin v5.0.2 and later
  • Still reports reachability when the API key is misconfigured; only authenticated reflects the key's validity

Path policy (folder-scoped permissions)

Three optional env vars gate which vault paths each tool can target. Default unset = full vault for both reads and writes — backwards compatible.

GoalConfig
Default (current behavior)all unset
Read everywhere, write only in projects/ and scratch/OBSIDIAN_WRITE_PATHS=projects/,scratch/
Read only public/, write only public/inbox/OBSIDIAN_READ_PATHS=public/, OBSIDIAN_WRITE_PATHS=public/inbox/
Read-only deployment — no writes anywhereOBSIDIAN_READ_ONLY=true

Matching is prefix-based with implicit recursion, case-insensitive, with trailing slashes normalized. projects/ matches projects/a.md, projects/sub/b.md, etc.

Write paths are implicitly readable — you can't sanely edit what you can't see. So a read passes when the target matches READ_PATHS or WRITE_PATHS.

OBSIDIAN_READ_ONLY=true short-circuits before the path checks — every write tool and the command-palette pair are wrapped with disabledTool() at startup (absent from tools/list), and any write that still reaches the service is denied at runtime regardless of WRITE_PATHS.

Denies are typed path_forbidden (JSON-RPC code Forbidden) with the active scope echoed back in data.recovery.hint and data.activeScope, so the LLM can self-correct without inspecting server logs. Search results from obsidian_search_notes are filtered against READ_PATHS silently — surfacing a "we hid N hits" indicator would defeat the gate.

Tag listing is vault-wide. obsidian_list_tags and the obsidian://tags resource aggregate tag names across the whole vault and are not narrowed by OBSIDIAN_READ_PATHS — they take no path to gate, so tag names (never note contents) from outside the read scope can surface.

The startup banner logs the active scope so operators can verify their config at boot.

Features

Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.

Obsidian-specific:

  • Wraps the Obsidian Local REST API plugin — typed client, deterministic error mapping
  • Section-aware editing across headings, block references, and frontmatter fields via PATCH-with-target operations
  • Search across three modes — text, JSONLogic, and (when reachable) BM25-ranked Omnisearch — cursor-paginated per the MCP 2025-11-25 spec
  • Tag reconciliation across both representations: frontmatter tags: array and inline #tag syntax
  • Folder-scoped read/write permissions via OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS and a global OBSIDIAN_READ_ONLY kill switch; opt-in command-palette pair gated by OBSIDIAN_ENABLE_COMMANDS. Server-level instructions on initialize report the active policy to the caller

Agent-friendly output:

  • Recovery-guided errors — every declared failure carries a reason, a JSON-RPC code, and a recovery.hint written for that case, so a rejection names what to do next instead of only what broke
  • Size-delta self-correction — every mutating tool returns previousSizeInBytes / currentSizeInBytes, so a caller can spot an accidental clobber or unexpected upstream behavior without a follow-up read
  • Ambiguity surfaced structurally — a heading leaf name shared by several headings returns candidates instead of silently picking one; tag operations report applied vs. skipped so a caller sees exactly what changed
  • Discriminated output contracts — format on obsidian_get_note, operation on obsidian_manage_frontmatter and obsidian_manage_tags, mode on obsidian_search_notes — callers branch on typed fields instead of parsing text

Getting started

Add the following to your MCP client configuration file. The Obsidian Local REST API plugin must be installed and enabled in your vault — see Prerequisites.

json
{
  "mcpServers": {
    "obsidian-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["obsidian-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "OBSIDIAN_API_KEY": "your-local-rest-api-key"
      }
    }
  }
}

Or with npx (no Bun required):

json
{
  "mcpServers": {
    "obsidian-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "obsidian-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "OBSIDIAN_API_KEY": "your-local-rest-api-key"
      }
    }
  }
}

Or with Docker:

json
{
  "mcpServers": {
    "obsidian-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT_TYPE=stdio",
        "-e", "MCP_LOG_LEVEL=info",
        "-e", "OBSIDIAN_API_KEY=your-local-rest-api-key",
        "ghcr.io/cyanheads/obsidian-mcp-server:latest"
      ]
    }
  }
}

The default OBSIDIAN_BASE_URL (http://127.0.0.1:27123) points at the container's own loopback, not your host — add -e OBSIDIAN_BASE_URL=http://host.docker.internal:27123 (Docker Desktop) or run with --network host (Linux) so the container can reach the plugin.

For Streamable HTTP, set the transport and start the server. Inline env vars work for one-off runs; for repeated use, copy values into .env (see .env.example) and run bun run start:http.

sh
MCP_TRANSPORT_TYPE=http OBSIDIAN_API_KEY=... bun run start:http
# Server listens at http://127.0.0.1:3010/mcp by default

Prerequisites

  • Bun v1.4.0 or higher (or Node.js v24+).
  • The Obsidian Local REST API plugin, v4.0.0 through v5.x, installed and enabled in your vault. Generate an API key in Settings → Community Plugins → Local REST API and copy it into OBSIDIAN_API_KEY. Plugin v6.0 removes the markdown-patch 1.x wire format this server pins for section-targeted writes and the document map.
  • Periodic-note targets (target: { "type": "periodic" }) work across that whole range: natively on plugin v5.0.1 and earlier, and on v5.0.2 and later — which moved the /periodic/ routes out of the plugin — once the companion periodic-notes API extension is installed. Without that extension on v5.0.2+, periodic targets fail with a periodic_unsupported error naming it; obsidian://status lists the registered extensions if you want to check first. Every other target type is unaffected.
  • An MCP client that can answer an input request (elicitation). obsidian_delete_note always asks for confirmation before deleting, so a client without that support can read and write notes but cannot delete one.
  • This server defaults to http://127.0.0.1:27123 for simplicity. Enable "Non-encrypted (HTTP) Server" in the plugin settings to use it. To use the always-on HTTPS port instead, set OBSIDIAN_BASE_URL=https://127.0.0.1:27124; the plugin's self-signed cert is handled by OBSIDIAN_VERIFY_SSL=false (the default), which relaxes verification for this server's requests to that endpoint only.

Installation

  1. Clone the repository:

    sh
    git clone https://github.com/cyanheads/obsidian-mcp-server.git
  2. Navigate into the directory:

    sh
    cd obsidian-mcp-server
  3. Install dependencies:

    sh
    bun install
  4. Configure environment:

    sh
    cp .env.example .env
    # edit .env and set OBSIDIAN_API_KEY

Configuration

VariableDescriptionDefault
OBSIDIAN_API_KEYRequired. Bearer token for the Obsidian Local REST API plugin.—
OBSIDIAN_BASE_URLBase URL of the Local REST API plugin. Use https://127.0.0.1:27124 for the always-on HTTPS port (self-signed cert). A trailing slash is stripped at startup.http://127.0.0.1:27123
OBSIDIAN_VERIFY_SSLVerify the TLS certificate. Default false because the plugin uses a self-signed cert. The relaxation is applied per request, to an https: OBSIDIAN_BASE_URL only — every other HTTPS connection the process makes still verifies normally, on both Bun and Node.false
OBSIDIAN_REQUEST_TIMEOUT_MSPer-request timeout in milliseconds.30000
OBSIDIAN_ENABLE_COMMANDSOpt-in flag for the command-palette pair (obsidian_list_commands + obsidian_execute_command). Off by default — Obsidian commands are opaque and can be destructive.false
OBSIDIAN_READ_PATHSComma-separated vault-relative folder allowlist for read operations. Prefix-based with implicit recursion; case-insensitive; trailing slashes normalized. Unset = full vault. Write paths are implicitly readable.unset
OBSIDIAN_WRITE_PATHSComma-separated vault-relative folder allowlist for write operations. Same syntax as OBSIDIAN_READ_PATHS. Unset = full vault.unset
OBSIDIAN_READ_ONLYGlobal kill switch. When true, denies every write regardless of OBSIDIAN_WRITE_PATHS, and suppresses the OBSIDIAN_ENABLE_COMMANDS pair (commands can mutate).false
OBSIDIAN_OMNISEARCH_URLOverride URL for the Omnisearch plugin's HTTP server. When unset, derives from OBSIDIAN_BASE_URL host with port 51361 (falling back to http://localhost:51361). Probed once at startup — if reachable, the omnisearch mode is added to obsidian_search_notes; otherwise it's omitted from the tool schema. Restart the server to re-probe.derived
MCP_TRANSPORT_TYPETransport: stdio or http.stdio
MCP_HTTP_HOSTHost for the HTTP server.127.0.0.1
MCP_HTTP_PORTPort for the HTTP server.3010
MCP_HTTP_ENDPOINT_PATHEndpoint path for the JSON-RPC handler./mcp
MCP_SESSION_MODESession handling for the HTTP transport: stateless, stateful, or auto. Defaults to stateful here — obsidian_delete_note confirms via an elicitation round, and under stateless a 2025-era client's round is refused (client_capability_missing).stateful
MCP_PUBLIC_URLPublic origin override for TLS-terminating reverse-proxy deployments (landing page, Server Card, RFC 9728 metadata).unset
MCP_AUTH_MODEAuth mode: none, jwt, or oauth.none
MCP_AUTH_SECRET_KEYRequired when MCP_AUTH_MODE=jwt. ≥32-char shared secret used to verify incoming JWTs.—
MCP_AUTH_DISABLE_SCOPE_CHECKSWhen true, bypasses per-tool scope enforcement after the auth-context presence check. Token signature, audience, issuer, and expiry validation remain intact. Use only when a custom claim can't be injected and combine with OBSIDIAN_READ_PATHS / OBSIDIAN_WRITE_PATHS / OBSIDIAN_READ_ONLY for access control. A WARNING is logged at startup whenever the bypass is active.false
MCP_LOG_LEVELLog level (RFC 5424).info
LOGS_DIRDirectory for log files (Node.js only).<project-root>/logs
OTEL_ENABLEDEnable OpenTelemetry instrumentation (spans, metrics, completion logs).false

See .env.example for the full list of optional overrides.

Running the server

Local development

  • Build and run the production version:

    sh
    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
  • Run checks and tests:

    sh
    bun run devcheck   # Lint, format, typecheck, security, changelog sync
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec

Docker

sh
docker build -t obsidian-mcp-server .
docker run --rm -e OBSIDIAN_API_KEY=your-key -p 3010:3010 obsidian-mcp-server

The Dockerfile defaults to HTTP transport, stateful session mode (required for the obsidian_delete_note confirmation round), and logs to /var/log/obsidian-mcp-server. Point OBSIDIAN_BASE_URL at http://host.docker.internal:27123 (Docker Desktop) or run with --network host (Linux) so the container reaches the plugin on your host. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.

The image binds to 0.0.0.0 inside the container (required for Docker port mapping). For any deployment reachable beyond your own machine, set MCP_AUTH_MODE=jwt (with MCP_AUTH_SECRET_KEY) or oauth — otherwise the listener forwards your OBSIDIAN_API_KEY to the vault on behalf of every caller.

Project structure

DirectoryPurpose
src/index.tscreateApp() entry point — registers tools/resources and inits the Obsidian service.
src/configServer-specific environment variable parsing (OBSIDIAN_*) with Zod.
src/services/obsidianLocal REST API client, frontmatter operations, section extractor, domain types.
src/mcp-server/toolsTool definitions (*.tool.ts) and shared input schemas.
src/mcp-server/resourcesResource definitions (*.resource.ts).
src/mcp-server/promptsPrompt definitions (currently empty — CRUD/search shape doesn't benefit from a structured template).
tests/Vitest tests mirroring src/.
docs/Upstream OpenAPI spec for the Local REST API plugin and the generated tree.md.
changelog/Per-version release notes; CHANGELOG.md is the regenerated rollup.

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic
  • Use ctx.log for request-scoped logging, ctx.state for tenant-scoped storage
  • Register new tools and resources via the barrels in src/mcp-server/*/definitions/index.ts
  • Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields

Contributing

Bugs, feature requests, and documentation gaps belong in an issue — see CONTRIBUTING.md for what makes one actionable, and CODE_OF_CONDUCT.md for how we work together. Security reports go through SECURITY.md, never a public issue.

Run checks and tests before submitting:

sh
bun run devcheck
bun run test

License

Apache-2.0 — see LICENSE for details.

Installation

TypingMind
Prerequisites:

Node.js 18+

{
  "mcpServers": {
    "obsidian-mcp-server": {
      "command": "npx",
      "args": [
        "obsidian-mcp-server"
      ],
      "env": {
        "OBSIDIAN_API_KEY": "YOUR_API_KEY_FROM_OBSIDIAN_PLUGIN",
        "OBSIDIAN_BASE_URL": "http://127.0.0.1:27123",
        "OBSIDIAN_VERIFY_SSL": "false",
        "OBSIDIAN_ENABLE_CACHE": "true"
      }
    }
  }
}

Use Obsidian Vault MCP with multiple AI models

TypingMind connects MCP tools at the workspace level, so once Obsidian Vault is connected, you can use it with different AI models in TypingMind instead of setting it up separately for each model. This MCP runs locally through the TypingMind MCP connector on your device.

Setup guide to use the local connector

Use this when the MCP server needs access to local files, apps, or private resources on your computer.

1

Open the MCP settings

In TypingMind, go to Settings, Advanced Settings, then Model Context Protocol and choose Setup Connector.

  1. Open TypingMind in your browser.
  2. Click the Settings icon.
  3. Go to Advanced Settings.
  4. Open the Model Context Protocol section.
  5. Click Setup Connector and choose This Device.
TypingMind MCP connector setup screen with This Device selected
2

Run the connector command

Choose This Device, copy the command from TypingMind, and run it in Terminal. Keep the process running while you use MCP.

  1. Copy the setup command shown by TypingMind.
  2. Open Terminal on macOS or Windows Terminal on Windows.
  3. Paste and run the command.
  4. Approve the package install if Terminal asks you to proceed.
  5. Keep the Terminal window running while using MCP tools.
3

Add Obsidian Vault as a server

When the connector status is Ready, click Edit Servers and paste the MCP server configuration.

  1. Wait until the connector status shows Ready.
  2. Click Edit Servers.
  3. Paste the Obsidian Vault MCP server configuration.
  4. Save the server list.
  5. Refresh if you want to confirm the connector is still ready.
TypingMind MCP settings showing active server and Edit Servers button
{
  "mcpServers": {
    "obsidian-vault": {
      "command": "npx",
      "args": [
        "-y",
        "obsidian-mcp-server"
      ]
    }
  }
}
4

Use it across models

Save the server list, open Plugins, enable the Obsidian Vault MCP tools, then select any supported AI model in TypingMind and use the tools in chat or assign them to an AI agent.

  1. Open the Plugins page in TypingMind.
  2. Enable the Obsidian Vault MCP tools.
  3. Start a chat and choose the AI model you want to use.
  4. Use the MCP tools in chat or assign them to an AI agent.
  5. Switch to another AI model whenever needed without reconnecting MCP.
TypingMind chat using enabled MCP tools with a selected AI model
Can you use Obsidian Vault to help me with this task?
Obsidian Vault
Sure. I read it.
Here is what I found using Obsidian Vault.

Frequently asked questions

What is the Obsidian Vault MCP server used for?

Obsidian Vault is an MCP server that lets compatible AI clients connect to external tools and context. In TypingMind, you can add this MCP server once and make its tools available in your AI workspace.

Can I use Obsidian Vault MCP with multiple AI models in TypingMind?

Yes. TypingMind connects MCP tools at the workspace level, so you can use Obsidian Vault with different AI models such as Claude, ChatGPT, Gemini, or other models you have configured in TypingMind without setting up the MCP server separately for each model.

Why use Obsidian Vault MCP with TypingMind?

TypingMind is one of the best frontends for LLM chat because it brings multiple AI models, prompts, plugins, AI agents, API keys, and MCP tools into one workspace. With Obsidian Vault connected, you can use its MCP tools across your preferred models while keeping your chat workflow organized in TypingMind.

How do I connect Obsidian Vault MCP to TypingMind?

Obsidian Vault runs through the TypingMind local MCP connector. This is best when the MCP server needs access to local files, desktop apps, command-line tools, or private resources on your computer.

What tools does Obsidian Vault MCP provide in TypingMind?

Obsidian Vault exposes MCP capabilities that can be enabled from the TypingMind Plugins page and used in chat or assigned to AI agents.

Do I need to share my API keys with TypingMind to use Obsidian Vault MCP?

No. TypingMind is local-first and lets you keep your model providers, API keys, prompts, and MCP configuration under your control. If Obsidian Vault requires authentication, add the required headers, OAuth settings, or local configuration for that MCP server when you create the connection.

Related MCP Servers

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇