# mcp-construe
A FastMCP server that loads personal context from Obsidian vaults using frontmatter filtering - curate your knowledge for AI conversations.

## Features

- **Bidirectional Knowledge Management**: Read from and write to your Obsidian vault
- **Smart Chunking**: Automatically splits large result sets to stay within context limits (95k characters per chunk)
- **Flexible Filtering**: Search by frontmatter properties and tags with AND/OR logic
- **File Protection**: Secure controls prevent overwriting files outside designated contexts
- **Frontmatter Integration**: Proper YAML frontmatter generation and parsing

## Usage

### Basic Usage
```bash
python3 mcp-construe.py
```

### Custom Configuration
```bash
python3 mcp-construe.py --config other-config.yaml
python3 mcp-construe.py --config /path/to/custom-config.yaml
```

### Configuration
Create a `config.yaml` file in the same directory as the script:

```yaml
# Path to your Obsidian vault (supports ~ for home directory)
vault_path: "/path/to/obsidian/vault"

# Default context criteria for fetch_context()
default_context:
  properties:
    context: "personal"
  tags: []

# Protection settings: Only allow creating/overwriting files with this property value
# The MCP server can only create files with this property, and can only overwrite
# files that have this property set to one of these values
protection_property: "author"     # which frontmatter property to check
protection_value: ["claude"]      # allowed values (supports single string or list)
```

## Tools

### Context Loading Tools
- **fetch_context(context_type, chunk_index=0)** - Load files by context type with chunking support
- **fetch_matching_files(properties, tags, match_all_tags, chunk_index=0)** - Flexible filtering with chunking
- **fetch_frontmatter_index(properties, tags, match_all_tags, chunk_index=0, max_chars=95000)** - Browse file metadata with pagination

### Chunking Management Tools  
- **list_context_chunks(context_type, max_chars=95000)** - List available chunks for a context type
- **list_matching_chunks(properties, tags, match_all_tags, max_chars=95000)** - List chunks for custom search
- **fetch_context_chunk(context_type, chunk_index, max_chars=95000)** - Fetch specific chunk by context
- **fetch_matching_chunk(chunk_index, properties, tags, match_all_tags, max_chars=95000)** - Fetch specific chunk by criteria

### File Creation Tools
- **create_file(filename, content, properties, tags, subfolder="", overwrite=False)** - Create new files with frontmatter

## Security Features

### File Protection System
The server includes a robust protection mechanism that prevents unauthorized file modifications:

1. **Dual Validation**: Both new files being created AND existing files being overwritten must have the required protection property
2. **Flexible Property Control**: Configure any frontmatter property (e.g., `author`, `context`, `owner`) as the protection key
3. **Multiple Allowed Values**: Support for multiple valid values (e.g., `["claude", "assistant"]`)
4. **Complete Coverage**: All file write operations are protected

### Example Protection Scenarios

**Configuration**: `protection_property: "author"`, `protection_value: ["claude"]`

✅ **Allowed**:
```python
# Create new file with required property
create_file("note.md", "content", properties={"author": "claude"})

# Overwrite existing file that has author: claude
create_file("existing.md", "new content", properties={"author": "claude"}, overwrite=True)
```

❌ **Blocked**:
```python
# Missing required property
create_file("note.md", "content", properties={})

# Wrong property value  
create_file("note.md", "content", properties={"author": "unauthorized"})

# Attempting to overwrite file with different author
# (existing file has author: human, config requires author: claude)
```

## Chunking Behavior

When search results exceed the 95k character limit, the system automatically chunks results:

1. **Use listing tools** to see available chunks: `list_context_chunks()` or `list_matching_chunks()`
2. **Fetch specific chunks** using chunk tools or `chunk_index` parameter
3. **Files are never split** - each chunk contains complete files only
4. **Automatic warnings** when multiple chunks are available

## Example Frontmatter

Files should include proper YAML frontmatter for filtering:

```markdown
---
author: claude
context: personal
type: note
tags: [ai, productivity, tools]
created: 2024-01-15
---

# Your Content Here

This note will be discoverable by the MCP server.
```

## Installation

1. Clone the repository
2. Install dependencies: `pip install fastmcp pyyaml pathlib`
3. Configure your `config.yaml`
4. Run: `python3 mcp-construe.py`

## Changelog

### 2025-09-15
- **Added pagination to fetch_frontmatter_index**: Added `chunk_index` and `max_chars` parameters to prevent LLM message size limit issues
- **Improved large result handling**: The frontmatter index function now automatically chunks large result sets for better performance
- **Enhanced API consistency**: All browsing functions now follow the same chunking pattern

## License

See LICENSE file for details.