# Obsidian MCP Server
Enables MCP clients (e.g., Claude Desktop) to interact with Obsidian vaults seamlessly.
## Features
- **Multi-Vault Support**: Access unlimited Obsidian vaults without per-vault configuration
- **Auto-Discovery**: Automatically discovers REST API credentials from plugin configuration
- **Concurrent-Safe**: File locking prevents data corruption during simultaneous access
- **Hybrid Access**: Filesystem operations (always available) + REST API integration (optional)
- **Security-First**: Path validation, rate limiting, command allowlist, and secure credential handling
- **Zero-Config**: Works immediately with filesystem access; REST API features activate when plugin is installed
## Installation
### From Source (Current)
Currently, installation from source is required:
```bash
git clone <repository-url>
cd obsidian-mcp-server
npm install
npm run build
```
### Via NPM (Coming Soon)
Once published to npm, you'll be able to install globally:
```bash
npm install -g obsidian-mcp-server
```
**Note**: The package is not yet published. Use "From Source" installation for now.
## Quick Start
### 1. Basic Setup (Filesystem Access Only)
The server automatically detects and configures your Obsidian vaults on first run! No manual configuration needed.
**What happens automatically:**
- Config file is created at `~/.config/mcp-obsidian/config.json` (macOS/Linux) or `%APPDATA%/mcp-obsidian/config.json` (Windows)
- Server scans common locations (Documents, Dropbox, iCloud, etc.) for Obsidian vaults
- Discovered vault paths are automatically added to the configuration
- Ready to use immediately!
**Common locations scanned:**
- `~/Documents/Obsidian`
- `~/Dropbox` and subdirectories
- `~/Library/CloudStorage/Dropbox` (macOS)
- `~/Library/Mobile Documents/iCloud~md~obsidian` (macOS)
- `~/OneDrive/Documents/Obsidian` (Windows)
**Note**: You can override the config location by setting the `MCP_OBSIDIAN_CONFIG` environment variable.
This enables immediate access to all discovered vaults using filesystem operations.
### 2. Enable REST API Features (Optional)
Install the [Obsidian Local REST API plugin](https://github.com/coddingtonbear/obsidian-local-rest-api) in your vault:
1. Open Obsidian Settings → Community Plugins
2. Browse and install "Local REST API"
3. Enable the plugin
4. The plugin will generate an API key automatically
No additional configuration needed - the server will auto-discover the credentials.
### 3. Connect to Claude
Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
```json
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": ["/path/to/obsidian-mcp-server/dist/index.js"]
}
}
}
```
**Note**: The `env` section is optional. If omitted, the server uses the default config location (`~/.config/mcp-obsidian/config.json`). Only add it if you want to use a custom config path:
```json
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": ["/path/to/obsidian-mcp-server/dist/index.js"],
"env": {
"MCP_OBSIDIAN_CONFIG": "/custom/path/to/config.json"
}
}
}
}
```
Restart Claude Desktop.
## Configuration
**Most users don't need to configure anything!** The server auto-detects your vaults on first run.
### Manual Configuration (Optional)
If you need to customize settings or add vaults in non-standard locations, edit `~/.config/mcp-obsidian/config.json`:
**Minimal Configuration:**
```json
{
"defaultVaultPath": "/Users/yourname/Documents/Obsidian"
}
```
**Full Configuration:**
See `config.example.json` for a complete configuration with all options:
- **defaultVaultPath**: Base directory containing your vaults
- **vaults**: Named vault mappings for easy access
- **security**: Path restrictions, rate limits, allowed hosts/ports
- **features**: File locking, caching, file watching settings
- **logging**: Log level and sensitive data sanitization
### Named Vaults
For easier access, define named vaults in your config:
```json
{
"defaultVaultPath": "/Users/yourname/Documents/Obsidian",
"vaults": {
"personal": "PersonalVault",
"work": "WorkVault"
}
}
```
Then reference them by name in Claude: `"vault": "personal"` instead of full paths.
## Available Tools
### File Operations
- **list_vaults**: List all accessible vaults
- **get_vault_info**: Get vault metadata (file count, plugin status)
- **list_files**: List files in a vault (supports recursive, hidden files)
- **get_file**: Read file content with optional frontmatter parsing
- **write_file**: Write or update files with conflict detection
- **append_content**: Append content to existing files
- **search_files**: Search with regex, case sensitivity, context
- **get_metadata**: Extract frontmatter, tags, links, word count
### Obsidian Integration (Requires REST API Plugin)
- **execute_command**: Execute whitelisted Obsidian commands
- **open_file**: Open files in Obsidian UI
- **get_active_file**: Get currently active file
- **open_graph**: Open graph view
### Allowed Commands
For security, only these Obsidian commands are allowed:
- `graph:open`, `graph:open-local`
- `editor:toggle-source`
- `app:go-back`, `app:go-forward`
- `global-search:open`
- `workspace:new-file`, `file-explorer:reveal-active-file`
- `workspace:split-vertical`, `workspace:split-horizontal`
## Testing
### Test with Claude Desktop
1. Restart Claude Desktop after configuration
2. Open a conversation and try:
```
List my Obsidian vaults
```
Expected response: List of discovered vaults with metadata.
```
Read the file "Daily Notes/2026-01-14.md" from my Personal vault
```
Expected response: File content with metadata.
```
Search for "project" in my Work vault
```
Expected response: Search results with context.
### Test with MCP Inspector
```bash
npx @modelcontextprotocol/inspector dist/index.js
```
This opens a web interface to test all tools interactively.
### Verify File Locking
Open a file in Obsidian and simultaneously have Claude read/write it. The server will handle concurrent access safely with file locking.
### Verify Auto-Discovery
Install the REST API plugin in a vault, then:
```
Get info about my Personal vault
```
Expected response should include `"hasRestApi": true` and `"pluginVersion": "1.x.x"`.
## Architecture
### Hybrid Provider System
```
Operation Request
↓
Router Decision
↓
┌───┴───┐
↓ ↓
Filesystem REST API
Provider Provider
↓ ↓
Direct Plugin
File I/O Commands
```
- **Filesystem Provider**: Always available, handles read/write/search
- **REST API Provider**: Optional, handles UI integration and commands
- **Operation Router**: Intelligently selects the appropriate provider
### Security Layers
1. **Path Validation**: Prevents directory traversal, validates symlinks
2. **Rate Limiting**: Global, per-vault, and per-operation limits
3. **Command Allowlist**: Only whitelisted Obsidian commands allowed
4. **Credential Security**: Memory-only cache, no disk serialization
### Concurrent Access Handling
- **File Locking**: Read locks (shared) and write locks (exclusive)
- **Conflict Detection**: Timestamp verification before writes
- **Atomic Writes**: Write to temp file, then rename
- **Lock Timeout**: Automatic cleanup of expired locks
## Troubleshooting
### Vaults Not Found
**Problem**: `list_vaults` returns empty array
**Solutions**:
- **First check**: Restart Claude Desktop to trigger auto-detection
- Verify `defaultVaultPath` in config points to correct directory
- Ensure vaults have `.obsidian` directory (valid Obsidian vaults)
- Check `security.allowedVaultPaths` includes the vault location
- If your vaults are in a non-standard location, manually add the path to `allowedVaultPaths` in the config
### REST API Features Not Working
**Problem**: "REST API required but plugin not installed"
**Solutions**:
- Install "Local REST API" plugin in Obsidian
- Enable the plugin in Obsidian settings
- Verify plugin created `data.json` in `.obsidian/plugins/obsidian-local-rest-api/`
- Clear credential cache: restart the MCP server
### File Lock Timeout
**Problem**: "Could not acquire write lock"
**Solutions**:
- Close files in Obsidian that are being edited
- Wait for ongoing operations to complete
- Increase `features.fileLocking.timeout` in config
- Check for stuck locks: restart the server
### Rate Limit Exceeded
**Problem**: "Rate limit exceeded"
**Solutions**:
- Wait before retrying
- Increase rate limits in config if legitimate usage
- Check for loops in your Claude interactions
### Permission Denied
**Problem**: "Vault path not in allowed directories"
**Solutions**:
- **First try**: Delete `~/.config/mcp-obsidian/config.json` and restart to trigger auto-detection
- Manually add vault path to `security.allowedVaultPaths` in the config
- Use absolute paths, not relative paths
- Check symlink targets are also in allowed paths
- Ensure the path exists and is accessible
## Security Considerations
### Threat Model
This server operates locally and assumes:
- The local machine is trusted
- Claude Desktop is trusted
- Only you have access to the MCP server process
### Protections Implemented
- **Path Traversal Prevention**: Rejects `..` and `~` patterns, validates all paths
- **API Key Security**: Credentials stored only in memory, never logged
- **Command Injection Prevention**: Explicit allowlist of safe commands only
- **Rate Limiting**: Prevents abuse and DoS scenarios
- **Symlink Validation**: Resolves and validates symlink targets
- **Host/Port Validation**: Only localhost connections allowed
### What This Does NOT Protect Against
- Malicious code in your Obsidian vault (markdown files can't execute code)
- Attacks on Obsidian itself
- Physical access to your machine
- Compromised Claude Desktop application
## Development
### Build
```bash
npm run build
```
### Watch Mode
```bash
npm run watch
```
### Run Tests
```bash
npm test
```
### Lint
```bash
npm run lint
```
## Contributing
Contributions welcome! Please:
1. Follow existing code style (TypeScript, ESLint, Prettier)
2. Add tests for new features
3. Update documentation
4. Ensure security best practices
## License
MIT
## Support
For issues, questions, or feature requests, please open an issue on the repository.
## Credits
Built with:
- [Model Context Protocol SDK](https://github.com/modelcontextprotocol/typescript-sdk)
- [gray-matter](https://github.com/jonschlinkert/gray-matter) for frontmatter parsing
- [axios](https://github.com/axios/axios) for HTTP requests