# vault-mcp

Markdown + SQLite knowledge store with bidirectional `[[wikilinks]]`, exposed as an MCP server. Designed for AI agents to maintain an interconnected knowledge base.

## Installation

```bash
uvx vault-mcp                           # run directly without install
pip install vault-mcp                   # core (keyword search only)
pip install "vault-mcp[semantic]"       # + embedding-based semantic search
```

## Running the MCP Server

```bash
# Start with default settings (vault in ./vault)
vault-mcp

# Custom vault directory
VAULT_DIR=/path/to/notes vault-mcp

# With semantic search enabled
VAULT_DIR=./vault VAULT_EMBEDDING_MODEL=jinaai/jina-embeddings-v5-text-nano vault-mcp
```

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `VAULT_DIR` | `./vault` | Root directory for markdown files |
| `VAULT_EMBEDDING_MODEL` | *(none)* | Sentence-transformers model name. Enables semantic search when set |

## Client Configuration

### Claude Code

```bash
claude mcp add vault -- vault-mcp
```

Or `.mcp.json`:

```json
{
  "mcpServers": {
    "vault": {
      "type": "stdio",
      "command": "vault-mcp",
      "env": { "VAULT_DIR": "./vault" }
    }
  }
}
```

### Cursor / Windsurf / Other MCP Clients

Add to your MCP settings:

```json
{
  "vault": {
    "command": "vault-mcp",
    "env": { "VAULT_DIR": "./vault" }
  }
}
```

### Python Library (no MCP)

```python
from vault_mcp import MarkdownVault, create_vault_tools

vault = MarkdownVault("./my-vault")
vault.write("skill/debugging", {"type": "skill", "confidence": "pattern"}, "# Debugging\n\n...")

# Or get all 11 tools as a dict of callables
tools = create_vault_tools(vault)
result = tools["vault_search"](query="debugging", mode="keyword")
```

## Note Format

Each note is a `.md` file with YAML frontmatter, organized in type-based folders:

```
vault/
  skill/
    timeout-diagnosis.md
  concept/
    connection-pooling.md
  episodic/
    2024-01-15-incident.md
```

```markdown
---
type: skill
tags: [database, timeout]
confidence: pattern
status: active
---

# Timeout Diagnosis

Description of the skill...

## Evidence
- [[episodic/2024-01-15-incident]]: First observed during outage

## Related
- [[concept/connection-pooling]]
```

### Frontmatter Fields

| Field | Required | Values |
|-------|----------|--------|
| `type` | Yes | `skill`, `episodic`, `concept`, `failure-pattern`, `system-knowledge` |
| `confidence` | Yes | `fact`, `pattern`, `heuristic` |
| `tags` | No | Free-form string list |
| `status` | Auto | `active`, `superseded`, `archived` |

## Tools

### Write & Edit

| Tool | Description |
|------|-------------|
| `vault_write(path, frontmatter, body)` | Create or overwrite a note |
| `vault_write_batch(entries)` | Write multiple notes atomically |
| `vault_edit(path, operation, params)` | Incremental edit (4 operations below) |
| `vault_delete(path)` | Delete a note |
| `vault_rename(old_path, new_path)` | Rename + auto-rewrite all backlinks |

#### Edit Operations

| Operation | Params | Use |
|-----------|--------|-----|
| `replace_string` | `{"old": "...", "new": "..."}` | Inline corrections |
| `set_frontmatter` | `{"confidence": "fact"}` | Update metadata |
| `replace_section` | `{"heading": "## Evidence", "body": "..."}` | Rewrite a section |
| `append_section` | `{"heading": "## Evidence", "content": "..."}` | Append to a section |

### Read & Browse

| Tool | Description |
|------|-------------|
| `vault_read(path)` | Read frontmatter + body |
| `vault_list(path, depth, type_filter)` | Browse directory |

### Search & Discovery

| Tool | Description |
|------|-------------|
| `vault_search(query, filters, mode, limit)` | FTS5 / semantic / hybrid search |
| `vault_backlinks(path)` | Who links to this note |
| `vault_traverse(start, depth, direction)` | BFS graph traversal with directed edges |
| `vault_lint()` | Find dead links + orphan notes |

## Validation

Every write/edit automatically checks and returns warnings:
- Required frontmatter fields (`type`, `confidence`)
- Valid enum values
- H1 heading present in body
- All `[[wikilinks]]` resolve to existing notes

The write succeeds regardless — warnings are informational for the agent to decide whether to fix.

## Architecture

```
.md files (source of truth, git-trackable)
    │
    ▼
.vault.db (SQLite index, auto-rebuilt if deleted)
    ├── notes       — YAML frontmatter metadata
    ├── notes_fts   — FTS5 full-text search
    ├── links       — [[wikilink]] directed graph
    ├── tags        — tag index
    └── notes_vec   — embedding vectors (optional)
```

## License

MIT
