turbovault
Production-grade MCP server for Obsidian vault management.
The main executable binary that exposes 38 MCP tools for AI agents to autonomously manage Obsidian vaults. This is the entry point for end users - it orchestrates all vault operations by integrating the core, parser, graph, vault, batch, export, and tools crates into a unified Model Context Protocol server.
What This Is
turbovault is the main binary that end users run to expose their Obsidian vault to AI agents via the Model Context Protocol (MCP). It provides:
- 38 MCP Tools: Complete vault management API (read, write, search, analyze, templates, batch operations)
- STDIO Transport: Standard MCP-compliant communication over stdin/stdout
- Full-Text Search: Tantivy-powered search with TF-IDF ranking
- Link Graph Analysis: Backlinks, hubs, orphans, cycles, health scoring
- Template System: Pre-built templates with field validation
- Batch Operations: Atomic multi-file transactions
- Export & Reporting: JSON/CSV exports for health reports, stats, broken links
- Production Observability: OpenTelemetry, structured logging, metrics, tracing
For AI agents (Claude, GPT, etc.): This server makes your Obsidian vault "programmable" through a type-safe, discoverable API.
For end users: Install once, configure your vault path, and connect to Claude or other MCP clients.
Quick Start
1. Build the Binary
# From project root
# Binary is at: target/release/turbovault
2. Run with Your Vault
# Simplest usage (single vault, STDIO mode)
# The --init flag scans the vault and builds the link graph on startup
3. Connect to Claude
Add to your ~/.config/claude/claude_desktop_config.json:
Restart Claude Desktop. The server will now be available to Claude.
Installation
Option 1: cargo install (Recommended for End Users)
Install directly from crates.io (after publishing):
# Minimal install (STDIO only, ~7.0 MB)
# Perfect for Claude Desktop
# With HTTP server support (~8.2 MB)
# With HTTP + WebSocket (~8.5 MB)
# With all transports (~8.8 MB)
# Binary installed to: ~/.cargo/bin/turbovault
Available Feature Flags (a la carte):
| Feature | Binary Size | Use Case |
|---|---|---|
(none) |
7.0 MB | Default: STDIO only, Claude Desktop standard |
http |
8.2 MB | Add HTTP server (+1.2 MB) |
websocket |
8.3 MB | Add WebSocket support |
tcp |
7.2 MB | Add TCP server |
unix |
7.2 MB | Add Unix socket support |
http-full |
8.5 MB | HTTP + WebSocket (convenience bundle) |
all-transports |
8.8 MB | All transports enabled |
full |
8.8 MB | Alias for all-transports |
Mix and Match Examples:
# HTTP + TCP (no WebSocket or Unix)
# WebSocket + Unix socket
# Just HTTP
Why Choose Minimal?
- Faster downloads (~20% smaller)
- Lower disk usage on constrained systems
- Faster startup (less code to initialize)
- Claude Desktop only needs STDIO (HTTP/WebSocket/TCP/Unix unused)
When to Add Features:
http: Building a web interface or REST APIwebsocket: Real-time browser-based clientstcp: Network-based MCP clientsunix: Local IPC with Unix domain sockets
Option 2: Build from Source
# Clone the repository
# Build with default features (STDIO only, ~7.0 MB)
# Or build with specific features
# Install to /usr/local/bin (optional)
# Verify installation
Option 3: Docker
# Build Docker image
# Run with docker-compose (see docker-compose.yml for config)
# View logs
Option 3: systemd Service (Linux)
See Deployment Guide for systemd setup.
Configuration
Configuration Profiles
Pre-built configuration profiles optimized for different use cases:
| Profile | Use Case | Features |
|---|---|---|
development |
Local development | Verbose logging, file watching enabled, permissive validation |
production |
Production deployments | Info logging, security auditing, performance monitoring |
readonly |
Read-only access | Disables all write operations, audit logging enabled |
high-performance |
Large vaults (10k+ notes) | Aggressive caching, disabled file watching, optimized for speed |
minimal |
Resource-constrained environments | Minimal caching, basic features only |
Usage:
# Use a profile via CLI
# Default is "development" if not specified
Vault Configuration
Vaults are configured programmatically via VaultConfig::builder():
use ;
// Create configuration
let mut config = Production.create_config;
// Add vault with defaults
let vault_config = builder
.build?;
config.vaults.push;
// Add vault with custom settings
let custom_vault = builder
.as_default
.with_watch_enabled
.with_max_file_size // 10MB
.with_cache_enabled
.with_cache_ttl // 1 hour
.with_excluded_paths
.build?;
config.vaults.push;
Available Options:
name: Unique identifier for the vaultpath: Filesystem path to vault rootis_default: Mark as default vault (first vault is default if not specified)watch_for_changes: Enable file watching for live updates (default: true)max_file_size: Maximum file size in bytes (default: 5MB)allowed_extensions: File extensions to process (default:.md)excluded_paths: Paths to exclude from scanning (default:.obsidian,.trash)enable_caching: Enable file content caching (default: true)cache_ttl: Cache time-to-live in seconds (default: 300 = 5 minutes)template_dirs: Additional template directories (default: vault root)allowed_operations: Restrict operations (default: all allowed)
Environment Variables
# Vault path (alternative to --vault CLI arg)
# Logging level (default: info for production, debug for development)
# OpenTelemetry endpoint (if using OTLP export)
Usage Scenarios
1. Single Vault with Claude Desktop
Goal: Connect your personal Obsidian vault to Claude.
Steps:
# 1. Build the server
# 2. Test it works
# You should see:
# [INFO] Observability initialized
# [INFO] Initializing vault at: ~/Documents/ObsidianVault
# [INFO] Scanning vault and building link graph...
# [INFO] Vault initialization complete
# [INFO] Server initialized with vault
# [INFO] Starting TurboVault Server
# [INFO] Running in STDIO mode for MCP protocol
# 3. Configure Claude Desktop
# Edit: ~/.config/claude/claude_desktop_config.json
# 4. Restart Claude Desktop
# The server is now available to Claude!
Verification:
Ask Claude:
- "What tools do you have available?"
- "Can you list the files in my vault?"
- "Search for notes about machine learning"
- "What's the health score of my vault?"
2. Multi-Vault Setup
Goal: Manage multiple vaults (personal, work, research) with a single server.
Implementation:
Multi-vault support requires using the MultiVaultManager API (currently requires code changes, CLI support coming soon):
// Create multi-vault configuration
use MultiVaultManager;
let manager = new;
// Add vaults
manager.add_vault.await?;
manager.add_vault.await?;
manager.add_vault.await?;
// Set active vault
manager.set_active_vault.await?;
// Initialize server
server.initialize_multi_vault.await;
Use Cases:
- Separate personal and work knowledge bases
- Isolate research projects
- Team collaboration with shared vaults
- Client-specific vaults for consulting
Switching Vaults (via MCP tools):
Claude can use:
list_vaults()- See all registered vaultsget_active_vault()- Check current vaultset_active_vault("work")- Switch to different vaultget_vault_config("research")- View vault settings
3. Docker Deployment
Goal: Run the server in a container for isolation and reproducibility.
docker-compose.yml:
version: '3.8'
services:
turbovault:
build:
context: .
dockerfile: Dockerfile
image: TurboVault:latest
container_name: turbovault
user: obsidian
volumes:
# Mount your vault (read-write)
- /path/to/your/vault:/var/obsidian-vault
environment:
- RUST_LOG=info
- OBSIDIAN_VAULT_PATH=/var/obsidian-vault
healthcheck:
test:
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
restart: unless-stopped
stdin_open: true
tty: true
Commands:
# Build and start
# View logs
# Stop
# Connect to running container
Benefits:
- Isolated dependencies (no Rust toolchain needed on host)
- Reproducible environment
- Easy rollback (just change image tag)
- Works on any platform (Linux, macOS, Windows with WSL)
4. Readonly Access (Security)
Goal: Expose vault to AI agents without allowing modifications.
Configuration:
# Use readonly profile
What's Disabled:
- All write operations (
write_note,delete_note,move_note) - Batch operations that modify files
- Template creation
- File operations fail with permission errors
What Works:
- All read operations (
read_note,list_files) - Search and discovery (
search,advanced_search) - Link graph analysis (
get_backlinks,get_hub_notes) - Health checks and exports (
export_health_report)
Use Cases:
- Public demo environments
- Shared vault access with untrusted agents
- Audit mode (agents can observe but not modify)
- Testing agent behavior safely
CLI Reference
Command Line Arguments
Options:
| Flag | Environment Variable | Default | Description |
|---|---|---|---|
--vault <PATH> |
OBSIDIAN_VAULT_PATH |
(required) | Path to Obsidian vault directory |
--profile <PROFILE> |
- | development |
Configuration profile: development, production, readonly, high-performance, minimal |
--transport <MODE> |
- | stdio |
Transport mode (only stdio is MCP-compliant) |
--port <PORT> |
- | 3000 |
HTTP server port (for future http transport) |
--init |
- | false |
Initialize vault on startup (scan files, build graph) |
--help |
- | - | Show help message |
--version |
- | - | Show version |
Examples
# Minimal usage (development mode, no init)
# Production mode with initialization
# Readonly mode (no modifications allowed)
# High-performance mode (large vaults)
# Use environment variable for vault path
Exit Codes
0- Success1- General error (vault not found, invalid config, etc.)2- Vault initialization failed3- Server startup failed
Claude Integration
Setup
-
Install Claude Desktop: Download from Anthropic
-
Build turbovault-server:
-
Configure Claude Desktop:
macOS/Linux:
~/.config/claude/claude_desktop_config.jsonWindows:%APPDATA%\Claude\claude_desktop_config.json -
Restart Claude Desktop
-
Verify Connection:
- Open Claude Desktop
- Look for the "MCP" indicator in the UI
- Ask: "What MCP tools do you have?"
- Claude should list 38 Obsidian tools
Example Workflows with Claude
1. Search and Summarize
You: "Search my vault for notes about Rust async programming and summarize the key concepts."
Claude will:
- Use
search(query="rust async programming") - Read the top results with
read_note(path=...) - Summarize the content
2. Vault Health Analysis
You: "Analyze the health of my vault and suggest improvements."
Claude will:
- Use
quick_health_check()to get overall score - Use
get_broken_links()to find issues - Use
get_hub_notes()to identify important notes - Provide actionable recommendations
3. Create Structured Notes
You: "Create a task note for implementing user authentication with high priority."
Claude will:
- Use
list_templates()to find available templates - Use
create_from_template(template_id="task", path="tasks/user-auth.md", fields={"title":"User Authentication","priority":"high"}) - Confirm creation and suggest related notes to link
4. Organize and Refactor
You: "Find all completed project notes and move them to the archive folder."
Claude will:
- Use
query_metadata(pattern='status: "completed"') - Build a list of files to move
- Use
batch_execute()to atomically move files and update backlinks - Report the results
Troubleshooting Claude Connection
Problem: Claude doesn't see the server
-
Check Claude Desktop logs:
# macOS # Linux -
Verify server runs standalone:
-
Check config file syntax (must be valid JSON)
-
Use absolute paths (not
~or relative paths)
Problem: Server starts but tools fail
- Check vault path is correct and accessible
- Verify vault contains
.obsidianfolder (valid Obsidian vault) - Check file permissions (server needs read/write access)
- Review server logs in Claude's MCP logs
Observability
The server includes production-grade observability via OpenTelemetry.
Logging
Log Levels:
# Environment variable controls logging
# All debug logs
# Info and above
# Warnings and errors only
# Debug for TurboVault only
# Multi-crate filtering
Log Output:
[2025-10-16T10:30:00Z INFO TurboVault] Observability initialized
[2025-10-16T10:30:00Z INFO TurboVault] Initializing vault at: /path/to/vault
[2025-10-16T10:30:01Z INFO TurboVault::vault] Scanning vault files...
[2025-10-16T10:30:02Z INFO TurboVault::graph] Building link graph (1250 nodes)...
[2025-10-16T10:30:03Z INFO TurboVault] Vault initialization complete
[2025-10-16T10:30:03Z INFO TurboVault] Server initialized with vault
[2025-10-16T10:30:03Z INFO TurboVault] Starting TurboVault Server
[2025-10-16T10:30:03Z INFO TurboVault] Running in STDIO mode for MCP protocol
Metrics
Built-in Metrics:
- Request count by tool
- Request duration (p50, p95, p99)
- Error rate by tool and error type
- Vault size (files, links, orphans)
- Cache hit/miss ratio
- File I/O operations
- Graph analysis performance
Accessing Metrics:
Metrics are emitted via OpenTelemetry and can be exported to:
- Prometheus: Scrape endpoint (future HTTP transport)
- OTLP Collector: Push to collector for aggregation
- Cloud Providers: AWS CloudWatch, GCP Monitoring, Azure Monitor
Example Prometheus Queries:
# Average request duration by tool
rate(mcp_request_duration_seconds_sum[5m]) / rate(mcp_request_duration_seconds_count[5m])
# Error rate
rate(mcp_request_errors_total[5m])
# Cache efficiency
mcp_cache_hits_total / (mcp_cache_hits_total + mcp_cache_misses_total)
Tracing
Distributed Tracing:
The server emits OpenTelemetry spans for:
- Each MCP tool invocation
- File operations (read, write, delete)
- Search queries
- Graph analysis
- Batch transactions
Viewing Traces:
-
Set up OTLP collector:
# docker-compose.yml -
Configure server:
-
View traces: Open http://localhost:16686
Trace Example:
Span: search_notes
├─ Span: parse_query (0.1ms)
├─ Span: tantivy_search (45ms)
│ ├─ Span: index_lookup (30ms)
│ └─ Span: score_results (15ms)
└─ Span: format_results (2ms)
Total: 47.1ms
Security Auditing
When enable_security_auditing() is enabled (production profile):
- All file operations are logged with user context
- Path traversal attempts are logged and blocked
- Invalid access attempts are recorded
- Configuration changes are audited
Audit Log Example:
Performance Tuning
For Small Vaults (<1000 notes)
Use development profile:
Defaults are fine - caching, file watching, full indexing.
For Medium Vaults (1k-10k notes)
Use production profile:
Tuning:
- Enable caching with 1-hour TTL
- Use
--initto build graph once on startup - Limit search results to 20-50 per query
- Use
quick_health_check()instead offull_health_analysis()
For Large Vaults (10k+ notes)
Use high-performance profile:
Tuning:
- Disable file watching (reduces CPU overhead)
- Aggressive caching with long TTLs
- Limit search results to 10-20
- Use pagination for large result sets
- Consider splitting into multiple vaults
- Increase cache size (code change required)
Memory Optimization:
// In code (future CLI options)
config.max_cache_entries = 10000; // Increase from default 1000
config.cache_ttl = 7200; // 2 hours instead of 5 minutes
config.enable_lazy_loading = true; // Load files on-demand
Disk I/O Optimization:
- Use SSD for vault storage
- Exclude large asset directories (images, PDFs) if not needed
- Use
.ignorefile to exclude temporary files
Benchmarking
# Run benchmarks (if available)
# Profile with perf (Linux)
# Memory profiling with valgrind (Linux)
Troubleshooting
Common Issues
1. Vault Not Found
Error:
Error: Failed to create vault config: Vault path does not exist: /path/to/vault
Solution:
- Verify the path is correct:
ls -la /path/to/vault - Use absolute paths (not relative or
~) - Ensure vault directory exists and contains
.obsidian/folder - Check file permissions
2. Server Starts But No Tools Available
Symptoms:
- Server runs without errors
- Claude doesn't see any tools
- MCP connection shows but no tools listed
Solution:
- Check server was initialized with vault:
# Look for these log lines: - If missing, use
--vaultflag: - Verify vault is valid (contains
.obsidian/and.mdfiles)
3. Permission Denied Errors
Error:
Error: Permission denied (os error 13)
Solution:
- Check vault directory permissions:
# Should show read/write for your user - Fix permissions:
- For Docker: ensure volume mount is correct and user has access
4. Link Graph Build Fails
Error:
[ERROR] Failed to initialize vault: Link parsing error
Solution:
- Check for malformed wikilinks in notes:
# Find suspicious links - Look for unclosed links:
[[link(missing]]) - Check for special characters in link targets
- Review server logs for specific file causing issues
5. Search Returns No Results
Symptoms:
search()tool returns empty array- You know matching content exists
Solution:
- Ensure vault was initialized with
--initflag - Check search query syntax (use simple keywords first)
- Verify files have content (not just frontmatter)
- Check excluded paths (might be filtering out results)
- Review search index build in logs:
[INFO] Building search index... (1250 files) [INFO] Search index ready
6. High Memory Usage
Symptoms:
- Server using excessive RAM (>500MB for <10k notes)
- System becomes sluggish
Solution:
- Use
high-performanceprofile (disables file watching) - Reduce cache TTL:
# Shorten cache lifetime - Check for memory leak (shouldn't happen, but report if found)
- Restart server periodically (systemd handles this)
7. Slow Performance
Symptoms:
- Operations take >5 seconds
- Search is slow (>1 second)
Solution:
- Use
--initto build graph once on startup (not on-demand) - Profile the slow operation:
# Look for slow operations in logs - Check disk I/O (vault on slow HDD?)
- Reduce vault size or split into multiple vaults
- Disable file watching in
high-performanceprofile
Debug Mode
Enable detailed logging:
|
Send debug logs when reporting issues:
# Sanitize logs (remove sensitive paths)
# Attach debug-sanitized.log to issue report
Getting Help
- Check logs: Look for ERROR or WARN messages
- Search issues: https://github.com/epistates/TurboVault/issues
- Create issue: Include:
- Server version (
turbovault --version) - OS and Rust version (
rustc --version) - Vault size (number of files)
- Minimal reproduction steps
- Relevant log output (sanitized)
- Server version (
Development
Building from Source
# Clone repository
# Build debug binary (fast compile, slower runtime)
# Build release binary (slow compile, optimized runtime)
# Run tests
# Run with cargo
Project Structure
crates/turbovault-server/
├── src/
│ ├── bin/
│ │ └── main.rs # CLI entry point, arg parsing, server startup
│ ├── lib.rs # Re-exports for public API
│ └── tools.rs # MCP tool implementations (38 tools)
├── tests/
│ └── integration_test.rs # Integration tests
├── Cargo.toml # Dependencies and binary config
└── README.md # This file
Adding a New Tool
-
Implement in
tools.rs:async -
Add to turbovault-tools (if reusable logic):
// crates/turbovault-tools/src/my_tools.rs -
Write tests:
async -
Update documentation in this README
Running Tests
# All server tests
# Specific test
# With output
# Integration tests only
Code Quality
# Format code
# Run linter
# Check compilation without building
Architecture
System Overview
┌─────────────────────────────────────────────────────────┐
│ AI Agent (Claude) │
└───────────────────────────┬─────────────────────────────┘
│ MCP Protocol (STDIO)
┌───────────────────────────▼─────────────────────────────┐
│ turbovault-server (THIS CRATE) │
│ │
│ ┌────────────────────────────────────────────────┐ │
│ │ main.rs - CLI Entry Point │ │
│ │ - Parse args (vault path, profile) │ │
│ │ - Initialize observability (OTLP) │ │
│ │ - Create VaultManager │ │
│ │ - Start MCP server (STDIO transport) │ │
│ └────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────┐ │
│ │ tools.rs - MCP Tool Implementations │ │
│ │ - ObsidianMcpServer struct │ │
│ │ - 38 #[tool] annotated methods │ │
│ │ - Error conversion (Error → McpError) │ │
│ └────────────────────────────────────────────────┘ │
└───────────────────────────┬─────────────────────────────┘
│
┌───────────────────┼───────────────────┐
│ │ │
┌───────▼──────┐ ┌───────▼──────┐ ┌───────▼──────┐
│ TurboVault- │ │ TurboVault- │ │ turbomcp │
│ tools │ │ vault │ │ (MCP SDK) │
│ │ │ │ │ │
│ - FileTools │ │ VaultManager │ │ - Protocol │
│ - SearchEng │ │ - File I/O │ │ - Transport │
│ - Templates │ │ - Caching │ │ - Macros │
│ - GraphTools │ │ - Validation │ │ - Observ. │
└──────────────┘ └──────────────┘ └──────────────┘
│ │
└───────────────────┼───────────────────┐
│ │
┌─────────▼─────────┐ ┌───────▼──────┐
│ turbovault-parser │ │ TurboVault- │
│ │ │ graph │
│ - OFM parsing │ │ │
│ - Wikilink extract │ │ - Link graph │
│ - Frontmatter │ │ - Analysis │
└────────────────────┘ └──────────────┘
Component Responsibilities
| Component | Responsibility | Lines of Code |
|---|---|---|
main.rs |
CLI parsing, initialization, startup | ~100 LOC |
tools.rs |
MCP tool wrappers, error conversion | ~500 LOC |
lib.rs |
Public API exports | ~10 LOC |
Key Design Decisions:
- Thin Server Layer: Business logic lives in
turbovault-tools, server just wraps it - Single Binary: All crates compile into one executable for easy deployment
- STDIO Transport Only: MCP standard, simplifies deployment (no network ports)
- Observability First: Production-grade logging/metrics/tracing from day one
- Profile-Based Config: Common use cases have pre-tuned profiles
Data Flow: MCP Request → Response
1. Claude sends JSON-RPC request via STDIO
↓
2. turbomcp deserializes request
↓
3. Server routes to tool method (e.g., `read_note()`)
↓
4. Tool method gets VaultManager
↓
5. Tool method creates domain tool (e.g., FileTools)
↓
6. Domain tool performs operation (read file, parse, etc.)
↓
7. Result or error returned
↓
8. Server converts Error → McpError
↓
9. turbomcp serializes response to JSON-RPC
↓
10. Response sent to Claude via STDIO
Latency Breakdown (typical):
- JSON-RPC parsing: <1ms
- Tool routing: <1ms
- Domain operation: 5-100ms (depends on operation)
- Response serialization: <1ms
- Total: 7-102ms
Crate Dependencies
turbovault-server depends on:
├── turbovault-core (types, config, errors)
├── turbovault-vault (file I/O, VaultManager)
├── turbovault-tools (all 11 tool categories)
├── turbomcp (MCP protocol + macros)
│ ├── turbomcp-protocol (JSON-RPC)
│ └── turbomcp-server (server infrastructure)
├── tokio (async runtime)
├── clap (CLI parsing)
├── serde + serde_json (serialization)
├── config (configuration loading - future use)
├── anyhow (error handling)
├── log + env_logger (logging)
└── tracing + tracing-subscriber (structured logging)
Security Architecture
Path Validation:
- All file paths validated against vault root
- Symlinks are NOT followed (prevents escaping vault)
..components rejected- Absolute paths outside vault rejected
Input Validation:
- All MCP inputs deserialized via serde (type-safe)
- String inputs sanitized for shell injection (not passed to shell)
- File sizes checked before reading (max 5MB default)
- Frontmatter YAML parsed safely (no code execution)
Error Handling:
- No panics in tool methods (all errors returned as
Result) - Sensitive paths redacted from error messages
- Stack traces only in debug mode
Audit Trail:
- All file operations logged with timestamp
- Security events (path traversal attempts) logged at WARN level
- Configuration changes recorded
References
For more details on specific components:
- Core Types & Config: See
../turbovault-core/README.md - Parser (OFM): See
../turbovault-parser/README.md - Link Graph: See
../turbovault-graph/README.md - Vault Operations: See
../turbovault-vault/README.md - Batch Transactions: See
../turbovault-batch/README.md - Export Tools: See
../turbovault-export/README.md - MCP Tools (38 tools): See
../turbovault-tools/README.md - Deployment Guide: See
/docs/deployment/index.md(project root) - Code Quality Audit: See
/DILIGENCE_PASS_COMPLETE.md(project root)
License
Part of the TurboVault project. See project root for license information.
Support
- Issues: https://github.com/epistates/TurboVault/issues
- Documentation: This README + component READMEs
- Examples: See
tests/integration_test.rsfor usage examples
Production Status: ✅ Ready for production use with Claude Desktop and MCP-compliant clients.