Witness
Witness is an MCP server that integrates with Obsidian to allow AI assistants like Claude to read, write, and organize notes in your vault. It supports file operations, semantic search, and remote access via Cloudflare tunnels.
README
Witness
Your AI companion for transforming chaos into order
Witness is an Obsidian plugin that turns your vault into an intelligent, AI-accessible knowledge base. It runs an MCP (Model Context Protocol) server directly inside Obsidian, allowing Claude Desktop and other AI assistants to read, write, and organize your notes on your behalf.
Philosophy: Chaos → Order
Witness is built around a simple organizational philosophy:
- Chaos: Unprocessed information flowing in from the world (articles, videos, quick notes, transcripts)
- Order: Structured knowledge you've refined and organized (topics, projects, synthesis)
The plugin helps you move information from chaos to order, with AI assistance to process, categorize, and synthesize your notes.
Features
Current (Phase 1 + 2 + 3) ✅
- MCP Server: Runs inside Obsidian, no external dependencies
- File Operations: Read, write, edit, and list files in your vault via AI
- Full-Text Search: Search across all markdown files with optional filters
- Semantic Search: Find documents by meaning using local Ollama embeddings + Orama vector store
- Search Panel: Sidebar search with path and tag filtering via fuzzy autocomplete
- Background Indexing: Automatic incremental indexing with idle-gated execution (waits for 2 minutes of inactivity), debounced saves, active file deferral, and status bar countdown timer
- Command Execution: Execute any Obsidian command via AI
- Claude Desktop Integration: Connect directly from Claude Desktop app
- Remote Access: Cloudflare Quick Tunnel or Named Tunnel (permanent URL) for access from anywhere
- Named Tunnel Support: Use your own domain with Cloudflare Named Tunnels for a permanent, stable URL
- Primary Machine: Designate which machine runs the tunnel when syncing across multiple devices
- Token Authentication: Protect your remote endpoint with a simple token
- Chaos Triage: AI-assisted processing of unread chaos items with queue management and safe frontmatter updates
- Chaos Queue Panel: Visual sidebar for browsing and triaging chaos items — card-based UI with hover actions, bulk edit mode, keyboard shortcuts, and file explorer context menu
- LLM Re-ranking: Optional two-stage search — fast hybrid results shown instantly, then re-ranked by a local LLM for higher precision
- Contextual Search: Toggle a mode where the search panel automatically shows related notes based on your cursor position, selection, or current paragraph — no typing needed
- Page Preview: Cmd+hover on any search result to preview the note without leaving the panel
- Privacy First: Everything runs locally, your tunnel, your data
16 MCP Tools Available:
read_file- Read file contents (with optional Dataview rendering)write_file- Create new files (create-only, errors on existing)list_files- Browse directoriesedit_file- Find and replace textsearch- Unified content search: hybrid (keyword + semantic), vector, or fulltext modes with tag/path filteringfind- Find files by name, path, tag, or frontmatter property with metadatamove_file- Move or rename filescopy_file- Copy files to new locationcreate_folder- Create folders (with mkdir -p support)delete- Delete files/folders (with trash support)execute_command- Run Obsidian commandsget_vault_context- Load your vault's context document (auto-renders Dataview)dataview_query- Execute Dataview queries, get structured vault data (requires Dataview plugin)get_next_chaos- Get next unprocessed chaos item for triage (single or list mode)mark_triage- Record triage decision (processed, deferred, acknowledged, next, reset)copy-obsidian-url- Copy the internal Obsidian URL for the current file
Coming Soon
- Chat Interface: Connect via WhatsApp/Telegram for mobile access
- Heartbeat Prompts: Daily/weekly prompts to keep your vault fresh
- Chaos Monitoring: Get notified when unprocessed items pile up
Installation
Prerequisites
- Obsidian 1.0.0 or higher
- Node.js 20+ (for Claude Desktop connection)
- Claude Desktop app (optional, for AI integration)
- Ollama (optional, for semantic search)
Install via BRAT (Recommended)
The easiest way to install Witness is using the BRAT plugin:
- Install BRAT from Obsidian's Community Plugins
- Open BRAT settings and click "Add Beta Plugin"
- Enter:
jawache/witness - Click "Add Plugin"
- Enable Witness in Community Plugins
BRAT will automatically keep Witness updated when new releases are published.
Manual Installation
If you prefer to install manually:
-
Download the latest release
- Go to Releases
- Download
main.jsandmanifest.json
-
Install in your vault
# Create plugin folder mkdir -p /path/to/your/vault/.obsidian/plugins/witness/ # Copy files cp main.js manifest.json /path/to/your/vault/.obsidian/plugins/witness/ -
Enable in Obsidian
- Open Obsidian Settings → Community Plugins
- Disable Safe Mode if prompted
- Find "Witness" in the list and enable it
Build from Source
For developers who want to build from source:
-
Clone the repository
git clone https://github.com/jawache/witness.git cd witness -
Build the plugin
npm install npm run build -
Install in your vault
cp main.js manifest.json /path/to/your/vault/.obsidian/plugins/witness/
Connect to Claude Desktop
-
Configure Claude Desktop
Edit
~/.claude/claude_desktop_config.json(or%APPDATA%\Claude\claude_desktop_config.jsonon Windows):{ "mcpServers": { "witness": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "http://localhost:3000/mcp", "--transport", "http-only", "--allow-http" ] } } } -
Restart Claude Desktop
-
Verify Connection
In Claude Desktop, you should see "witness" in the MCP servers list. Try asking:
"Can you list the files in my vault?"
Usage
Organizing Your Vault
For best results, organize your vault with these top-level folders:
vault/
├── chaos/
│ ├── external/ # Articles, videos, clippings
│ └── inbox/ # Quick capture notes
└── order/
├── knowledge/ # Organized information
├── heartbeat/ # Daily/weekly notes
├── projects/ # Active work
└── synthesis/ # Published output
This structure isn't required, but Witness is designed to help you maintain this flow.
Settings
Open Obsidian Settings → Witness. Settings are organised into tabs:
General Tab
- Enable MCP Server: Turn the server on/off
- Port: HTTP server port (default: 3000)
Remote Access Tab
- Enable Tunnel: Expose your MCP server via Cloudflare tunnel
- Tunnel Type: Quick (random URL) or Named (permanent URL on your domain)
- Require Authentication: Protect remote access with a token
Search Tab
- Base URL: Ollama server address (default:
http://localhost:11434) - Embedding Model: Which Ollama model to use for embeddings (see Supported Models)
- Index Status: Shows the number of indexed documents and provides Build/Clear buttons
- Minimum Content Length: Skip files shorter than this many characters (default: 50). Short files produce noisy, generic embeddings that match any query — filtering them significantly improves search quality. See Why Filter Short Documents? for details.
- Folder Exclusions: Choose folders to exclude from indexing (e.g., attachments, templates). Uses a folder picker for easy selection.
Remote Access
Witness supports two types of Cloudflare tunnels to expose your vault remotely:
Option A: Quick Tunnel (Easy, Temporary)
A quick tunnel gives you a random URL that changes every time Obsidian restarts. Good for testing.
- Go to Obsidian Settings → Witness
- Toggle "Enable Tunnel"
- Set Tunnel Type to "Quick Tunnel (ephemeral)"
- Wait for the tunnel URL to appear
- Enable "Require Authentication" and copy your MCP URL
The URL will look like: https://random-words.trycloudflare.com/mcp?token=xxx
Option B: Named Tunnel (Permanent URL)
A named tunnel gives you a permanent URL on your own domain. Requires a free Cloudflare account.
Step 1: Create the tunnel in Cloudflare
- Sign up at Cloudflare Zero Trust
- Go to Networks → Tunnels
- Click Create a tunnel
- Choose Cloudflared as the connector type
- Name your tunnel (e.g., "witness")
- On the "Install connector" page, copy the tunnel token (the long
eyJh...string) - Skip the connector installation (Witness handles this automatically)
- Add a Public Hostname:
- Subdomain: e.g.,
witness - Domain: select your domain (e.g.,
example.com) - Service Type:
HTTP - URL:
localhost:3456(or whatever port you set in Witness settings)
- Subdomain: e.g.,
- Save the tunnel
Step 2: Configure Witness
- Go to Obsidian Settings → Witness
- Set the MCP Server Port to match your tunnel config (e.g.,
3456) - Toggle "Enable Tunnel"
- Set Tunnel Type to "Named Tunnel (permanent)"
- Paste your Tunnel Token from Cloudflare
- Set Tunnel URL to your public hostname (e.g.,
https://witness.example.com) - Enable "Require Authentication" (recommended)
- Click "Copy URL" to get your full MCP URL
Step 3: Connect Claude
Use the tunnel URL in your MCP client configuration:
{
"mcpServers": {
"witness": {
"command": "npx",
"args": [
"-y",
"mcp-remote@latest",
"https://witness.example.com/mcp?token=YOUR_TOKEN",
"--transport",
"http-only"
]
}
}
}
This works with Claude Desktop, Claude.ai web, and Claude mobile.
Multiple Devices (Obsidian Sync)
If you sync your vault across multiple computers using Obsidian Sync, the Witness plugin settings sync too — including the tunnel token. Without precaution, every machine would try to start the tunnel, and Cloudflare would round-robin traffic between them unpredictably.
To prevent this, Witness has a Primary Machine feature:
- Open Obsidian Settings → Witness on the machine you want to run the tunnel
- Under Named Tunnel settings, click "Set as primary"
- This saves the machine's hostname — only this machine will start the tunnel
- On other machines, the tunnel is silently skipped on startup
To switch the primary to a different machine, open Witness settings on that machine and click "Set as primary". To clear the restriction entirely, click the ✕ button next to the primary hostname.
Mobile Devices
The tunnel and MCP server features are desktop-only. Obsidian mobile (iOS/Android) cannot run the HTTP server or cloudflared binary. To access your vault from a mobile device, connect to the tunnel URL from a client app (e.g., Claude mobile) — the vault is served by whichever desktop machine is running the tunnel.
Security Notes
- The auth token is included in the URL query parameter. HTTPS encrypts this in transit, but be cautious about sharing URLs or logging them.
- For additional security, the token can also be passed via
Authorization: Bearer xxxheader instead of the query parameter. - The
cloudflaredbinary is automatically downloaded and stored in~/.witness/bin/.
Semantic Search
Witness provides semantic search powered by Ollama for local embeddings and Orama for the vector store. Everything runs locally — no cloud services, no API keys.
Prerequisites
-
Install Ollama: Download from ollama.com
-
Pull an embedding model:
ollama pull nomic-embed-text # Good default (768 dims, 2048 token context) ollama pull mxbai-embed-large # Higher quality (1024 dims, 512 token context)You can also pull models from the Witness settings page directly.
-
Build the index: Open Witness settings → Search tab → click "Build Index"
Search Modes
The search MCP tool (and the Search panel) supports three modes:
- Hybrid (default): Combines QPS keyword matching with vector cosine similarity. Best for most queries — gets the precision of keywords with the recall of semantic understanding.
- Vector: Pure semantic similarity. Finds conceptually related documents even when they don't share keywords. Good for exploratory queries like "notes about improving sleep quality".
- Fulltext: Pure QPS (Quantum Proximity Scoring) keyword matching. Fast and precise when you know the exact terms. No embeddings needed. Scores by token proximity — "carbon intensity" as adjacent words ranks higher than scattered occurrences.
Supported Embedding Models
| Model | Dimensions | Context | Prefixes | Notes |
|---|---|---|---|---|
nomic-embed-text |
768 | 2048 tokens | Both (mandatory) | Good default. Requires search_document: / search_query: prefixes — handled automatically. |
mxbai-embed-large |
1024 | 512 tokens | Query only | Higher quality embeddings. Requires query prefix — handled automatically. |
all-minilm |
384 | 256 tokens | None | Smallest and fastest. Short context window. |
bge-m3 |
1024 | 8192 tokens | None | Longest context — best for very long documents. |
bge-large |
1024 | 512 tokens | None | Good quality, no prefix needed. |
snowflake-arctic-embed |
384 | 512 tokens | Query only | Compact model with decent quality. |
Task prefixes are special strings prepended to input text that tell the model whether it's processing a document for storage or a query for search. Witness handles this automatically via embedDocuments() and embedQuery() — you don't need to add prefixes manually. Using the wrong prefix (or no prefix when one is required) produces embeddings in the wrong vector space, making similarity scores meaningless.
Context Length and Truncation
Each embedding model has a maximum context window measured in tokens. Documents longer than this are truncated before embedding. Witness handles this automatically:
- Dynamic resolution: On startup, Witness queries Ollama's
/api/showendpoint to get the model's actual architecture context length - Client-side pre-truncation: As a safety net, text is truncated to
context_tokens × 2characters before sending to Ollama (the factor of 2 is a conservative chars-per-token estimate) - Server-side truncation: Ollama's
truncate: trueparameter provides a second safety net
Important: The context length that matters is the model's architecture context length (e.g., nomic-bert.context_length: 2048), not the Modelfile num_ctx parameter (which may be 8192 but doesn't extend the embedding context). This distinction caught us out — nomic-embed-text reports num_ctx 8192 but can only embed 2048 tokens.
Documents with heavy JSON, HTML, URLs, or non-ASCII content tokenise less efficiently (as low as ~1.5 characters per token vs the typical ~4 for English prose). The conservative CHARS_PER_TOKEN = 2 accounts for this.
Why Filter Short Documents?
Very short documents (e.g., a file containing just a single word like "gold") produce generic embeddings that sit near the centre of the vector space. Because they lack distinctive content, they end up equidistant from everything — and cosine similarity scores them surprisingly high against any query.
The Minimum Content Length setting (default: 50 characters) filters these out at indexing time. This is the single most effective setting for improving search quality without changing your embedding model.
Signs you might want to increase this threshold:
- Search results include stub pages, empty templates, or placeholder files
- The same short documents appear in results for unrelated queries
- Vector search returns noticeably worse results than fulltext
Index Persistence
The index is stored at .witness/index.orama in your vault as a single JSON file. It includes a schema version number — when the schema changes (e.g., when new fields are added), old indexes are automatically discarded and a full re-index is triggered on next use.
To force a complete re-index: Settings → Search → Clear Index → Build Index.
Example Commands
Once connected to Claude Desktop, you can ask:
- "Show me all the files in my chaos/inbox folder"
- "Read the contents of my daily note"
- "Create a new note in order/knowledge about [topic]"
- "List all markdown files in my vault"
Development
Building
npm run build # Production build
npm run dev # Development mode with watch
Testing
# Build and install plugin in test vault
npm run test:install-plugin
# Start Obsidian with test vault
npm run test:start-obsidian
# Run integration tests (47 tests)
npm test
# Check server status
curl http://localhost:3000/health
Logs
MCP server logs are written to your vault's plugin folder:
.obsidian/plugins/witness/logs/mcp-YYYY-MM-DD.log
This makes it easy to:
- Share logs for bug reports
- Debug issues without Developer Console
- Let AI assistants read logs directly
Additional log locations:
- Obsidian console:
Cmd+Option+I→ Console tab - Claude Desktop:
~/Library/Logs/Claude/mcp-server-witness.log
Troubleshooting
Plugin won't load
- Check Obsidian console for errors
- Verify files are in correct location:
.obsidian/plugins/witness/ - Try disabling and re-enabling the plugin
Claude Desktop won't connect
-
Check the MCP server is running:
curl http://localhost:3000/health # Should return: {"status":"ok","plugin":"witness"} -
Check Claude Desktop logs:
tail -f ~/Library/Logs/Claude/mcp-server-witness.log -
Verify Node.js version:
node --version # Should be 20.x or higher
MCP server drops connection (macOS sleep)
If the MCP server becomes unreachable after periods of inactivity, your Mac is likely sleeping and dropping network connections. Check your current power settings:
pmset -g
The key setting is networkoversleep — if it's 0, macOS drops all network connections during sleep, killing the MCP server for remote clients.
Fix: Enable network access during sleep
sudo pmset -a networkoversleep 1
Other useful power settings for keeping the server reachable:
# Prevent system sleep on AC power
sudo pmset -c sleep 0
# Enable Wake on LAN (allows remote wake)
sudo pmset -c womp 1
# Disable Power Nap (can interfere with network stability)
sudo pmset -c powernap 0
Quick fix: Keep awake temporarily
If you don't want to change system settings permanently, run caffeinate in a terminal:
# Prevent idle and system sleep (Ctrl+C to stop)
caffeinate -si
# Or run in the background
caffeinate -si &
Key pmset settings
| Setting | Value | Effect |
|---|---|---|
networkoversleep |
1 |
Keep network alive during sleep |
womp |
1 |
Wake on LAN enabled |
tcpkeepalive |
1 |
Maintain TCP connections during sleep |
sleep |
0 |
Disable system sleep (AC power: -c) |
powernap |
0 |
Disable Power Nap |
Port already in use
If port 3000 is taken:
- Open Obsidian Settings → Witness
- Change the port number (e.g., 3001)
- Update your Claude Desktop config to match
Architecture
Witness runs an HTTP server inside Obsidian's Electron process:
Claude Desktop (MCP Client)
↓ stdio
mcp-remote bridge
↓ HTTP + SSE
Witness Plugin (MCP Server)
↓ Direct API
Obsidian Vault
This is different from other Obsidian MCP servers that run externally and connect via REST APIs. Witness has direct access to Obsidian's internal APIs for maximum reliability and performance.
Roadmap
Phase 1: MCP Server ✅
- [x] Basic plugin scaffold
- [x] HTTP server implementation
- [x] File operations (read, write, list, edit)
- [x] Claude Desktop integration
- [x] Full-text search
- [x] Command execution
- [x] Orientation document system
- [x] File-based logging
- [x] Integration test suite (47 tests)
Phase 2: Remote Access ✅
- [x] Cloudflare Quick Tunnel integration
- [x] Cloudflare Named Tunnel support (permanent URLs)
- [x] Primary machine designation for multi-device sync
- [x] Token authentication for remote access
- [ ] WhatsApp/Telegram bot
- [ ] Multi-user sessions
Phase 3: Semantic Search ✅
- [x] Local embeddings via Ollama (nomic-embed-text, mxbai-embed-large, and more)
- [x] Orama vector store with hybrid (BM25 + vector), vector-only, and fulltext modes
- [x] Model-specific task prefixes for optimal retrieval quality
- [x] Dynamic model info resolution via Ollama
/api/show - [x] Client-side pre-truncation for context length safety
- [x] Minimum content length filter for short document noise
- [x] Folder exclusions with folder picker UI
- [x] Search panel sidebar view
- [x] Tabbed settings UI with model pull and live indexing progress
- [x] Tested on 4,097-document vault
Dataview Integration ✅
- [x]
dataview_queryMCP tool (markdown + JSON output) - [x]
read_filerender parameter for resolving Dataview codeblocks - [x]
get_vault_contextauto-renders Dataview queries - [x] 8 integration tests
Chaos Triage ✅
- [x]
get_next_chaostool (single + list mode, queue counts, priority sorting) - [x]
mark_triagetool (processed, deferred, acknowledged, next, reset) - [x] Safe frontmatter updates via
processFrontMatterAPI - [x] AI guardrails: create-only
write_file, improvededit_fileerrors
Chaos Queue Panel ✅
- [x] Visual sidebar with card-based UI (title, path, smart snippets)
- [x] "Next Up" and "Queue" groups with collapsible sections
- [x] Hover-only action buttons (acknowledge, mark next, move to death, reset)
- [x] Bulk Edit mode with select all, bulk acknowledge, bulk move-to-death
- [x] 10 keyboard commands (triage actions, sibling navigation, panel toggles)
- [x] Inline hotkey capture in settings with conflict detection
- [x] File explorer context menu for chaos files and folders
- [x] Post-action navigation (next sibling file after move-to-death)
- [x] Live vault event listeners (deleted/renamed files removed from panel)
Phase 4: Intelligence
- [ ] Heartbeat scheduler (daily/weekly prompts)
- [ ] Chaos monitoring (detect stale items)
- [ ] Smart suggestions
- [ ] Auto-categorization
Phase 5: Advanced Features
- [ ] Graph analysis
- [ ] Template system
- [ ] Workflow automation
Contributing
Contributions are welcome! This project is in active early development.
Guidelines
- Keep it simple and focused
- Maintain zero dependencies on other plugins
- Test with the included
test-vault/ - Follow the existing code style
License
MIT
Acknowledgments
- Built on the Model Context Protocol by Anthropic
- Inspired by the Zettelkasten and PARA methods
- Thanks to the Obsidian community for the amazing platform
Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Twitter: @jawache
"The best way to predict the future is to invent it." - Alan Kay
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.