
Local Vector Search MCP
io.github.DimonSmart由 GitHub 帳號 DimonSmart 發布v0.1.3更新於 Nov 2, 2026
Local Markdown search, navigation and editing via MCP, with optional vector embeddings.
概覽
本機 MCP 伺服器,將專案的 Markdown 索引到 SQLite,支援詞彙、語意或混合檢索,並提供帶雜湊校驗的讀取、編輯與圖片資源管理。
- 可以做什麼
- 檢索與索引:查看索引狀態、啟動背景重建,並依路徑範圍執行詞彙、語意或混合搜尋。
- 讀取與瀏覽 Markdown:依語意指標讀取局部片段,列出檔案與資源,取得標題大綱。
- 編輯 Markdown:依元素或整節替換、刪除與插入,編輯 GFM 表格,建立、移動、刪除檔案。
- 匯出與下載:將 Markdown 文件渲染為具樣式的 PDF 書籍,並把工作區檔案以二進位資源下載。
- 管理圖片:儲存、列出、載入、移動與刪除 PNG、JPEG、WebP、GIF 資源,且不納入索引。
- 適用情境
- 適合助理在擁有大量 Markdown 文件的儲存庫中工作:需要在不把全部文件塞進上下文的情況下找到正確的規格、架構決策或指南,並對這些檔案做精確、具衝突校驗的修改。
- 執行需求
- 以 stdio 在本機執行,需要 .NET 10 執行環境或 SDK(可全域安裝 dotnet 工具或以 dnx 啟動)。需提供指向 Markdown 工作區的專案根目錄參數。詞彙模式完全離線;語意或混合搜尋需要本機 Ollama 相容的嵌入端點並已拉取模型,除非關閉嵌入。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Local Vector Search MCP,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
LocalVectorSearchMcp
[Local Vector Search MCP server]
Give Codex, Claude Code, and ChatGPT a local, editable, project-aware Markdown workbench.
LocalVectorSearchMcp is a local MCP server that indexes one project's Markdown files into a project-local SQLite database. Agents can search, read focused semantic slices, edit by semantic pointer, manage Markdown files, navigate the workspace, and manage ordinary image assets.
It helps an agent find the right specification, architectural decision, guide, or invariant without loading the entire documentation set into its context.
Why use it?
Large repositories often contain the answer, but not in the file the agent happens to open first.
- Exact text search finds identifiers, API names, and quoted terminology.
- Vector search finds conceptually related documentation even when wording differs.
- Hybrid search combines both result lists through Reciprocal Rank Fusion.
kb_readreturns focused slices from the current Markdown source instead of forcing the agent to read whole files or wait for indexing.- Element-level optimistic concurrency prevents an agent from overwriting a semantic target that changed after it was read, while unrelated document edits do not block the patch.
- Optional file watching keeps the index synchronized with edits from VS Code, Obsidian, or other editors.
- PNG, JPEG, WebP, and GIF files can be stored as non-indexed assets throughout
knowledgeBase.root(defaultimages/). - Every project gets its own local SQLite index.
- No cloud database or mandatory YAML configuration is required.
How it works
Claude Code and Codex can launch the stdio server directly. ChatGPT can use the same MCP surface through OpenAI Secure MCP Tunnel, where the external tunnel-client bridges ChatGPT to the local stdio process.
Quick start: offline lexical search
Install the .NET tool (requires .NET 10):
Alternatively, run a pinned published version directly with dnx (requires the .NET 10 SDK; no global tool install):
The official MCP Registry uses the canonical name io.github.DimonSmart/local-vector-search-mcp. A listing is available only after a matching NuGet release has been successfully registered.
To register the server using dnx without a global install:
Replace <version> with a version published on NuGet.org, and run the commands from the Markdown project's root. The server uses stdio and offline lexical mode here; no Ollama endpoint or API key is required.
From the project you want to index, run the following. This needs no Ollama server, no remote embedding endpoint and no API key:
Register a project-specific MCP server using the same arguments:
The SQLite FTS5 index is stored in .local-vector-search-mcp/index.db under
the project root. Markdown remains the source of truth. The server is read-only
for Markdown and images unless knowledgeBase.allowWrites: true is explicitly set in YAML.
See the IDD integration example
for .idd/intent, explicit paths, dnx, and Claude Code.
Optional hybrid/semantic quick start
1. Install the tool and embedding model
Make sure Ollama is running before the first reindex.
2. Connect your client
Run the command from the project whose documentation should be indexed.
Claude Code
Codex
ChatGPT
Keep LocalVectorSearchMcp as a local stdio server and bridge it with OpenAI Secure MCP Tunnel. For the tunnel scenario, use an explicit configuration with absolute knowledge-base and storage paths.
See ChatGPT via Secure MCP Tunnel.
3. Ask the agent to initialize and use the index
By default, the server indexes *.md files under the detected project root and stores the index in .local-vector-search-mcp/index.db.
See Getting started for the complete setup and verification flow.
Example tasks
Capabilities
The MCP server exposes eighteen tools. MCP reindexing is asynchronous: kb_reindex starts or joins the single active reindex and returns immediately, while kb_status.indexing reports progress and the last outcome. The CLI --reindex command remains synchronous and exits only after indexing finishes.
kb_status— inspect the current index.kb_reindex— start a background build or rebuild; monitorkb_status.indexingfor progress and the final result.kb_search— run optionally path-scoped lexical, semantic, or hybrid search against the derived index; each result identifies its indexed revision withindexedSourceHash.kb_read— read the current Markdown source from a semantic pointer and receive the exact source revisionsourceHash.kb_patch— atomically replace/delete individual semantic elements or complete heading sections, and insert before/after elements.kb_edit_table— source-aware editing of GFM table cells, rows, columns and alignment through a hashed table pointer.kb_create,kb_move,kb_delete— manage Markdown source files.kb_list_files— list Markdown files and non-indexed assets; usepathPrefixfor a directory or exact file, andincludeGlobfor filename patterns.kb_outline— return a deterministic heading tree.kb_create_pdf_book— render a Markdown document as a formatted PDF book.kb_download_file— return any permitted workspace file as a downloadable binary resource.kb_save_image— save an image supplied through the OpenAI file parameter (optionaltargetPath).kb_list_images— list supported image assets recursively with cursor pagination.kb_load_image— return an existing image as a real MCP image content block.kb_delete_image— delete one binary image under root without changing Markdown.kb_move_image— safely move one binary image anywhere inside root without changing Markdown references.
For low-level MCP or connector calls, a tool with no user arguments still uses an explicit empty arguments object. The canonical kb_status wire call is:
Clients should not rely on omitting the argument object; {} is the interoperable contract for parameterless tools.
File-list filters
kb_list_files.pathPrefix is a root-relative directory path or an exact file
path, not a partial filename prefix. books and books/ include files below
books/; books/chapter.md selects that exact file; books/chapter does not
match books/chapter.md. Use includeGlob for filename matching. Both filters
apply when supplied.
PDF book export
kb_create_pdf_book(path, outputPath?, pageFormat?, style?, profile?) creates a PDF from a root-relative Markdown file. It renders headings, emphasis, code, lists, quotes, links, GFM tables, and local images. The default output is the source name with a .pdf extension; it must remain under knowledgeBase.root. As a derived reading artifact, an existing PDF at that path is atomically replaced on the next export. Export requires knowledgeBase.allowWrites: true, does not alter Markdown, assets, or the search index, and returns {path,bytes,warnings}. Unavailable images are represented by a PDF placeholder and included in warnings; remote and absolute image URLs are not fetched. Formats: a4, a5 (default), a6, b5, letter; styles: compact (default), classic, modern, technical, academic.
Profiles (application-defined presets): screen = 96 DPI / JPEG quality 65, standard = 150 DPI / JPEG quality 82 (default), print = 300 DPI / JPEG quality 95. All profiles use PDF full compression, preserve Unicode text and the layout/physical size of images, and share identical embedded image resources. High-resolution JPEGs and PNGs may be downsampled; unchanged or already efficient files stay in their original encoding. JPEG with EXIF/ICC/Adobe metadata and PNG with explicit color metadata are preserved rather than risk altering orientation or colors; unsupported GIF/WebP retain the renderer's prior behavior. Output size is not guaranteed to fit kb_download_file's unchanged 25 MiB limit. Print is for ordinary printing, not PDF/X, CMYK production, or press-ready preflight. Image processing may take longer than before; the default profile may change the raster quality/size of previously exported PDFs.
Examples (all calls use the existing nested request):
Workspace file download
kb_download_file(path) returns the original bytes of one root-relative workspace file as an embedded MCP binary resource, followed by {path,mimeType,bytes,sha256} metadata. It works without write permission and supports any regular file up to 25 MiB; unknown extensions use application/octet-stream. Absolute/traversal paths, .git, internal index files, and symlink/junction/reparse-point paths are rejected. Use kb_load_image instead when an image preview or GIF-to-PNG conversion is needed.
Image assets
All five image tools work with PNG, JPEG, WebP and GIF files anywhere under knowledgeBase.root. Paths are root-relative; .git/, internal SQLite files, traversal and symlink/junction/reparse-point paths are forbidden. images/ is the recommended default folder, not an API restriction. Images are ordinary assets and are never indexed or embedded.
kb_save_image(file, fileName?, altText?, targetPath?) requires allowWrites=true and preserves the OpenAI openai/fileParams metadata. Upload or select an actual image in the client and pass the resulting file reference. Arbitrary text, raw Base64, and data URIs are not valid file values; if a client rejects them before invoking the tool, that client-side validation cannot be normalized by the server. Downloads remain HTTPS-only with SSRF/redirect protection, a 25 MiB streaming limit, MIME/signature checks and SHA-256. Without targetPath, saves default to images/, using fileName or source basename and numeric suffixes for collisions (cover.png, cover-2.png). Explicit targetPath includes the final file name and extension, may create intermediate safe directories, and never renames or overwrites an occupied destination (ALREADY_EXISTS). Combining targetPath and fileName is invalid.
The save result includes path, mimeType, bytes, lowercase sha256, and markdown. The generated Markdown destination is relative to the workspace root. For a document in chapters/, the caller must recompute and escape the relative destination from that document.
kb_list_images(cursor?, pageSize?) lists supported image extensions throughout the root, sorted case-insensitively with ordinal tie-breaking. Cursor pagination defaults to 50 items (range 1–200) and supports the last cursor item being deleted. kb_load_image(path) validates signature, extension and size; its MCP result contains an ImageContentBlock first and JSON metadata about the original file second, without StructuredContent. PNG/JPEG/WebP return their original bytes. GIF returns the first frame rendered as a PNG image block (image/png) because some ChatGPT connectors do not expose image/gif blocks; the text metadata still reports the source GIF's path, MIME type, byte count and SHA-256. The original GIF remains unchanged. The preview is static (no animation).
kb_move_image renames or moves only one binary image, anywhere under root. Input is {sourcePath,targetPath,expectedSha256?}. expectedSha256 is an optional 64-digit hex optimistic concurrency check; mismatches produce CONFLICT. Markdown links must be updated separately with kb_read and kb_patch. The response is {previousPath,path,sha256} and contains no Markdown/index fields.
kb_delete_image(path) simply deletes the supported binary file, without scanning for Markdown references, checking if it is used, or removing its parent directories. Its result remains {path,deleted:true}. Both binary move and delete can leave broken Markdown links. Image operations never schedule indexing.
To repair links, use separate kb_read / kb_patch calls on correctly addressable Markdown elements. A move-and-patch workflow is not a multi-file transaction: find relevant documents before the move, move the image, patch the necessary elements with current semantic anchors, and verify the new paths. Raw link constructs that cannot be addressed safely should not be rewritten by replacing arbitrary larger sections. Git can be used for recovery.
Saving, moving, and deleting require:
Expected tool errors return IsError=true and a JSON text object with code and message, e.g. INVALID_PATH, UNSUPPORTED_FORMAT, ALREADY_EXISTS, CONFLICT, PERMISSION_DENIED. Image tools have no indexSynchronized; for Markdown mutations its value is true only when reconciliation has already been confirmed or was unnecessary, and false when source changes succeeded but reconciliation is still unconfirmed.
Local-first and project-isolated
Each server process belongs to one project and one configured Markdown root. It cannot select or search another project's index through the MCP API.
The default embedding endpoint is local Ollama. Remote embedding endpoints are rejected unless they are explicitly enabled in YAML. Document text, embedding text, API keys, raw vectors, and signed image download URLs are not logged.
Documentation
- Getting started
- Offline IDD integration
- MCP Registry discovery (entry available after the first registry release)
- Claude Code setup
- Codex setup
- ChatGPT via Secure MCP Tunnel
- Configuration
- Maintenance and updates
- Verification
- Troubleshooting
- Product specification
- Architecture decision
Editable workspaces
Writes and external file watching are explicit opt-ins:
Markdown files remain the source of truth for indexed knowledge. kb_read and kb_outline parse the current source directly; kb_search uses the derived SQLite index and may temporarily return an older indexed revision. A Markdown mutation commits the source file first and then schedules synchronization of the derived SQLite index. The mutation call does not wait for reconciliation to finish; indexSynchronized: false means the source commit succeeded but derived-index synchronization has not yet been confirmed. Internal semantic pointers remain logical structural addresses. Public concrete-element pointers use logical~selfHash~subtreeHash, where both values are 16-character lowercase XxHash64 hashes over exact UTF-8 source. selfHash covers the element itself; heading subtreeHash covers the complete section source range owned by replace_section and delete_section, while leaf hashes are equal. kb_patch relocates only by kind plus selfHash; replace_section and delete_section additionally validate subtreeHash. sourceHash is still returned by kb_read for whole-file operations such as kb_move and kb_delete.
For structural edits, replace_element replaces exactly one Markdown element and delete removes exactly one element; deleting a heading with delete preserves its section body. replace_section replaces a heading together with its complete owned section subtree, while delete_section removes that whole subtree. Both section operations require a canonical v2 heading pointer and validate subtreeHash.
None of the five image tools changes Markdown or schedules Markdown index synchronization.
kb_patch examples
The MCP method accepts one request object. Inside it, operations is always an array, even when applying a single operation. New concrete-element pointers should use the canonical v2 anchors returned by kb_read, kb_search, or kb_outline. Legacy logical~selfHash anchors remain accepted for navigation and Self mutations, but replace_section requires the v2 subtree hash. kb_patch does not accept expectedSourceHash.
Use replace_element to replace exactly one editable Markdown element. For a heading, it changes only the heading itself and keeps the existing section body. The replacement must parse as exactly one editable element, and a heading replacement must keep the same heading level. Legacy replace remains supported as a deprecated alias with the same validation.
Use replace_section to rewrite a complete heading section atomically. The target must be a canonical v2 heading anchor with both selfHash and subtreeHash. The replaced range starts at that heading and continues through all nested content until the next heading with level less than or equal to the target level, or EOF. The replacement must start with a heading of the same level and may contain only deeper headings after it.
Replace one element:
Replace a whole section:
Insert after:
Delete:
Supported kind values are replace, replace_element, replace_section, delete_section, insert_before, insert_after, and delete. replace, replace_element, replace_section, and insert operations require markdown; delete does not. The special document pointer remains unhashed and can be used with insert_before or insert_after at document boundaries. Existing valid single-element replace requests remain compatible; multi-element replacement through replace is intentionally rejected and should use replace_section or other explicit operations.
An unrelated edit elsewhere in the file does not invalidate a Self mutation when the target selfHash is still valid. If the target moved because content was inserted above it, kb_patch relocates it only when the same element kind and exact selfHash identify exactly one current element. replace_section then also verifies the original subtreeHash, so edits anywhere in the owned section range—including raw/non-indexed Markdown—are rejected rather than overwritten.
Current scope
The current version supports indexed local Markdown plus ordinary image assets. All five image tools use knowledgeBase.root as the boundary; saving defaults to images/. Remote access from ChatGPT is supported through OpenAI Secure MCP Tunnel, which externally launches and bridges the existing local stdio server.
PDF/DOCX/OCR, arbitrary binary upload, image embeddings/search, image resizing/transcoding/thumbnails, automatic Markdown image insertion, a media database, a web UI, Git history indexing, direct remote HTTP MCP transport, application-level authentication, multi-user mode, CRDT, and automatic merge are outside the current scope.
Addressable Markdown list items and atomic quotes
kb_read exposes individual list items as list_item using li1, 1.li2, 1.li2.li1 plus the normal two-hash anchor suffix. Parent Text excludes nested item text. replace_element (and its deprecated alias replace) changes the item's own source content before its first nested child, preserving all descendants and untouched parent-owned content after them; it checks selfHash. Explicit replace_subtree or delete replaces/removes the whole subtree and requires both current hashes. Adjacent insertions check self hash and accept one source-indented sibling with a compatible list marker; neither blank lines nor ordered numbers are silently normalized.
A stand-alone Markdown quote is one opaque block_quote with qN or 1.qN, regardless of internal Markdown (including > - item). It can only be read, searched, deleted, inserted around, or replaced as a whole. Older paragraph pointers suppressed inside lists/quotes must be re-read.
List-item editing uses exact half-open source ranges: the subtree contains every descendant, whereas the parent's own text consists only of its non-child source segments. replace_element replaces the contiguous own prefix, preserving any nested items and later parent-owned source; replace_subtree replaces the full subtree; delete consumes its terminating line ending when present; insert_after inserts after all descendants. No AST serialization or document-wide whitespace normalization is performed, and unmodified source bytes (including BOM and mixed EOL) are retained.
A list insertion or replacement must supply one item with the target's physical indentation and compatible marker style (ordered marker numbers may differ). replace_element accepts an item without child items; it preserves existing children, and fails closed if a safe source prefix cannot be proven. To deliberately change the nested list, use replace_subtree with a current subtreeHash. Nested items are supported in replace_subtree and sibling insertions; code, HTML comments, and other Markdown blocks remain permitted within the new item when Markdig assigns them to it. Independent blocks outside the new subtree are rejected. For example, - Updated\n\n<!-- detached --> cannot replace a top-level item when the comment splits its list; - Updated\n\n <!-- nested --> is allowed if Markdig assigns the comment to the item. A quote fragment similarly must form exactly one opaque quote without absorbing its neighbors.
The server re-parses the entire proposed result before writing: existing elements, non-addressable blocks, list-container ownership, parent relationships, and neighboring boundaries must survive. Ambiguous or overlapping edits (including multiple operations in one kb_patch) fail atomically with a structural error; the source file is left unchanged. Unsupported indentation, list splitting/merging, and quote-boundary ambiguity are intentionally rejected instead of being auto-formatted.
Search pointer and read hint still identify the first chunk element, not necessarily the exact list-item match. Chunker v5 requires explicit derived-index rebuild: kb_reindex(force=true) or CLI --reindex --force. No Markdown migration is performed.
Semantic Markdown tables
Standalone GFM pipe tables appear as atomic table elements with section-local tN pointers. Address kb_read with a table's hashed pointer to obtain table.columns (name, index, alignment) and table.rows (data-row indexes beginning at zero and visible cell text). Ordinary document paging does not duplicate the structured projection.
The new kb_edit_table tool takes path, a current pointer of the form tN~selfHash~subtreeHash, and one of seven actions: update_cells, insert_row, delete_row, insert_column, delete_column, rename_column, or set_alignment. Example:
Prefer where when a row value is unique and column when the header is unique; otherwise use numeric rowIndex and columnIndex. Lookups are exact and case-sensitive. update_cells batches multiple updates atomically. Values default to literal text, safely escaping Markdown; valueFormat=markdown permits intentional inline formatting. Newly inserted row values and column defaults are literal text.
Successful responses contain the new table pointer, updated sourceHash and index synchronization status. Reuse the returned pointer to chain edits; on CONFLICT, reread the table. Edits reject tables with extra ignored physical cells, preserve unrelated Markdown, and use the existing atomic workspace writer. Tables inside code, lists or block quotes have no independent table pointers. To remove a table entirely, use kb_patch.
Table parsing changes the derived index format to chunker version 6. Rebuild incompatible indexes via kb_reindex(force=true) or CLI --reindex --force; no Markdown-file migration is needed.
Markdown link graph
After kb_reindex, use kb_links to browse explicit Markdown references in either direction (or perform a depth-limited graph walk) and to diagnose missing linked documents. The graph does not infer semantic relationships and operates without embeddings. See Markdown link graph and MCP examples.
來源:README.md,提交 d6ac68e
工具
0版本歷史
2- v0.1.3最新Oct 12, 2026
- v0.1.2Oct 11, 2026
評分
已滿足適用檢查項的 40%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分
請在儲存庫或註冊中心條目中宣告授權條款。