local-notes-search-mcp
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., "@local-notes-search-mcpsearch my notes for what I decided about the auth redesign"
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.
π local-notes-search-mcp
Semantic search over your own files β as an MCP server.
Ask questions in plain language instead of guessing the exact keyword you typed six months ago.
πΉπ· TΓΌrkΓ§e README β
β¨ What it does
Point it at a folder β project notes, a scattered Claude projeler/ tree, a docs
directory β and search it by meaning, not by exact string match.
βΈ index_directory("C:/Users/you/Desktop/notes")
β
128 files indexed Β· 941 chunks Β· 12 unchanged (skipped)
βΈ search_notes("what did I decide about the auth redesign?")
π― 3 results:
ββ notes/2026-08-decisions.md:12-24 Β· distance 0.31 ββββββββββββββ
## Auth redesign
Decided: session-based instead of JWT, because the refresh-token
rotation story was getting worse than the problem it solved...
ββ notes/meeting-2026-07-30.md:88-101 Β· distance 0.44 ββββββββββββ
...agreed to revisit auth after the billing migration ships.Nothing in that flow touched the network. No OpenAI key, no Pinecone account,
no Docker container, no docker compose up before you can search your own
notes.
Want a synthesized answer instead of a result list? π‘ ask_notes runs the
exact same retrieval, then has an LLM answer grounded only in the retrieved
chunks, with file:line sources attached. It's strictly opt-in β set
GROQ_API_KEY or MISTRAL_API_KEY and it synthesizes; set neither and it
quietly returns the raw matches instead of failing.
Related MCP server: code-rag
π§ The 30-second pitch
grep / ripgrep | Cloud RAG SaaS | local-notes-search-mcp | |
Finds "the auth decision" when you wrote "session vs JWT" | β | β | β |
Works with no API key | β | β | β |
Your files never leave the machine | β | β | β |
No server / daemon / container to run | β | β | β |
Answers with exact | β | β οΈ | β |
Costs money per query | β free | β | β free |
Usable directly by Claude / any MCP client | β | β οΈ | β |
Optional grounded LLM answer with sources | β | β | β opt-in |
ποΈ How it works
flowchart LR
subgraph INDEX["π₯ Index pipeline β runs when you ask it to"]
direction LR
A["π Local folder"] --> B["πΆ Walk + filter<br/>skip .git, node_modules,<br/>.venv, files > 2MB"]
B --> H{"π Content hash<br/>changed?"}
H -- "no" --> SKIP["βοΈ Skip<br/>zero CPU"]
H -- "yes" --> C["βοΈ Line-based chunker<br/>1500 chars + 200 overlap<br/>never splits a line"]
C --> D["π§ fastembed ONNX<br/>paraphrase-multilingual-MiniLM-L12-v2 Β· 384-d"]
end
D --> DB[("ποΈ sqlite-vec<br/>vec0 virtual table<br/>~/.local-notes-search/index.db")]
subgraph QUERY["π Query path β 100% offline"]
direction LR
Q["π¬ Natural-language<br/>question"] --> QE["π§ Embed query<br/>same model"]
end
QE --> DB
DB --> R["π― Top-k chunks<br/>file:line + snippet<br/>+ distance score"]
R -. "opt-in: ask_notes<br/>needs an API key" .-> LLM["π€ LLM synthesis<br/>Groq β Mistral fallback<br/>grounded in retrieved chunks only"]
LLM --> ANS["π‘ Answer + file:line sources"]
style LLM fill:#1c1730,stroke:#a371f7,color:#ffffff
style ANS fill:#1c1730,stroke:#a371f7,color:#ffffff
style DB fill:#003b57,stroke:#00b4d8,color:#ffffff
style R fill:#1a7f37,stroke:#3fb950,color:#ffffff
style SKIP fill:#4d3800,stroke:#d4a72c,color:#ffffffπ§° MCP tools
π οΈ Tool | What it does |
ποΈ | Recursively indexes a directory. Skips |
π | Natural-language semantic search. Returns |
π‘ | Optional. Same retrieval as |
π | What's in the index right now: path, chunk count, last-indexed timestamp. Useful before searching, or to debug a stale result. |
π§Ή | Drops everything under |
π
index_directory,search_notes,list_indexed_filesandremove_directoryrequire no API key and make no network calls at all.ask_notesis the one tool that can talk to a remote provider, and only when you explicitly give it a key.
π Quickstart
git clone https://github.com/Furkiozknn/local-notes-search-mcp.git
cd local-notes-search-mcp
uv syncRegister local_notes_search.py as a stdio MCP server:
{
"mcpServers": {
"local-notes-search": {
"command": "uv",
"args": [
"--directory", "/absolute/path/to/local-notes-search-mcp",
"run", "local_notes_search.py"
]
}
}
}On the first index_directory / search_notes call, the fastembed model
(~130 MB) is downloaded once and cached locally. Every call after that is fully
offline.
Env var | Default | What it does |
|
| Where the index lives. One single file for every indexed directory β so a single |
| unset | Optional allowlist. When set, |
| unset | Optional. Enables |
| unset | Optional. Fallback provider for |
Keys are read from the environment only β never commit them, and never put them in the MCP client config file you check into git.
Default indexed extensions: .md .txt .py .js .ts .tsx .jsx .json
.yaml .yml .rst .toml β override per call with extensions=[...].
π What can be indexed
index_directory reads whatever it is pointed at, and ask_notes sends the
chunks it retrieves to a third-party LLM (Groq or Mistral) when a key is
configured. So an indexed path is a path whose contents can leave the machine.
Two guards exist:
1. LOCAL_NOTES_SEARCH_ALLOWED_ROOTS (opt-in). Unset by default β that is
the historical behaviour, any directory the running user can read is
indexable, and this project does not pretend an empty default is a sandbox.
Set it and index_directory refuses anything outside:
export LOCAL_NOTES_SEARCH_ALLOWED_ROOTS="$HOME/notes:$HOME/projects"Paths are resolved (.. collapsed, symlinks followed) before the check, and a
subdirectory of an allowed root is allowed. A configured entry that is not a
directory is an error rather than being silently dropped β a typo must not
quietly switch the allowlist off.
2. A credential-filename denylist (always on). These are never indexed,
whatever the allowlist or the extensions=[...] argument says:
.env Β· .env.* Β· .netrc Β· _netrc Β· id_rsa Β· id_dsa Β· id_ecdsa Β·
id_ed25519 Β· credentials.json Β· *.pem
Matching is case-insensitive. It is a name denylist, not a secret scanner:
it stops the obvious cases (credentials.json would otherwise sail through the
default .json extension filter), not a key pasted into a .md file.
π§ Why this architecture
Decision | Why |
ποΈ | A |
β‘ | Local embedding here is the only path β it runs on every index and every search. |
𧬠| Small (0.22 GB), Apache-2.0, and β decisive for this tool β actually multilingual: the previous |
βοΈ Line-based chunking, no NLP/AST dependency | Chunks accumulate whole lines until a character budget is hit β a line is never split in half, so every |
π Whole-file content-hash skip on re-index |
|
π§ͺ Tests
uv run pytest -v50 tests, on a deliberate two-tier strategy. Pure-logic tests (chunking,
hashing, file walking, ask_notes' provider-chain and degradation paths)
always run β no model, no network, no API key. Tests that need the real
fastembed model or the sqlite-vec extension skip honestly when those can't
be loaded β an offline runner, a blocked model download β rather than faking a
green result.
What that means in practice, reported exactly as measured:
Environment | Result |
β Development environment (fastembed model downloadable) | 64 tests, including the real end-to-end flow β the fastembed model really loaded, the sqlite-vec extension really ran, and a "how do I bake a cake" query really retrieved the relevant file while excluding the irrelevant one. |
β οΈ A sandbox with the model download blocked | 50 passed, 14 skipped β measured 15 September 2026. Every model-free test green, and the model-backed ones skipped with an explicit reason instead of a false pass. |
The second row is the honest cost of the first: this suite tells you when it couldn't verify something.
β οΈ Known limitations
Written down on purpose, because a README that claims no weaknesses is a README you shouldn't trust.
No query-instruction prefix is needed anymore. The previous English-only
bge-small-en-v1.5recommended embedding queries with an instruction prefix, which this tool skipped as a v1 simplification. The current default,paraphrase-multilingual-MiniLM-L12-v2, is a symmetric model: queries and passages are meant to embed identically, so the simplification is now simply the correct usage. If you overrideLOCAL_NOTES_SEARCH_MODELwith an asymmetric model (BGE/E5 family), know that its prefix convention is still not applied.CI re-downloads the fastembed model on every run (no
actions/cacheconfigured). Acceptable for a small project; easy to speed up later. Low priority, and honestly labelled as not done.Single-writer SQLite. Concurrent
index_directory/search_notescalls from separate processes can collide on writes. The tool is designed around a single MCP client session.
π License
MIT β and every runtime dependency was license-checked:
sqlite-vec (Apache-2.0), fastembed (Apache-2.0), mcp (MIT),
litellm (MIT). No non-commercial or field-restricted weights anywhere in
the stack.
Built as part of an ecosystem of small, focused, self-hostable AI tools.
Available Tools
5 toolsask_notesA
Ask a question in natural language about your indexed files. Retrieves the most relevant chunks (same retrieval as search_notes) and asks an LLM (Groq, then Mistral fallback - needs GROQ_API_KEY or MISTRAL_API_KEY) to synthesize an answer grounded ONLY in those chunks, with file:line sources. Without either key configured, degrades to returning the raw retrieved chunks with a note that no LLM is available - never fails outright just because synthesis isn't possible.
| Name | Required | Description | Default |
|---|---|---|---|
| top_k | No | ||
| question | Yes | ||
| path_prefix | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full behavioral burden. It discloses LLM provider fallback chain (Groq then Mistral), API key requirements, graceful degradation without keys, grounding in retrieved chunks with file:line sources, and guarantees no outright failure. This is exceptionally transparent.
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?
Though lengthy, the description is information-dense and front-loaded with the core purpose. The second sentence packs several critical behavioral details efficiently. Slightly more compact writing might be possible, but the content justifies the length.
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 complexity (LLM synthesis, API keys, fallback, grounding), the description covers the essential behavior well. An output schema exists, so not explaining return values is acceptable. Minor gaps like parameter details are addressed under parameter semantics, so overall completeness is high but not perfect.
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 0%, so the description must explain the parameters. It implicitly covers 'question' via the purpose, but says nothing about 'top_k' or 'path_prefix'. The retrieval similarity to search_notes does not substitute for explaining these parameters.
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 states a specific verb ('Ask a question') and resource ('indexed files'), and explicitly contrasts with search_notes by adding LLM synthesis. It is clear what the tool does and how it differs from its closest sibling.
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?
It notes the same retrieval as search_notes and explains the synthesized vs. raw output difference, implying when to choose this over search_notes. However, it does not explicitly state 'use this when you need a synthesized answer' or provide exclusion criteria, so it stops 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.
index_directoryA
Index (or re-index) a local directory for semantic search. Walks
recursively, skips .git/node_modules/.venv/etc and files >2MB, and
skips any file whose content is unchanged since the last index (cheap:
a whole-file hash check before touching the embedding model). Files
that were indexed before but no longer exist under path are removed
from the index.
Credential-shaped file names (.env, id_rsa, credentials.json, .netrc,
*.pem, ...) are never indexed. If LOCAL_NOTES_SEARCH_ALLOWED_ROOTS is
set, `path` must resolve inside one of its entries; unset (the default)
means any readable directory is indexable.| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| extensions | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations to lean on, the description fully covers side effects and behaviors: recursive walking, skipped directories and size limits, unchanged-file hashing, stale-entry removal, credential-shaped file exclusions, and the LOCAL_NOTES_SEARCH_ALLOWED_ROOTS constraint. This is exemplary disclosure for a tool with no annotations.
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 dense but every sentence earns its place. It is front-loaded with the core purpose, followed by skip rules, side effects, security exclusions, and configuration constraints. There is no fluff or redundant restating of the tool name.
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 is unusually complete for a complex tool: it covers scope, side effects, security, and environment constraints, and an output schema exists to document return values. The only notable gap is the undocumented `extensions` parameter, which prevents a perfect score.
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 0%, so the description must compensate. It adds useful meaning for `path` (must resolve inside allowed roots, must be readable), but it never mentions the `extensions` parameter at all, leaving its purpose and possible values entirely undocumented.
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 opens with a specific verb and resource: 'Index (or re-index) a local directory for semantic search.' It then adds behavioral specifics that distinguish this tool from sibling tools like search_notes and list_indexed_files, making the tool's role unmistakable.
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 makes the tool's use case clear: build or refresh a semantic-search index for a local directory. It does not explicitly name alternatives or say 'use search_notes instead for queries,' but the context is unambiguous and no exclusion conditions are omitted.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_indexed_filesA
Lists what's currently in the index - file path, chunk count, last indexed time. Useful to check what's covered before searching, or to debug a stale/missing result.
| Name | Required | Description | Default |
|---|---|---|---|
| path_prefix | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description must carry the behavior. It conveys a read-only metadata snapshot ('currently'), states the returned fields, and frames staleness as an expected condition. It does not explicitly state that it never triggers indexing or how recently the index was refreshed, so it is not fully exhaustive.
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 short sentences: the first front-loads the operation and result fields, the second adds pragmatic use cases. 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?
For a read-only listing with one optional parameter and an output schema, the description nearly suffices; the only real gap is the unmentioned path_prefix filtering, but the optional nature and param name mitigate the risk.
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 0%, and the description never mentions path_prefix or how filtering works. An agent must infer the parameter's meaning from its title alone, so the description fails to compensate for the missing schema documentation.
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 ('Lists') and resource ('what's currently in the index'), and enumerates the returned fields (file path, chunk count, last indexed time). This is enough to separate it from siblings like index_directory or search_notes.
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?
Gives concrete use cases: checking coverage before searching and debugging stale/missing results. It does not name sibling tools or explicitly list exclusions, but the guidance clearly implies reading index state rather than changing it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_directoryA
Removes every indexed file/chunk under path from the index. The
index is persistent local state in ~/.local-notes-search/ (or
LOCAL_NOTES_SEARCH_DB) - this is how you clean it up without deleting
the whole database file.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It explicitly describes the destructive scope ('every indexed file/chunk under path'), the persistent local state affected, and that the database file itself is not removed. It could mention irreversibility or permissions, but the core behavior is transparent.
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 compact sentences front-load the action and scope, then add the relevant storage and cleanup context. There is no filler, and every sentence contributes useful information.
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 one-parameter destructive index tool, the description covers what is removed, where the state lives, and why you would use it. The output schema handles return details, so the only mild gaps are explicit caveats about reversibility and path format, which are not critical.
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?
At 0% schema coverage, the description must compensate for the bare 'path' property; it does so by explaining that path defines the subtree whose indexed entries are removed. It does not specify whether path must be absolute or can point to a single file, but the parameter's role is clear.
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 a specific verb ('Removes') and names the exact resource ('every indexed file/chunk under path from the index'). This clearly separates it from sibling tools like index_directory or search_notes. It also identifies the storage location, reinforcing that it is an index-cleanup 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?
The description states this is how you clean up the persistent local index without deleting the whole database file, giving a clear when-to-use context. It does not explicitly name alternative sibling tools, but the cleanup intent is evident and not misleading.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_notesA
Semantic search across everything indexed so far. Returns the top matching chunks with file path, line range, and a relevance-ordered snippet - not just a bag of file names.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| top_k | No | ||
| path_prefix | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations to lean on, so the description carries the transparency burden. It discloses important behavior: results are relevance-ordered, returned as chunks with file path and line range, and not merely a list of file names. It does not mention side effects, but 'search' strongly implies read-only, and no contradiction exists.
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 tight sentences, with the verb and scope front-loaded and the return behavior stated in a single clause. The extra 'not just a bag of file names' earns its place by highlighting the key differentiator.
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 core purpose and return shape are present, and an output schema exists for detailed return fields, so this is viable. However, there is no guidance on path_prefix semantics or when to prefer ask_notes, and with 0% schema descriptions the agent must infer too much for a tool with three parameters.
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 0%, and the description does not compensate by explaining query, top_k, or path_prefix. 'Top matching chunks' implies the role of top_k and query, but path_prefix is undocumented, and the phrase 'across everything indexed so far' obscures the fact that path_prefix can scope the search.
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?
States a specific verb ('semantic search') over a defined corpus ('everything indexed so far') and goes on to describe the return granularity (matching chunks with file path, line range, and snippet). This distinguishes it clearly from the sibling tools index_directory, list_indexed_files, ask_notes, and remove_directory.
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 use when the agent needs semantic retrieval of relevant chunks, rather than file listing or Q&A, but it never explicitly says when to choose this over ask_notes or how path_prefix narrows the search. Usage context is clear, but exclusions and alternative routing are left to inference.
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.
5 tool updates
v0.1.0- First observed
ask_notes - First observed
index_directory - First observed
list_indexed_files - First observed
remove_directory - First observed
search_notes
TDQS
Scored across 5 tools
Each tool has a clearly distinct role: index_directory ingests data, search_notes and ask_notes are differentiated as raw retrieval vs. LLM-synthesized answers, list_indexed_files provides observability, and remove_directory cleans up. Even the two retrieval-based tools are easy to tell apart because their outputs and purposes are explicit.
All tool names follow a consistent snake_case verb_noun pattern: index_directory, search_notes, list_indexed_files, ask_notes, remove_directory. There are no mixed conventions or vague generic verbs.
Five tools is a well-scoped surface for a local notes search server: ingest, search, ask, list, and remove each earn their place. The count is neither bloated nor too thin.
The index lifecycle is fully covered: create/update via index_directory, read via search_notes and ask_notes, inspection via list_indexed_files, and deletion via remove_directory. Re-indexing handles changed and removed files, so there are no obvious dead ends or missing operations.
Maintenance
Related MCP Connectors
Search your AI chat history (ChatGPT, Claude, Codex) from any MCP client. Remote, private, read-only
Serve a folder of Markdown notes as an MCP server: hybrid search, reading, and sourced answers.
Personal knowledge base MCP server with semantic search, auto-categorization, metadata extraction
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceLocal MCP server that provides semantic search (RAG) over code repositories, enabling AI clients like Claude and Gemini to access project context without manual re-upload.-
- FlicenseNot gradedqualityCmaintenanceA semantic code search MCP server that enables natural language queries against your codebase, supporting features like related file discovery and context expansion, all running locally.2-
- AlicenseAqualityAmaintenanceLocal MCP server for semantic code search using Tree-sitter AST parsing, local embeddings, and hybrid search; enables indexing and querying codebases entirely offline.5MIT
- AlicenseAqualityDmaintenanceLocal-first MCP server for semantic + keyword hybrid code search. Zero external services, no API keys required.2MIT