nl-file-search
This server lets you search indexed local files by natural language and retrieve stored metadata for indexed items.
search_filesruns a natural-language semantic search over the local index (notes, images, videos, PDFs, etc.).Search can be narrowed by optional
modality(text,image,video, orpdf) and result countk(default 8).get_filereturns metadata for a specific indexed path already in the index, such as text or media page/time range info.It does not read arbitrary disk paths; only paths previously ingested are accessible.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@nl-file-search search my notes for anything about the vintage red truck in the rain"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
nl-file-search
Natural-language search over local files. Phase 1 indexes markdown, plain text, images, videos, and PDFs with Gemini Embedding 2, stores vectors in SQLite (sqlite-vec), and exposes search through a CLI and a Cursor MCP server.
Work in progress. Designed by Gary Lucero. Coded by Cursor.
A later Python app can import the same nl_file_search.search module. Office documents are Phase 2; music is Phase 3. See background/ROADMAP.md.
Phase 1 file types
Type | Extensions | How it is indexed |
Text |
| Heading/paragraph chunks |
Images |
| Sent to Gemini as image bytes |
Video |
| Split into 120s clips with ffmpeg |
| One page per embedding |
Unknown extensions are skipped. HEIC is skipped. Secret-like names (.env, *.pem, credentials.json, SSH keys) are never read or sent to Gemini.
Related MCP server: embgrep
Requirements
Windows, macOS, or Linux
Python 3.12+
A Gemini API key (
GEMINI_API_KEY)ffmpeg on
PATHwhen you index videos (Windows:winget install Gyan.FFmpeg; macOS:brew install ffmpeg; Linux: your package manager)Network access for every ingest and every search (queries are embedded with the same model)
SQLite is not Windows-only. The same code uses Path.home() / "nl-file-search" on every OS.
Setup
Windows (PowerShell):
cd C:\source\repos\nl-file-search
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -U pip
python -m pip install -e .macOS / Linux:
cd ~/src/nl-file-search
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -e .Copy the example config and env files into ~/nl-file-search (your home directory on every OS). Run this from the repo, with the venv active. nl-search does not create these files.
python scripts/copy_profile.pyThen:
Edit
~/nl-file-search/config.yamland set the folders to index.Edit
~/nl-file-search/.envand setGEMINI_API_KEY=...(never commit this file).
If a key was ever pasted into a chat or ticket, revoke it in Google AI Studio and issue a new one.
Data lives outside the repo:
Path | |
Data folder |
|
SQLite index |
|
~/nl-file-search/
config.yaml # copied from config.example.yaml; you edit this
.env # copied from .env.example; you put the API key here
index.sqlite # created on the first successful nl-search ingest
logs/ # created when a command runs after config existsPaths in config.yaml
List each folder under sources with a path value. Use forward slashes in double quotes; that form works on Windows, macOS, and Linux:
sources:
- path: "~/Notes"
- path: "~/Pictures"
- path: "/absolute/path/to/folder"~ is expanded to your home directory. Paths are resolved to absolute locations when ingest runs.
On Windows, a backslash in a double-quoted string is a YAML escape (\U in C:\Users is not a folder separator). Use one of these instead:
Form | Example |
Forward slashes |
|
Single quotes |
|
Escaped backslashes |
|
Example config.yaml (also in config.example.yaml):
sources:
- path: "~/Notes"
- path: "~/Pictures"
exclude:
- "**/.git/**"
- "**/node_modules/**"
embed:
model: gemini-embedding-2
dimensions: 768
video:
max_seconds: 120CLI
nl-search ingest
nl-search ingest --path /path/to/folder
nl-search search "vintage red truck in the rain"
nl-search statusCursor MCP
Add a server in Cursor’s MCP settings (user or project). Point command at this repo’s venv Python:
{
"mcpServers": {
"nl-file-search": {
"command": "/absolute/path/to/nl-file-search/.venv/bin/python",
"args": ["-m", "nl_file_search.mcp_server"]
}
}
}On Windows, use .venv\\Scripts\\python.exe instead of .venv/bin/python. Restart Cursor MCP after saving. Do not put GEMINI_API_KEY in that config; the server reads ~/nl-file-search/.env.
Tools:
search_files— natural-language search; use this first when asking about indexed local filesget_file— indexed text or media metadata for a path already in the index (not an arbitrary disk read)
Security
The API key lives only in
~/nl-file-search/.env.The SQLite database lives only in
~/nl-file-search/index.sqlite.Ingest skips credential-like files and default junk directories (
.git,node_modules,.venv,__pycache__).get_fileonly returns rows already in the index. It will not open..\..\.envor other paths that were never ingested.Retrieved snippets go to Cursor the same way an open file would. Do not index folders that must never leave the machine.
Phase 2 and 3 (not built yet)
Phase 2: modern Office (
.docx,.xlsx,.pptx)Phase 3: music (
.mp3,.m4a,.flac)
Out of scope: Google Docs, Drive export, LibreOffice, legacy .doc / .xls / .ppt.
Available Tools
2 toolsget_fileGet FileA
Return indexed text or media metadata for a path already in the index.
Does not read arbitrary disk paths. Pass a path from search_files. Media results include path and page/time range, not binary bytes.
Inputs: path (required). Returns: object
search_filesSearch FilesA
Search the local file index with natural language.
Use this first when the user asks to find notes, images, videos, PDFs, or other files that may have been ingested by nl-search. modality may be text, image, video, or pdf.
Inputs: query (required), k, modality. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 2 tools
search_files and get_file have clearly distinct roles: search finds indexed files by natural language, while get_file retrieves content or metadata for a path returned by search. The descriptions reinforce this boundary by explicitly telling users to pass paths from search_files and not to use get_file for arbitrary disk paths.
Both tools follow a consistent verb_noun snake_case pattern: search_files and get_file. The singular/plural difference mirrors the operation, and the naming is predictable and readable.
Two tools are slightly below the typical 3-15 range, but they form a focused search-then-retrieve workflow. The scope is narrow enough that each tool earns its place without bloat.
The server covers the core lifecycle of finding indexed files and retrieving their indexed content or media metadata. Minor gaps remain around index management or broader listing, but these may be intentionally handled by the companion nl-search ingestion system.
Maintenance
Related MCP Connectors
Search and reason over your Obsidian-style Markdown vault, right from ChatGPT.
Securely search and manage workspace context files for AI agents and teams.
A search engine that learns from your grades. Store text, records, images or embeddings.
Read and search folders on your own computer with explicit consent. Files are never uploaded.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceProvides AI assistants with semantic search and read access to local files and directories, enabling knowledge retrieval from indexed content.36 npm17MIT
- AlicenseNot gradedqualityDmaintenanceProvides local semantic search over files using embeddings, enabling directory indexing and natural language queries without external services.23 PyPIMIT
- AlicenseAqualityCmaintenanceEnables local-first hybrid knowledge retrieval from authorized Markdown and plain-text files, combining full-text and vector search with reranking and traceable source references via a single search tool.1MIT
- AlicenseAqualityBmaintenanceEnables local AI agents to perform hybrid search (BM25 + vector) over privately indexed local files, including notes, PDFs, DOCX, source code, and OCR'd images. All indexing and retrieval stay on the machine with read-only, whitelist-scoped access.3MIT