mcp-local-rag
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., "@mcp-local-ragWhat does the API documentation say about authentication?"
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.
MCP Local RAG
Search private documents from an MCP client or the terminal without sending them to an embedding API.
mcp-local-rag indexes PDF, DOCX, Markdown, and text files on your machine. Search combines semantic similarity with keyword matching, so queries can match both intent and exact technical terms such as API names, class names, and error codes.
Features
Runs locally: Document parsing, embeddings, storage, and search run on your machine. After the initial model download, text ingestion and search work offline.
Hybrid search: Semantic retrieval finds related concepts, while keyword matching boosts exact technical terms.
Configurable embeddings: Choose a Hugging Face embedding model that fits the language and domain of your documents.
Semantic chunking: Documents are split at topic boundaries instead of fixed character counts. Markdown code blocks stay intact.
MCP and CLI: Use the same index from an AI coding tool or directly from the terminal.
No API key, Docker, Python, or external database is required.
Related MCP server: local-Rag
Quick Start
Requirements
Node.js 22 or later
Internet access on first use to download the npm package and embedding model
A directory containing the documents you want to search
Set BASE_DIR to that directory. It is also the security boundary for file operations. Replace
/absolute/path/to/your/documents below with the directory's absolute path.
mcp-local-rag uses the standard MCP protocol over a local stdio server, so it works with AI coding tools and other MCP hosts that support local MCP servers.
Use one of the examples below, or register npx -y mcp-local-rag and set BASE_DIR using your
client's MCP configuration format.
For Claude Code: Run this command:
claude mcp add local-rag --scope user --env BASE_DIR=/absolute/path/to/your/documents -- npx -y mcp-local-ragFor Codex: Add to ~/.codex/config.toml:
[mcp_servers.local-rag]
command = "npx"
args = ["-y", "mcp-local-rag"]
[mcp_servers.local-rag.env]
BASE_DIR = "/absolute/path/to/your/documents"For OpenCode: Add to ~/.config/opencode/opencode.json (or opencode.jsonc):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"local-rag": {
"type": "local",
"command": ["npx", "-y", "mcp-local-rag"],
"environment": {
"BASE_DIR": "/absolute/path/to/your/documents"
}
}
}
}For Cursor: Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"local-rag": {
"command": "npx",
"args": ["-y", "mcp-local-rag"],
"env": {
"BASE_DIR": "/absolute/path/to/your/documents"
}
}
}
}Restart the client, then ask it to build the index:
Sync all documents in the configured root and wait until it finishes.The first sync downloads the default embedding model (about 90 MB) and may take 1–2 minutes before ingestion starts. Later runs use the local cache.
Once the sync completes:
What does the API documentation say about authentication?CLI Quick Start
To use the CLI without an MCP client:
npx mcp-local-rag ingest ./docs/
npx mcp-local-rag query "authentication API"The CLI uses the current directory as its document root by default. Run both commands from the
same directory so they use the same default index, or set BASE_DIR and DB_PATH explicitly.
Why This Exists
Some document sets cannot be sent to a hosted embedding service because of confidentiality or organizational policy. Keeping the index local makes them searchable without adding a per-query API cost.
Semantic search alone can miss exact identifiers that matter in technical documentation. Keyword reranking keeps those terms visible without giving up natural-language retrieval.
Supported Content
Input | How to ingest |
PDF, DOCX, TXT, Markdown | File ingestion or directory sync |
HTML already fetched by the client |
|
Plain text or Markdown held in memory |
|
HTML fetching is not built into the server. An MCP client can fetch a page and pass its HTML to
ingest_data.
Excel, PowerPoint, standalone images, and source-code file extensions are not supported by file ingestion. PDFs can optionally use a local vision model to describe figures, but this is not OCR or image search.
MCP Tools
Tool | Purpose |
| Reconcile the index with all configured roots or one path |
| Poll a running sync job |
| Ingest or replace one file |
| Ingest text, Markdown, or HTML already held by the client |
| Search with semantic matching and keyword boost |
| Read surrounding chunks from a search result |
| Show supported files and their ingestion state |
| Delete an indexed file or an |
| Show index and search status |
Syncing a Document Root
sync_start ingests new and changed files, skips byte-identical files, and removes index entries
for files that no longer exist:
Sync everything under the configured document roots and wait for completion.The tool returns a jobId immediately. Clients should poll sync_status until its state becomes
succeeded or failed. A changed PDF keeps the visual profile it was indexed with; sync_start
cannot change it. Set STORE_IMAGES=true in the MCP server environment to store supported PDF and
DOCX images for new or changed files selected by sync; unchanged files remain skipped.
Only one sync job is retained by the server process. A newer job replaces a finished record, and restarting the server discards it.
Ingesting One File
ingest_file accepts PDF, DOCX, TXT, and Markdown. MCP file paths must be absolute and must stay
inside a configured document root:
Ingest the document at /Users/me/docs/api-spec.pdf.Re-ingesting the same path replaces its existing chunks.
Searching and Reading More Context
What does the API documentation say about authentication?
Find the documented behavior of ERR_CONNECTION_REFUSED.Results contain the text, source path, title, chunk index, relevance score, and any images stored
on that chunk. MCP returns each image as an image content block paired with its result identity;
CLI query includes an images array of { imageIndex, mimeType, data } on every result. Pass the
chunkIndex and either filePath or source from a result to read_chunk_neighbors when the
answer needs more context:
Read the surrounding chunks for that authentication result.Both query_documents and list_files accept an optional absolute scope path prefix, or a
list of prefixes. A prefix matches the exact path and its descendants.
Ingesting HTML
Use ingest_data after the MCP client fetches a page:
Fetch https://example.com/docs and ingest the HTML.The server extracts the main article, converts it to Markdown, and stores it under the supplied source identifier. Reusing the same source updates the existing content.
Respect the source site's terms and copyright when indexing external content.
PDF Visual Captions and Stored Images
Visual mode adds a generated caption for figure-heavy PDF pages. It is opt-in and does not load a vision model during normal ingestion.
Ingest /Users/me/docs/research-paper.pdf with visual: true.npx mcp-local-rag ingest ./docs/research-paper.pdf --visualImage storage is independent of visual captions. Set STORE_IMAGES=true for the MCP server, or
pass --images to CLI ingestion and sync:
npx mcp-local-rag ingest ./docs/research-paper.pdf --images
npx mcp-local-rag sync ./docs/ --imagesPDF storage uses detected figure/table regions. DOCX storage includes only PNG/JPEG images that
the existing Mammoth conversion emits as <img>; charts, SmartArt, and shapes are not separately
rendered. Stored images follow their surrounding text into the final semantic chunk and do not
alter ranking, scores, or result count.
|
| PDF behavior |
false | false | Text only; no visual captions or returned images. |
true | false | Generated captions become searchable text; no images are stored or returned. |
true | true | Generated captions become searchable text, and images from matched chunks are returned inline. |
false | true | Images are attached to nearby retained PDF text and returned inline for matched chunks; the VLM is not imported, loaded, or run. |
Profile | Model cache | Use case |
| about 250 MB | Lightweight visual indexing |
| about 1.7 GB | Figures containing labels, annotations, or other in-image text |
Select the larger model with visualQuality: "quality" over MCP or
--visual-quality quality over CLI. Measured CPU inference was about three times as slow as
fast, though results depend on hardware and model updates.
Updating Existing quality Captions
From 0.18.4 quality runs Qwen3.5-2B; earlier versions ran Qwen2.5-VL-3B. Captions already indexed
keep the wording the old model produced, and sync will not redo them, so re-ingest the files you
want refreshed:
npx mcp-local-rag ingest ./docs/research-paper.pdf --visual --visual-quality qualityAdd --images if the file was ingested with it, because a run without it replaces the stored
images. The old model stays on disk. Once nothing else uses it, delete
onnx-community/Qwen2.5-VL-3B-Instruct-ONNX/ from the model cache directory — <cache-dir>, which
defaults to ./models/.
Visual Mode Across Syncs
The profile a PDF was indexed with is recorded, and sync reuses it: a PDF indexed with fast or
quality is re-ingested with that same profile, and a PDF with no recorded profile is ingested as
text.
npx mcp-local-rag sync ./docs/ # keep each PDF's recorded profile
npx mcp-local-rag sync ./docs/ --visual # request fast for every PDF in scope
npx mcp-local-rag sync ./docs/ --visual --visual-quality quality--visual overrides recorded profiles, so it also captions PDFs that were indexed as text.
Changing a profile re-ingests the PDF even when the file itself has not changed; running the same
command again does nothing and loads no model. Image settings are never recorded, so --images
and STORE_IMAGES never cause a re-ingest.
To turn captions off for a path, run ingest on it: a successful normal ingest clears the
recorded profile. To retry a page whose captioning failed, run ingest <path> --visual --visual-quality <profile> with the profile you want — a plain ingest clears it instead. If a
PDF's indexed rows disagree about the profile, sync stops before changing anything and names the
file; re-run it with --visual to settle the profile.
Captions are auxiliary text, not faithful transcriptions. Treat retrieved captions and document text as untrusted input rather than instructions.
At high limits, matched chunks and their attachments can approach the model/client context ceiling; choose the query limit with the calling model's available context in mind.
CLI
The CLI uses the same parser, embedder, and vector store without an MCP client:
npx mcp-local-rag ingest ./docs/
npx mcp-local-rag sync ./docs/
npx mcp-local-rag query "authentication API"
npx mcp-local-rag query "auth" --scope /docs/api --scope /docs/guide
npx mcp-local-rag read-neighbors --file-path /abs/path.md --chunk-index 5
npx mcp-local-rag list
npx mcp-local-rag status
npx mcp-local-rag delete ./docs/old.pdf
npx mcp-local-rag delete --source "https://example.com/docs"Global options such as --db-path, --cache-dir, and --model-name go before the subcommand.
Subcommand options go after it:
npx mcp-local-rag --db-path ./my-db query "authentication"Run npx mcp-local-rag --help for the complete command reference.
The CLI does not read MCP client configuration. Set the same environment variables or flags if
both interfaces should share an index. In particular, MODEL_NAME and the CLI --model-name
must match for a shared database.
query writes its results to stdout as JSON, best match first, so it can be piped into
another tool. The field-by-field contract is in
docs/schema/query-output.schema.json.
Search Tuning
Keyword boost is enabled by default. Relevance-gap grouping and the distance and file filters are
optional controls for corpora that need tighter result selection. All four apply to the MCP
server and to CLI query alike.
Variable | Default | Description |
|
| Keyword boost factor (0.0–1.0). 0 disables keyword reranking; 1 applies the maximum boost. |
| (not set) |
|
| (not set) | Filter out low-relevance results (e.g., |
| (not set) | Limit results to top N files (e.g., |
| (not set) | MCP server only: external command template that reorders results. Matched text is sent on stdin; |
|
| Time budget per rerank call in milliseconds (100–600000). |
For API specifications and other documents containing many identifiers, a stronger keyword weight can improve exact-term ranking:
"env": {
"RAG_HYBRID_WEIGHT": "0.7"
}0.7: slightly stronger exact-term reranking than the default1.0: maximum keyword boost
External Reranking (RAG_RERANK_CMD)
The server sends each set of search results, including the matched chunk text, to the command on
stdin. It passes the search query only where the template contains {query}. A command that calls
a remote service may send the content it receives off this machine.
Give the executable and its complete argument template. Put {query} and {top} where the
command expects the query and result count. Single or double quotes
group paths or arguments containing spaces, and backslashes stay literal. The server runs the
executable without a shell, so an npm-installed .cmd shim on Windows will not start.
"env": {
"RAG_RERANK_CMD": "/path/to/reranker --query {query} --top {top}",
"RAG_RERANK_TIMEOUT_MS": "10000"
}The command receives each result in the form published at
docs/schema/query-output.schema.json and has to answer
in that same form. Within it the command decides everything: what to keep, how to order it, and
what the text says. Whatever it returns is what you see.
Results keep their original order if the command fails, times out, or answers with something that is not that form.
How It Works
During ingestion:
The parser extracts text for the input format.
The semantic chunker finds topic boundaries and preserves Markdown code blocks.
Transformers.js creates embeddings locally.
LanceDB stores the chunks, metadata, vectors, and full-text index.
During search:
The query is embedded with the same model.
Vector search retrieves semantically related chunks.
Optional distance and relevance-group filters narrow the candidates when configured.
Full-text matches boost exact query terms.
Agent Skills
Agent Skills provide query and ingestion guidance for AI assistants:
npx mcp-local-rag skills install --claude-code
npx mcp-local-rag skills install --claude-code --global
npx mcp-local-rag skills install --codexInstalled skills cover query formulation, result refinement, and HTML ingestion. Ask the assistant to use the mcp-local-rag skill explicitly if it does not activate automatically.
Configuration
The MCP server reads environment variables. The CLI accepts the listed global environment
variables and flags; image storage on CLI ingestion and sync is enabled only with --images.
Environment Variable | CLI Flag | Default | Description |
|
| Current directory | One document root; the CLI flag is repeatable on |
| N/A | (unset) | JSON array of document roots; takes precedence over |
|
|
| Vector database location |
|
|
| Model cache directory |
| N/A |
| Hugging Face model download endpoint; use a mirror URL when direct downloads are blocked |
|
|
| Hugging Face embedding model |
|
|
| Maximum file size in bytes |
|
|
| Minimum length in characters (1–10000) for ordinary chunks; a fragment of content split to fit the model's token limit can be shorter |
| N/A |
| MCP server only: store supported PDF/DOCX images and return them with matched chunks. CLI uses |
| N/A |
| ONNX Runtime execution device |
| N/A |
| Embedding dtype passed to the selected model |
Document Roots (BASE_DIR and BASE_DIRS)
mcp-local-rag only allows file operations inside configured roots. For multiple roots,
BASE_DIRS must be a JSON array of non-empty paths:
export BASE_DIRS='["/Users/me/Documents/work","/Users/me/Projects/specs"]'Root configuration is resolved in this order:
CLI
--base-dir <path>flags (repeatable oningest,list, andsync)BASE_DIRSBASE_DIRCurrent directory
Each source replaces the lower-priority source rather than merging with it. Invalid BASE_DIRS
configuration fails instead of falling back to BASE_DIR or the current directory. status
remains available in MCP so the client can report the configuration error.
npx mcp-local-rag ingest --base-dir /Users/me/work --base-dir /Users/me/specs /Users/me/work/readme.md
npx mcp-local-rag list --base-dir /Users/me/work --base-dir /Users/me/specs
npx mcp-local-rag sync --base-dir /Users/me/work --base-dir /Users/me/specs
BASE_DIRS='["/Users/me/work","/Users/me/specs"]' npx mcp-local-rag listStorage and Models
DB_PATH and CACHE_DIR are relative to the process working directory by default. Set absolute
paths when the MCP client may start the server from different project directories.
Set MODEL_NAME or pass --model-name to choose a Hugging Face embedding model that fits the
language and domain of your documents.
mcp-local-rag generates embeddings with mean pooling and L2 normalization. When choosing a model, check whether these settings match its recommended inference setup, since the pooling method can affect retrieval quality.
Changing MODEL_NAME, RAG_DEVICE, or RAG_DTYPE can make existing vectors incompatible.
Use a new DB_PATH or delete the existing index and re-ingest after changing the embedding
configuration.
An example model for English documents is Xenova/bge-small-en-v1.5.
Security and Operation
File access is restricted to
BASE_DIR,BASE_DIRS, or CLI--base-dirroots.Symlinks that resolve outside every configured root are rejected.
Document processing and search make no network requests after the required models are cached, unless
RAG_RERANK_CMDnames a command that makes them.The server is designed for one local user and does not provide authentication or access control.
Do not run multiple CLI or MCP writers against the same
DB_PATH. Read-only queries can run while a sync is active.Back up an index by copying its
DB_PATHdirectory while no writer is active.
"No results found"
Documents must be ingested first. Run "List all ingested files" to verify.
Model download failed
Check internet connection. If behind a proxy, configure network settings. The model can also be downloaded manually.
"File too large"
Default limit is 100MB. Split large files or increase MAX_FILE_SIZE.
Slow queries
Check chunk count with status. Large documents with many chunks may slow queries. Consider splitting very large files.
"Path outside BASE_DIR"
Ensure file paths are within one of the configured roots (BASE_DIR, any BASE_DIRS entry, or any CLI --base-dir). Use absolute paths.
"BASE_DIRS must be a JSON array..."
BASE_DIRS accepts a JSON array of one or more non-empty path strings:
Valid:
BASE_DIRS='["/Users/me/work","/Users/me/specs"]'Invalid:
BASE_DIRS=/a:/b(delimiter syntax not supported)Invalid:
BASE_DIRS='[]'(empty array)
MCP client doesn't see tools
Verify config file syntax
Restart client completely (Cmd+Q on Mac for Cursor)
Test directly:
npx mcp-local-ragshould run without errors
Contributing
Contributions welcome! See CONTRIBUTING.md for setup and guidelines.
License
MIT License. Free for personal and commercial use.
Blog Posts
Building a Local RAG for Agentic Coding: Technical deep-dive into the semantic chunking and hybrid search design.
Acknowledgments
Built with Model Context Protocol by Anthropic, LanceDB, and Transformers.js.
Available Tools
9 toolsdelete_fileA
Delete a previously ingested file or data from the vector database. Use filePath for files ingested via ingest_file, or source for data ingested via ingest_data. Either filePath or source must be provided. Returns deleted (operation succeeded), removedChunks, and existed (whether anything was actually present).
| Name | Required | Description | Default |
|---|---|---|---|
| source | No | Source identifier used in ingest_data. Examples: "https://example.com/page", "clipboard://2024-12-30" | |
| filePath | No | Absolute path to the file (for ingest_file). Example: "/Users/user/documents/manual.pdf" |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses return values (deleted, removedChunks, existed) and the conditional requirement, which goes beyond the schema. It does not explicitly state irreversibility, but the term 'delete' implies it, and chunk removal is mentioned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, front-loaded with the action, and every sentence adds value. It is concise without sacrificing important details like return values and parameter selection.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the moderate complexity of the tool, the description covers the essential decision (filePath vs source), the required parameter constraint, and the return values. It lacks edge-case details like what happens if both parameters are provided, but this is minor given the overall clarity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description adds critical semantic context by mapping parameters to ingestion methods and clarifying the 'either/or' requirement. This goes beyond the schema's examples and helps the agent choose correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool deletes a previously ingested file or data from the vector database, using specific verbs and resource. It distinguishes itself from sibling tools like ingest_file and query_documents, as deletion is a unique operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly explains when to use each parameter: filePath for files ingested via ingest_file, source for data ingested via ingest_data. It also states that either must be provided, guiding the agent on parameter selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ingest_dataA
Ingest in-memory content as a string (use ingest_file for files on disk). The source identifier enables re-ingestion to update existing content. Returns { filePath, chunkCount, timestamp, fileTitle }.
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | The content to ingest (text, HTML, or Markdown) | |
| metadata | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the burden of behavioral disclosure. It reveals a key behavioral trait—re-ingestion with the same source identifier updates existing content—and specifies the return shape. While it does not mention auth, permissions, or side effects, it covers the main behavioral consequences for the typical use case.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long and front-loaded with the tool's core purpose. It efficiently packs the alternative tool reference, the re-ingestion behavior, and the return value into a compact, well-structured format with zero filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has 2 parameters (one nested), no annotations, and no output schema, the description provides a complete picture: what it does, when to use it, how the source identifier behaves, and what it returns. It lacks explicit error scenarios or prerequisites, but these are not critical for a simple ingestion tool. The return value statement covers the output side.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50% (content and format described in schema, metadata partially). The description adds significant value by explaining the 'source' identifier protocol with examples (e.g., 'clipboard://2024-12-30', 'chat://2024-12-30/project-discussion'), which is essential for correct invocation. This compensates well for the moderate schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses the specific verb 'Ingest' and clearly specifies the resource: 'in-memory content as a string'. It further distinguishes itself from a sibling tool by explicitly pointing to 'ingest_file' for disk files, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool (in-memory string content) and when not to (files on disk, via 'use ingest_file for files on disk'). This provides clear alternatives and context for selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ingest_fileA
Ingest a document file (PDF, DOCX, TXT, MD) into the vector database. Path must be absolute; re-ingesting the same path replaces its existing data. Returns { filePath, chunkCount, timestamp, fileTitle }.
| Name | Required | Description | Default |
|---|---|---|---|
| visual | No | Run VLM captioning on figure pages (PDF only; default false). | |
| filePath | Yes | Absolute path to the file to ingest. Example: "/Users/user/documents/manual.pdf" | |
| visualQuality | No | VLM profile when visual is true (default "fast"). "quality" is more accurate on figures with in-image text but much heavier and slower. Ignored when visual is false. | fast |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the burden of disclosing behavior. It explicitly states that re-ingesting replaces existing data, revealing a destructive side effect, and also specifies the return object structure. It does not cover other potential behaviors like long-running VLM processing, but the key destructive behavior is disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero waste. First sentence front-loads action and resource, second sentence covers constraints and return value. Highly scannable and efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and no annotations, the description covers essential operational context: supported file types, absolute path requirement, replacement behavior, and return format. It lacks explicit separation from sibling ingest tools (ingest_data, ingest_directory) but otherwise provides a complete picture for a single-file ingestion tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds value by listing allowed file extensions (PDF, DOCX, TXT, MD) for filePath, which the schema does not specify. It also clarifies replacement semantics tied to the file path. It does not add extra detail for visual or visualQuality beyond what the schema provides, so a slight uplift is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly specifies the verb 'Ingest' and resource 'document file (PDF, DOCX, TXT, MD) into the vector database'. It implicitly distinguishes itself from sibling tools like ingest_directory by focusing on a single document file with an absolute path, and from ingest_data by specifying file formats.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states clear context: use for ingesting a document file, path must be absolute, and re-ingesting the same path replaces existing data. It does not explicitly name alternatives or exclusions, but the singular 'file' and mention of supported extensions imply single-file use, differentiating from ingest_directory.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_filesA
List supported files (PDF, DOCX, TXT, MD) under the configured base directories and whether each is ingested. Returns { baseDirs, files, sources }; sources lists ingested items reported apart from the file scan, chiefly ingest_data content (web pages, clipboard, etc.).
| Name | Required | Description | Default |
|---|---|---|---|
| scope | No | Optional absolute path prefix(es) — one string or a list (unioned) — restricting the listing to files reachable at a path equal to or under a prefix within the base directories. "/docs/api" matches "/docs/api/x.md" but not "/docs/apiv2". Must be absolute (server OS style); a relative prefix matches nothing. A prefix outside every base directory yields an empty files list, so compare it against the baseDirs in the response before concluding no files exist. Scope filters files by their scan path; ingest_data sources, which have no base-directory path, are always listed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses the return structure ({ baseDirs, files, sources }), explains that sources lists non-file ingested items, and the scope parameter details behavior for relative/out-of-base prefixes. It does not explicitly state read-only intent or mention recursion depth/sorting, but for a list tool the essentials are covered. Edge cases for scope are thoroughly disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences: first states the core function and return object, second clarifies what 'sources' contains. No filler, front-loaded with the verb 'List'. The parameter schema is detailed but that is separate. The main description earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a list tool with no output schema, the description explains the return object and the meaning of sources. The scope parameter covers traversal/filtering behavior. It could additionally disclose recursion depth or permission requirements, but these are less critical for a read-only list operation. Overall, sufficiently complete for an agent to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single optional parameter 'scope', and its description is detailed (absolute path, prefix matching, union for arrays, behavior for relative/out-of-base). The tool description adds no extra parameter semantics beyond the schema. Per guidelines, high schema coverage yields a baseline of 3, which is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states what the tool does: 'List supported files (PDF, DOCX, TXT, MD) under the configured base directories and whether each is ingested.' This is a specific verb+resource combination with scope (supported extensions, base directories, ingestion status). It distinguishes from siblings: query_documents and status focus on querying, ingest_* on adding content, delete_file on removal. The tool is unambiguously the file-listing utility.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage: use this when you need to see files and their ingestion status, and it notes that sources include non-file ingest_data content (web pages, clipboard). The scope parameter description adds clear guidance about absolute path prefixes and how to interpret empty results (compare against baseDirs). However, it does not explicitly contrast with alternative tools such as query_documents or status, nor state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
query_documentsA
Search ingested documents with hybrid keyword + semantic matching. Use the returned order as the ranking; score may disagree with it. Each has filePath, chunkIndex, text, fileTitle, score (lower is closer), and source (for ingest_data items).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (default 10, range 1-100). Lower favors precision, higher recall. | |
| query | Yes | Search query. Preserve specific user terms (for keyword match); add context when the query is vague (for semantic match). | |
| scope | No | Optional absolute path prefix(es) — one string or a list (unioned) — restricting results to a filePath equal to or under a prefix. "/docs/api" matches "/docs/api/auth.md" but not "/docs/apiv2". Must be absolute (server OS style); a relative prefix matches nothing — derive one from a filePath returned by an earlier query, or omit scope. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full disclosure burden and does it well: it explains the hybrid matching strategy, warns that returned order — not score — is the ranking, and clarifies 'score (lower is closer)'. These are non-obvious behaviors an agent must know before interpreting results. It stops short of stating read-only safety or empty-result behavior, but for a search tool that is a minor gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with zero filler; the core purpose is front-loaded in sentence one, and sentences two and three each add distinct, high-value behavioral and return-format facts. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Complete for a search tool with a rich schema: it documents the return shape (critical since there is no output schema), the ranking-vs-score nuance, and the conditional 'source' field. Remaining gaps — pagination beyond limit=100, empty-result behavior, and an explicit read-only statement — are minor given the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all three parameters in detail, including limit's default/range and scope's prefix-matching semantics. The description adds modest value by explaining what score means and that order is authoritative, which gives semantic weight to the limit tradeoff, but it does not need to compensate for any coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb ('Search'), a resource ('ingested documents'), and a method ('hybrid keyword + semantic matching'), which cleanly separates it from siblings like list_files, read_chunk_neighbors, and the ingest/sync tools. The result-field list (filePath, chunkIndex, text) makes it unambiguous that this searches document content rather than listing the file tree.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Parameter-level guidance is strong: the query description tells when to preserve user terms vs. add context, and the scope description warns that relative prefixes match nothing and suggests deriving one from an earlier filePath. However, the description never explicitly states when to choose query_documents over a sibling such as list_files or read_chunk_neighbors; the use case is implied by the word 'search' rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_chunk_neighborsA
Read the chunks immediately before and after a query_documents result, in the same document, for more surrounding context. Pass chunkIndex from the result plus exactly one of filePath (ingest_file) or source (ingest_data). Returns the target chunk (isTarget: true) and its neighbors, ascending by chunkIndex; an out-of-range chunkIndex returns []. Defaults: before=2, after=2 (max 50 each).
| Name | Required | Description | Default |
|---|---|---|---|
| after | No | Number of chunks to retrieve after the target (0–50, default 2). | |
| before | No | Number of chunks to retrieve before the target (0–50, default 2). | |
| source | No | Source identifier (for ingest_data documents). Provide exactly one of filePath or source. Examples: "https://example.com/page", "clipboard://2024-12-30". | |
| filePath | No | Absolute path to the file (for ingest_file documents). Provide exactly one of filePath or source. Example: "/Users/user/documents/manual.pdf". | |
| chunkIndex | Yes | Zero-based target chunk index (non-negative integer). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden for behavioral disclosure. It thoroughly explains return behavior: target chunk (isTarget: true), neighbors ascending by chunkIndex, out-of-range returns [], and defaults (before=2, after=2, max 50 each). This goes well beyond basic descriptions and covers edge cases and ordering.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, directly front-loaded with the main purpose. Each sentence earns its place: purpose, parameter usage, and return behavior. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite lacking an output schema, the description fully explains the return structure: target chunk, neighbors, ordering, and edge-case behavior. It also sets expectations for defaults and limits, making it complete for a moderate-complexity read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds significant context beyond the schema: it explicitly ties chunkIndex to a query_documents result, emphasizes the exclusivity of filePath vs source, and reiterates defaults and maximums. This enriches the parameter semantics meaningfully.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific action: 'Read the chunks immediately before and after a query_documents result, in the same document.' This distinguishes it from query_documents (which retrieves results) and other tools by focusing on neighboring chunks. The verb 'read' and resource 'chunks' are explicit and specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage guidance by instructing to 'Pass chunkIndex from the result plus exactly one of filePath (ingest_file) or source (ingest_data).' This contextualizes the tool as a follow-up to query_documents. However, it does not explicitly compare to alternatives or state when not to use it, so it falls just short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
statusA
Get index status: { documentCount, chunkCount, memoryUsage (MB), uptime (s), ftsIndexEnabled, searchMode }.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the burden of behavioral disclosure. It communicates the output fields and implies a read-only operation via 'Get', but it does not explicitly state safety, side effects, or any operational conditions. The field list adds context, but some behavioral aspects remain implicit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence that immediately states the tool's purpose and then lists the output fields in a structured way. There is no redundancy or wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple status tool with no parameters and no output schema, the description adequately covers the return values and purpose. It does not mention potential delays or whether the status is a snapshot, but for its simplicity, the information provided is sufficient for basic invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has no parameters and an empty input schema, so parameter semantics are not needed. The description adds value by enumerating the output fields, which helps the agent understand what to expect, thus justifying a baseline score of 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action (Get) and resource (index status), and the listed field names specify exactly what the tool returns. This distinguishes it from sibling tools like query_documents or sync_status, which have different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given on when to use this tool versus alternatives such as sync_status, which may also report on index state. There is no mention of exclusions or typical use cases, leaving the agent to infer when this tool is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sync_startA
Reconcile the index with the files on disk: ingest new and changed files, leave unchanged files alone, and remove index entries for files that are gone. Each changed PDF is re-ingested with the visual profile ("fast" or "quality") already recorded for it, so a PDF indexed with VLM captions keeps them; a PDF with no recorded profile stays text-only. There is no option to change a profile here — use the CLI (mcp-local-rag sync --visual) to set one, or ingest_file to replace the file, where a normal ingest clears the recorded profile. Stored images are unrelated: STORE_IMAGES applies to whatever this run re-ingests and never makes a file changed. Returns { jobId } without waiting for the run to finish; poll sync_status with that jobId for progress and the final outcome. Only one job is kept, and it is lost when the server process exits.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Optional absolute path to a file or directory inside a configured base directory; list_files returns those directories as baseDirs. A file synchronizes only itself and a directory only its own subtree, leaving every path outside it untouched. Omit it to synchronize every configured base directory. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses side effects (index updates/removals), non-blocking execution, job retention, and process-exit loss. It also clarifies the behavior regarding visual profiles and STORE_IMAGES, ensuring the agent understands the tool's operational nuances.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is overly verbose and repetitive. Phrases like 'visual profile' and 'only one job is kept' are repeated, and the whole text could be condensed to a few sentences without losing meaning. The single-paragraph structure lacks scannable clarity, and the redundancy detracts from conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the main operational aspects: return value, polling mechanism, job limitations, and process-exit behavior. It is slightly incomplete regarding error cases or permission requirements, but given the moderate complexity and the absence of an output schema, it provides sufficient context for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema description for 'path' is already highly detailed, covering optionality, file/directory semantics, baseDirs, and omission behavior. The tool description repeats this verbatim without adding new semantic information, so the value beyond the schema is minimal, resulting in the baseline score of 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Reconcile the index with the files on disk: ingest new and changed files, leave unchanged files alone, and remove index entries for files that are gone.' It also specifies the non-blocking return of a jobId, making the tool's primary function unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly mentions alternatives and complementary tools: 'use the CLI (mcp-local-rag sync --visual) to set one, or ingest_file to replace the file' and 'poll sync_status with that jobId'. Also clarifies scope behavior and omission of path to sync all base directories, providing clear guidance on when and how to use the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sync_statusA
Get the current or latest sync job record: { jobId, state ("running" | "succeeded" | "failed"), total (null until scanning has counted the files on disk), completed (upserted + skipped + empty; pruned is counted separately), summary { upserted, skipped, empty, pruned }, warnings, error (null unless the job failed) }. An unknown jobId means the job was replaced by a newer one or lost with a previous server process.
| Name | Required | Description | Default |
|---|---|---|---|
| jobId | Yes | Identifier returned by sync_start. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It clearly states the return shape (jobId, state, total, completed, summary, warnings, error) and explains null/unknown meanings. It does not mention side effects, but 'Get' implies a read-only operation, and no side effects are likely. The level of detail is strong for a status tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than a typical one-liner, but it is dense and structured with the return object in braces, using spaces and parentheses for clarity. Every sentence adds value, though it could be slightly trimmed without loss. It is front-loaded with the core action.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter status tool with no output schema, the description is remarkably complete. It details all possible state values, null semantics, and the meaning of an unknown jobId. There is no obvious missing behavior; the tool's functionality is fully described.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers jobId with 'Identifier returned by sync_start.' The description adds meaning by explaining that an unknown jobId indicates replacement/loss, and by showing jobId in the return structure. This goes beyond the schema's basic parameter comment.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with 'Get the current or latest sync job record' — a specific verb and resource. It clearly distinguishes itself from siblings like sync_start (which creates a job) and status (which likely relates to something else) by focusing on sync job state retrieval.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the intended context: to poll or inspect a previously started sync job. It does not explicitly name alternatives, but the mention of 'unknown jobId means the job was replaced by a newer one or lost with a previous server process' gives practical guidance on interpreting results, which helps decide when this tool is useful.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
9 tool updates
v0.19.1- First observed
delete_file - First observed
ingest_data - First observed
ingest_file - First observed
list_files - First observed
query_documents - First observed
read_chunk_neighbors - First observed
status - First observed
sync_start - First observed
sync_status
TDQS
Scored across 9 tools
Each tool has a distinct purpose: ingest_file vs ingest_data are cleanly split by path vs in-memory string, delete_file consolidates deletion for both, query_documents is search, read_chunk_neighbors is follow-up context, and sync_start/sync_status form a clear job/poll pair. list_files and status both give overviews but their descriptions clearly separate file scanning from index metrics.
Most tools follow a consistent verb_noun pattern (query_documents, ingest_file, ingest_data, delete_file, list_files, read_chunk_neighbors, sync_start, sync_status). The lone 'status' noun breaks the pattern, and sync_ prefix is a minor variant, but overall it reads predictably.
Nine tools is well-scoped for a local RAG server, with each tool earning its place across search, ingest, delete, listing, status, context retrieval, and sync operations. No redundancy or bloat.
The surface covers the RAG lifecycle well: create/update via ingest and re-ingest, read via query and chunk neighbors, delete, list, status, and disk reconciliation via sync. Minor gaps exist (no explicit whole-index reset or single-document metadata fetch), but agents can work around them via delete_file and query_documents.
Maintenance
Related MCP Connectors
- docs2mcpOAuthcom.docs2mcp
Query your own PDFs and documents from any MCP client. Every answer cites the page it came from.
Personal knowledge base MCP server with semantic search, auto-categorization, metadata extraction
Agentic search over your Dewey document collections from any MCP-compatible client.
Cloud or self-hosted knowledge for AI agents: hybrid search, reranking, GraphRAG, scoped MCP tools.
Related MCP Servers
- AlicenseAqualityAmaintenancePrivacy-first local document search using semantic search. Runs entirely on your machine with no cloud services, supporting PDF, DOCX, TXT, and Markdown files.2298,055 npm403MIT
- AlicenseAqualityDmaintenanceA local-first document retrieval MCP server that enables AI coding tools like Codex to search private local documents via semantic search and keyword boost, supporting ingestion of PDF, DOCX, TXT, Markdown, and HTML files.7MIT
- AlicenseNot gradedqualityBmaintenanceA local-first semantic search server for documents, supporting PDFs, Office files, and text/markdown, enabling natural language search via the Model Context Protocol (MCP).1MIT
- AlicenseAqualityCmaintenanceMCP server that enables local hybrid semantic and keyword search over private PDF, DOCX, Markdown, and text documents without sending data to embedding APIs.98,055 npmMIT