Local Knowledge RAG MCP Server
by patakuti
README.md
# Local Knowledge RAG MCP Server
**A semantic search and retrieval system for local documents using vector embeddings. Powered by MCP (Model Context Protocol).**
> This project is based on the RAG implementation from [Obsidian Smart Composer](https://github.com/glowingjade/obsidian-smart-composer).
> We've adapted it to focus on local document search and knowledge management as a standalone MCP server.
Provides semantic search across your local documents using vector embeddings and similarity search, with support for multiple embedding providers (OpenAI, Ollama, and OpenAI-compatible APIs).
---
## Overview
Local Knowledge RAG MCP Server enables AI-powered semantic search of your local document collections. Rather than keyword-based search, it understands the meaning of your queries and finds relevant content through vector embeddings.
**Key capabilities:**
- Semantic search powered by vector embeddings
- Support for multiple embedding providers (OpenAI, Ollama, LiteLLM, and any OpenAI-compatible APIs)
- Session-based search result caching
- Customizable report generation with multiple templates
- PostgreSQL with pgvector for high-performance vector similarity search
- HNSW indexing for fast approximate nearest neighbor search
- Incremental indexing and full rebuilds
---
## Why This Project?
While experimenting with various RAG (Retrieval-Augmented Generation) solutions like Dify and RAGFlow, we encountered several limitations:
1. **High Knowledge Base Management Cost**: Adding, removing, and updating documents required time-consuming manual steps
2. **Poor Citation Usability**: Citations referenced internal knowledge base resources rather than actual source files, making them difficult to work with
3. **Limited Output Format Flexibility**: Report generation was rigid and couldn't be easily customized
**Obsidian Smart Composer** solved problems #1 and #2 beautifully by working directly with your local files. This inspired us to bring that same experience to VS Code, where many developers spend most of their time.
**What makes Local Knowledge RAG MCP Server unique:**
- **Flexible Report Templates**: Customize RAG output format freely with template files (unlike rigid output formats in other solutions)
- **Scalable to Large Knowledge Bases**: Uses PostgreSQL's pgvector extension for efficient vector similarity search, handling large document collections
- **Built-in Index Manager**: Web-based interface for monitoring indexing progress and managing your knowledge base
- **VS Code Integration**: Seamless integration with Claude Code extension, bringing RAG capabilities directly into your development workflow
---
## Recommended Environment
This MCP server is optimized for the following environment:
- **IDE**: [VS Code](https://code.visualstudio.com/)
- **Extension**: [Claude Code for VS Code](https://marketplace.visualstudio.com/items?itemName=anthropic.claude-code)
- **AI Model**: Claude Sonnet 4.5 (latest)
While the server works with any MCP-compatible client, the above combination provides the best experience with optimal performance and integration.
---
## Quick Start
Get up and running in 5 steps:
### 1. Set up PostgreSQL with pgvector
**Using Docker (easiest):**
```bash
docker run -d \
--name local-knowledge-rag-db \
-e POSTGRES_DB=local_knowledge_rag \
-e POSTGRES_USER=user \
-e POSTGRES_PASSWORD=password \
-p 5432:5432 \
-v local-knowledge-rag-data:/var/lib/postgresql/data \
--restart unless-stopped \
ankane/pgvector
```
> **Note:** The credentials above are for local development only. If port 5432 is already in use, change the host port (e.g., `-p 5433:5432`) and update `DATABASE_URL` accordingly.
### 2. Clone and build the project
```bash
git clone https://github.com/patakuti/local-knowledge-rag-mcp.git
cd local-knowledge-rag-mcp
npm install
npm run build
```
### 3. Configure environment variables
```bash
# Copy the example file
cp .env.example .env
# Edit .env with your settings
# Minimal configuration:
DATABASE_URL=postgresql://user:password@localhost:5432/local_knowledge_rag
# Choose ONE embedding provider:
# Option A: OpenAI
OPENAI_API_KEY=sk-your-openai-api-key
# Option B: LiteLLM (recommended - supports multiple providers)
OPENAI_COMPATIBLE_BASE_URL=http://localhost:4000/v1
OPENAI_COMPATIBLE_API_KEY=your-litellm-key
EMBEDDING_MODEL=cl-nagoya/ruri-v3-310m
# Option C: Ollama (local, offline)
OLLAMA_BASE_URL=http://localhost:11434/v1
EMBEDDING_MODEL=nomic-embed-text
```
### 4. Add to Claude Code
Add this MCP server to Claude Code:
```bash
# Add globally (available in all projects)
claude mcp add -s user local-knowledge-rag -- node /path/to/local-knowledge-rag-mcp/dist/mcp-server.js
# Add to a specific project
cd /path/to/your/project
claude mcp add local-knowledge-rag -- node /path/to/local-knowledge-rag-mcp/dist/mcp-server.js
```
**Note:** Environment variables are loaded from `.env` file automatically. Do not add them to MCP server configuration for security reasons.
### 5. Start using it!
Restart Claude Code and start a conversation:
1. **Open Index Manager**: Say to Claude: "Open the Index Manager"
2. **Build Index**: In the web interface that opens, click "Update Index" button
3. **Start Searching**: Say to Claude: "Search my documents for information about [your topic] and create a report"
That's it! Claude will use the RAG tools automatically to search your documents and generate reports.
See [Usage Examples](#usage-examples) for more details.
---
## Features
- **Semantic Search**: Uses vector embeddings to find semantically similar content
- **Multiple Embedding Providers**: OpenAI, Ollama, or any OpenAI-compatible API
- **Multi-Workspace Support**: Use the same database for multiple independent workspaces
- **Session Management**: Cache and reuse search results across multiple queries
- **Template-Driven Reports**: Generate formatted Markdown reports with customizable templates
- **pgvector Extension**: High-performance vector similarity search with PostgreSQL
- **HNSW Indexing**: Fast approximate nearest neighbor search for large datasets
- **Flexible File Patterns**: Include/exclude file patterns for fine-grained control
- **MCP Integration**: Seamless integration with Claude Code and other MCP clients
- **Real-time Progress Tracking**: Web-based progress viewer showing live updates during index operations with percentage completion, file count, and current file being processed
---
## Configuration
All configuration is done via environment variables in a `.env` file. See [Quick Start](#quick-start) for basic setup.
**Common configuration tasks:**
- **Changing embedding models**: Edit `.env`, run `reload_config` tool, then rebuild index
- **Adjusting search parameters**: Edit `.env` RAG settings, restart MCP server
- **File patterns**: Edit `RAG_INCLUDE_PATTERNS` and `RAG_EXCLUDE_PATTERNS` in `.env`
**For complete configuration reference, see [docs/configuration.md](docs/configuration.md).**
---
## Multi-Workspace Support
Multiple workspaces can share the same PostgreSQL database. Each workspace automatically maintains its own isolated index based on its absolute path.
**Key Features:**
- ✅ Multiple workspaces share the same `DATABASE_URL` (configured in `.env`)
- ✅ Each workspace has its own isolated index (no data conflicts)
- ✅ Concurrent updates are safe (protected by PostgreSQL advisory locks)
Just use the same database for all your projects - the system handles workspace isolation automatically.
---
## Usage Examples
### Creating the Index
Before you can search, you need to create an index of your documents:
1. Say to Claude: "Open the Index Manager"
2. In the web interface, click the **"Update Index"** button to index your documents
3. Wait for indexing to complete - you'll see real-time progress in the interface
**Note:** The Index Manager will only index files matching your patterns (default: `**/*.md` and `**/*.txt`). You can change these patterns in your `.env` file.
### Searching Your Documents
Once your index is ready, just talk to Claude naturally:
**Simple search:**
- "Search my documents for information about React hooks and create a report"
- "Find documentation about database setup and create a summary"
- "Look for examples of error handling and create a report"
**Search in specific folders:**
- "Search the /src/components folder for button implementations and create a report"
- "Find configuration examples in the docs directory and create a summary"
**Advanced analysis:**
- "Search for React patterns and create a detailed summary report"
- "Analyze my database schema and generate documentation"
Claude will automatically:
1. Search your indexed documents
2. Find relevant content based on semantic similarity
3. Generate a formatted Markdown report
4. Save the report to `./rag-reports/` directory
**Advanced:** For direct MCP tool usage and detailed parameters, see [docs/mcp-tools.md](docs/mcp-tools.md).
**Report customization:** Reports are saved to `./rag-reports/` by default. You can create custom templates (built-in: `basic`, `paper`, `bullet_points`, `manual`) - see [docs/templates.md](docs/templates.md).
---
## Available MCP Tools
**Search & Reports:**
- `search_knowledge` - Perform semantic search
- `get_search_results` - Retrieve detailed results
- `create_rag_report` - Generate Markdown reports
- `list_search_results` - List cached sessions
**Indexing:**
- `rebuild_index` - Rebuild document index
- `cancel_index_generation` - Cancel indexing
- `index_status` - Check index status
**Management:**
- `reload_config` - Reload .env configuration
- `open_index_manager` - Open web UI
- `reinitialize_schema` - Reset workspace (⚠️ destructive)
**For detailed parameters and examples, see [docs/mcp-tools.md](docs/mcp-tools.md).**
---
## Index Manager
Web-based interface for monitoring indexing progress and managing your knowledge base. Runs as an independent process on localhost:3456 (or next available port).
**Access:** Say to Claude "Open the Index Manager" or use `open_index_manager` tool
**Features:** Real-time progress tracking, project statistics, index operations (update/rebuild/cancel)
**Logs:** `/tmp/local-knowledge-rag-mcp/{workspaceId}/index-manager.log`
---
## CLI Tool (`lkrag`)
A command-line interface for index management and search, suitable for cron jobs, editor integrations, and automation.
### Installation
After building the project, install globally or use via `npx`:
```bash
npm run build
npm link # makes lkrag available in PATH
```
### Commands
```
lkrag search <query> Search indexed documents
lkrag update-index Incrementally update the index
lkrag rebuild-index Rebuild the entire index from scratch
lkrag status Show index status
```
### Options
| Option | Default | Description |
|--------|---------|-------------|
| `--workspace-path <path>` | current directory | Workspace to operate on |
| `--find-workspace` | — | Traverse up from current directory to find an indexed workspace |
| `--limit <n>` | 5 | Number of search results |
| `--min-similarity <n>` | 0.3 | Minimum similarity score (0–1) |
| `--format <fmt>` | plain | Output format: `plain`, `tsv`, `json` |
| `--quiet` | — | Suppress informational messages on stderr |
| `--env-file <path>` | — | Load additional .env file |
### Examples
```bash
# Search with plain output
lkrag search "authentication flow" --workspace-path /path/to/docs
# Search from a subdirectory — finds the nearest indexed ancestor automatically
lkrag search "error handling" --find-workspace
# TSV output for editor integration (path, line, score, content)
lkrag search "setup guide" --format tsv --limit 10
# JSON output for scripting
lkrag search "database schema" --format json | jq '.[0].path'
# Update index from a subdirectory
lkrag update-index --find-workspace
# Schedule index updates via cron (daily at 3am)
# 0 3 * * * node /path/to/dist/cli.js update-index --workspace-path /path/to/docs
# Check index status
lkrag status
```
### Emacs Integration Example
Results are displayed in a persistent `*rag-results*` buffer.
| Key | Action |
|-----|--------|
| `n` / `p` | Next/previous result — previews the file in other window, focus stays on results |
| `RET` | Open selected file full-screen (`delete-other-windows`) |
| `.` | Open file at point in other window (focus stays on results) |
| `,` | Close (kill) the buffer of the file at point |
| `q` | Close results buffer |
```elisp
;;; lkrag integration
(defvar rag-workspace-path nil
"Explicit lkrag workspace path.
When nil (default), --find-workspace is used to locate the nearest
indexed ancestor directory automatically.
Example: (setq rag-workspace-path \"~/etc/txt/myproject/\")")
(defvar rag-results-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "n") #'rag-results-next)
(define-key map (kbd "p") #'rag-results-prev)
(define-key map (kbd "RET") #'rag-results-open)
(define-key map (kbd ".") #'rag-results-open-other-window)
(define-key map (kbd ",") #'rag-results-close)
(define-key map (kbd "q") #'quit-window)
map))
(define-derived-mode rag-results-mode special-mode "RAG"
"Major mode for lkrag search results.
\\{rag-results-mode-map}")
(defun rag-results--loc ()
"Return (path . line) for the result at point, or nil."
(get-text-property (line-beginning-position) 'rag-location))
(defun rag-results--preview ()
"Show file at point in other window; focus stays on results buffer."
(when-let ((loc (rag-results--loc)))
(save-selected-window
(find-file-other-window (car loc))
(goto-line (cdr loc))
(recenter))))
(defun rag-results-open ()
"Open result at point full-screen."
(interactive)
(when-let ((loc (rag-results--loc)))
(find-file-other-window (car loc))
(goto-line (cdr loc))
(recenter)
(delete-other-windows)))
(defun rag-results-open-other-window ()
"Open result at point in other window; focus stays on results buffer."
(interactive)
(when-let ((loc (rag-results--loc)))
(save-selected-window
(find-file-other-window (car loc))
(goto-line (cdr loc))
(recenter))))
(defun rag-results-close ()
"Kill the buffer visiting the file at point."
(interactive)
(when-let ((loc (rag-results--loc)))
(when-let ((buf (find-buffer-visiting (car loc))))
(kill-buffer buf))))
(defun rag-results-next ()
"Move to the next result and preview it."
(interactive)
(let ((pos (save-excursion
(forward-line 1)
(while (and (not (eobp)) (null (rag-results--loc)))
(forward-line 1))
(and (rag-results--loc) (point)))))
(when pos
(goto-char pos)
(rag-results--preview))))
(defun rag-results-prev ()
"Move to the previous result and preview it."
(interactive)
(let ((pos (save-excursion
(forward-line -1)
(while (and (not (bobp)) (null (rag-results--loc)))
(forward-line -1))
(and (rag-results--loc) (point)))))
(when pos
(goto-char pos)
(rag-results--preview))))
(defun rag-search (query)
"Search lkrag index and display results in *rag-results* buffer."
(interactive "sSearch: ")
(let* ((explicit-workspace (and rag-workspace-path
(expand-file-name rag-workspace-path)))
(current-dir (expand-file-name default-directory))
(lkrag (or (executable-find "lkrag")
(expand-file-name "~/.npm-global/bin/lkrag")))
(stderr-file (make-temp-file "lkrag-stderr"))
(cmd (if explicit-workspace
(format "%s search %s --format tsv --limit 50 --quiet --workspace-path %s 2>%s"
lkrag
(shell-quote-argument query)
(shell-quote-argument explicit-workspace)
(shell-quote-argument stderr-file))
(format "%s search %s --format tsv --limit 50 --find-workspace 2>%s"
lkrag
(shell-quote-argument query)
(shell-quote-argument stderr-file))))
(output (shell-command-to-string cmd))
(stderr (prog1 (with-temp-buffer
(insert-file-contents stderr-file)
(buffer-string))
(delete-file stderr-file)))
(found-workspace (when (string-match "^\\[lkrag\\] workspace: \\(.*\\)" stderr)
(match-string 1 stderr)))
;; When --find-workspace returned a parent of current-dir, filter to current-dir
(filter-to-current (and (null explicit-workspace)
found-workspace
(not (string= (file-truename found-workspace)
(file-truename current-dir)))))
;; expand-root: workspace root used to resolve lkrag's relative paths
;; display-root: shown in From: header and used for file-relative-name
(expand-root (or explicit-workspace found-workspace current-dir))
(display-root (if filter-to-current current-dir expand-root))
(all-tsv-lines (seq-filter (lambda (l) (string-match-p "\t" l))
(split-string (string-trim output) "\n" t)))
(tsv-lines (if filter-to-current
(seq-filter
(lambda (line)
(let* ((parts (split-string line "\t"))
(path (expand-file-name (nth 0 parts) expand-root)))
(string-prefix-p (file-truename current-dir)
(file-truename path))))
all-tsv-lines)
all-tsv-lines))
(buf (get-buffer-create "*rag-results*")))
(with-current-buffer buf
(let ((inhibit-read-only t))
(erase-buffer)
(rag-results-mode)
(insert (propertize (format "Search: %s\n" query) 'face 'bold))
(insert (propertize (format "From: %s\n\n" display-root) 'face 'shadow))
(if (null tsv-lines)
(insert "No results found.\n")
(dolist (line tsv-lines)
(let* ((parts (split-string line "\t"))
(path (expand-file-name (nth 0 parts) expand-root))
(lineno (string-to-number (nth 1 parts)))
(score (nth 2 parts))
(content (nth 3 parts))
(relpath (file-relative-name path display-root))
(excerpt (truncate-string-to-width content 60))
(start (point)))
(insert (propertize relpath 'face 'compilation-info)
(propertize (format ":%d" lineno) 'face 'compilation-line-number)
(propertize (format " [%s] " score) 'face 'shadow)
excerpt "\n")
(put-text-property start (point) 'rag-location (cons path lineno)))))
(goto-char (point-min))
(forward-line 3)))
(pop-to-buffer buf)
(rag-results--preview)))
;; Optional key binding
;; (global-set-key (kbd "C-c r") #'rag-search)
```
Notes:
- `rag-workspace-path` — set only when the indexed root differs from the directory you work in. When nil, `--find-workspace` locates the nearest indexed ancestor automatically.
- When `--find-workspace` is used, lkrag prints the resolved workspace path to stderr (`[lkrag] workspace: /path/to/ws`). The Emacs integration captures this via a temp file to display the correct `From:` path and compute relative paths accurately.
- When `--find-workspace` resolves to a parent of `default-directory` (i.e. the current directory is not itself indexed), results are automatically filtered to files under `default-directory`. The search fetches 50 candidates upfront to leave enough headroom after filtering. `From:` and relative paths are shown relative to `default-directory` in this case.
- `expand-file-name` ensures `~` is resolved before passing to the shell, avoiding single-quote quoting issues.
- The `*rag-results*` buffer persists across searches; each new search overwrites it.
### VS Code Integration Example
A minimal VS Code extension is included in `vscode-extension/`. It opens a **QuickPick** search panel where results are previewed as you navigate, and Enter opens the selected file at the matching line.
**Installation**
```bash
# From the repo root — link or copy into VS Code's extensions directory
ln -s "$(pwd)/vscode-extension" ~/.vscode/extensions/lkrag-search-0.1.0
# Then reload VS Code (Developer: Reload Window)
```
Alternatively, package as a `.vsix` and install via the Extensions sidebar:
```bash
npm install -g @vscode/vsce
cd vscode-extension
vsce package # produces lkrag-search-0.1.0.vsix
# Extensions sidebar → ⋯ → Install from VSIX…
```
**Usage**
Open the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) and run **lkrag: Search**.
- Type a query — results appear after a short debounce
- Arrow keys move through results; the file is previewed in the editor
- `Enter` opens the selected file at the matching line
- `Escape` cancels
**Keybinding (optional)**
Add to `keybindings.json` (`Ctrl+Shift+P` → "Open Keyboard Shortcuts (JSON)"):
```json
{ "key": "ctrl+alt+r", "command": "lkrag.search" }
```
**Settings**
| Setting | Default | Description |
|---------|---------|-------------|
| `lkrag.workspacePath` | `""` | Explicit workspace path. Leave empty to use `--find-workspace`. |
| `lkrag.executablePath` | `""` | Path to `lkrag` binary. Leave empty to auto-detect. |
| `lkrag.limit` | `20` | Maximum number of results. |
Notes:
- `lkrag.workspacePath` — set only when the indexed root differs from the directory you work in. When empty, `--find-workspace` locates the nearest indexed ancestor automatically.
- The extension has no npm dependencies; no `npm install` is required before use.
- The VS Code extension host inherits PATH from the environment VS Code was launched in. If `lkrag` is not found, set `lkrag.executablePath` explicitly.
### Index Update Behavior
- If an **Index Manager** server is running for the workspace, `update-index` and `rebuild-index` delegate to it via HTTP (non-blocking).
- If no server is running, the CLI runs the operation **directly** with progress output to stderr.
---
## Troubleshooting
### Documents not being indexed
1. Check logs: `/tmp/local-knowledge-rag-mcp/{workspaceId}/index-manager.log`
2. Verify `.env` configuration (DATABASE_URL, API keys)
3. Check file patterns: `RAG_INCLUDE_PATTERNS` and `RAG_EXCLUDE_PATTERNS`
### No search results
- Try different search terms or lower similarity threshold
- Verify indexing completed: use `index_status` tool
- Rebuild index if needed
### API errors
- Verify API key is valid and has correct permissions
- Check rate limits (switch to Ollama if needed)
### Switching embedding models
1. Edit `.env` with new model settings
2. Run `reload_config` tool
3. Run `rebuild_index` with `reindex_all: true`
**For complete troubleshooting guide, see [docs/troubleshooting.md](docs/troubleshooting.md).**
---
## Security
### API Key Management
- **Never commit API keys** to version control
- Use `.env` files locally and `.env.example` in the repository
- Rotate keys regularly
- Use environment-specific keys when possible
### Network Security
- **Index Manager (Web UI)**: Binds to `127.0.0.1:3456` (loopback only) without authentication
- Not accessible from external networks by default
- Designed for trusted local development environments only
### Local Data Handling
- All documents are processed locally by default
- Embeddings are stored in PostgreSQL database
- Progress logs are stored in system temporary directory
- Ensure proper database access control and backup
- Database connections should only be allowed from trusted networks
### Best Practices
- Review `.gitignore` to ensure sensitive files are excluded
- For sensitive data, consider using Ollama for fully offline, local processing
- Regularly rotate API keys and monitor API usage for unusual patterns
---
## Contributing
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
**Note:** This project is maintained on a limited-time basis. PR reviews may take several weeks. Security issues are prioritized.
---
## About this project
This tool was designed and implemented entirely by Claude. The human provided the idea. However, this isn't a one-shot output; the human shaped it through hands-on testing and iterative, detail-oriented feedback.
---
## License
MIT License - see [LICENSE](LICENSE) for details.
---
## Credits
- [Obsidian Smart Composer](https://github.com/glowingjade/obsidian-smart-composer) - Original RAG implementation
- [Model Context Protocol (MCP)](https://github.com/modelcontextprotocol/specification)
- [Claude Code](https://claude.com/claude-code)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessUnresponsive