| Crates.io | turbovault |
| lib.rs | turbovault |
| version | 1.2.6 |
| created_at | 2025-10-24 17:48:03.005875+00 |
| updated_at | 2025-12-16 18:24:16.669367+00 |
| description | Production-grade MCP server for Obsidian vault management - Transform your vault into an intelligent knowledge system for AI agents |
| homepage | https://github.com/epistates/turbovault |
| repository | https://github.com/epistates/turbovault |
| max_upload_size | |
| id | 1898936 |
| size | 311,847 |
Production-grade MCP server for Obsidian vault management.
The main executable binary that exposes 44 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.
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:
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.
# From project root
make release
# Binary is at: target/release/turbovault
# Simplest usage (single vault, STDIO mode)
./target/release/turbovault \
--vault /path/to/your/obsidian/vault \
--init
# The --init flag scans the vault and builds the link graph on startup
Add to your ~/.config/claude/claude_desktop_config.json:
{
"mcpServers": {
"obsidian": {
"command": "/path/to/turbovault",
"args": [
"--vault", "/path/to/your/vault",
"--profile", "production",
"--init"
]
}
}
}
Restart Claude Desktop. The server will now be available to Claude.
Install directly from crates.io (after publishing):
# Minimal install (STDIO only, ~7.0 MB)
# Perfect for Claude Desktop
cargo install turbovault
# With HTTP server support (~8.2 MB)
cargo install turbovault --features http
# With HTTP + WebSocket (~8.5 MB)
cargo install turbovault --features "http,websocket"
# With all transports (~8.8 MB)
cargo install turbovault --features full
# Binary installed to: ~/.cargo/bin/turbovault
turbovault --help
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)
cargo install turbovault --features "http,tcp"
# WebSocket + Unix socket
cargo install turbovault --features "websocket,unix"
# Just HTTP
cargo install turbovault --features http
Why Choose Minimal?
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# Clone the repository
git clone https://github.com/epistates/TurboVault.git
cd TurboVault
# Build with default features (STDIO only, ~7.0 MB)
make release
# Or build with specific features
cargo build -p turbovault-server --release --features "http,websocket"
# Install to /usr/local/bin (optional)
sudo cp target/release/turbovault /usr/local/bin/
# Verify installation
turbovault --help
# Build Docker image
make docker-build
# Run with docker-compose (see docker-compose.yml for config)
make docker-up
# View logs
make docker-logs
See Deployment Guide for systemd setup.
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
turbovault --vault /path/to/vault --profile production
# Default is "development" if not specified
Vaults are configured programmatically via VaultConfig::builder():
use TurboVault_core::{VaultConfig, ConfigProfile};
// Create configuration
let mut config = ConfigProfile::Production.create_config();
// Add vault with defaults
let vault_config = VaultConfig::builder("my-vault", "/path/to/vault")
.build()?;
config.vaults.push(vault_config);
// Add vault with custom settings
let custom_vault = VaultConfig::builder("research", "/path/to/research")
.as_default()
.with_watch_enabled(true)
.with_max_file_size(10 * 1024 * 1024) // 10MB
.with_cache_enabled(true)
.with_cache_ttl(3600) // 1 hour
.with_excluded_paths(vec![".obsidian", ".trash"])
.build()?;
config.vaults.push(custom_vault);
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)# Vault path (alternative to --vault CLI arg)
export OBSIDIAN_VAULT_PATH=/path/to/vault
# Logging level (default: info for production, debug for development)
export RUST_LOG=info,TurboVault=debug
# OpenTelemetry endpoint (if using OTLP export)
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
Goal: Connect your personal Obsidian vault to Claude.
Steps:
# 1. Build the server
cd TurboVault
make release
# 2. Test it works
./target/release/turbovault \
--vault ~/Documents/ObsidianVault \
--init
# 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
{
"mcpServers": {
"obsidian": {
"command": "/Users/yourname/TurboVault/target/release/turbovault",
"args": [
"--vault", "/Users/yourname/Documents/ObsidianVault",
"--profile", "production",
"--init"
]
}
}
}
# 4. Restart Claude Desktop
# The server is now available to Claude!
Verification:
Ask Claude:
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 TurboVault_core::MultiVaultManager;
let manager = MultiVaultManager::new();
// Add vaults
manager.add_vault("personal", "/vaults/personal").await?;
manager.add_vault("work", "/vaults/work").await?;
manager.add_vault("research", "/vaults/research").await?;
// Set active vault
manager.set_active_vault("personal").await?;
// Initialize server
server.initialize_multi_vault(manager).await;
Use Cases:
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 settingsGoal: 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: ["CMD", "/usr/local/bin/turbovault", "--help"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
restart: unless-stopped
stdin_open: true
tty: true
Commands:
# Build and start
make docker-build
make docker-up
# View logs
make docker-logs
# Stop
make docker-down
# Connect to running container
docker exec -it turbovault /bin/sh
Benefits:
Goal: Expose vault to AI agents without allowing modifications.
Configuration:
# Use readonly profile
turbovault \
--vault /path/to/vault \
--profile readonly \
--init
What's Disabled:
write_note, delete_note, move_note)What Works:
read_note, list_files)search, advanced_search)get_backlinks, get_hub_notes)export_health_report)Use Cases:
turbovault [OPTIONS]
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 |
# Minimal usage (development mode, no init)
turbovault --vault /path/to/vault
# Production mode with initialization
turbovault \
--vault /path/to/vault \
--profile production \
--init
# Readonly mode (no modifications allowed)
turbovault \
--vault /path/to/vault \
--profile readonly
# High-performance mode (large vaults)
turbovault \
--vault /path/to/vault \
--profile high-performance \
--init
# Use environment variable for vault path
export OBSIDIAN_VAULT_PATH=/path/to/vault
turbovault --profile production --init
0 - Success1 - General error (vault not found, invalid config, etc.)2 - Vault initialization failed3 - Server startup failedInstall Claude Desktop: Download from Anthropic
Build turbovault-server:
cd TurboVault
make release
Configure Claude Desktop:
macOS/Linux: ~/.config/claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"obsidian": {
"command": "/absolute/path/to/turbovault",
"args": [
"--vault", "/absolute/path/to/your/vault",
"--profile", "production",
"--init"
]
}
}
}
Restart Claude Desktop
Verify Connection:
You: "Search my vault for notes about Rust async programming and summarize the key concepts."
Claude will:
search(query="rust async programming")read_note(path=...)You: "Analyze the health of my vault and suggest improvements."
Claude will:
quick_health_check() to get overall scoreget_broken_links() to find issuesget_hub_notes() to identify important notesYou: "Create a task note for implementing user authentication with high priority."
Claude will:
list_templates() to find available templatescreate_from_template(template_id="task", path="tasks/user-auth.md", fields={"title":"User Authentication","priority":"high"})You: "Find all completed project notes and move them to the archive folder."
Claude will:
query_metadata(pattern='status: "completed"')batch_execute() to atomically move files and update backlinksProblem: Claude doesn't see the server
Check Claude Desktop logs:
# macOS
tail -f ~/Library/Logs/Claude/mcp*.log
# Linux
tail -f ~/.config/Claude/logs/mcp*.log
Verify server runs standalone:
/path/to/turbovault --vault /path/to/vault --init
Check config file syntax (must be valid JSON)
Use absolute paths (not ~ or relative paths)
Problem: Server starts but tools fail
.obsidian folder (valid Obsidian vault)The server includes production-grade observability via OpenTelemetry.
Log Levels:
# Environment variable controls logging
export RUST_LOG=debug # All debug logs
export RUST_LOG=info # Info and above
export RUST_LOG=warn # Warnings and errors only
export RUST_LOG=TurboVault=debug # Debug for TurboVault only
# Multi-crate filtering
export RUST_LOG=info,TurboVault=debug,turbomcp=trace
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
Built-in Metrics:
Accessing Metrics:
Metrics are emitted via OpenTelemetry and can be exported to:
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)
Distributed Tracing:
The server emits OpenTelemetry spans for:
Viewing Traces:
Set up OTLP collector:
# docker-compose.yml
services:
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686" # Jaeger UI
- "4317:4317" # OTLP receiver
Configure server:
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
turbovault --vault /path/to/vault --profile production
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
When enable_security_auditing() is enabled (production profile):
Audit Log Example:
{
"timestamp": "2025-10-16T10:30:05Z",
"level": "WARN",
"message": "Path traversal attempt blocked",
"fields": {
"requested_path": "../../etc/passwd",
"vault_root": "/path/to/vault",
"operation": "read_note",
"client": "claude-desktop"
}
}
Use development profile:
turbovault --vault /path/to/vault --profile development
Defaults are fine - caching, file watching, full indexing.
Use production profile:
turbovault --vault /path/to/vault --profile production --init
Tuning:
--init to build graph once on startupquick_health_check() instead of full_health_analysis()Use high-performance profile:
turbovault --vault /path/to/vault --profile high-performance --init
Tuning:
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:
.ignore file to exclude temporary files# Run benchmarks (if available)
cargo bench -p turbovault-server
# Profile with perf (Linux)
perf record --call-graph dwarf ./target/release/turbovault --vault /path/to/vault
perf report
# Memory profiling with valgrind (Linux)
valgrind --tool=massif ./target/release/turbovault --vault /path/to/vault
Error:
Error: Failed to create vault config: Vault path does not exist: /path/to/vault
Solution:
ls -la /path/to/vault~).obsidian/ folderSymptoms:
Solution:
# Look for these log lines:
[INFO] Server initialized with vault
[INFO] Vault: /path/to/vault
--vault flag:
turbovault --vault /path/to/vault --init
.obsidian/ and .md files)Error:
Error: Permission denied (os error 13)
Solution:
ls -ld /path/to/vault
# Should show read/write for your user
chmod -R u+rw /path/to/vault
Error:
[ERROR] Failed to initialize vault: Link parsing error
Solution:
# Find suspicious links
grep -r '\[\[.*\[\[' /path/to/vault/*.md
[[link (missing ]])Symptoms:
search() tool returns empty arraySolution:
--init flag[INFO] Building search index... (1250 files)
[INFO] Search index ready
Symptoms:
Solution:
high-performance profile (disables file watching)# Shorten cache lifetime
turbovault --vault /path/to/vault --profile production
Symptoms:
Solution:
--init to build graph once on startup (not on-demand)export RUST_LOG=debug
# Look for slow operations in logs
high-performance profileEnable detailed logging:
export RUST_LOG=debug
turbovault --vault /path/to/vault --init 2>&1 | tee debug.log
Send debug logs when reporting issues:
# Sanitize logs (remove sensitive paths)
sed 's|/Users/yourname/|/home/user/|g' debug.log > debug-sanitized.log
# Attach debug-sanitized.log to issue report
turbovault --version)rustc --version)# Clone repository
git clone https://github.com/epistates/TurboVault.git
cd TurboVault
# Build debug binary (fast compile, slower runtime)
cargo build -p turbovault-server
# Build release binary (slow compile, optimized runtime)
cargo build -p turbovault-server --release
# Run tests
cargo test -p turbovault-server
# Run with cargo
cargo run -p turbovault-server -- --vault /path/to/vault --init
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 (44 tools)
├── tests/
│ └── integration_test.rs # Integration tests
├── Cargo.toml # Dependencies and binary config
└── README.md # This file
Implement in tools.rs:
#[tool("my_new_tool")]
async fn my_new_tool(&self, param: String) -> McpResult<String> {
let manager = self.get_manager().await?;
let tools = MyTools::new(manager);
let result = tools.my_operation(¶m).await.map_err(to_mcp_error)?;
Ok(result)
}
Add to turbovault-tools (if reusable logic):
// crates/turbovault-tools/src/my_tools.rs
pub struct MyTools {
pub manager: Arc<VaultManager>,
}
impl MyTools {
pub async fn my_operation(&self, param: &str) -> Result<String> {
// Implementation
}
}
Write tests:
#[tokio::test]
async fn test_my_new_tool() {
let (_temp, manager) = create_test_vault().await;
let server = ObsidianMcpServer::new();
server.initialize(manager).await;
// Test tool invocation
let result = server.my_new_tool("test".to_string()).await;
assert!(result.is_ok());
}
Update documentation in this README
# All server tests
cargo test -p turbovault-server
# Specific test
cargo test -p turbovault-server test_server_initialization
# With output
cargo test -p turbovault-server -- --nocapture
# Integration tests only
cargo test -p turbovault-server --test integration_test
# Format code
cargo fmt --all
# Run linter
cargo clippy --all -- -D warnings
# Check compilation without building
cargo check -p turbovault-server
┌─────────────────────────────────────────────────────────┐
│ 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 │ │
│ │ - 44 #[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 | 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:
turbovault-tools, server just wraps it1. 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):
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)
Path Validation:
.. components rejectedInput Validation:
Error Handling:
Result)Audit Trail:
For more details on specific components:
../turbovault-core/README.md../turbovault-parser/README.md../turbovault-graph/README.md../turbovault-vault/README.md../turbovault-batch/README.md../turbovault-export/README.md../turbovault-tools/README.md/docs/deployment/index.md (project root)/DILIGENCE_PASS_COMPLETE.md (project root)Part of the TurboVault project. See project root for license information.
tests/integration_test.rs for usage examplesProduction Status: ✅ Ready for production use with Claude Desktop and MCP-compliant clients.