Obsidian Knowledge Management MCP Server
A local MCP (Model Context Protocol) server that provides stateless I/O access to Obsidian vaults. This server enables LLMs to read, analyze, and manage Obsidian markdown files, YAML frontmatter, and wikilinks.
Key Features
- Stateless I/O Layer: Pure data access and atomic operations - no semantic analysis
- 35+ MCP Tools: Comprehensive vault management across 5 categories
- Frontmatter Management: Parse, update, and validate YAML metadata
- Wikilink Operations: Extract, analyze, and manipulate
[[wikilinks]] - Graph Operations: Build link graphs, find backlinks, identify orphan notes
- Full-Text Search: Literal and regex pattern matching across vault
- Security: Path validation prevents directory traversal attacks
Installation
npm install
npm run build
Configuration
Create a .env file based on .env.example:
VAULT_PATH=./Test Vault
LOG_LEVEL=info
MAX_CONCURRENT_OPS=10
Or set environment variables when running:
VAULT_PATH="./Test Vault" node dist/index.js
Usage
Running the Server
The server uses stdio transport for MCP communication:
VAULT_PATH="./Test Vault" node dist/index.js
Claude Desktop Integration
Add to your Claude Desktop MCP configuration:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"obsidian-knowledge": {
"command": "node",
"args": ["/absolute/path/to/obsidian-knowledge-mcp/dist/index.js"],
"env": {
"VAULT_PATH": "/absolute/path/to/your/vault"
}
}
}
}
Available Tools (Phase 1 - Navigation)
1. list_notes
List all notes with optional filtering.
Arguments:
folder(optional): Filter by folder pathtags(optional): Array of tags (note must have all)dateRange(optional):{ start, end }in ISO formatoffset(optional): Skip N notes for paginationlimit(optional): Return max N notes
Example:
{
"folder": "Studies/MATH 31AH",
"tags": ["MATH31AH"],
"limit": 10
}
Returns: Array of NoteMetadata with path, title, created date, tags, modified date, size.
2. read_note
Read a note with full metadata.
Arguments:
path(required): Vault-relative path (e.g.,"Studies/MATH 31AH/Vectors.md")
Returns:
content: Full markdown contentfrontmatter: Parsed YAML (or null if missing/malformed)frontmatterError: Parse error message if YAML is malformedoutgoingLinks: Array of wikilinks with target, alias, heading, line, columnheadings: Array of headings with level, text, line, idstats: Line count, character count, modified timestamp
3. read_notes_batch
Read multiple notes in one call.
Arguments:
paths(required): Array of vault-relative paths
Returns: Array of ReadNoteResult (same as read_note)
4. search_notes
Full-text search across vault.
Arguments:
pattern(required): Search string or regexisRegex(optional): Treat pattern as regex (default: false)folder(optional): Limit search to folderlimit(optional): Max occurrences per note (default: 10)
Returns: Array of SearchResult with path, match count, and occurrences (with line, column, context).
5. get_vault_structure
Get folder hierarchy with note counts.
Arguments: None
Returns: FolderNode tree with path, name, note count, and children.
Architecture
┌─────────────────────────────────────────┐
│ MCP Server (index.ts) │
│ - Tool registration │
│ - Request routing │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Tool Handlers (tools/*.ts) │
│ - navigation.ts - list, read, search │
│ - notes.ts - create, update, move │
│ - frontmatter.ts - get, update, bulk │
│ - links.ts - get links, backlinks │
│ - stats.ts - tags, titles │
└─────────────────────────────────────────┘
↓
┌──────────────────┬──────────────────────┐
│ Vault (vault.ts)│ Parser (parser.ts) │
│ - Path security │ - Frontmatter parse │
│ - File I/O │ - Wikilink extract │
│ - Validation │ - Heading extract │
└──────────────────┴──────────────────────┘
Error Handling
The server returns structured errors with actionable suggestions:
{
"success": false,
"error": {
"code": "FILE_NOT_FOUND",
"message": "File not found: nonexistent.md",
"context": { "path": "nonexistent.md" },
"actionable": "Use list_notes or get_note_titles to find available notes"
}
}
Error Codes:
PATH_OUTSIDE_VAULT: Path contains..or escapes vaultFILE_NOT_FOUND: File does not existFILE_LOCKED: File in use by another processINVALID_FRONTMATTER: YAML parse errorINVALID_PATH: Path contains illegal characters
Development
Building
npm run build # Compile TypeScript
npm run dev # Watch mode
Testing
npm test # Run all tests
npm run test:unit # Unit tests only
npm run test:integration # Integration tests with Test Vault
Linting
npm run lint
Roadmap
Phase 1: Foundation & Navigation (Completed)
- MCP server initialization
- Vault access with path security
- Frontmatter and wikilink parsing
- 5 navigation tools (list, read, search, structure)
Phase 2: Note Management (Planned)
- create_note - Create with content + frontmatter
- update_note - Replace or patch sections
- move_note - Relocate + update backlinks
- delete_note - Remove + clean dangling references
Phase 3: Frontmatter Operations (Planned)
- get_frontmatter - Parse metadata
- update_frontmatter - Modify fields
- bulk_update_frontmatter - Update across multiple notes
- audit_frontmatter - Validate against schema
Phase 4: Link Operations (Planned)
- get_links - Outgoing wikilinks
- get_backlinks - Incoming links
- get_all_links - Complete link graph
- insert_link - Add wikilink
- get_orphan_notes - Notes with no links
- get_headings - Heading structure
- find_text_occurrences - Pattern matching
Phase 5: Statistics & Polish (Planned)
- get_tag_list - All tags with counts
- get_note_titles - All titles + aliases
- Comprehensive documentation
- Integration tests
- Performance optimization
Design Principles
- Stateless: No caching, each call is independent
- Security: Path validation prevents escapes
- Rich Metadata: Include line numbers and positions for precise edits
- Graceful Degradation: Malformed frontmatter returns with error flag
- SOLID Principles: Clean separation of vault, parser, and tool layers
License
MIT
Contributing
Contributions welcome! This project follows SOLID principles and maintains a strict separation between the I/O layer (server) and intelligence layer (LLM).
