@ssmeo/mcp-local-rag 0.18.14 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/README.de.md +248 -215
  2. package/README.es.md +241 -215
  3. package/README.fr.md +249 -215
  4. package/README.md +207 -297
  5. package/README.pt-BR.md +236 -215
  6. package/README.zh-CN.md +133 -206
  7. package/dist/chunker/semantic-chunker.d.ts +23 -5
  8. package/dist/chunker/semantic-chunker.d.ts.map +1 -1
  9. package/dist/chunker/semantic-chunker.js +13 -5
  10. package/dist/chunker/semantic-chunker.js.map +1 -1
  11. package/dist/cli/common.d.ts +7 -0
  12. package/dist/cli/common.d.ts.map +1 -1
  13. package/dist/cli/common.js +26 -2
  14. package/dist/cli/common.js.map +1 -1
  15. package/dist/cli/delete.d.ts.map +1 -1
  16. package/dist/cli/delete.js +2 -0
  17. package/dist/cli/delete.js.map +1 -1
  18. package/dist/cli/file-collection.d.ts +2 -1
  19. package/dist/cli/file-collection.d.ts.map +1 -1
  20. package/dist/cli/file-collection.js +2 -2
  21. package/dist/cli/file-collection.js.map +1 -1
  22. package/dist/cli/ingest.d.ts +1 -0
  23. package/dist/cli/ingest.d.ts.map +1 -1
  24. package/dist/cli/ingest.js +45 -25
  25. package/dist/cli/ingest.js.map +1 -1
  26. package/dist/cli/list.d.ts.map +1 -1
  27. package/dist/cli/list.js +9 -13
  28. package/dist/cli/list.js.map +1 -1
  29. package/dist/cli/options.d.ts +8 -0
  30. package/dist/cli/options.d.ts.map +1 -1
  31. package/dist/cli/options.js +21 -0
  32. package/dist/cli/options.js.map +1 -1
  33. package/dist/cli/query.d.ts.map +1 -1
  34. package/dist/cli/query.js +2 -1
  35. package/dist/cli/query.js.map +1 -1
  36. package/dist/cli/read-neighbors.d.ts.map +1 -1
  37. package/dist/cli/read-neighbors.js +1 -0
  38. package/dist/cli/read-neighbors.js.map +1 -1
  39. package/dist/cli/relocate.d.ts +3 -0
  40. package/dist/cli/relocate.d.ts.map +1 -0
  41. package/dist/cli/relocate.js +135 -0
  42. package/dist/cli/relocate.js.map +1 -0
  43. package/dist/cli/sync.d.ts.map +1 -1
  44. package/dist/cli/sync.js +17 -8
  45. package/dist/cli/sync.js.map +1 -1
  46. package/dist/cli-main.d.ts +1 -1
  47. package/dist/cli-main.d.ts.map +1 -1
  48. package/dist/cli-main.js +5 -0
  49. package/dist/cli-main.js.map +1 -1
  50. package/dist/embedder/embedding-snapshot.d.ts +52 -0
  51. package/dist/embedder/embedding-snapshot.d.ts.map +1 -0
  52. package/dist/embedder/embedding-snapshot.js +413 -0
  53. package/dist/embedder/embedding-snapshot.js.map +1 -0
  54. package/dist/embedder/index.d.ts +36 -5
  55. package/dist/embedder/index.d.ts.map +1 -1
  56. package/dist/embedder/index.js +346 -23
  57. package/dist/embedder/index.js.map +1 -1
  58. package/dist/embedder/remote.d.ts +16 -2
  59. package/dist/embedder/remote.d.ts.map +1 -1
  60. package/dist/embedder/remote.js +48 -11
  61. package/dist/embedder/remote.js.map +1 -1
  62. package/dist/embedder/sentence-transformers-config.d.ts +24 -0
  63. package/dist/embedder/sentence-transformers-config.d.ts.map +1 -0
  64. package/dist/embedder/sentence-transformers-config.js +93 -0
  65. package/dist/embedder/sentence-transformers-config.js.map +1 -0
  66. package/dist/features/sync.d.ts +7 -0
  67. package/dist/features/sync.d.ts.map +1 -1
  68. package/dist/features/sync.js +2 -1
  69. package/dist/features/sync.js.map +1 -1
  70. package/dist/ingest/compute.d.ts +15 -7
  71. package/dist/ingest/compute.d.ts.map +1 -1
  72. package/dist/ingest/compute.js +74 -14
  73. package/dist/ingest/compute.js.map +1 -1
  74. package/dist/ingest/file.d.ts +3 -3
  75. package/dist/ingest/file.d.ts.map +1 -1
  76. package/dist/ingest/file.js +0 -5
  77. package/dist/ingest/file.js.map +1 -1
  78. package/dist/ingest/visual.d.ts +6 -2
  79. package/dist/ingest/visual.d.ts.map +1 -1
  80. package/dist/ingest/visual.js +20 -4
  81. package/dist/ingest/visual.js.map +1 -1
  82. package/dist/parser/docx-parser.d.ts +2 -0
  83. package/dist/parser/docx-parser.d.ts.map +1 -1
  84. package/dist/parser/docx-parser.js +12 -3
  85. package/dist/parser/docx-parser.js.map +1 -1
  86. package/dist/parser/index.d.ts +11 -1
  87. package/dist/parser/index.d.ts.map +1 -1
  88. package/dist/parser/index.js +27 -11
  89. package/dist/parser/index.js.map +1 -1
  90. package/dist/parser/pdf-extract.d.ts +2 -0
  91. package/dist/parser/pdf-extract.d.ts.map +1 -1
  92. package/dist/parser/pdf-extract.js +3 -0
  93. package/dist/parser/pdf-extract.js.map +1 -1
  94. package/dist/parser/pdf-filter.d.ts +2 -9
  95. package/dist/parser/pdf-filter.d.ts.map +1 -1
  96. package/dist/parser/pdf-filter.js +110 -144
  97. package/dist/parser/pdf-filter.js.map +1 -1
  98. package/dist/parser/pdf-headings.d.ts +6 -0
  99. package/dist/parser/pdf-headings.d.ts.map +1 -0
  100. package/dist/parser/pdf-headings.js +166 -0
  101. package/dist/parser/pdf-headings.js.map +1 -0
  102. package/dist/parser/text-source-map.d.ts +3 -0
  103. package/dist/parser/text-source-map.d.ts.map +1 -0
  104. package/dist/parser/text-source-map.js +33 -0
  105. package/dist/parser/text-source-map.js.map +1 -0
  106. package/dist/pdf-visual/detector.js +3 -3
  107. package/dist/pdf-visual/detector.js.map +1 -1
  108. package/dist/rerank/command.d.ts +10 -7
  109. package/dist/rerank/command.d.ts.map +1 -1
  110. package/dist/rerank/command.js +51 -10
  111. package/dist/rerank/command.js.map +1 -1
  112. package/dist/rerank/index.d.ts +3 -3
  113. package/dist/rerank/index.d.ts.map +1 -1
  114. package/dist/rerank/index.js +3 -3
  115. package/dist/rerank/index.js.map +1 -1
  116. package/dist/server/index.d.ts +5 -1
  117. package/dist/server/index.d.ts.map +1 -1
  118. package/dist/server/index.js +168 -95
  119. package/dist/server/index.js.map +1 -1
  120. package/dist/server/list-scanner.d.ts +2 -1
  121. package/dist/server/list-scanner.d.ts.map +1 -1
  122. package/dist/server/list-scanner.js +2 -2
  123. package/dist/server/list-scanner.js.map +1 -1
  124. package/dist/server/tool-definitions.js +2 -2
  125. package/dist/server/tool-definitions.js.map +1 -1
  126. package/dist/server/types.d.ts +9 -0
  127. package/dist/server/types.d.ts.map +1 -1
  128. package/dist/server-main.d.ts +2 -2
  129. package/dist/server-main.d.ts.map +1 -1
  130. package/dist/server-main.js +22 -20
  131. package/dist/server-main.js.map +1 -1
  132. package/dist/utils/base-dirs.d.ts +9 -10
  133. package/dist/utils/base-dirs.d.ts.map +1 -1
  134. package/dist/utils/base-dirs.js +28 -30
  135. package/dist/utils/base-dirs.js.map +1 -1
  136. package/dist/utils/scan.d.ts +25 -5
  137. package/dist/utils/scan.d.ts.map +1 -1
  138. package/dist/utils/scan.js +40 -10
  139. package/dist/utils/scan.js.map +1 -1
  140. package/dist/utils/source-context.d.ts +29 -0
  141. package/dist/utils/source-context.d.ts.map +1 -0
  142. package/dist/utils/source-context.js +86 -0
  143. package/dist/utils/source-context.js.map +1 -0
  144. package/dist/utils/sync-lock.d.ts +8 -0
  145. package/dist/utils/sync-lock.d.ts.map +1 -1
  146. package/dist/utils/sync-lock.js +41 -9
  147. package/dist/utils/sync-lock.js.map +1 -1
  148. package/dist/utils/sync-path-key.d.ts +1 -1
  149. package/dist/utils/sync-path-key.d.ts.map +1 -1
  150. package/dist/utils/sync-path-key.js +1 -1
  151. package/dist/utils/sync-path-key.js.map +1 -1
  152. package/dist/vectordb/index.d.ts +4 -2
  153. package/dist/vectordb/index.d.ts.map +1 -1
  154. package/dist/vectordb/index.js +30 -7
  155. package/dist/vectordb/index.js.map +1 -1
  156. package/dist/vectordb/relocate.d.ts +18 -0
  157. package/dist/vectordb/relocate.d.ts.map +1 -0
  158. package/dist/vectordb/relocate.js +179 -0
  159. package/dist/vectordb/relocate.js.map +1 -0
  160. package/dist/vectordb/types.d.ts +10 -23
  161. package/dist/vectordb/types.d.ts.map +1 -1
  162. package/dist/vectordb/types.js +14 -23
  163. package/dist/vectordb/types.js.map +1 -1
  164. package/package.json +14 -14
package/README.md CHANGED
@@ -4,10 +4,14 @@
4
4
 
5
5
  # MCP Local RAG
6
6
 
7
- [![GitHub stars](https://img.shields.io/github/stars/shinpr/mcp-local-rag?style=social)](https://github.com/shinpr/mcp-local-rag)
8
- [![npm version](https://img.shields.io/npm/v/mcp-local-rag.svg)](https://www.npmjs.com/package/mcp-local-rag)
9
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
- [![MCP Registry](https://img.shields.io/badge/MCP-Registry-green.svg)](https://registry.modelcontextprotocol.io/)
7
+ [![GitHub
8
+ stars](https://img.shields.io/github/stars/shinpr/mcp-local-rag?style=social)](https://github.com/shinpr/mcp-local-rag)
9
+ [![npm
10
+ version](https://img.shields.io/npm/v/mcp-local-rag.svg)](https://www.npmjs.com/package/mcp-local-rag)
11
+ [![License:
12
+ MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
13
+ [![MCP
14
+ Registry](https://img.shields.io/badge/MCP-Registry-green.svg)](https://registry.modelcontextprotocol.io/)
11
15
 
12
16
  <p align="center">
13
17
  <strong>English</strong> |
@@ -23,46 +27,46 @@ embedding API.
23
27
 
24
28
  mcp-local-rag indexes PDF, DOCX, Markdown, and text files on your machine. Search combines
25
29
  semantic similarity with keyword matching, so queries can match both intent and exact technical
26
- terms such as API names, class names, and error codes.
30
+ terms such as API names, class names, and error codes. Results include source passages and,
31
+ where available, headings, line numbers, or page numbers so you can check and cite the original
32
+ document.
27
33
 
28
- ## Features
29
-
30
- - **Runs locally:** Document parsing, embeddings, storage, and search run on your machine.
31
- After the initial model download, text ingestion and search work offline.
32
- - **Hybrid search:** Semantic retrieval finds related concepts, while keyword matching boosts
33
- exact technical terms.
34
- - **Configurable embeddings:** Choose a Hugging Face embedding model that fits the language and
35
- domain of your documents.
36
- - **Semantic chunking:** Documents are split at topic boundaries instead of fixed character
37
- counts. Markdown code blocks stay intact.
38
- - **MCP and CLI:** Use the same index from an AI coding tool or directly from the terminal.
39
-
40
- No API key, Docker, Python, or external database is required.
34
+ No API key, Docker, Python, or external database is required. After the initial model download,
35
+ text ingestion and search work offline.
41
36
 
42
37
  ## Quick Start
43
38
 
44
39
  ### Requirements
45
40
 
46
- - Node.js 22 or later
41
+ - Node.js 22.20 or later
47
42
  - Internet access on first use to download the npm package and embedding model
48
43
  - A directory containing the documents you want to search
49
44
 
50
45
  Set `BASE_DIR` to that directory. It is also the security boundary for file operations. Replace
51
46
  `/absolute/path/to/your/documents` below with the directory's absolute path.
52
47
 
53
- mcp-local-rag uses the standard MCP protocol over a local stdio server, so it works with AI
54
- coding tools and other MCP hosts that support local MCP servers.
55
-
56
48
  Use one of the examples below, or register `npx -y mcp-local-rag` and set `BASE_DIR` using your
57
49
  client's MCP configuration format.
58
50
 
59
- **For Claude Code:** Run this command:
51
+ Set `DB_PATH` and `CACHE_DIR` to absolute paths as well. Relative paths resolve from the
52
+ server's working directory, so starting the server from different projects creates a separate
53
+ index and model cache in each.
54
+
55
+ <details>
56
+ <summary>Claude Code</summary>
57
+
58
+ Run this command:
60
59
 
61
60
  ```bash
62
61
  claude mcp add local-rag --scope user --env BASE_DIR=/absolute/path/to/your/documents -- npx -y mcp-local-rag
63
62
  ```
64
63
 
65
- **For Codex:** Add to `~/.codex/config.toml`:
64
+ </details>
65
+
66
+ <details>
67
+ <summary>Codex</summary>
68
+
69
+ Add to `~/.codex/config.toml`:
66
70
 
67
71
  ```toml
68
72
  [mcp_servers.local-rag]
@@ -73,7 +77,12 @@ args = ["-y", "mcp-local-rag"]
73
77
  BASE_DIR = "/absolute/path/to/your/documents"
74
78
  ```
75
79
 
76
- **For OpenCode:** Add to `~/.config/opencode/opencode.json` (or `opencode.jsonc`):
80
+ </details>
81
+
82
+ <details>
83
+ <summary>OpenCode</summary>
84
+
85
+ Add to `~/.config/opencode/opencode.json` (or `opencode.jsonc`):
77
86
 
78
87
  ```json
79
88
  {
@@ -90,7 +99,12 @@ BASE_DIR = "/absolute/path/to/your/documents"
90
99
  }
91
100
  ```
92
101
 
93
- **For Cursor:** Add to `~/.cursor/mcp.json`:
102
+ </details>
103
+
104
+ <details>
105
+ <summary>Cursor</summary>
106
+
107
+ Add to `~/.cursor/mcp.json`:
94
108
 
95
109
  ```json
96
110
  {
@@ -106,6 +120,8 @@ BASE_DIR = "/absolute/path/to/your/documents"
106
120
  }
107
121
  ```
108
122
 
123
+ </details>
124
+
109
125
  Restart the client, then ask it to build the index:
110
126
 
111
127
  ```text
@@ -133,31 +149,39 @@ npx mcp-local-rag query "authentication API"
133
149
  The CLI uses the current directory as its document root by default. Run both commands from the
134
150
  same directory so they use the same default index, or set `BASE_DIR` and `DB_PATH` explicitly.
135
151
 
136
- ## Why This Exists
137
-
138
- Some document sets cannot be sent to a hosted embedding service because of confidentiality or
139
- organizational policy. Keeping the index local makes them searchable without adding a per-query
140
- API cost.
141
-
142
- Semantic search alone can miss exact identifiers that matter in technical documentation.
143
- Keyword reranking keeps those terms visible without giving up natural-language retrieval.
144
-
145
152
  ## Supported Content
146
153
 
147
154
  | Input | How to ingest |
148
155
  |---|---|
149
156
  | PDF, DOCX, TXT, Markdown | File ingestion or directory sync |
150
- | HTML already fetched by the client | `ingest_data`; cleaned with Readability and converted to Markdown |
157
+ | HTML already fetched by the client | `ingest_data` |
151
158
  | Plain text or Markdown held in memory | `ingest_data` with a stable source identifier |
152
159
 
153
160
  HTML fetching is not built into the server. An MCP client can fetch a page and pass its HTML to
154
161
  `ingest_data`.
155
162
 
156
163
  Excel, PowerPoint, standalone images, and source-code file extensions are not supported by file
157
- ingestion. PDFs can optionally use a local vision model to describe figures, but this is not OCR
158
- or image search.
164
+ ingestion. PDFs can optionally use a local vision model to describe figures, but this is not
165
+ OCR or image search.
166
+
167
+ ## Using the Index
168
+
169
+ Sync after adding, editing, or removing documents. For searches and follow-up reading, ask your
170
+ MCP client:
159
171
 
160
- ## MCP Tools
172
+ ```text
173
+ Find the documented behavior of ERR_CONNECTION_REFUSED.
174
+ Read the surrounding chunks for that result.
175
+ ```
176
+
177
+ You can also ingest a single file or HTML already fetched by the client. To refresh an existing
178
+ entry, ingest the document again using the same path or source identifier. `sync` skips unchanged
179
+ files. MCP file paths must be absolute and inside a configured document root.
180
+
181
+ PDF section headings may be inaccurate. Check the original page when you need the exact heading.
182
+
183
+ <details>
184
+ <summary>MCP Tools</summary>
161
185
 
162
186
  | Tool | Purpose |
163
187
  |---|---|
@@ -171,161 +195,14 @@ or image search.
171
195
  | `delete_file` | Delete an indexed file or an `ingest_data` item |
172
196
  | `status` | Show index and search status |
173
197
 
174
- ### Syncing a Document Root
175
-
176
- `sync_start` ingests new and changed files, skips byte-identical files, and removes index entries
177
- for files that no longer exist:
178
-
179
- ```text
180
- Sync everything under the configured document roots and wait for completion.
181
- ```
182
-
183
- The tool returns a `jobId` immediately. Clients should poll `sync_status` until its state becomes
184
- `succeeded` or `failed`. A changed PDF keeps the visual profile it was indexed with; `sync_start`
185
- cannot change it. Set `STORE_IMAGES=true` in the MCP server environment to store supported PDF and
186
- DOCX images for new or changed files selected by sync; unchanged files remain skipped.
187
-
188
- Only one sync job is retained by the server process. A newer job replaces a finished record, and
189
- restarting the server discards it.
190
-
191
- ### Ingesting One File
192
-
193
- `ingest_file` accepts PDF, DOCX, TXT, and Markdown. MCP file paths must be absolute and must stay
194
- inside a configured document root:
195
-
196
- ```text
197
- Ingest the document at /Users/me/docs/api-spec.pdf.
198
- ```
199
-
200
- Re-ingesting the same path replaces its existing chunks.
201
-
202
- ### Searching and Reading More Context
203
-
204
- ```text
205
- What does the API documentation say about authentication?
206
- Find the documented behavior of ERR_CONNECTION_REFUSED.
207
- ```
208
-
209
- Results contain the text, source path, title, chunk index, relevance score, and any images stored
210
- on that chunk. MCP returns each image as an image content block paired with its result identity;
211
- CLI `query` includes an `images` array of `{ imageIndex, mimeType, data }` on every result. Pass the
212
- `chunkIndex` and either `filePath` or `source` from a result to `read_chunk_neighbors` when the
213
- answer needs more context:
214
-
215
- ```text
216
- Read the surrounding chunks for that authentication result.
217
- ```
218
-
219
- Both `query_documents` and `list_files` accept an optional absolute `scope` path prefix, or a
220
- list of prefixes. A prefix matches the exact path and its descendants.
221
-
222
- ### Ingesting HTML
223
-
224
- Use `ingest_data` after the MCP client fetches a page:
225
-
226
- ```text
227
- Fetch https://example.com/docs and ingest the HTML.
228
- ```
229
-
230
- The server extracts the main article, converts it to Markdown, and stores it under the supplied
231
- source identifier. Reusing the same source updates the existing content.
232
-
233
- Respect the source site's terms and copyright when indexing external content.
234
-
235
- ### PDF Visual Captions and Stored Images
236
-
237
- Visual mode adds a generated caption for figure-heavy PDF pages. It is opt-in and does not load
238
- a vision model during normal ingestion.
239
-
240
- ```text
241
- Ingest /Users/me/docs/research-paper.pdf with visual: true.
242
- ```
243
-
244
- ```bash
245
- npx mcp-local-rag ingest ./docs/research-paper.pdf --visual
246
- ```
247
-
248
- Image storage is independent of visual captions. Set `STORE_IMAGES=true` for the MCP server, or
249
- pass `--images` to CLI ingestion and sync:
250
-
251
- ```bash
252
- npx mcp-local-rag ingest ./docs/research-paper.pdf --images
253
- npx mcp-local-rag sync ./docs/ --images
254
- ```
255
-
256
- PDF storage uses detected figure/table regions. DOCX storage includes only PNG/JPEG images that
257
- the existing Mammoth conversion emits as `<img>`; charts, SmartArt, and shapes are not separately
258
- rendered. Stored images follow their surrounding text into the final semantic chunk and do not
259
- alter ranking, scores, or result count.
260
-
261
- | `visual` / `--visual` | `STORE_IMAGES` / `--images` | PDF behavior |
262
- |---|---|---|
263
- | false | false | Text only; no visual captions or returned images. |
264
- | true | false | Generated captions become searchable text; no images are stored or returned. |
265
- | true | true | Generated captions become searchable text, and images from matched chunks are returned inline. |
266
- | false | true | Images are attached to nearby retained PDF text and returned inline for matched chunks; the VLM is not imported, loaded, or run. |
267
-
268
- | Profile | Model cache | Use case |
269
- |---|---:|---|
270
- | `fast` (default) | about 250 MB | Lightweight visual indexing |
271
- | `quality` | about 1.7 GB | Figures containing labels, annotations, or other in-image text |
272
-
273
- Select the larger model with `visualQuality: "quality"` over MCP or
274
- `--visual-quality quality` over CLI. Measured CPU inference was about three times as slow as
275
- `fast`, though results depend on hardware and model updates.
276
-
277
- #### Updating Existing `quality` Captions
278
-
279
- From 0.18.4 `quality` runs Qwen3.5-2B; earlier versions ran Qwen2.5-VL-3B. Captions already indexed
280
- keep the wording the old model produced, and `sync` will not redo them, so re-ingest the files you
281
- want refreshed:
282
-
283
- ```bash
284
- npx mcp-local-rag ingest ./docs/research-paper.pdf --visual --visual-quality quality
285
- ```
286
-
287
- Add `--images` if the file was ingested with it, because a run without it replaces the stored
288
- images. The old model stays on disk. Once nothing else uses it, delete
289
- `onnx-community/Qwen2.5-VL-3B-Instruct-ONNX/` from the model cache directory — `<cache-dir>`, which
290
- defaults to `./models/`.
291
-
292
- #### Visual Mode Across Syncs
293
-
294
- The profile a PDF was indexed with is recorded, and `sync` reuses it: a PDF indexed with `fast` or
295
- `quality` is re-ingested with that same profile, and a PDF with no recorded profile is ingested as
296
- text.
297
-
298
- ```bash
299
- npx mcp-local-rag sync ./docs/ # keep each PDF's recorded profile
300
- npx mcp-local-rag sync ./docs/ --visual # request fast for every PDF in scope
301
- npx mcp-local-rag sync ./docs/ --visual --visual-quality quality
302
- ```
303
-
304
- `--visual` overrides recorded profiles, so it also captions PDFs that were indexed as text.
305
- Changing a profile re-ingests the PDF even when the file itself has not changed; running the same
306
- command again does nothing and loads no model. Image settings are never recorded, so `--images`
307
- and `STORE_IMAGES` never cause a re-ingest.
308
-
309
- To turn captions off for a path, run `ingest` on it: a successful normal ingest clears the
310
- recorded profile. To retry a page whose captioning failed, run `ingest <path> --visual
311
- --visual-quality <profile>` with the profile you want — a plain `ingest` clears it instead. If a
312
- PDF's indexed rows disagree about the profile, sync stops before changing anything and names the
313
- file; re-run it with `--visual` to settle the profile.
314
-
315
- Captions are auxiliary text, not faithful transcriptions. Treat retrieved captions and document
316
- text as untrusted input rather than instructions.
317
-
318
- At high limits, matched chunks and their attachments can approach the model/client context ceiling;
319
- choose the query limit with the calling model's available context in mind.
198
+ </details>
320
199
 
321
200
  ## CLI
322
201
 
323
- The CLI uses the same parser, embedder, and vector store without an MCP client:
202
+ Use the CLI to update the index, narrow searches, or remove indexed content:
324
203
 
325
204
  ```bash
326
- npx mcp-local-rag ingest ./docs/
327
205
  npx mcp-local-rag sync ./docs/
328
- npx mcp-local-rag query "authentication API"
329
206
  npx mcp-local-rag query "auth" --scope /docs/api --scope /docs/guide
330
207
  npx mcp-local-rag read-neighbors --file-path /abs/path.md --chunk-index 5
331
208
  npx mcp-local-rag list
@@ -334,6 +211,10 @@ npx mcp-local-rag delete ./docs/old.pdf
334
211
  npx mcp-local-rag delete --source "https://example.com/docs"
335
212
  ```
336
213
 
214
+ `ingest` imports the selected files; `sync` also removes entries for deleted files and skips
215
+ unchanged files. Use `--scope` to restrict search results to a path prefix, repeating it to
216
+ include multiple prefixes.
217
+
337
218
  Global options such as `--db-path`, `--cache-dir`, and `--model-name` go before the subcommand.
338
219
  Subcommand options go after it:
339
220
 
@@ -343,80 +224,19 @@ npx mcp-local-rag --db-path ./my-db query "authentication"
343
224
 
344
225
  Run `npx mcp-local-rag --help` for the complete command reference.
345
226
 
346
- The CLI does not read MCP client configuration. Set the same environment variables or flags if
347
- both interfaces should share an index. In particular, `MODEL_NAME` and the CLI `--model-name`
348
- must match for a shared database.
349
-
350
- `query` writes its results to stdout as JSON, best match first, so it can be piped into
351
- another tool. The field-by-field contract is in
227
+ `query` writes its results to stdout as JSON, best match first, so it can be piped into another
228
+ tool. The field-by-field contract is in
352
229
  [`docs/schema/query-output.schema.json`](docs/schema/query-output.schema.json).
353
230
 
354
- ## Search Tuning
355
-
356
- Keyword boost is enabled by default. Relevance-gap grouping and the distance and file filters are
357
- optional controls for corpora that need tighter result selection. All four apply to the MCP
358
- server and to CLI `query` alike.
359
-
360
- | Variable | Default | Description |
361
- |----------|---------|-------------|
362
- | `RAG_HYBRID_WEIGHT` | `0.6` | Keyword boost factor (0.0–1.0). 0 disables keyword reranking; 1 applies the maximum boost. |
363
- | `RAG_GROUPING` | (not set) | `similar` keeps the first relevance group; `related` keeps up to two, using significant vector-distance gaps as boundaries. |
364
- | `RAG_MAX_DISTANCE` | (not set) | Filter out low-relevance results (e.g., `0.5`). |
365
- | `RAG_MAX_FILES` | (not set) | Limit results to top N files (e.g., `1` for single best file). |
366
- | `RAG_RERANK_CMD` | (not set) | MCP server only: external command that reorders results. Your query and the matched text are sent to it. |
367
- | `RAG_RERANK_TIMEOUT_MS` | `10000` | Time budget per rerank call in milliseconds (100–600000). |
368
-
369
- For API specifications and other documents containing many identifiers, a stronger keyword
370
- weight can improve exact-term ranking:
231
+ If you move a project and want to keep its index, stop the MCP server and other database
232
+ writers, move the files and database together without changing the directory layout, then run:
371
233
 
372
- ```json
373
- "env": {
374
- "RAG_HYBRID_WEIGHT": "0.7"
375
- }
376
- ```
377
-
378
- - `0.7`: slightly stronger exact-term reranking than the default
379
- - `1.0`: maximum keyword boost
380
-
381
- ### External Reranking (`RAG_RERANK_CMD`)
382
-
383
- Name a command here and the server hands it each set of search results to reorder, together with
384
- your query and the text of the matched chunks. A command that calls a remote service sends all of
385
- that off this machine.
386
-
387
- Give the command and its arguments separated by spaces. It has to be an executable: the server
388
- runs it without a shell, so an npm-installed `.cmd` shim on Windows will not start.
389
-
390
- ```json
391
- "env": {
392
- "RAG_RERANK_CMD": "/path/to/reranker",
393
- "RAG_RERANK_TIMEOUT_MS": "10000"
394
- }
234
+ ```bash
235
+ npx mcp-local-rag --db-path /new/project/lancedb relocate --from /old/project --to /new/project
395
236
  ```
396
237
 
397
- The command receives each result in the form published at
398
- [`docs/schema/query-output.schema.json`](docs/schema/query-output.schema.json) and has to answer
399
- in that same form. Within it the command decides everything: what to keep, how to order it, and
400
- what the text says. Whatever it returns is what you see.
401
-
402
- Results keep their original order if the command fails, times out, or answers with something that
403
- is not that form.
404
-
405
- ## How It Works
406
-
407
- During ingestion:
408
-
409
- 1. The parser extracts text for the input format.
410
- 2. The semantic chunker finds topic boundaries and preserves Markdown code blocks.
411
- 3. Transformers.js creates embeddings locally.
412
- 4. LanceDB stores the chunks, metadata, vectors, and full-text index.
413
-
414
- During search:
415
-
416
- 1. The query is embedded with the same model.
417
- 2. Vector search retrieves semantically related chunks.
418
- 3. Optional distance and relevance-group filters narrow the candidates when configured.
419
- 4. Full-text matches boost exact query terms.
238
+ Update `BASE_DIR`/`BASE_DIRS`, `DB_PATH`, and any other moved paths in your MCP configuration,
239
+ then restart the client.
420
240
 
421
241
  ## Agent Skills
422
242
 
@@ -431,72 +251,152 @@ npx mcp-local-rag skills install --codex
431
251
  Installed skills cover query formulation, result refinement, and HTML ingestion. Ask the
432
252
  assistant to use the mcp-local-rag skill explicitly if it does not activate automatically.
433
253
 
434
- ## Configuration
254
+ ## Advanced Options
255
+
256
+ Start with the defaults. Open the sections below when you need different document roots, better
257
+ results for your corpus, or searchable PDF figures.
258
+
259
+ <details>
260
+ <summary>Storage and Document Roots</summary>
435
261
 
436
- The MCP server reads environment variables. The CLI accepts the listed global environment
437
- variables and flags; image storage on CLI ingestion and sync is enabled only with `--images`.
262
+ The MCP server reads environment variables. The CLI accepts the listed variables and flags.
263
+ Keep the same `DB_PATH` when commands should use the same index.
438
264
 
439
265
  | Environment Variable | CLI Flag | Default | Description |
440
266
  |---------------------|----------|---------|-------------|
441
267
  | `BASE_DIR` | `--base-dir` | Current directory | One document root; the CLI flag is repeatable on `ingest`, `list`, and `sync` |
442
268
  | `BASE_DIRS` | N/A | (unset) | JSON array of document roots; takes precedence over `BASE_DIR` |
269
+ | `IGNORE_PATHS` | N/A | (unset) | JSON array of glob patterns for files to keep out of the index |
443
270
  | `DB_PATH` | `--db-path` | `./lancedb/` | Vector database location |
444
271
  | `CACHE_DIR` | `--cache-dir` | `./models/` | Model cache directory |
445
272
  | `HF_ENDPOINT` | N/A | `https://huggingface.co` | Hugging Face model download endpoint; use a mirror URL when direct downloads are blocked |
446
- | `MODEL_NAME` | `--model-name` | `Xenova/all-MiniLM-L6-v2` | Hugging Face embedding model |
447
273
  | `MAX_FILE_SIZE` | `--max-file-size` | `104857600` (100MB) | Maximum file size in bytes |
274
+
275
+ File operations stay within configured roots. For multiple directories, set
276
+ `BASE_DIRS='["/absolute/docs","/absolute/specs"]'` or repeat CLI `--base-dir`. Precedence: CLI
277
+ roots, `BASE_DIRS`, `BASE_DIR`, then the current directory. Only the highest-priority source is
278
+ used; roots from different sources are not merged. Invalid `BASE_DIRS` is an error. Relative
279
+ `DB_PATH` and `CACHE_DIR` are resolved from the working directory.
280
+
281
+ To keep files out of the index, set `IGNORE_PATHS` to a JSON array of glob patterns, for example
282
+ `IGNORE_PATHS='["plugs/**","**/*.draft.md"]'`. Each pattern is matched against the file's path
283
+ relative to the root that contains it, written with `/` on every OS. `*` and `**` do not match
284
+ names that start with `.`, so write such directories out, as in `".obsidian/**"`. `ingest`,
285
+ `list`, and `sync` skip matching files when they scan a directory, and `sync` removes any that
286
+ are already indexed. Invalid `IGNORE_PATHS` is an error.
287
+
288
+ </details>
289
+
290
+ <details>
291
+ <summary>Models and Search Tuning</summary>
292
+
293
+ Choose an embedding model for your documents’ language and subject. Compare settings using
294
+ questions you actually ask and check which source passages are returned. The model must support
295
+ mean pooling and L2 normalization, which this tool uses to produce embeddings.
296
+
297
+ | Environment Variable | CLI Flag | Default | Description |
298
+ |---------------------|----------|---------|-------------|
299
+ | `MODEL_NAME` | `--model-name` | `Xenova/all-MiniLM-L6-v2` | Hugging Face embedding model |
448
300
  | `CHUNK_MIN_LENGTH` | `--chunk-min-length` | `50` | Minimum length in characters (1–10000) for ordinary chunks; a fragment of content split to fit the model's token limit can be shorter |
449
- | `STORE_IMAGES` | N/A | `false` | MCP server only: store supported PDF/DOCX images and return them with matched chunks. CLI uses `--images`. |
301
+ | `EMBED_TITLE_PREFIX` | N/A | `false` | Add the document title to each chunk's embedding input |
302
+ | `EMBED_HEADING_PREFIX` | N/A | `false` | Add the heading hierarchy to each chunk's embedding input when it fits |
450
303
  | `RAG_DEVICE` | N/A | `cpu` | ONNX Runtime execution device |
451
304
  | `RAG_DTYPE` | N/A | `fp32` | Embedding dtype passed to the selected model |
452
305
 
453
- ### Document Roots (`BASE_DIR` and `BASE_DIRS`)
306
+ Both prefix options default to `false` and work independently. Try `EMBED_TITLE_PREFIX` when a
307
+ passage needs the document’s overall topic, or `EMBED_HEADING_PREFIX` when it needs its
308
+ section’s topic. Enabling both is not always better. They affect embeddings, not the returned
309
+ text or keyword index; heading context is omitted when it would exceed the input budget.
454
310
 
455
- mcp-local-rag only allows file operations inside configured roots. For multiple roots,
456
- `BASE_DIRS` must be a JSON array of non-empty paths:
311
+ When changing embedding models, build a fresh index at a new `DB_PATH`. Vectors from different
312
+ models are not comparable, even when their dimensions match. After changing `RAG_DTYPE` or
313
+ either prefix option, re-ingest all indexed documents before searching. `sync` skips unchanged
314
+ files.
457
315
 
458
- ```bash
459
- export BASE_DIRS='["/Users/me/Documents/work","/Users/me/Projects/specs"]'
316
+ The CLI does not read MCP client configuration. When sharing an index, use the same model,
317
+ `RAG_DTYPE`, and prefix settings for ingestion and search. A change to `RAG_DEVICE` alone does
318
+ not require a new index.
319
+
320
+ ### Search Tuning
321
+
322
+ The first four settings below apply to both MCP and CLI queries. To give exact terms more
323
+ weight, try increasing `RAG_HYBRID_WEIGHT` and compare results on your own questions. External
324
+ reranking is MCP-only.
325
+
326
+ | Variable | Default | Description |
327
+ |----------|---------|-------------|
328
+ | `RAG_HYBRID_WEIGHT` | `0.6` | Keyword boost factor (0.0–1.0). 0 disables keyword reranking; 1 applies the maximum boost. |
329
+ | `RAG_GROUPING` | (not set) | `similar` keeps the first relevance group; `related` keeps up to two, using significant vector-distance gaps as boundaries. |
330
+ | `RAG_MAX_DISTANCE` | (not set) | Filter out low-relevance results (e.g., `0.5`). |
331
+ | `RAG_MAX_FILES` | (not set) | Limit results to top N files (e.g., `1` for single best file). |
332
+ | `RAG_RERANK_CMD` | (not set) | MCP only: external command; `{query}` passes the query and `{top}` the requested result count. |
333
+ | `RAG_RERANK_TIMEOUT_MS` | `10000` | Time budget per rerank call in milliseconds (100–600000). |
334
+
335
+ ### External Reranking (`RAG_RERANK_CMD`)
336
+
337
+ The command reads search results, including matched text, from stdin. If it calls a remote
338
+ service, that text may leave your machine.
339
+
340
+ Give the executable and its complete argument template. Put `{query}` and `{top}` where the
341
+ command expects the query and result count. Single or double quotes group paths or arguments
342
+ containing spaces, and backslashes stay literal. The server runs the executable without a
343
+ shell, so an npm-installed `.cmd` shim on Windows will not start.
344
+
345
+ ```json
346
+ {
347
+ "env": {
348
+ "RAG_RERANK_CMD": "/path/to/reranker --query {query} --top {top}",
349
+ "RAG_RERANK_TIMEOUT_MS": "10000"
350
+ }
351
+ }
460
352
  ```
461
353
 
462
- Root configuration is resolved in this order:
354
+ The command must read and return results in the format defined by [the query output
355
+ schema](docs/schema/query-output.schema.json). It can remove or reorder results and modify
356
+ their text. The server returns its output.
463
357
 
464
- 1. CLI `--base-dir <path>` flags (repeatable on `ingest`, `list`, and `sync`)
465
- 2. `BASE_DIRS`
466
- 3. `BASE_DIR`
467
- 4. Current directory
358
+ Results keep their original order if the command fails, times out, or returns output that does
359
+ not match the schema.
468
360
 
469
- Each source replaces the lower-priority source rather than merging with it. Invalid `BASE_DIRS`
470
- configuration fails instead of falling back to `BASE_DIR` or the current directory. `status`
471
- remains available in MCP so the client can report the configuration error.
361
+ </details>
362
+
363
+ <details>
364
+ <summary>PDF Figures and Stored Images</summary>
365
+
366
+ By default, ingestion indexes only text. To make PDF figures searchable, enable local caption
367
+ generation with `visual: true` in MCP or `--visual` in the CLI. Captions are generated
368
+ descriptions, not OCR or exact transcriptions.
369
+
370
+ `fast` (default) downloads about 250 MB on first use. Choose `quality` for labels and text
371
+ within figures; it downloads about 1.7 GB and takes longer to run.
372
+
373
+ Select the profile with `visualQuality: "quality"` in MCP or `--visual-quality quality` in the
374
+ CLI.
472
375
 
473
376
  ```bash
474
- npx mcp-local-rag ingest --base-dir /Users/me/work --base-dir /Users/me/specs /Users/me/work/readme.md
475
- npx mcp-local-rag list --base-dir /Users/me/work --base-dir /Users/me/specs
476
- npx mcp-local-rag sync --base-dir /Users/me/work --base-dir /Users/me/specs
477
- BASE_DIRS='["/Users/me/work","/Users/me/specs"]' npx mcp-local-rag list
377
+ npx mcp-local-rag ingest ./docs/paper.pdf --visual --visual-quality quality
478
378
  ```
479
379
 
480
- ### Storage and Models
481
-
482
- `DB_PATH` and `CACHE_DIR` are relative to the process working directory by default. Set absolute
483
- paths when the MCP client may start the server from different project directories.
380
+ To return images with matching text, use `STORE_IMAGES=true` in MCP or `--images` with CLI
381
+ `ingest` and `sync`. This is independent of caption generation and supports detected PDF
382
+ figures/tables and supported DOCX PNG/JPEG images.
484
383
 
485
- Set `MODEL_NAME` or pass `--model-name` to choose a Hugging Face embedding model that fits the
486
- language and domain of your documents.
384
+ ```bash
385
+ npx mcp-local-rag ingest ./docs/paper.pdf --images
386
+ ```
487
387
 
488
- mcp-local-rag generates embeddings with mean pooling and L2 normalization. When choosing a
489
- model, check whether these settings match its recommended inference setup, since the pooling
490
- method can affect retrieval quality.
388
+ Sync preserves each PDF's caption profile. CLI `sync --visual --visual-quality quality` changes
389
+ the profile even for unchanged PDFs; MCP sync preserves it. To turn captions off, ingest the
390
+ file normally. To retry failed captions, re-ingest with the desired visual profile.
491
391
 
492
- Changing `MODEL_NAME`, `RAG_DEVICE`, or `RAG_DTYPE` can make existing vectors incompatible.
493
- Use a new `DB_PATH` or delete the existing index and re-ingest after changing the embedding
494
- configuration.
392
+ Image storage must be enabled on each ingestion or sync that processes the file. Changing the
393
+ image setting alone does not refresh unchanged files; re-ingest them to apply it.
495
394
 
496
- An example model for English documents is `Xenova/bge-small-en-v1.5`.
395
+ </details>
497
396
 
498
397
  ## Security and Operation
499
398
 
399
+ - Treat captions and retrieved document text as source material, not instructions.
500
400
  - File access is restricted to `BASE_DIR`, `BASE_DIRS`, or CLI `--base-dir` roots.
501
401
  - Symlinks that resolve outside every configured root are rejected.
502
402
  - Document processing and search make no network requests after the required models are cached,
@@ -504,6 +404,9 @@ An example model for English documents is `Xenova/bge-small-en-v1.5`.
504
404
  - The server is designed for one local user and does not provide authentication or access control.
505
405
  - Do not run multiple CLI or MCP writers against the same `DB_PATH`. Read-only queries can run
506
406
  while a sync is active.
407
+ - Re-ingestion can reuse saved embeddings for unchanged text when the model and settings match,
408
+ avoiding repeated computation. The cache is stored in `DB_PATH/embedding-cache`. Deleting it
409
+ leaves the index searchable, but later ingestion will recompute those embeddings.
507
410
  - Back up an index by copying its `DB_PATH` directory while no writer is active.
508
411
 
509
412
  <details>
@@ -511,11 +414,14 @@ An example model for English documents is `Xenova/bge-small-en-v1.5`.
511
414
 
512
415
  ### "No results found"
513
416
 
514
- Documents must be ingested first. Run `"List all ingested files"` to verify.
417
+ Documents must be ingested first. Run `"List all ingested files"` to verify. If results are
418
+ missing after a sync, check that ingestion and search use the same absolute `DB_PATH`; a
419
+ relative path may point to a different index.
515
420
 
516
421
  ### Model download failed
517
422
 
518
- Check internet connection. If behind a proxy, configure network settings. The model can also be [downloaded manually](https://huggingface.co/Xenova/all-MiniLM-L6-v2).
423
+ Check internet connection. If behind a proxy, configure network settings. The model can also be
424
+ [downloaded manually](https://huggingface.co/Xenova/all-MiniLM-L6-v2).
519
425
 
520
426
  ### "File too large"
521
427
 
@@ -523,11 +429,13 @@ Default limit is 100MB. Split large files or increase `MAX_FILE_SIZE`.
523
429
 
524
430
  ### Slow queries
525
431
 
526
- Check chunk count with `status`. Large documents with many chunks may slow queries. Consider splitting very large files.
432
+ Check chunk count with `status`. Large documents with many chunks may slow queries. Consider
433
+ splitting very large files.
527
434
 
528
435
  ### "Path outside BASE_DIR"
529
436
 
530
- Ensure file paths are within one of the configured roots (`BASE_DIR`, any `BASE_DIRS` entry, or any CLI `--base-dir`). Use absolute paths.
437
+ Ensure file paths are within one of the configured roots (`BASE_DIR`, any `BASE_DIRS` entry, or
438
+ any CLI `--base-dir`). Use absolute paths.
531
439
 
532
440
  ### "BASE_DIRS must be a JSON array..."
533
441
 
@@ -559,4 +467,6 @@ MIT License. Free for personal and commercial use.
559
467
 
560
468
  ## Acknowledgments
561
469
 
562
- Built with [Model Context Protocol](https://modelcontextprotocol.io/) by Anthropic, [LanceDB](https://lancedb.com/), and [Transformers.js](https://huggingface.co/docs/transformers.js).
470
+ Built with [Model Context Protocol](https://modelcontextprotocol.io/) by Anthropic,
471
+ [LanceDB](https://lancedb.com/), and
472
+ [Transformers.js](https://huggingface.co/docs/transformers.js).