roelven/obsidian-mcp-server
If you are the rightful owner of obsidian-mcp-server and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
The Obsidian MCP Server is a Model Context Protocol server that allows AI models to access Obsidian notes through a LiveSync CouchDB setup.
Obsidian MCP Server
A Model Context Protocol (MCP) server that provides AI models with access to your Obsidian notes through your existing LiveSync CouchDB setup.
Disclaimer: This MCP server is vibe-coded by Claude, Gemini and me. See the for details.
Features
- Read-only access to your Obsidian notes via MCP protocol version 2025-03-26
- Performance-optimized resource listing (10 recent notes) with comprehensive search tools
- Enhanced UX: Automatic content inclusion for small result sets (≤3 notes) to reduce back-and-forth
- Seamless integration with existing Obsidian LiveSync infrastructure
- Metadata extraction including frontmatter, tags, and aliases
- Content reassembly for chunked notes
- Handles encrypted vaults (if
VAULT_PASSPHRASE
is provided) - Docker support for easy deployment
- Configurable via environment variables
Architecture
[AI Clients (ChatGPT, Claude)]
↓ (MCP Protocol - stdio/SSE)
[Obsidian MCP Server]
↓ (CouchDB API)
[Your LiveSync CouchDB Instance]
↓ (LiveSync Protocol)
[Your Obsidian Vaults]
Prerequisites
- A running Obsidian LiveSync CouchDB instance
- CouchDB credentials with read access to your LiveSync database
- Python 3.10+ (if running locally) or Docker
Quick Start
Using Docker (Recommended)
-
Clone and configure:
git clone <this-repo> cd obsidian-mcp-server cp env.example .env
-
Edit
.env
with your settings:COUCHDB_BASE_URL=https://your-couchdb-instance.com/secret-path COUCHDB_DATABASE_NAME=your-livesync-db-name COUCHDB_USER=your-username COUCHDB_PASSWORD=your-password
-
Run with Docker Compose:
docker-compose up -d
-
Test the connection:
curl http://localhost:8000/sse
Local Development
-
Install dependencies:
pip install -e .
-
Set environment variables:
export COUCHDB_BASE_URL="https://your-couchdb-instance.com" export COUCHDB_DATABASE_NAME="your-db-name" export COUCHDB_USER="your-username" export COUCHDB_PASSWORD="your-password"
-
Run the server:
# For stdio transport (direct MCP client connection) obsidian-mcp-server --transport stdio # For SSE transport (HTTP-based) obsidian-mcp-server --transport sse --port 8000
Setup and Configuration
All configuration is done via environment variables:
Variable | Required | Default | Description |
---|---|---|---|
COUCHDB_BASE_URL | Yes | - | Full URL to your CouchDB instance |
COUCHDB_DATABASE_NAME | Yes | - | Name of your LiveSync database |
COUCHDB_USER | Yes | - | CouchDB username |
COUCHDB_PASSWORD | Yes | - | CouchDB password |
SERVER_PORT | No | 8000 | Port for SSE transport |
USE_PATH_OBFUSCATION | No | false | Whether LiveSync uses path obfuscation (currently not supported) |
VAULT_PASSPHRASE | No | - | Optional. Passphrase for decrypting encrypted Obsidian LiveSync notes. If not set, encrypted notes will not be decrypted. |
VAULT_ID | No | default | Identifier for your vault in URIs |
COUCHDB_LIST_LIMIT_FOR_PATH_SEARCH | No | 500 | Max recent notes to scan when direct path lookup fails or path obfuscation is on. |
CouchDB URL Format
Your COUCHDB_BASE_URL
should include any secret paths or authentication prefixes:
- Direct CouchDB:
http://localhost:5984
- With Caddy proxy:
https://vault.example.com/secret-path
- Self-hosted LiveSync:
https://your-domain.com/e=your-secret
CouchDB Index Creation (Recommended)
To ensure efficient querying of notes, especially for listing and sorting by modification time (mtime
), it is highly recommended to create a JSON index in your CouchDB LiveSync database. This index helps CouchDB quickly find and sort notes based on their type and modification time.
Index Definition:
{
"index": {
"fields": ["type", "mtime"]
},
"name": "idx-type-mtime-sorted",
"type": "json"
}
How to Create the Index:
You can create this index using CouchDB's Fauxton interface or via curl
.
Using Fauxton:
- Navigate to your CouchDB instance in your browser (e.g.,
http://localhost:5984/_utils/
). - Select your LiveSync database.
- Go to "All Documents" -> "New Index" (or similar, depending on Fauxton version; older versions might have it under "Design Documents" -> "New View/Index").
- Choose "JSON" as the index type.
- Enter the JSON definition above into the editor.
- Click "Create Index".
Using curl
:
Replace YOUR_COUCHDB_URL
, YOUR_DATABASE_NAME
, YOUR_USERNAME
, and YOUR_PASSWORD
with your actual CouchDB details.
curl -X POST \
YOUR_COUCHDB_URL/YOUR_DATABASE_NAME/_index \
-H "Content-Type: application/json" \
-u "YOUR_USERNAME:YOUR_PASSWORD" \
-d '{ \
"index": { \n "fields": ["type", "mtime"] \n }, \n "name": "idx-type-mtime-sorted", \n "type": "json" \n }'
Example with placeholder values:
curl -X POST \
http://localhost:5984/my_livesync_db/_index \
-H "Content-Type: application/json" \
-u "admin:password" \
-d '{ \
"index": { \n "fields": ["type", "mtime"] \n }, \n "name": "idx-type-mtime-sorted", \n "type": "json" \n }'
Creating this index will significantly improve the performance of operations like listing recent notes.
MCP Client Integration
Claude Desktop
Add to your Claude Desktop configuration:
{
"mcpServers": {
"obsidian": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"--env-file", "/path/to/your/.env",
"obsidian-mcp-server",
"--transport", "stdio"
]
}
}
}
Custom MCP Client
from mcp import ClientSession
from mcp.client.stdio import stdio_client
# Connect to the server
async with stdio_client() as streams:
async with ClientSession(streams[0], streams[1]) as session:
# Initialize the connection
await session.initialize()
# Get the most recent note with content in one call
recent_note = await session.call_tool("get_recent_note", {})
print("Most recent note:", recent_note)
# Search for specific content (auto-includes content for ≤3 results)
search_results = await session.call_tool("search_notes", {"query": "project", "limit": 3})
print("Search results with content:", search_results)
# Browse recent notes (auto-includes content for ≤3 results)
browse_results = await session.call_tool("browse_notes", {"limit": 2})
print("Recent notes with content:", browse_results)
# List available notes (metadata only, for discovery)
resources = await session.list_resources()
# Read a specific note if needed
if resources.resources:
content = await session.read_resource(resources.resources[0].uri)
print("Specific note content:", content)
API Reference
The server implements the MCP protocol version 2025-03-26:
Resources
resources/list
Lists up to 10 recent Obsidian notes for performance optimization. For comprehensive note discovery, use the search and browse tools.
Response:
{
"resources": [
{
"uri": "mcp-obsidian://vault-id/path/to/note.md",
"name": "Note Title",
"description": "Path: path/to/note.md",
"mimeType": "text/markdown"
}
]
}
resources/read
Reads the content of a specific note.
Parameters:
uri
: The resource URI fromresources/list
or tool output
Response:
{
"contents": [
{
"uri": "mcp-obsidian://vault-id/path/to/note.md",
"mimeType": "text/markdown",
"text": "# Note Title\n\nNote content..."
}
]
}
Tools
search_notes
Search through notes by title, content, or tags with rich metadata and relevance scoring. Automatically includes full content for small result sets (≤3 notes) to improve user experience.
Parameters:
query
(string): Search query (leave empty to browse recent notes)limit
(integer): Maximum results (default: 10, max: 50)include_content
(boolean): Force content inclusion (auto-enabled for ≤3 results)
browse_notes
Browse recent notes with sorting options. Automatically includes full content for small result sets (≤3 notes) to improve user experience.
Parameters:
limit
(integer): Maximum results (default: 20, max: 50)sort_by
(string): Sort order - "mtime", "ctime", or "path"include_content
(boolean): Force content inclusion (auto-enabled for ≤3 results)
get_recent_note
Get the most recent note with full content. Optimized for "show me the latest note" queries - returns complete note content in a single call.
Parameters:
sort_by
(string): How to determine "most recent" - "mtime" or "ctime" (default: "mtime")
Supported Note Features
- ✅ Frontmatter - YAML metadata is preserved
- ✅ Tags - Both
#hashtags
and frontmatter tags - ✅ Aliases - From frontmatter
- ✅ Chunked notes - Automatically reassembled
- ✅ Markdown content - Full content with formatting
- ✅ Encrypted notes - Decrypted if
VAULT_PASSPHRASE
is set (compatible withoctagonal-wheels
) - ❌ Attachments - Not yet supported
- ❌ Write operations - Read-only for safety
Future Enhancements
- Custom HTTP API: Bearer token authentication and custom endpoints for advanced deployment scenarios
- Write Operations: Note creation and modification capabilities
- Real-time Updates: MCP resource subscriptions and live vault change notifications
- Advanced Search: Enhanced querying with date ranges, tag filters, and graph traversal
Troubleshooting
Connection Issues
-
Test CouchDB access:
curl -u username:password https://your-couchdb-url/your-database
-
Check server logs:
docker-compose logs obsidian-mcp-server
-
Verify environment variables:
docker-compose config
Common Problems
- "Failed to connect to CouchDB": Check your URL, credentials, and network access
- "No notes found": Verify your database name and that LiveSync has synced notes
- "Path obfuscation errors": Set
USE_PATH_OBFUSCATION=true
if LiveSync uses it - "Decryption failed" or "Content looks encrypted": Ensure
VAULT_PASSPHRASE
is correctly set in your.env
file if your vault uses encryption. If it is set, verify the passphrase is correct. Encrypted content that cannot be decrypted will be marked.
Security Considerations
- The server provides read-only access to your notes
- Use strong API keys and secure your CouchDB credentials
- Consider running behind a reverse proxy with SSL
- Limit network access to the CouchDB instance
- Regularly rotate your API keys
Development
Running Tests
pytest tests/
Code Quality
ruff check .
pyright .
Building Docker Image
docker build -t obsidian-mcp-server .
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
MIT License - see LICENSE file for details.