A Ruby-based Model Context Protocol (MCP) server for interacting with Obsidian vaults. Built with fast-mcp, this server allows AI models to search, read, and analyze your evergreen notes.
- Search Notes: Find notes by content, title, or tags
- Read Individual Notes: Get full note content including frontmatter and links
- List All Notes: Browse all notes with metadata
- Tag-based Filtering: Find notes by specific tags
- Vault Statistics: Get comprehensive statistics about your vault
- Tag Cloud: Analyze tag usage patterns
-
Clone this repository:
git clone <repository-url> cd obsidian-mcp-server
-
Install dependencies:
bundle install
-
Set your vault path (optional):
export OBSIDIAN_VAULT_PATH="/path/to/your/obsidian/vault"
./obsidian_server.rbThe server will automatically discover your vault using these methods based on the OBSIDIAN_VAULT_PATH environment variable.
Search for notes by query text in titles, tags, or content.
Read the full content of a specific note by filename or title.
Get a list of all notes in the vault with basic metadata.
Find notes that contain specific tags with flexible matching options.
Access comprehensive statistics about your vault:
- Total notes and words
- Average words per note
- Unique tags count
- Internal and external link counts
Get tag usage statistics and counts across your vault.
Set environment variables to customize the server:
OBSIDIAN_VAULT_PATH: Path to your Obsidian vault
The project follows a clean, modular architecture built on the fast-mcp Ruby framework:
├── obsidian_server.rb # Main executable server entry point
├── Gemfile # Dependencies (fast-mcp ~> 1.5, rspec, rubocop)
├── mise.toml # Development environment configuration
├── CHANGELOG.md # Project changelog and version history
├── lib/ # Main application code
│ ├── obsidian_mcp.rb # Main module and server factory
│ └── obsidian_mcp/
│ ├── config.rb # Environment-based configuration
│ ├── logger.rb # Semantic logging configuration
│ ├── models/ # Domain models
│ │ ├── vault.rb # Vault discovery and file operations
│ │ └── note.rb # Note parsing and metadata extraction
│ ├── services/ # Business logic services
│ │ ├── search_service.rb # Content and metadata search
│ │ └── stats_service.rb # Vault statistics calculation
│ ├── base/ # Abstract base classes
│ │ ├── tool.rb # MCP tool interface
│ │ └── resource.rb # MCP resource interface
│ ├── tools/ # MCP tool implementations
│ │ ├── search_notes.rb # Full-text search across notes
│ │ ├── read_note.rb # Single note content retrieval
│ │ ├── list_notes.rb # Vault-wide note listing
│ │ └── find_by_tags.rb # Tag-based filtering
│ └── resources/ # MCP resource implementations
│ ├── vault_statistics.rb # Comprehensive vault metrics
│ └── tag_cloud.rb # Tag usage analytics
└── spec/ # Comprehensive test suite
├── spec_helper.rb # RSpec configuration and setup
├── support/ # Test helpers and shared contexts
│ └── test_vault_setup.rb # Comprehensive test vault fixture
├── models/ # Model unit tests
│ └── vault_spec.rb # Vault model testing
└── integration/ # Integration tests
└── tools/ # Tool-specific integration tests
└── list_notes_spec.rb # Complete ListNotes tool test- Server Entry (
obsidian_server.rb): Executable script that initializes and starts the MCP server - Configuration (
config.rb): Manages vault discovery and environment variables - Models: Domain objects representing vaults and individual notes with frontmatter parsing
- Services: Business logic for search operations and statistical analysis
- Tools: MCP tool implementations providing interactive capabilities
- Resources: MCP resource implementations providing read-only data access
- Test Suite (
spec/): Comprehensive RSpec-based testing with 270+ assertions - Test Vault Setup (
spec/support/test_vault_setup.rb): Creates realistic test scenarios with:- 11 different note types (simple, tagged, frontmatter-only, empty, malformed, etc.)
- Subdirectory handling (
projects/project-alpha.md) - Unicode and special character support
- Predictable timestamps for consistent testing
- Temporary vault cleanup
- Integration Tests: Full end-to-end testing of MCP tools with edge case coverage
- Shared Contexts: Reusable test fixtures with
:vault_setuptag
The server automatically discovers vaults in this priority order:
OBSIDIAN_VAULT_PATHenvironment variable/vault(container volume)
- Initialization: Server discovers vault path and validates accessibility
- Tool Requests: MCP client sends tool calls (search, read, list, filter)
- Processing: Services handle business logic using models for data access
- Resource Requests: MCP client requests statistical resources
- Response: Formatted JSON responses with note content and metadata
The project uses a comprehensive testing approach:
- Integration Testing: Tests complete MCP tool workflows from input to output
- Realistic Fixtures: Test vault with diverse note types and edge cases
- Performance Testing: Ensures sub-second response times
- Error Handling: Tests graceful handling of malformed data and missing paths
- Unicode Support: Validates proper handling of international characters and emojis
- Consistency Testing: Verifies identical results across multiple calls
You can test the server using the official MCP inspector:
npx @modelcontextprotocol/inspector ./obsidian_server.rbAdd to your Claude Desktop configuration:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\\Claude\\claude_desktop_config.json
{
"mcpServers": {
"obsidian-vault": {
"command": "ruby",
"args": ["/path/to/obsidian-mcp-server/obsidian_server.rb"],
"env": {
"OBSIDIAN_VAULT_PATH": "/path/to/your/obsidian/vault"
}
}
}
}Run the MCP server using Docker for easy deployment and environment consistency.
-
Build and run with Docker Compose (recommended):
# Build and start the server docker-compose up --build # Run in detached mode docker-compose up -d --build # Stop the server docker-compose down
-
Build and run with Docker directly:
# Build the image docker build -t obsidian-mcp-server . # Run the container with your vault mounted docker run -it --rm \ -v "/path/to/your/obsidian/vault:/vault:ro" \ -e OBSIDIAN_VAULT_PATH=/vault \ obsidian-mcp-server
Set environment variables to customize the Docker deployment:
# Set your vault path (host machine)
export OBSIDIAN_VAULT_PATH="/Users/you/Documents/MyVault"
# Start with custom configuration
docker-compose upFor development work, use the development container that includes test dependencies:
# Start development container
docker-compose up obsidian-mcp-server-dev
# Or run interactively
docker-compose run --rm obsidian-mcp-server-dev /bin/sh
# Inside the container, you can run tests
bundle exec rspec
# Or start the server
./obsidian_server.rbTo use the Dockerized server with Claude Desktop, you can run it as a persistent service:
{
"mcpServers": {
"obsidian-vault": {
"command": "docker",
"disabled": true,
"args": [
"run",
"-i",
"--rm",
"-v",
"/path/to/your/vault:/vault",
"obsidian-mcp-server"
]
}
}
}
Note: Make sure to build the Docker image first: docker build -t obsidian-mcp-server .
Dockerfile: Production-ready image with minimal dependenciesDockerfile.dev: Development image with test dependencies and toolsdocker-compose.yml: Easy orchestration for both production and development.dockerignore: Optimizes build context by excluding unnecessary files
The Docker setup mounts your Obsidian vault as a read-only volume for security:
- Host path: Your actual Obsidian vault location
- Container path:
/vault(mapped viaOBSIDIAN_VAULT_PATH=/vault) - Access: Read-only (
:ro) to prevent accidental modifications
- Permission issues: Ensure your vault directory is readable
- Path issues: Use absolute paths when mounting volumes
- Build issues: Clear Docker cache with
docker system prune - Container logs: Check with
docker-compose logs obsidian-mcp-server
- Install dependencies:
mise run bundle
# or
bundle install- Run the development server:
mise run dev
# or
./obsidian_server.rb- Run tests:
bundle exec rspecThe project uses mise for task automation:
# Install dependencies
mise run bundle
# Start development server
mise run dev
# Fix code style issues automatically
mise run rubocop-fix
# Update RuboCop todo list (after fixing violations)
mise run rubocop-todo-update
# Build production Docker image
mise run docker:build
# Build development Docker image
mise run docker:build:devThis project enforces code style using RuboCop with rubocop-rspec:
- Automatic fixes: Run
mise run rubocop-fixto auto-correct violations - Todo list approach: Existing violations are tracked in
.rubocop_todo.yml - CI enforcement: New violations will fail GitHub Actions checks
- Incremental improvement: Fix violations gradually by removing entries from the todo list
Metrics/MethodLength: Allows longer methods where appropriateRSpec/MultipleExpectations: Permits multiple assertions in integration tests
Comprehensive test suite with 270+ assertions:
# Run all tests
bundle exec rspec
# Run with coverage
bundle exec rspec --format documentation
# Run specific test files
bundle exec rspec spec/integration/GitHub Actions automatically:
- Runs the full test suite on Ruby 3.4
- Enforces code style with RuboCop
- Runs integration tests
- Provides inline PR feedback for violations
-
Fork the repository
-
Create your feature branch (
git checkout -b feature/amazing-feature) -
Make your changes following the code style guidelines
-
Run tests and fix any style violations:
bundle exec rspec mise run rubocop-fix -
Commit your changes (
git commit -m 'Add some amazing feature') -
Push to the branch (
git push origin feature/amazing-feature) -
Open a Pull Request
- Tests pass locally (
bundle exec rspec) - No RuboCop violations (
bundle exec rubocop) - New features include tests
- Documentation updated if needed
- CI checks pass on GitHub
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with fast-mcp
- Test notes from keikhcheung/notes
- Inspired by the Model Context Protocol specification