Obsidian Remote MCP Server
You can manage and analyze an Obsidian vault through 33 schema-defined tools covering files, notes, search, daily notes, metadata, tasks, links, tags, and bases.
Inspect vault metadata, list folders/files recursively, and get file details.
Read notes and create, append, prepend, update, move/rename, or delete/trash notes with optional revision checks.
Search vault text, get contextual search results, find notes by query/tag/folder/property, and review recent changes.
Read and modify today's or dated daily notes.
Read, set, and remove frontmatter properties.
List tasks and toggle task completion with optional text/revision verification.
Analyze link structure: backlinks, outgoing links, orphans, unresolved links, and dead ends.
List tags with counts and retrieve notes for a specific tag.
List .base database files and query a base view.
Retrieve rich note context with configurable content, headings, backlinks, links, frontmatter, and related-note limits.
Provides strongly-typed semantic operations against an Obsidian vault, enabling AI agents to list vaults and files, read/create/append/prepend/update/patch/move/delete notes, perform full-text vault searches with context, manage daily notes, bookmarks, templates, frontmatter properties, tags, tasks (list/toggle), and knowledge-graph relationships (backlinks, outgoing links, orphans, deadends, unresolved links), as well as query .base database views and execute vault commands.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Obsidian Remote MCP Server search my Obsidian vault for notes about MCP servers"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Obsidian Remote MCP Server
Obsidian Remote MCP Server is an enterprise-grade capability runtime connecting AI assistants and agents (ChatGPT, Claude, Codex, Cursor, and Hermes Agent) to an Obsidian vault. It provides strongly-typed semantic operations, timing-safe Bearer authentication, vault path isolation, dual-transport support (stdio and Streamable HTTP/SSE), and systemd supervision for production VPS hosting.
This server is accompanied by the official companion repository: Universal Obsidian Suite (dharmikbhesaniya/obsidian-skill), which provides standardized Agent Skills, prompt rules, and pre-packaged IDE plugins for these tools.
Table of Contents
Related MCP server: mcp-obsidian
System Architecture
Internet (Remote AI Clients)
[ChatGPT / Claude / Hermes]
│
│ HTTPS / MCP (Streamable HTTP)
▼
┌─────────────────────────────────┐
│ Reverse Proxy / TLS (HTTPS) │
│ Caddy / Nginx │
│ https://mcp.domain.com │
└────────────────┬────────────────┘
│ HTTP (127.0.0.1:9435)
▼
┌─────────────────────────────────┐
│ Obsidian MCP Server │
│ │
│ • Bearer Token Authentication │
│ • Scoped Permission Matrix │
│ • Path Traversal Guard │
│ • Rate Limiting & Audit Log │
│ • Zod-validated tool inputs │
└────────────────┬────────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
Typed Tools Resources Prompts
(51 Semantic) (URI Context) (Guided Workflows)
│ │ │
└─────────────────────┼─────────────────────┘
▼
Service Layer
(Concurrency & Rules)
│
▼
Obsidian CLI Adapter
│
▼
Obsidian Desktop
(Headless via Xvfb)
│
▼
Hostinger VPS Vault
(/srv/obsidian/vault)Feature & Capability Summary
The server exposes 62 strongly-typed semantic tools (61 standard tools including sandboxed Git operations, plus an advanced CLI escape hatch gated behind ENABLE_ADVANCED_CLI=true), 7 direct read resources, and 7 guided prompts:
Tools (62 Semantic Capabilities)
Vault Domain (4 tools):
obsidian_list_vaults(multi-vault inventory with deduplication),obsidian_get_vault,obsidian_list_files(recursive traversal & extension filtering),obsidian_get_file_infoNotes Domain (8 tools):
obsidian_read_note,obsidian_create_note,obsidian_append_note,obsidian_prepend_note,obsidian_update_note,obsidian_patch_note(surgical search/replace/regex editing),obsidian_move_note,obsidian_delete_note(safe atomic trash by default)Search Domain (2 tools):
obsidian_search,obsidian_search_contextContext & Discovery Domain (3 tools):
obsidian_get_note_context(selective include budget controls),obsidian_find_notes,obsidian_recent_changesDaily Notes Domain (3 tools):
obsidian_read_daily_note,obsidian_append_daily_note,obsidian_prepend_daily_noteBookmarks Domain (2 tools):
obsidian_list_bookmarks,obsidian_create_bookmarkOutline & Structure Domain (2 tools):
obsidian_get_outline,obsidian_outline(hierarchical heading tree with line offsets)Aliases Domain (2 tools):
obsidian_list_aliases,obsidian_get_aliases(frontmatter alias resolution)Templates Domain (2 tools):
obsidian_list_templates,obsidian_read_template(variable resolution for{{title}},{{date}},{{time}})Metrics & Stats Domain (1 tool):
obsidian_word_count(words, characters, sentences, paragraphs, reading time)Random & Unique Notes (2 tools):
obsidian_random_note,obsidian_create_unique_note(Zettelkasten style with entropy and guaranteed collision prevention)Desktop Integration (2 tools):
obsidian_open_note,obsidian_open_in_app(desktop app launch with accurate execution reporting and URI fallback)Plugins & Customization (2 tools):
obsidian_list_plugins,obsidian_list_snippetsCommands Domain (2 tools):
obsidian_list_commands,obsidian_execute_commandProperties Domain (4 tools):
obsidian_get_properties,obsidian_get_property,obsidian_set_property,obsidian_remove_propertyTasks Domain (2 tools):
obsidian_list_tasks,obsidian_toggle_taskKnowledge Graph Domain (6 tools):
obsidian_get_backlinks,obsidian_get_links,obsidian_get_link_path,obsidian_get_orphans,obsidian_get_unresolved_links,obsidian_get_deadendsTags & Bases Domain (4 tools):
obsidian_get_tags,obsidian_get_tag_notes,obsidian_list_bases,obsidian_query_baseGit Subsystem Domain (8 tools):
obsidian_git_status(working tree and branch inspection),obsidian_git_diff(staged or unstaged unified diffs),obsidian_git_log(structured commit history),obsidian_git_add(safe path staging),obsidian_git_commit(atomic commit creation),obsidian_git_push(upstream remote push),obsidian_git_pull(upstream remote fetch and merge),obsidian_git_exec(guarded allowlisted Git command execution)Guarded Escape Hatch (1 tool):
obsidian_cli(strictly allowlisted through central command registry, disabled by default, gated byENABLE_ADVANCED_CLI=trueandvault:developerscope)
Resources (7 Direct Read Contexts)
obsidian://vault: Vault statistics, file count, and connectivity state.obsidian://daily/today: Content of today's daily note.obsidian://tasks: Vault-wide pending task inventory.obsidian://tags: Inventory of all tags and occurrence frequencies.obsidian://note/{path}: Read-only access to a specific note.obsidian://folder/{path}: Directory listing for a vault folder.obsidian://base/{path}: Schema and view definitions of a.basefile.
Prompts (7 Standard Workflows)
daily-work-report: Synthesizes today's daily note and tasks into an executive summary.knowledge-capture: Extracts reusable lessons and decisions from meeting/daily notes into permanent knowledge notes.weekly-review: Aggregates the last 7 daily notes and active project milestones.monthly-review: Conducts a broad retrospective across deliverables and patterns.project-review: Evaluates project status, open tasks, and incoming backlinks.meeting-summary: Extracts action items and decision records from raw meeting notes.vault-health-check: Scans for broken wikilinks and orphan notes.
Companion Agent Skills & Plugins Suite
For complete instruction sets, prompts, and IDE rule definitions that empower AI coding agents to use these MCP tools autonomously, see the official companion repository:
👉 Universal Obsidian Suite (dharmikbhesaniya/obsidian-skill)
What the Companion Suite Provides
obsidian-mcpSkill: Clear operational instructions, tool schemas, and best practices for AI agents executing these 62 semantic tools.Claude Code & Antigravity Plugins: Discoverable plugins (
.claude-plugin/) and pre-configured.mcp.jsondefinitions to register this MCP server automatically.Cursor Rules & MDC: Ready-to-copy
.cursorrulesand.cursor/rules/obsidian.mdcfiles.OpenAI & ChatGPT Tools: Pre-built JSON function definitions (function_tools.json).
Complementary CLI & Markdown Skills: Official Obsidian CLI commands, Obsidian Flavored Markdown (OFM), database Bases (
.base), and JSON Canvas (.canvas) specifications.
Access Control & Multi-Vault Architecture
Access control in the Obsidian MCP Server is an enterprise authorization framework that isolates knowledge vaults, restricts filesystem operations, and provides deterministic multi-vault access across all AI clients and agent runtimes.
The architecture eliminates directory escape vulnerabilities and guarantees that AI assistants operate strictly within authorized vaults.
flowchart TD
AI["AI Client (ChatGPT / Claude / Cursor / Antigravity)"]
Router["Multi-Vault Router & PathGuard"]
subgraph Storage ["Mounted Storage"]
V1["Primary Vault (read/write)"]
V2["Personal Vault (read-only)"]
Auto["Auto-Discovered Vaults (Configured Default Mode)"]
end
AI -->|"1. obsidian_list_vaults"| Router
AI -->|"2. Tool Call { vault: 'name', ... }"| Router
Router -->|"Permitted (Scope Check Passed)"| V1
Router -->|"Permitted Read / Blocked Write (403)"| V2
Router -->|"Dynamic Detection on Query"| AutoCore Access Control Principles
Vault Sandboxing (
PathGuard): Every registered vault possesses an isolated filesystem boundary. AI agents cannot traverse directories (../), escape to host filesystems, or follow external symlinks.Granular Permissions (
read/writevs.read-only): Vaults can be individually designated with full mutation rights or locked into immutable query-only modes.Dynamic Zero-Downtime Auto-Discovery: Placing a new folder containing
.obsidianinto the root vault directory registers the vault immediately without container restarts or configuration updates.Safety Defaults for Unlisted Vaults: When parent folders are scanned, unlisted vaults adopt the access mode specified by
OBSIDIAN_AUTO_DISCOVERY_MODE(defaulting to saferead-onlyor agileread/write).
Capability Scopes Matrix
Tool Category | Required Scope | Permitted in Read-Only | Operations Included |
Search & Discovery |
| Yes |
|
Note Consumption |
| Yes |
|
Structure & Graph |
| Yes |
|
Content Mutation |
| Blocked (403) |
|
Metadata Editing |
| Blocked (403) |
|
File Deletion |
| Blocked (403) |
|
Git Read Operations |
| Yes |
|
Git Mutation & Sync |
| Blocked (403) |
|
Git Advanced |
| Blocked (403) | Guarded allowlisted subcommand execution via |
Desktop CLI |
| Blocked (403) | Allowlisted CLI process executions via |
Universal AI Client Protocol
All AI clients operate through a standardized two-phase interaction lifecycle:
Phase 1: Vault Inventory Discovery
When an AI assistant initializes or begins a query, it executes obsidian_list_vaults to discover available vaults and their active permissions:
{
"summary": "Found 2 configured vault(s): [work-vault, research-vault]. Active default vault: 'work-vault'.",
"defaultVault": "work-vault",
"totalVaults": 2,
"vaults": [
{
"name": "work-vault",
"path": "/vault/work-vault",
"accessMode": "read/write",
"readOnly": false,
"totalFiles": 1240,
"markdownFiles": 1180,
"topLevelFolders": ["Projects", "Meetings", "Roadmap"]
},
{
"name": "research-vault",
"path": "/vault/research-vault",
"accessMode": "read-only",
"readOnly": true,
"totalFiles": 450,
"markdownFiles": 430,
"topLevelFolders": ["Archive", "Papers", "Readings"]
}
]
}Phase 2: Targeted Execution & Default Fallback
Targeted Operations: The AI client passes the
"vault"parameter in any tool call (e.g.,obsidian_read_note({ "vault": "research-vault", "path": "Papers/Overview.md" })).Default Fallback: If the user or AI omits the
"vault"argument, the server automatically routes the operation toOBSIDIAN_DEFAULT_VAULT.Deterministic 403 Rejection: If an AI attempts to modify a read-only vault, the server responds with a clear
403 Forbiddenerror payload:{ "error": { "code": "FORBIDDEN", "message": "Tool 'obsidian_create_note' requires scope 'vault:write', but vault 'research-vault' is read-only or restricted to: [vault:read]" } }This signals the AI assistant that the action was rejected by security policy, preventing repetitive mutation loops.
Smart Alias Resolution & Ambiguity Protection
To provide natural collaboration without requiring manual configuration for every auto-discovered vault, the server features an intelligent alias resolution and ambiguity protection layer:
Automatic Colloquial Aliases: When vault names are long (e.g.,
dharmik-professional-obsidian-vaultandobsidian-daily-update-report), users naturally refer to them with conversational keywords (e.g., "daily", "daily vault", "daily update", "professional", or "dharmik"). The server tokenizes names, strips stop words (obsidian,vault,notes,my,the), and generates recognized alias combinations dynamically.Explicit Custom Aliases: Configured via
OBSIDIAN_VAULT_ALIASES(e.g.,daily=obsidian-daily-update-report,work=dharmik-professional-obsidian-vaultor JSON format).Ambiguity Protection (
AMBIGUOUS_VAULT): If an input is ambiguous across multiple vaults (e.g. generic references like"vault"or"obsidian"matching multiple vaults), the server returns anAMBIGUOUS_VAULTerror payload containing all matching candidates:{ "error": { "code": "AMBIGUOUS_VAULT", "message": "Ambiguous vault reference 'obsidian'. Multiple vaults matched: [dharmik-professional-obsidian-vault, obsidian-daily-update-report]. Please specify the exact vault name or choose from the candidates.", "details": { "query": "obsidian", "candidates": [ "dharmik-professional-obsidian-vault", "obsidian-daily-update-report" ] } } }This error protocol informs the AI assistant (ChatGPT, Claude, Cursor) that multiple candidates exist, prompting the AI to request clarification from the user rather than guessing or modifying the wrong vault.
Sandboxed Vault Git Integration
The Sandboxed Vault Git Subsystem provides version control automation directly inside authorized Obsidian repositories. It enables AI coding assistants and autonomous agents to inspect repository status, review unified diffs, stage files, create atomic commits, and synchronize with upstream remotes within strict containment boundaries.
The architecture ensures that version control workflows remain isolated to the designated vault path, preventing command injection, unauthorized directory escape, and credential leakage.
flowchart TD
Client["AI Assistant (Claude / ChatGPT / Cursor)"] --> Tools{"Git Semantic Tools"}
Tools -->|"obsidian_git_status / diff / log"| ReadCheck["Scope: vault:read"]
Tools -->|"obsidian_git_add / commit / push / pull"| WriteCheck["Scope: vault:write & Mode != :ro"]
Tools -->|"obsidian_git_exec"| DevCheck["Scope: vault:developer & Allowlist Validated"]
ReadCheck --> PathGuard["PathGuard (Boundary & RelPath Validation)"]
WriteCheck --> PathGuard
DevCheck --> Denylist["Argument Denylist Filter"]
Denylist --> PathGuard
PathGuard --> GitAdapter["GitCliAdapter (execFile)"]
GitAdapter --> EnvGuard["Ceiling Directory & CWD Injection"]
EnvGuard --> Exec["git binary (Isolated Child Process)"]
Exec --> OutputFilter["Credential & Token Redaction"]
OutputFilter --> Response["Clean JSON Result to Client"]Security & Sandboxing Guarantees
Root Boundary Containment:
All Git subcommands execute with the working directory locked tocwd: vault.root. The process cannot wander into external parent directories or adjacent sibling folders.Ceiling Directory Trapping:
The runtime automatically injectsGIT_CEILING_DIRECTORIES: path.dirname(vault.root). If a vault does not contain an initialized.gitrepository, Git halts immediately instead of ascending into a parent workspace or system folder.Shell Injection Immunity:
Subprocess invocations bypass the system shell by utilizing Node.jsexecFile("git", ...)directly. Metacharacters, command chaining operators, and shell expansions (|,;,&&,$()) are treated as literal arguments.Dangerous Argument Denylist:
The system blocks flags that execute commands or redirect repository boundaries. Banned arguments include--upload-pack,--receive-pack, arbitrary configuration injection (-c <key>=<value>), and path redirection flags (--work-tree,--git-dir).Read-Only Mode Isolation (
:ro):
Vaults registered with the:roflag permit historical queries (status,diff,log) while deterministically blocking modifications (add,commit,push,pull,exec) with a403 Forbiddenerror.PathGuard Relative Path Sanitization:
All path parameters supplied to staging and diff routines undergo strict normalization. Attempts to reference parent paths (such as../../etc/passwd) are rejected withPATH_INVALIDbefore reaching the Git executable.Credential and Token Redaction:
Output streams pass through a credential masking filter that replaces embedded authentication tokens and user passwords in remote URLs (https://***@github.com) before returning data to the AI assistant.
Git Tools Reference Table
Tool Name | Required Scope | Primary Operation | Key Parameters |
|
| Inspect branch state, tracking branch, staged, modified, and untracked files |
|
|
| Produce unified diffs for uncommitted or staged changes |
|
|
| Retrieve structured commit history with hashes, authors, dates, and messages |
|
|
| Stage modified or newly created markdown notes for commit |
|
|
| Author an atomic Git commit with a descriptive message and optional author |
|
|
| Push committed local revisions to an upstream remote repository |
|
|
| Fetch and merge changes from an upstream remote repository |
|
|
| Execute allowlisted low-level Git commands within vault boundary |
|
Tool Invocation Examples
1. Inspecting Working Tree Status (obsidian_git_status)
{
"vault": "dharmik-professional-obsidian-vault"
}Structured Response:
{
"initialized": true,
"branch": "main",
"clean": false,
"staged": [
{ "path": "Projects/Enterprise Architecture.md", "status": "modified" }
],
"unstaged": [
{ "path": "Daily/2026-11-02.md", "status": "modified" }
],
"untracked": [
"Meeting Notes/Q4 Review.md"
]
}2. Inspecting Working Tree Diffs (obsidian_git_diff)
{
"file": "Projects/Enterprise Architecture.md",
"staged": true,
"vault": "professional"
}Structured Response:
{
"file": "Projects/Enterprise Architecture.md",
"staged": true,
"diff": "diff --git a/Projects/Enterprise Architecture.md b/Projects/Enterprise Architecture.md\n--- a/Projects/Enterprise Architecture.md\n+++ b/Projects/Enterprise Architecture.md\n@@ -12,3 +12,4 @@\n- Status: In Progress\n+ Status: Completed"
}3. Staging and Creating an Atomic Commit (obsidian_git_add & obsidian_git_commit)
// Step 1: Stage specific relative files
{
"files": ["Projects/Enterprise Architecture.md", "Daily/2026-11-02.md"],
"vault": "professional"
}
// Step 2: Author atomic commit
{
"message": "docs: update enterprise architecture review and daily summary",
"author_name": "Antigravity Agent",
"author_email": "agent@enterprise.local",
"vault": "professional"
}Structured Response:
{
"success": true,
"message": "Commit created successfully.",
"output": "[main 4e8b1d2] docs: update enterprise architecture review and daily summary\n 2 files changed, 14 insertions(+), 3 deletions(-)"
}4. Synchronizing with Upstream Remote (obsidian_git_push)
{
"remote": "origin",
"branch": "main",
"vault": "professional"
}Structured Response:
{
"success": true,
"remote": "origin",
"branch": "main",
"output": "To github.com:org/vault.git\n 3c7a91f..4e8b1d2 main -> main"
}Remote Server Synchronization Setup
For remote production environments such as headless VPS nodes or Docker containers, upstream synchronization requires credential configuration on the host:
SSH Deploy Keys (Recommended):
Generate a dedicated ED25519 deploy key for the service user and grant read/write access in your repository settings:ssh-keygen -t ed25519 -C "obsidian-mcp@server" -f ~/.ssh/id_ed25519Personal Access Token via HTTPS:
Configure the upstream remote URL with a personal access token. Any sensitive token embedded in the URL is masked automatically in tool responses:git remote set-url origin https://ghp_SECRET_TOKEN@github.com/organization/vault.git
Error Handling Protocol
Error Code | HTTP Status | Description |
|
| The specified vault directory is not an initialized Git repository (missing |
|
| The underlying Git process returned a non-zero exit code (e.g. merge conflict, network timeout). |
|
| Mutation attempted on a |
|
| File path argument attempts directory escape outside the designated vault boundary. |
Multi-Client Integration Guide
The server supports all primary AI client environments with uniform access control:
1. ChatGPT (OpenAI Custom MCP Plugin)
In ChatGPT → Plugins → Add custom MCP server:
Server URL:
https://<domain>/s/<token>/mcpAuthentication:
No authentication(token is verified via the secret path)Icon: Use icon-chatgpt-256.png (256x256 PNG, 7.8 KB).
2. Claude Desktop & Claude Code
In
claude_desktop_config.json:{ "mcpServers": { "obsidian": { "url": "https://<domain>/mcp", "headers": { "Authorization": "Bearer <your_token>" } } } }
3. Cursor & Windsurf IDE
In
.cursor/mcp.json:{ "mcpServers": { "obsidian": { "command": "node", "args": ["/absolute/path/to/obsidian-mcp/dist/index.js"], "env": { "OBSIDIAN_VAULT_PATH": "/path/to/vault", "OBSIDIAN_AUTO_DISCOVERY_MODE": "read-only" } } } }
4. Google Antigravity & Gemini CLI
Declared in your agent configuration or loaded lazily:
{ "mcpServers": { "obsidian": { "url": "https://<domain>/mcp", "headers": { "Authorization": "Bearer <your_token>" } } } }
5. Open-Source Clients (LibreChat, Cline, Continue.dev)
Connect using Streamable HTTP (
https://<domain>/mcp) or Server-Sent Events (https://<domain>/sse) with standard Bearer authorization headers.
Environment Variables & Configuration Reference
The Obsidian MCP Server is configured entirely via environment variables (in your .env file or within your AI client's MCP configuration).
Environment Variables Overview
Variable | Type | Default | Description |
| string | None | Absolute path to a single target vault or parent folder containing multiple auto-discovered vaults (e.g. |
| string / JSON | None | Multi-vault custom inventory. Accepts comma-separated |
| string / JSON | None | Custom short aliases mapping colloquial names to full vault names (e.g. |
| string | First vault | Name of the primary vault used when tool calls omit an explicit |
| boolean |
| When |
| boolean |
| Default access mode for auto-discovered vaults. Set |
| enum |
| Access mode for auto-discovered vaults: |
| string | None | Comma-separated list of custom vault names to lock as read-only (e.g. |
| string / JSON | None | Per-vault scopes (e.g. |
| string |
| System path to the official Obsidian desktop binary (e.g. |
| boolean |
| Enables cryptographic credential checks. Required ( |
| string | None | Plain-text secret passkey. The server computes a SHA-256 hash internally for verification. |
| string | None | Hexadecimal SHA-256 hash of your Bearer access token (for zero-trust setups where raw keys are never placed in configs). |
| boolean |
| Safety toggle. When |
| string | All | Comma-separated list of granted capabilities: |
| enum |
| Transport mechanism: |
| number |
| Network port when running over HTTP transport. |
| string |
| Network interface binding. Set to |
| number |
| Maximum allowed tool invocations per minute per client session to prevent runaway AI loops. |
| number |
| Timeout threshold (in milliseconds) before CLI subsystem commands are aborted. |
| number |
| Maximum results returned by full-text and semantic search routines. |
| boolean |
| Allows deletion tools. When enabled, |
| boolean |
| Gated escape-hatch exposing raw |
| boolean |
| Master toggle registering Git tools ( |
| string |
| System binary name or absolute path to the Git executable. |
| string | None | Fallback commit author name when not configured in local vault repository. |
| string | None | Fallback commit author email when not configured in local vault repository. |
| string |
| Default remote target for push and pull synchronization. |
| number |
| Process execution timeout (milliseconds) for Git operations. |
| boolean |
| Emits structured JSON audit records to standard error ( |
Architectural Importance of Variables
Vault Sandboxing (
OBSIDIAN_VAULT_PATH&OBSIDIAN_VAULTS)
The server implements a strict path-containment engine (PathGuard). By defining vault boundaries, the server prevents path traversal (../), symlink escapes, and null-byte injection attacks. AI agents are contained entirely within authorized vault folders.Timing-Safe Credential Verification (
AUTH_ENABLED&AUTH_TOKEN/BEARER_TOKEN_HASH)
When exposed over HTTP or shared environments, authentication ensures only authorized callers interact with private notes. Token comparisons usecrypto.timingSafeEqualover SHA-256 digests, eliminating side-channel timing analysis. In production HTTP mode, disabling auth triggers a startup safety violation.Immutable Guardrail (
READ_ONLY)
For read-only assistants, research agents, or untrusted models, settingREAD_ONLY=trueimmediately strips write, delete, and execution scopes. Even if an AI attempts to callobsidian_create_noteorobsidian_delete_note, the request is denied with a403 Forbiddenresponse.Blast Radius Control (
SCOPES)
Scopes provide least-privilege access. An agent tasked with drafting daily logs can be assignedvault:read,vault:writewithout grantingvault:delete(preventing note loss) orvault:developer(preventing CLI access).Session Safety & Loop Prevention (
RATE_LIMIT_PER_MINUTE)
Autonomous AI agents occasionally enter repetitive retry loops. The sliding-window rate limiter prevents CPU exhaustion, excessive disk I/O, or Obsidian UI unresponsiveness.
Managing Variables Across Deployment Environments
The Obsidian MCP Server loads configuration from standard operating system environment variables, with native .env loading support via dotenv. Depending on the runtime platform, environment variables can be declared through configuration files, command-line arguments, container definitions, or service supervisors.
1. Standard .env File Configuration
When executing directly with Node.js or developing locally, copy .env.example to .env in the server root. Variables declared in .env load automatically on startup:
# Vault Discovery and Permissions
OBSIDIAN_VAULT_PATH=/srv/obsidian/vault
OBSIDIAN_VAULTS=dharmik-professional-obsidian-vault=/vault/dharmik-professional-obsidian-vault:rw,obsidian-daily-update-report=/vault/obsidian-daily-update-report:rw
OBSIDIAN_VAULT_ALIASES=daily=obsidian-daily-update-report,professional=dharmik-professional-obsidian-vault
OBSIDIAN_DEFAULT_VAULT=dharmik-professional-obsidian-vault
OBSIDIAN_AUTO_DISCOVERY_MODE=read/write
# Transport and Network Binding
MCP_TRANSPORT=http
PORT=9435
HOST=127.0.0.1
# Security and Credentials
AUTH_ENABLED=true
AUTH_TOKEN=your-32-byte-hex-token2. Docker Run CLI Deployment
When running via docker run, pass environment variables using individual -e flags or pass an environment file using --env-file:
docker run -d \
--name obsidian-mcp \
--restart unless-stopped \
-p 9435:9435 \
-e PORT=9435 \
-e AUTH_ENABLED=true \
-e AUTH_TOKEN="your-secure-token" \
-e OBSIDIAN_VAULT_PATH="/vault" \
-e OBSIDIAN_AUTO_DISCOVERY_MODE="read/write" \
-e OBSIDIAN_VAULT_ALIASES="daily=obsidian-daily-update-report,pro=dharmik-professional-obsidian-vault" \
-e OBSIDIAN_DEFAULT_VAULT="dharmik-professional-obsidian-vault" \
-v "/root/obsidian-vault:/vault" \
obsidian-remote-mcp:latest3. Docker Compose Deployment
Docker Compose centralizes variable management by referencing local environment files or declaring inline key-value pairs in docker-compose.yml:
services:
obsidian-mcp:
image: obsidian-remote-mcp:latest
container_name: obsidian-mcp
restart: unless-stopped
ports:
- "9435:9435"
environment:
PORT: 9435
AUTH_ENABLED: "true"
AUTH_TOKEN: "${AUTH_TOKEN}"
OBSIDIAN_VAULT_PATH: "/vault"
OBSIDIAN_AUTO_DISCOVERY_MODE: "read/write"
OBSIDIAN_VAULT_ALIASES: "daily=obsidian-daily-update-report,pro=dharmik-professional-obsidian-vault"
OBSIDIAN_DEFAULT_VAULT: "dharmik-professional-obsidian-vault"
volumes:
- /root/obsidian-vault:/vault4. Systemd Service Configuration (Linux VPS)
For production Linux VPS deployments running directly on Ubuntu/Debian, store environment variables in a protected file such as /etc/obsidian-mcp/.env with 600 permissions and reference it via EnvironmentFile:
# /etc/systemd/system/obsidian-mcp.service
[Unit]
Description=Obsidian Remote MCP Server
After=network.target obsidian-xvfb.service
[Service]
Type=simple
User=obsidian
Group=obsidian
WorkingDirectory=/opt/obsidian-mcp
EnvironmentFile=/etc/obsidian-mcp/.env
ExecStart=/usr/bin/node /opt/obsidian-mcp/dist/index.js
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target5. Local AI Desktop Clients (Claude Desktop & Cursor IDE)
Desktop AI applications initialize the MCP server as a managed child process over stdio. Environment variables are declared inside the application's JSON configuration file:
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": ["/absolute/path/to/obsidian-mcp/dist/index.js"],
"env": {
"OBSIDIAN_VAULT_PATH": "/Users/dharmik/Documents/obsidian-vault",
"OBSIDIAN_VAULT_ALIASES": "daily=obsidian-daily-update-report,pro=dharmik-professional-obsidian-vault",
"OBSIDIAN_AUTO_DISCOVERY_MODE": "read/write",
"READ_ONLY": "false"
}
}
}
}Access Management & Security Configuration Recipes
Access control in the Obsidian MCP Server operates on a dual-tier security model: filesystem boundary enforcement via PathGuard and semantic capability validation via scoped access tokens.
Recipe 1: Granting Read-Only vs. Read/Write Access to Specific Vaults
To allow an AI assistant to modify active project notes while strictly protecting personal records from alteration, assign the :ro (read-only) or :rw (read/write) suffix to each vault declaration:
# Syntax: name=path:mode
OBSIDIAN_VAULTS="work=/vault/work-vault:rw,personal=/vault/personal-vault:ro"
OBSIDIAN_DEFAULT_VAULT="work"When an assistant executes obsidian_create_note or obsidian_update_note targeting personal-vault, the server halts the operation with a deterministic error:
{
"error": {
"code": "FORBIDDEN",
"message": "Vault 'personal' is configured as read-only. Tool 'obsidian_create_note' requires scope 'vault:write', which is not permitted on this vault."
}
}Recipe 2: Safe Auto-Discovery for Enterprise Repositories
When hosting multiple folders inside a parent directory (e.g. /vault), administrators can enable dynamic vault detection while locking newly discovered vaults into read-only mode by default:
OBSIDIAN_VAULT_PATH="/vault"
OBSIDIAN_ENABLE_AUTO_DISCOVERY="true"
OBSIDIAN_AUTO_DISCOVERY_MODE="read-only"
OBSIDIAN_VAULTS="approved-editor=/vault/approved-editor:rw"Under this configuration:
approved-editorretains authorized write permissions.Any new vault created inside
/vaultis automatically discovered by AI clients without server restarts, but remains restricted tovault:readoperations.
Recipe 3: Dual Read/Write Setup with Natural Colloquial Aliases
For environments where users frequently switch between long vault names (such as dharmik-professional-obsidian-vault and obsidian-daily-update-report), configure both repositories with full read/write access and short conversational aliases:
OBSIDIAN_VAULT_PATH="/vault"
OBSIDIAN_AUTO_DISCOVERY_MODE="read/write"
OBSIDIAN_VAULT_ALIASES="daily=obsidian-daily-update-report,pro=dharmik-professional-obsidian-vault,work=dharmik-professional-obsidian-vault"
OBSIDIAN_DEFAULT_VAULT="dharmik-professional-obsidian-vault"The user can prompt ChatGPT or Claude using natural terminology:
"Add standup notes to my daily vault" → routes directly to
obsidian-daily-update-report."Read my system architecture note in professional" → routes directly to
dharmik-professional-obsidian-vault.
Recipe 4: Ambiguity Trapping Across Similar Vault Names
When multiple vaults share common words (such as "vault" or "obsidian"), the server rejects ambiguous calls using AMBIGUOUS_VAULT rather than guessing a target:
{
"error": {
"code": "AMBIGUOUS_VAULT",
"message": "Ambiguous vault reference 'vault'. Multiple vaults matched: [dharmik-professional-obsidian-vault, obsidian-daily-update-report]. Please specify the exact vault name or choose from the candidates.",
"details": {
"query": "vault",
"candidates": [
"dharmik-professional-obsidian-vault",
"obsidian-daily-update-report"
]
}
}
}This response compels the AI client to stop execution and ask the user: "Did you mean dharmik-professional-obsidian-vault or obsidian-daily-update-report?", ensuring data integrity across all connected systems.
Local Development Setup
Prerequisites
Node.js: v20+ LTS
Obsidian Desktop: v1.12.0+ installed and running locally
CLI Enabled: Inside Obsidian, open Settings → Command line interface → Toggle ON
Installation & Build
# 1. Clone repository
git clone https://github.com/dharmikbhesaniya/obsidian-mcp.git
cd obsidian-mcp
# 2. Install dependencies
npm install
# 3. Create local environment configuration
cp .env.example .envEdit .env for your local path:
OBSIDIAN_VAULT_PATH=/Users/yourusername/Documents/MyVault
MCP_TRANSPORT=stdio
AUTH_ENABLED=falseBuild and test:
# Run test suite (unit, integration, and security checks)
npm test
# Build TypeScript to dist/
npm run buildRunning with Claude Desktop (stdio)
Add the server to your Claude Desktop configuration file:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
Single Vault vs. Multi-Vault Configuration
Scenario 1: Single Vault (Full Read & Write Access)
Use this setup when you have one primary vault and want your AI assistant to read notes, answer questions, draft content, and organize tags.
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": [
"/absolute/path/to/obsidian-mcp/dist/index.js"
],
"env": {
"OBSIDIAN_VAULT_PATH": "/Users/yourusername/Documents/MyVault",
"READ_ONLY": "false"
}
}
}
}Scenario 2: Single Vault (Safe Read-Only Mode)
Use this setup if you want an AI assistant to query and reference your vault without the ability to create, edit, or delete any files.
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": [
"/absolute/path/to/obsidian-mcp/dist/index.js"
],
"env": {
"OBSIDIAN_VAULT_PATH": "/Users/yourusername/Documents/MyVault",
"READ_ONLY": "true"
}
}
}
}Scenario 3: Multi-Vault with Per-Vault Permissions (e.g. Personal Read-Only, Work Read-Write)
Use this setup if you want a single AI assistant connected to multiple vaults, but want one vault to be strictly read-only (e.g. personal notes) while allowing full read-and-write on another (e.g. work projects).
Syntax A: Using :ro and :rw Suffixes (Recommended)
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": [
"/absolute/path/to/obsidian-mcp/dist/index.js"
],
"env": {
"OBSIDIAN_VAULTS": "personal=/Users/yourusername/Documents/PersonalVault:ro,work=/Users/yourusername/Documents/WorkVault:rw",
"OBSIDIAN_DEFAULT_VAULT": "work"
}
}
}
}Syntax B: Using OBSIDIAN_READ_ONLY_VAULTS
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": [
"/absolute/path/to/obsidian-mcp/dist/index.js"
],
"env": {
"OBSIDIAN_VAULTS": "personal=/Users/yourusername/Documents/PersonalVault,work=/Users/yourusername/Documents/WorkVault",
"OBSIDIAN_READ_ONLY_VAULTS": "personal",
"OBSIDIAN_DEFAULT_VAULT": "work"
}
}
}
}Syntax C: Hybrid Custom Vaults + Dynamic Auto-Discovery
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": [
"/absolute/path/to/obsidian-mcp/dist/index.js"
],
"env": {
"OBSIDIAN_VAULTS": "vip-client=/custom/external/path:rw",
"OBSIDIAN_VAULT_PATH": "/Users/yourusername/Documents/obsidian-vault",
"OBSIDIAN_AUTO_DISCOVER_READ_ONLY": "true",
"OBSIDIAN_DEFAULT_VAULT": "vip-client"
}
}
}
}How it works:
vip-clientis explicitly added with custom path and read/write privileges.Any vault inside
/Users/yourusername/Documents/obsidian-vaultis auto-discovered dynamically.OBSIDIAN_AUTO_DISCOVER_READ_ONLY: trueensures all dynamically discovered vaults default to read-only access, whilevip-clientretains full write access.
How it works:
The AI discovers both vaults via
obsidian_list_vaults, which explicitly reportsreadOnly: trueforpersonalandreadOnly: falseforwork.Reading and querying notes in
personalsucceeds normally.If the AI attempts to create, edit, patch, or delete a note targeting
personal, the server halts execution with a403 Forbiddenerror:Vault 'personal' is configured as read-only. Tool 'obsidian_create_note' requires scope 'vault:write', which is not permitted on this vault.Modifying notes in
worksucceeds with full authoring capabilities.Requests omitting the
vaultparameter automatically fall back to the default vault (work).
Scenario 4: Multi-Vault with Separate Server Blocks (Independent Permissions)
Use this setup when you want different security policies for each vault—such as allowing the AI to write to your work vault while keeping your personal vault strictly read-only.
{
"mcpServers": {
"obsidian_work": {
"command": "node",
"args": [
"/absolute/path/to/obsidian-mcp/dist/index.js"
],
"env": {
"OBSIDIAN_VAULT_PATH": "/Users/yourusername/Documents/WorkVault",
"READ_ONLY": "false"
}
},
"obsidian_personal": {
"command": "node",
"args": [
"/absolute/path/to/obsidian-mcp/dist/index.js"
],
"env": {
"OBSIDIAN_VAULT_PATH": "/Users/yourusername/Documents/PersonalVault",
"READ_ONLY": "true"
}
}
}
}Running with Cursor IDE
Add the server to Cursor's MCP configuration in ~/.cursor/mcp.json or project .cursor/mcp.json:
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": ["/absolute/path/to/obsidian-mcp/dist/index.js"],
"env": {
"OBSIDIAN_VAULT_PATH": "/absolute/path/to/your/vault",
"READ_ONLY": "false"
}
}
}
}Testing with MCP Inspector
Test tools interactively in the browser without an external client:
npx @modelcontextprotocol/inspector@latest node dist/index.jsProduction VPS Setup (Hostinger / Ubuntu / Debian)
This guide walks through deploying the MCP server on a remote Linux VPS (e.g. Hostinger Ubuntu 24.04 LTS or Debian 12).
Step 1: Install Operating System Dependencies
Obsidian Desktop on Linux requires a virtual frame buffer (xvfb) when running in headless server environments:
sudo apt update
sudo apt install -y xvfb libnotify4 libnss3 libasound2 libgbm1 libsecret-1-0 nodejs npm caddyVerify Node.js is v20+:
node -vStep 2: Create Dedicated Service Account
Run all Obsidian and MCP processes under a restricted service account:
# Create service user
sudo useradd -r -m -d /opt/obsidian -s /bin/bash obsidian
# Create application and vault directories
sudo mkdir -p /srv/obsidian/vault
sudo mkdir -p /etc/obsidian-mcp
sudo mkdir -p /opt/obsidian-mcp
# Assign ownership
sudo chown -R obsidian:obsidian /srv/obsidian
sudo chown -R obsidian:obsidian /opt/obsidian-mcpStep 3: Install Obsidian Desktop and Enable CLI
Download and install the official Obsidian .deb package:
wget https://github.com/obsidianmd/obsidian-releases/releases/download/v1.12.0/obsidian_1.12.0_amd64.deb
sudo dpkg -i obsidian_1.12.0_amd64.deb
sudo apt install -f -yVerify the binary is available:
which obsidian
# Output: /usr/bin/obsidianStep 4: Configure Headless Display (Xvfb Service)
Copy the Xvfb systemd service file:
sudo cp deploy/systemd/obsidian-xvfb.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now obsidian-xvfb.serviceVerify that virtual display :5 is active:
sudo systemctl status obsidian-xvfb.serviceStep 5: Deploy the MCP Server
# Clone repository to deployment location
sudo -u obsidian git clone https://github.com/dharmikbhesaniya/obsidian-mcp.git /opt/obsidian-mcp
cd /opt/obsidian-mcp
# Install dependencies and compile
sudo -u obsidian npm ci
sudo -u obsidian npm run buildGenerate a secure Bearer access token:
# Generate random 32-byte secret token
TOKEN=$(openssl rand -hex 32)
echo "Your Raw Token: $TOKEN"
# Compute SHA-256 hash for configuration
TOKEN_HASH=$(echo -n "$TOKEN" | sha256sum | awk '{print $1}')
echo "Your Token Hash: $TOKEN_HASH"Configure /etc/obsidian-mcp/.env:
NODE_ENV=production
MCP_TRANSPORT=http
PORT=9435
HOST=127.0.0.1
OBSIDIAN_VAULT_PATH=/srv/obsidian/vault
OBSIDIAN_BIN_PATH=/usr/bin/obsidian
AUTH_ENABLED=true
BEARER_TOKEN_HASH=<paste_computed_token_hash_here>
RATE_LIMIT_PER_MINUTE=120
MAX_SEARCH_RESULTS=50
COMMAND_TIMEOUT_MS=15000
ENABLE_DESTRUCTIVE_TOOLS=true
ENABLE_ADVANCED_CLI=false
LOG_LEVEL=infoFeature Flag Controls
ENABLE_DESTRUCTIVE_TOOLS: When set tofalse, destructive operations (obsidian_delete_noteandobsidian_move_note) are excluded from MCP registration. Defaults totrue.ENABLE_ADVANCED_CLI: When set totrue, the guardedobsidian_clitool is registered for allowlisted commands (requiresvault:developerscope). Defaults tofalse.
Set secure permissions on the environment configuration:
sudo chown obsidian:obsidian /etc/obsidian-mcp/.env
sudo chmod 600 /etc/obsidian-mcp/.envInstall and enable the systemd service:
sudo cp deploy/systemd/obsidian-mcp.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now obsidian-mcp.serviceStep 6: Configure Reverse Proxy with TLS (Caddy or Nginx)
Option A: Caddy (Recommended — Automatic TLS)
Edit /etc/caddy/Caddyfile:
mcp.yourdomain.com {
encode gzip zstd
reverse_proxy 127.0.0.1:9435 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
transport http {
keepalive 120s
response_header_timeout 600s
}
}
log {
output file /var/log/caddy/obsidian_mcp.log
format json
}
}Restart Caddy:
sudo systemctl restart caddyOption B: Nginx
Copy deploy/nginx/obsidian-mcp.conf to /etc/nginx/sites-available/obsidian-mcp.conf and obtain a certificate using Certbot:
sudo certbot --nginx -d mcp.yourdomain.com
sudo systemctl restart nginxStep 7: Verify Health Endpoints
Test that the service is running and accessible:
# 1. Check MCP process health
curl https://mcp.yourdomain.com/health
# Response: {"status":"ok","mcp":"running","uptimeSeconds":42,"timestamp":"..."}
# 2. Check vault and Obsidian readiness
curl https://mcp.yourdomain.com/ready
# Response: {"status":"ready","vaultAccessible":true,"obsidianConnected":true,...}Docker Deployment (Compose & Docker Run)
The server is fully containerized with default network port 9435 and can be launched using either docker run or docker compose.
Docker Run with Default Port (9435) and Bearer Token
The server listens on default port 9435:
# 1. Build the container image
docker build --load -t obsidian-remote-mcp .
# 2. Run with default port 9435 and Bearer token
docker run -d \
--name obsidian-mcp \
--restart unless-stopped \
-p 9435:9435 \
-e AUTH_ENABLED=true \
-e AUTH_TOKEN=your-custom-secret-token \
-v /path/to/your/obsidian/vault:/vault \
obsidian-remote-mcpAlternatively, map any custom host port (e.g. 8080) to the container's default port 9435:
docker run -d \
--name obsidian-mcp \
--restart unless-stopped \
-p 8080:9435 \
-e AUTH_ENABLED=true \
-e AUTH_TOKEN=your-custom-secret-token \
-v /path/to/your/obsidian/vault:/vault \
obsidian-remote-mcpOr pass a custom port inside the container using the -e PORT=... environment variable or --port=... CLI argument:
docker run -d \
--name obsidian-mcp \
--restart unless-stopped \
-p 8080:8080 \
-e PORT=8080 \
-e AUTH_ENABLED=true \
-e AUTH_TOKEN=your-custom-secret-token \
-v /path/to/your/obsidian/vault:/vault \
obsidian-remote-mcpDocker Access Control Recipes
Recipe 1: Hybrid Setup (Custom Read/Write Vault + Auto-Discovered Read-Only Default)
Protects against unauthorized note mutations while granting write access to an approved primary vault:
docker run -d \
--name obsidian-mcp \
--restart unless-stopped \
-p 9435:9435 \
-e PORT=9435 \
-e AUTH_ENABLED=true \
-e AUTH_TOKEN=your-custom-secret-token \
-e OBSIDIAN_VAULTS="primary-vault=/vault/primary-vault:rw" \
-e OBSIDIAN_VAULT_PATH=/vault \
-e OBSIDIAN_AUTO_DISCOVERY_MODE="read-only" \
-e OBSIDIAN_DEFAULT_VAULT="primary-vault" \
-v "/root/obsidian-vault:/vault" \
obsidian-remote-mcp:latestRecipe 2: Full Auto-Discovery with Read/Write Access
Automatically discovers any folder containing .obsidian and allows AI clients full read and write access:
docker run -d \
--name obsidian-mcp \
--restart unless-stopped \
-p 9435:9435 \
-e PORT=9435 \
-e AUTH_ENABLED=true \
-e AUTH_TOKEN=your-custom-secret-token \
-e OBSIDIAN_VAULT_PATH=/vault \
-e OBSIDIAN_AUTO_DISCOVERY_MODE="read/write" \
-v "/root/obsidian-vault:/vault" \
obsidian-remote-mcp:latestRecipe 3: Strict Static Vaults (Auto-Discovery Disabled)
Permits access only to explicitly declared vaults, ignoring all other subfolders:
docker run -d \
--name obsidian-mcp \
--restart unless-stopped \
-p 9435:9435 \
-e PORT=9435 \
-e AUTH_ENABLED=true \
-e AUTH_TOKEN=your-custom-secret-token \
-e OBSIDIAN_VAULTS="work=/vault/work:rw,archive=/vault/archive:ro" \
-e OBSIDIAN_ENABLE_AUTO_DISCOVERY=false \
-v "/root/obsidian-vault:/vault" \
obsidian-remote-mcp:latestDocker Compose Deployment
Configure .env in the repository directory (defaults to port 9435):
# Network Port (defaults to 9435)
PORT=9435
# Host Vault Mount Path
OBSIDIAN_VAULT_PATH=/path/to/your/obsidian/vault
# Authentication
AUTH_ENABLED=true
AUTH_TOKEN=your-custom-secret-tokenStart the service:
docker compose up -dVerify service status:
curl http://127.0.0.1:9435/health
curl http://127.0.0.1:9435/readyConnecting Remote Clients
For a comprehensive guide covering token passing, OAuth vs. direct tokens, and cloud tunnel setup, see CLIENT_AUTHENTICATION_GUIDE.md.
The server provides two HTTP transport modes:
Streamable HTTP (
/mcp): Native high-performance streaming transport for modern MCP clients.Server-Sent Events (
/sse): Dedicated SSE stream transport with/messagesfor legacy MCP clients.
Connecting ChatGPT (Plugins & Custom MCP Servers)
When connecting via ChatGPT → Plugins → Add custom MCP server:
Icon (optional): Click
+and upload assets/icon-chatgpt-256.png (256 × 256 PNG, 7.8 KB, fits within ChatGPT's 10 KB upload limit).Name:
Obsidian MCPDescription:
Enterprise integration providing direct access to Obsidian knowledge vaults, notes, metadata, and full-text search.Connection: Select
Server URL.Server URL: Enter your public HTTPS URL with the secret token path or query parameter:
# Recommended: Secret path URL https://<your-domain>/s/<your-secret-token>/mcp # Alternative: Query parameter https://<your-domain>/mcp?token=<your-secret-token>Authentication: Select
No authenticationfrom the dropdown (the token is cryptographically validated directly from the URL path).Check "I understand and want to continue" and click Create as a plugin.
(Note: If hosting locally on Docker, expose port 9435 using a tunnel like ngrok http 9435 or Cloudflare Tunnel so ChatGPT's cloud servers can connect).
Connecting Remote Claude
Add the remote server to Claude Desktop via Streamable HTTP (/mcp) or SSE (/sse):
{
"mcpServers": {
"obsidian-remote": {
"url": "https://mcp.yourdomain.com/mcp",
"headers": {
"Authorization": "Bearer <your_raw_bearer_token>"
}
}
}
}(For legacy Claude clients requiring SSE, use https://mcp.yourdomain.com/sse)
Connecting Hermes Agent (Nous Research)
In Hermes Agent, configure the remote MCP endpoint in ~/.hermes/config.yaml:
mcp:
servers:
obsidian:
url: "https://mcp.yourdomain.com/sse"
headers:
Authorization: "Bearer <your_raw_bearer_token>"Automated Test Suite
The repository contains an automated test matrix covering unit logic, path isolation, security policies, concurrency control, and protocol integration:
# Execute entire test suite
npm test
# Run build typecheck
npm run buildThe test suite covers:
Frontmatter & YAML Serialization: Tests scalar properties, flow lists, block arrays, colons in titles, and wikilink parsing.
PathGuard Security: Strict rejection of leading slashes, path traversal (
../), null byte injections, and symlink escapes.Timing-Safe Authentication: Bearer token parsing, timing-safe SHA-256 verification, and scope validation.
Optimistic Concurrency: Conflict detection across note updates, appends, prepends, property mutations, and note deletions.
CLI Allowlist: Enforces command allowlisting rejecting unauthorized process execution.
Context Engine: Integration test of single-call note context assembly (content, metadata, headings, backlinks, and related notes).
Protocol Discovery: McpServer initialization and capability registration.
Security Model & Path Isolation
The server enforces four security boundaries:
PathGuard: All note paths must be vault-relative. Attempts to traverse directories (
../), inject null bytes (\0), use absolute paths (/etc/passwd), or follow external symlinks are rejected before touching disk.Bearer Token Authentication: Uses SHA-256 constant-time hash verification. Raw tokens are never stored on the server.
Scope Enforcement:
vault:read: Allows searches, task reads, property inspection, and note reading.vault:write: Allows note creation, appends, prepends, and property updates.vault:delete: Required for note moves, renames, and deletion.vault:developer: Required for allowlisted CLI command execution (obsidian_cli).
Audit Trail: Every invocation logs structured JSON with
request_id, client identity, tool name, and duration without recording private note content.
Error Handling Protocol
Every failure returns structured error payloads:
Error Code | HTTP Status | Meaning |
| 401 | Missing or invalid Bearer token credentials. |
| 403 | Token lacks the required scope for the requested tool. |
| 400 | Path attempted directory traversal or points outside the vault. |
| 404 | Target note, folder, or property does not exist. |
| 409 | Concurrent modification detected via revision hash. |
| 503 | Obsidian desktop or CLI IPC is offline. |
| 429 | Client exceeded request quota. |
| 400 | Malformed arguments failing schema validation. |
| 500 | Unexpected service error. |
NPM Package Distribution
The package is configured for direct zero-install execution via npx or standard installation via npm:
# Execute directly without cloning or building
OBSIDIAN_VAULT_PATH="/path/to/vault" npx -y obsidian-mcp
# Or install globally
npm install -g obsidian-mcpPublishing to NPM
Verify Tarball Contents:
npm pack --dry-runOnly
dist/,package.json,README.md, andLICENSEare packaged.Authenticate with NPM:
npm loginPublishing Manually:
# Automatically executes prepublishOnly (runs build and tests) npm publish --access publicAutomated Publishing via GitHub Actions: Create a new release or tag on GitHub (
v0.1.0). The workflow in.github/workflows/publish.ymlwill automatically build, test, and publish the package to the NPM registry using the repository'sNPM_TOKENsecret.
License
MIT License. See LICENSE for full details.
Available Tools
33 toolsobsidian_append_daily_noteC
Appends a work item or note to the daily note with revision check
Inputs: content (required), date, expectedRevision.
obsidian_append_noteC
Appends text content to an existing note with revision check
Inputs: path (required), content (required), ensureNewline, expectedRevision.
obsidian_create_noteC
Creates a new note with optional template
Inputs: path (required), content, template, overwrite.
obsidian_delete_noteC
Deletes or moves a note to the vault trash with revision check
Inputs: path (required), permanent, expectedRevision.
obsidian_find_notesC
Multi-criteria note discovery by title, tag, folder, property, or content query
Inputs: tag, limit, query, folder, +1 more.
obsidian_get_backlinksB
Lists all incoming links referencing a target note
Inputs: path (required).
obsidian_get_deadendsA
Lists notes with incoming links but zero outgoing links
Inputs: no named parameters.
obsidian_get_file_infoB
Retrieves size, modification timestamp, and metadata of a file
Inputs: path (required).
obsidian_get_linksC
Lists all outgoing internal links within a note
Inputs: path (required).
obsidian_get_note_contextC
Retrieves full note context (content, frontmatter, headings, backlinks, and related notes) with budget options
Inputs: path (required), include, maxRelatedNotes.
obsidian_get_orphansB
Discovers orphaned notes that have no internal links
Inputs: no named parameters.
obsidian_get_propertiesA
Retrieves all frontmatter properties of a note
Inputs: path (required).
obsidian_get_propertyC
Retrieves a specific frontmatter property value
Inputs: name (required), path (required).
obsidian_get_tag_notesC
Retrieves all notes tagged with a specific tag
Inputs: tag (required).
obsidian_get_tagsB
Returns all tags and their occurrence counts
Inputs: no named parameters.
obsidian_get_unresolved_linksB
Lists broken internal wikilinks pointing to non-existent notes
Inputs: no named parameters.
obsidian_get_vaultB
Returns vault metadata, file counts, and connectivity status
Inputs: no named parameters.
obsidian_list_basesB
Lists all .base database schema files in the vault
Inputs: no named parameters.
obsidian_list_filesC
Lists files and subdirectories under a vault folder
Inputs: folder, recursive.
obsidian_list_tasksC
Lists pending or completed tasks vault-wide or in a note
Inputs: path, status.
obsidian_move_noteC
Moves or renames a note within the vault with revision check
Inputs: sourcePath (required), targetPath (required), expectedRevision.
obsidian_prepend_daily_noteC
Prepends text to the daily note with revision check
Inputs: content (required), date, expectedRevision.
obsidian_prepend_noteB
Prepends text content below frontmatter in an existing note with revision check
Inputs: path (required), content (required), expectedRevision.
obsidian_query_baseC
Queries a .base database view
Inputs: path (required), view.
obsidian_read_daily_noteB
Reads today's or a specific date's daily note
Inputs: date.
obsidian_read_noteC
Reads the full content and frontmatter of a vault note
Inputs: path (required).
obsidian_recent_changesC
Lists notes recently modified or created within the vault for change awareness
Inputs: limit, folder, sinceDays.
obsidian_remove_propertyB
Removes a frontmatter property from a note with revision check
Inputs: name (required), path (required), expectedRevision.
obsidian_searchC
Performs full-text vault search returning file matches and line numbers
Inputs: query (required), limit.
obsidian_search_contextC
Performs full-text vault search returning contextual lines around matches
Inputs: query (required), limit, contextLines.
obsidian_set_propertyC
Sets or updates a frontmatter property with structured types and revision check
Inputs: name (required), path (required), value, expectedRevision.
obsidian_toggle_taskC
Toggles the completion checkbox on a specific line of a note with verification
Inputs: line (required), path (required), expectedText, expectedRevision.
obsidian_update_noteC
Updates note content with optimistic revision control
Inputs: path (required), content (required), expectedRevision.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 33 tools
Most tools have distinct resource+action targets, but several pairs overlap: obsidian_read_note vs obsidian_get_note_context both retrieve note content and frontmatter; obsidian_search vs obsidian_search_context both perform full-text search with different output formats; obsidian_append_note vs obsidian_append_daily_note target the same operation on different note types. These could cause occasional misselection without careful reading.
All tools use the obsidian_ prefix and snake_case, with a consistent verb_noun pattern (e.g., get_vault, list_files, create_note). Minor deviations like recent_changes (noun phrase) and search (bare verb) slightly break the pattern, but overall highly consistent.
33 tools is above the typical 3-15 range and exceeds the 25+ threshold for 'too many'. While each tool covers a distinct Obsidian feature, the set is heavy and could be consolidated (e.g., get_property/get_properties, append_note/append_daily_note), indicating over-provisioning for a single MCP server.
The surface covers note CRUD, daily notes, properties, tasks, links, tags, bases, search, and discovery comprehensively. Minor gaps exist: no folder creation/deletion/rename, no explicit daily note creation, and no bulk operations, but agents can work around these.
Maintenance
Related MCP Connectors
Connect AI assistants to your GitHub-hosted Obsidian vault to seamlessly access, search, and analy…
Persistent memory, hybrid search and a goal graph for AI agents, over stdio or remote HTTP.
Agent-native notes, tasks, dev-docs, vaults, sync & handoffs. MCP + OpenAPI dual surface.
Hosted MCP server for Obsidian Sync vaults: read, search, edit notes. Not affiliated with Obsidian.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables AI assistants to interact with Obsidian vaults for creating, reading, searching, and managing notes, daily notes, TODOs, session reports, and backlinks through both stdio and HTTP/SSE transports.103,512 npm4MIT
- AlicenseNot gradedqualityCmaintenanceConnects AI assistants to Obsidian vaults via the Local REST API to search notes, retrieve content, and perform semantic searches. It features self-healing multi-URL connectivity and supports both stdio and HTTP transports for flexible deployment.283 npm13MIT
- AlicenseNot gradedqualityCmaintenanceExposes Obsidian vault tools via Model Context Protocol (MCP) server over stdio, HTTP, or SSE transports, enabling AI assistants to read, write, search, and manage vault notes with 28+ built-in tools and CLI bridge integration.1PolyForm Noncommercial 1.0.0
- AlicenseNot gradedqualityCmaintenanceEnables reading, searching, and writing an Obsidian vault directly on disk without Obsidian running, and walking its wikilink graph for backlinks, N-hop neighbors, unresolved links, and orphans. Available over Streamable HTTP with bearer auth, stdio, or a Claude Desktop extension.20 npmMIT