Local Knowledge Rag Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Local Knowledge Rag Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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. 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).
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:
While experimenting with various RAG (Retrieval-Augmented Generation) solutions like Dify and RAGFlow, we encountered several limitations:
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:
This MCP server is optimized for the following environment:
While the server works with any MCP-compatible client, the above combination provides the best experience with optimal performance and integration.
Get up and running in 5 steps:
Using Docker (easiest):
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/pgvectorNote: 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 updateDATABASE_URLaccordingly.
git clone https://github.com/patakuti/local-knowledge-rag-mcp.git
cd local-knowledge-rag-mcp
npm install
npm run build# 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-textAdd this MCP server to Claude Code:
# 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.jsNote: Environment variables are loaded from .env file automatically. Do not add them to MCP server configuration for security reasons.
Restart Claude Code and start a conversation:
That's it! Claude will use the RAG tools automatically to search your documents and generate reports.
See Usage Examples for more details.
All configuration is done via environment variables in a .env file. See Quick Start for basic setup.
Common configuration tasks:
.env, run reload_config tool, then rebuild index.env RAG settings, restart MCP serverRAG_INCLUDE_PATTERNS and RAG_EXCLUDE_PATTERNS in .envFor complete configuration reference, see [docs/configuration.md](docs/configuration.md).
Multiple workspaces can share the same PostgreSQL database. Each workspace automatically maintains its own isolated index based on its absolute path.
Key Features:
DATABASE_URL (configured in .env)Just use the same database for all your projects - the system handles workspace isolation automatically.
Before you can search, you need to create an index of your documents:
Note: The Index Manager will only index files matching your patterns (default: **/*.md and **/*.txt). You can change these patterns in your .env file.
Once your index is ready, just talk to Claude naturally:
Simple search:
Search in specific folders:
Advanced analysis:
Claude will automatically:
./rag-reports/ directoryAdvanced: For direct MCP tool usage and detailed parameters, see 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.
Search & Reports:
search_knowledge - Perform semantic searchget_search_results - Retrieve detailed resultscreate_rag_report - Generate Markdown reportslist_search_results - List cached sessionsIndexing:
rebuild_index - Rebuild document indexcancel_index_generation - Cancel indexingindex_status - Check index statusManagement:
reload_config - Reload .env configurationopen_index_manager - Open web UIreinitialize_schema - Reset workspace (⚠️ destructive)For detailed parameters and examples, see [docs/mcp-tools.md](docs/mcp-tools.md).
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
lkrag)A command-line interface for index management and search, suitable for cron jobs, editor integrations, and automation.
After building the project, install globally or use via npx:
npm run build
npm link # makes lkrag available in PATHlkrag 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| 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 |
# 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 statusResults 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 |
;;; 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.--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.--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.*rag-results* buffer persists across searches; each new search overwrites it.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
# 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:
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.
Enter opens the selected file at the matching lineEscape cancelsKeybinding (optional)
Add to keybindings.json (Ctrl+Shift+P → "Open Keyboard Shortcuts (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.npm install is required before use.lkrag is not found, set lkrag.executablePath explicitly.update-index and rebuild-index delegate to it via HTTP (non-blocking)./tmp/local-knowledge-rag-mcp/{workspaceId}/index-manager.log.env configuration (DATABASE_URL, API keys)RAG_INCLUDE_PATTERNS and RAG_EXCLUDE_PATTERNSindex_status tool.env with new model settingsreload_config toolrebuild_index with reindex_all: trueFor complete troubleshooting guide, see [docs/troubleshooting.md](docs/troubleshooting.md).
.env files locally and .env.example in the repository127.0.0.1:3456 (loopback only) without authentication.gitignore to ensure sensitive files are excludedContributions are welcome! Please see CONTRIBUTING.md for guidelines.
Note: This project is maintained on a limited-time basis. PR reviews may take several weeks. Security issues are prioritized.
MIT License - see LICENSE for details.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.