mcp-construe CLAUDE.md
This FastMCP server provides tools to extract and concatenate personal context from an Obsidian vault. The primary use case is loading curated personal knowledge into an LLM conversation by leveraging Obsidian's frontmatter tagging system.
FastMCP Obsidian Context Server - Development Brief
Overview
This FastMCP server provides tools to extract and concatenate personal context from an Obsidian vault. The primary use case is loading curated personal knowledge into an LLM conversation by leveraging Obsidian's frontmatter tagging system.
Core Functionality
Purpose
- Load personal context from Obsidian notes into LLM conversations
- Use Obsidian frontmatter properties and tags as filtering criteria
- Provide concatenated, chronologically ordered content for comprehensive context
Architecture
The server consists of several main tools:
- fetch_context() - Loads context based on context type (e.g., 'personal', 'work')
- fetch_matching_files() - Flexible tool for runtime filtering by properties/tags
- fetch_frontmatter_index() - Lightweight metadata browsing without full content
- fetch_specific_file() - Targeted retrieval of specific files by path
- search_vault_content() - Content-based search (hardcore mode) with frontmatter results
Configuration System
config.yaml Structure
vault_path: "/path/to/obsidian/vault"
default_context:
properties:
context: "personal"
tags: []
Configuration Loading
- config.yaml must be located in the same directory as the MCP server script
- Server reads configuration on startup
- Vault path supports user home directory expansion (~)
File Processing Pipeline
1. File Discovery
- Recursively scan vault directory for
.mdfiles using pathlib - Filter out non-markdown files automatically
2. Frontmatter Parsing
- Extract YAML frontmatter between first and second
---at line start - Parse properties and tags from frontmatter
- Handle malformed YAML gracefully (skip file or log warning)
3. Filtering Logic
Properties Matching:
- AND logic: All specified properties must match exactly
- Case-sensitive property names and values
Tags Matching:
- Default OR logic: File matches if it contains any specified tag
- Optional AND logic:
match_all_tags=Truerequires all specified tags - Tags expected as YAML list in frontmatter:
tags: [personal, finance]
Combined Filtering:
- Properties AND tags criteria must both be satisfied
- Empty criteria arrays are ignored (no filtering applied)
4. Sorting
- Sort matched files by file modification time (oldest first)
- Use pathlib.Path.stat().st_mtime for consistent cross-platform behavior
5. Content Concatenation
Format:
================================================================================
/absolute/path/to/file.md
================================================================================
[full file content including frontmatter]
================================================================================
/absolute/path/to/next/file.md
================================================================================
[full file content including frontmatter]
Tool Specifications
fetch_context()
- Parameters:
context_type: str- Context type to match (e.g., 'personal', 'work')chunk_index: int = 0- Which chunk to retrievemax_chars: int = 95000- Maximum characters per chunk
- Returns: String (concatenated content)
- Behavior: Uses context type to filter by context property from config.yaml
- Error Handling: Returns error message if config missing or vault inaccessible
fetch_matching_files()
- Parameters:
properties: dict- Key-value pairs to match in frontmattertags: list[str]- Tags to search formatch_all_tags: bool = False- Whether to require all tags (AND) vs any tags (OR)chunk_index: int = 0- Which chunk to retrievemax_chars: int = 95000- Maximum characters per chunk
- Returns: String (concatenated content)
- Behavior: Runtime filtering with specified criteria, with chunking support
- Error Handling: Returns error message for invalid parameters or processing errors
fetch_frontmatter_index()
- Parameters:
properties: dict- Key-value pairs to match in frontmattertags: list[str]- Tags to search formatch_all_tags: bool = False- Whether to require all tags (AND) vs any tags (OR)
- Returns: String (formatted table of file metadata)
- Behavior: Returns lightweight frontmatter index without full content - ideal for browsing
- Error Handling: Returns error message for invalid parameters or processing errors
fetch_specific_file()
- Parameters:
file_path: str- Absolute or relative path to the file
- Returns: String (complete file content with formatting header)
- Behavior: Retrieves full content of a specific file by path - use after browsing index
- Error Handling: Returns error message for invalid paths or inaccessible files
search_vault_content() (Hardcore Mode)
- Parameters:
search_pattern: str- Text or regex pattern to search for in file contentcase_sensitive: bool = False- Whether to perform case-sensitive searchregex: bool = False- Whether to treat search_pattern as regex (default: plain text)context_chars: int = 100- Number of characters of context around matches
- Returns: String (formatted index with match context)
- Behavior: Searches through all file content and returns frontmatter index of matching files
- Error Handling: Returns error message for invalid regex or processing errors
Technical Implementation Details
Dependencies
fastmcp- MCP server frameworkpathlib- File system operations (built-in)yaml- Configuration and frontmatter parsingre- Frontmatter extraction regex- Standard library modules for file operations
Error Handling Strategy
- Graceful degradation: Skip problematic files rather than failing entirely
- Informative error messages for configuration issues
- Log warnings for malformed frontmatter (continue processing)
Performance Considerations
- Lazy file reading (only read files that pass initial filtering)
- Efficient frontmatter extraction (stop reading after second
---) - Reasonable limits on number of files processed (configurable if needed)
Security Considerations
- Restrict vault path to prevent directory traversal
- Validate file extensions to prevent processing of non-markdown files
- Handle file permission errors gracefully
File Structure
obsidian_context_server.py # Main MCP server implementation
config.yaml # Configuration file
README.md # Documentation and usage examples
Example Usage Scenarios
Loading Personal Context
# LLM calls: fetch_personal_context()
# Returns: All files with context: personal property, chronologically ordered
Finding Project Notes
# LLM calls: fetch_matching_files(properties={"type": "project"}, tags=["active"])
# Returns: Files with type: project AND containing "active" tag
Research Collection
# LLM calls: fetch_matching_files(tags=["research", "ai"], match_all_tags=True)
# Returns: Files containing both "research" AND "ai" tags
Progressive Discovery Workflow (New Feature)
# Phase 1: Browse metadata without loading full content
# LLM calls: fetch_frontmatter_index(tags=["ai"])
# Returns: Table showing titles, paths, tags, context types for 25 files
# Phase 2: Agent selects specific files based on metadata
# LLM calls: fetch_specific_file("research/ai-governance-framework.md")
# Returns: Complete content of just that targeted file
Hardcore Content Search (New Feature)
# Content-based discovery when you don't know the frontmatter structure
# LLM calls: search_vault_content("machine learning algorithms")
# Returns: Frontmatter index of files containing that phrase, with match context
# Advanced regex search
# LLM calls: search_vault_content("neural.*network", regex=True)
# Returns: Files matching regex pattern, sorted by relevance (match count)
This implementation provides a robust, flexible system for integrating Obsidian vault content into LLM conversations while maintaining clear separation of concerns and comprehensive error handling. The progressive disclosure and hardcore search features enable efficient context browsing, content discovery, and selective loading.