mcp-code-indexer
Uses a LAN-local Ollama instance for generating code embeddings (default qwen3-embedding:8b, 4096-dim), enabling semantic indexing and search of local project directories.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-code-indexersearch my ~/code/api project for where auth tokens get validated"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-code-indexer
An MCP stdio server that keeps an automatic semantic index of one or more
local project directories in Qdrant, using Ollama (qwen3-embedding:8b,
4096-dim) for embeddings. Fully LAN-local; no cloud.
Agents never index anything themselves. They only call semantic_search
(which transparently runs a staleness check + incremental indexing first) plus
a few admin tools. Chunks, hashes, and collections are never exposed.
Tools
Tool | Description |
| Register a project directory; creates the Qdrant collection and starts a full initial index in the background. |
| Deregister and delete the Qdrant collection, SQLite manifest, and registry entry. |
| Registered projects with file/chunk counts, last-indexed time, and state. |
| The hot path. Always runs a staleness check first; |
|
|
| Force a full rebuild. |
Related MCP server: ollqd
How indexing / staleness works
First index (
add_project) runs on a background thread; the tool returns immediately. Useindex_statusto wait for completion.Staleness check (on every
semantic_search/index_status): if the project hasn't been scanned withinSTALE_TTLseconds (default 60), the server re-scans file hashes and incrementally re-indexes only what changed. Answers are never served from a stale index by more than one scan interval.Incremental diff: files are classified
unchanged/changed/added/deletedby content hash (sha256 — not mtime, which lies after branch switches). Only chunks whose own hash changed get re-embedded; point IDs are deterministic (uuid5(project|file|chunk_index)), so upserts are idempotent. Deleted files are purged from Qdrant by payload filter and dropped from the SQLite manifest.Chunking: tree-sitter AST units (function/class-level, with symbol names) via
tree-sitter-language-pack, falling back to a ~80-line regex window chunker with 10-line overlap when a language is unsupported or the parse fails. Chunks are capped at ~1000 chars.Filtering: honors
.gitignoreand.codeindexignore(nested, per- directory), skips.git/node_modules/venv/__pycache__/dist/build/target, files > 1 MB, and binary/non-UTF-8 files.Concurrency: multiple MCP client processes (multiple agents) are safe — per-project
O_EXCLlock files (stale locks stolen after 30 min), WAL-mode SQLite, idempotent point IDs. Two servers indexing the same project at once is wasteful, not corrupting.
State layout
$INDEX_ROOT/ (default ~/.mcp-code-indexer)
├── registry.db # path -> slug mapping (SQLite, WAL)
├── <slug>.lock # per-project lock
└── <slug>/manifest.db # per-project file manifest (SQLite, WAL)Qdrant holds one collection per project: idx_{slug} where slug is an 8-hex
hash of the absolute path.
Configuration
Resolution order: CLI flags > environment variables > defaults.
Env var | Default | Description |
|
| Ollama base URL |
|
| Qdrant base URL |
|
| Embedding model |
|
| State directory |
|
| Seconds between staleness re-scans |
|
| Texts per Ollama embed request |
|
| Points per Qdrant upsert |
|
| Skip files larger than this |
CLI flags: --ollama-url, --qdrant-url, --embed-model, --index-root.
MCP client config (Claude Desktop / Hermes / any stdio MCP client)
{
"mcpServers": {
"mcp-code-indexer": {
"command": "uv",
"args": [
"--directory", "/path/to/mcp-code-indexer",
"run", "mcp-code-indexer"
],
"env": {
"OLLAMA_URL": "http://192.168.X.X:11434",
"QDRANT_URL": "http://192.168.X.X:6333"
}
}
}
}Performance note
Measured on a CPU-only Ollama host (8B model, 4096-dim): ~0.17 docs/s embedding (~6 s/chunk). The first index of a large repo is slow (the design targets hours on CPU for thousands of chunks); incremental updates only re-embed changed chunks, so a typical edit session re-indexes in seconds-to-minutes. Qdrant upsert throughput is ~550 pts/s. Embeddings are batched (one HTTP round trip per 48 inputs) with keep_alive to avoid model unload between batches.
Development
uv sync # install deps (.venv)
uv run mcp-code-indexer # run the stdio server
uv run pytest # unit tests
uv run python scripts/benchmark.py # M0 embed-throughput benchmark
uv run python scripts/stdio_probe.py # stdio handshake + tools/list probe
uv run python scripts/e2e.py # end-to-end test (real repo, real backends)
uv run python scripts/concurrency_smoke.pyPython 3.11. Constraints: pins numpy<2 (1.26.4), qdrant-client<1.15,
mcp<2, tree-sitter==0.26.0, tree-sitter-language-pack==1.18.0
(older x86-64 CPUs without x86-64-v2; all pure/prebuilt wheels).
Available Tools
6 toolsadd_projectA
Register an absolute project directory for semantic indexing.
Creates the Qdrant collection and starts a full initial index in the
background (check progress with index_status). Errors if the path does
not exist or is already registered.
| 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?
No annotations are provided, so the description carries the full burden and does meaningfully discharge it: it discloses side effects (creates a Qdrant collection, kicks off a background initial index) and two failure conditions. It stops short of describing idempotency, permissions, or what happens if indexing fails partway.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with the core action front-loaded, followed by side effects and then error conditions. No filler or restatement 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?
An output schema exists, so return values need no explanation, and the description covers the mutation's side effects and error cases. For a no-annotation write tool it is nearly complete, missing only permissions/auth requirements.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter has 0% schema description coverage, so the description must compensate. It adds real meaning by specifying the path must be an absolute project directory and must already exist, though it gives no format examples or edge-case handling.
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?
Specific verb ('Register') plus resource ('absolute project directory') plus domain ('semantic indexing'). It clearly distinguishes itself from siblings like remove_project, list_projects, and reindex_project.
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?
Names a sibling for follow-up ('check progress with index_status') and states two preconditions that cause errors (path missing, already registered). It does not explicitly contrast with reindex_project, which the 'already registered' clause implies but never names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
index_statusA
Check indexing state for a project: idle | indexing | stale | error, plus last-pass progress. Also triggers the staleness check.
| 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?
No annotations, so the description carries full burden. It discloses the interesting side effect – the tool also triggers the staleness check – which is behavior beyond a pure read. However it doesn't say whether this mutates state, whether it's safe to call repeatedly, or cost/latency implications of triggering a check.
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 terse sentences, front-loaded with the outcome space; every clause earns its place and the enum-like state list is immediately scannable.
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?
Output schema exists so return value needn't be explained, and the description covers states plus the side effect. But the undocumented 'path' param and unstated mutation/reversibility of the staleness trigger leave the agent with unanswered questions for a tool that does more than read.
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% with one required param ('path') left undocumented. The description implies a project scope but never says the param identifies the project by path, and gives no format guidance. Baseline 3 given the single-param simplicity, but a gap remains.
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?
Specific verb (Check) and resource (indexing state for a project), and enumerates the four possible states. It is distinguishable from siblings like reindex_project (which mutates) and list_projects, though it doesn't explicitly name alternatives.
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?
Usage is implied: check status before/after indexing or when results seem stale. No explicit when-to-use, when-not-to-use, or alternative routing is given, so the agent must infer context from the sibling set.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_projectsA
List registered projects with per-project index summary and staleness.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It does disclose that results carry an index summary and staleness flag, which tells the agent something about the shape and freshness semantics of the output. It does not state that the operation is read-only/non-mutating, nor anything about pagination or scoping, so it is only partially 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?
One sentence, no filler, with the resource and the returned information front-loaded. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and with zero parameters the schema side is fully covered. For a simple list tool the description is nearly complete, missing only explicit routing versus its sibling listing/inspection tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to clarify; the schema is trivially complete. Baseline 4 applies since no parameter explanation is possible or needed.
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 ('List') and resource ('registered projects') and goes further by naming the payload contents (per-project index summary and staleness). That distinguishes it from index_status and reindex_project, though it never names those siblings explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No indication of when to prefer this over index_status or semantic_search, and no prerequisites or ordering advice. The tool's read-only nature is only implied by the verb 'List'; the agent must infer all usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reindex_projectA
Force a full rebuild of a project's index (chunker/model change, suspected corruption).
| 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?
No annotations are provided, so the description carries the disclosure burden. It does indicate this is a 'force full' destructive-ish rebuild scoped to a project, which is meaningful, but it omits whether the operation is blocking, whether it can run while the project is in use, or reset semantics.
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?
One tight sentence with no waste; the operation is front-loaded and reasons are compactly delivered in a parenthetical.
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?
Output schema exists, so return values needn't be explained. However, with no annotations, a destructive full rebuild, and ambiguous 'path', the description should say more about safety and what 'path' means to be complete.
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?
Only one parameter (path) with 0% schema description coverage. The description does not clarify what 'path' refers to (project root, project id, config path). With a single parameter the baseline is 4 per rules, but the ambiguous 'path' semantics and absent description warrant a modest downgrade to 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (force full rebuild) and resource (project's index), and parenthetically gives the precise conditions that motivate it. Clearly distinguishable from siblings like add_project or semantic_search.
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 parenthetical lists trigger conditions (chunker/model change, suspected corruption), which is explicit when-to-use guidance. It lacks any when-not-to-use or named alternative, so it falls 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.
remove_projectA
Deregister a project and DELETE its Qdrant collection + manifest + registry entry entirely.
| 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 behavioral burden and does well by naming exactly what is destroyed (collection, manifest, registry entry) and signaling irreversibility via 'DELETE ... entirely'. It omits permission/auth requirements and behavior when the project does not exist or is already removed.
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?
One tightly written sentence with the destructive action and its full blast radius front-loaded. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be described, and the destruction scope is covered. However, for an unannotated destructive tool the description should also address the undocumented path parameter and failure/idempotency behavior, which it does not.
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 never mentions the single required 'path' parameter, so it adds no meaning about what path refers to or how it is resolved. The bare parameter name is the only clue available.
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 ('deregister') and resource (project) with an explicit scope that enumerates exactly what is torn down: Qdrant collection, manifest, and registry entry. This cleanly distinguishes it from siblings like add_project, list_projects, and reindex_project.
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 destructive language implies a caution context for use, but there is no explicit statement of when to choose this over reindex_project or list_projects, nor any prerequisite or confirmation guidance. Usage is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
semantic_searchA
Semantic code search across indexed projects. THE hot path.
Automatically runs a staleness check first and incrementally re-indexes
changed files, so results are always fresh (within one scan interval).
Args: query (natural language); project (optional path — omit to search
all registered projects); limit; file_filter (optional substring/glob
on file path, e.g. '*.py').
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| project | No | ||
| file_filter | 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 the full burden and it discloses a significant hidden behavior: an automatic staleness check plus incremental re-indexing of changed files (a write side effect) with a stated freshness bound of one scan interval. It omits cost/latency, permission requirements, and failure behavior, which keeps it below a 5.
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?
Front-loaded with purpose and priority, followed by behavior and a compact Args block; almost every sentence earns its place. The Args list is terse rather than well-structured, and 'THE hot path' is stylistic, but nothing is wasted.
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?
An output schema exists, so return values need not be described. Given four parameters at 0% schema coverage, the description adequately documents param meaning and the key side-effect behavior, leaving only minor gaps (limit semantics, performance/error characteristics).
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, and it explains three of four parameters: query (natural language), project (optional path, omit to search all), and file_filter (substring/glob with a '*.py' example). Only 'limit' is named without explanation, though its meaning is self-evident from the name and default.
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 and resource ('Semantic code search across indexed projects'), which is unambiguous and clearly distinguishable from the sibling management tools (add/remove/list/index_status/reindex_project). An agent can identify this as the retrieval tool without opening the schema.
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?
Signals primacy with 'THE hot path' and explains that it auto-reindexes, which implicitly tells the agent not to call reindex_project first. It also notes that omitting 'project' searches all registered projects, giving conditional usage guidance, though it never explicitly names alternatives or when-not-to-use conditions.
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.
6 tool updates
v0.1.0- First observed
add_project - First observed
index_status - First observed
list_projects - First observed
reindex_project - First observed
remove_project - First observed
semantic_search
TDQS
Scored across 6 tools
Each tool has a clearly distinct purpose: add_project registers, remove_project deregisters, list_projects lists, semantic_search searches, index_status checks status, and reindex_project forces rebuild. No overlapping or ambiguous functions.
All tool names follow a consistent verb_noun pattern (add_project, remove_project, list_projects, semantic_search, index_status, reindex_project) with snake_case throughout.
Six tools perfectly cover the lifecycle of project management and indexing for a code indexer: add, remove, list, search, status, and reindex. No tool is extraneous or missing.
The tool set provides complete CRUD for projects (add, remove, list) plus essential operations for indexing and searching (semantic_search, index_status, reindex_project). This covers all core workflows for a code indexer.
Maintenance
Related MCP Connectors
Project memory, semantic code search, and grounded agent context.
Shared memory for coding agents. Stop re-explaining your codebase every session.
Give your AI agent a persistent map of your project's structure, dependencies, and bugs.
Code intelligence for coding agents: semantic, AST, graph, and full-text search. 279+ languages.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables semantic search across your codebase using Google's Gemini embeddings and Qdrant Cloud vector storage. Supports 15+ programming languages with smart code chunking and real-time file change monitoring.1720MIT
- AlicenseAqualityCmaintenanceEnables indexing and semantic search of codebases and documents via MCP, using Ollama embeddings and Qdrant vector store.5Apache 2.0
- AlicenseNot gradedqualityFmaintenanceIndexes codebases into Qdrant for semantic search, enabling AI assistants to find relevant code by meaning without re-exploring the repo.MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI coding agents to perform semantic code search locally, finding code by meaning rather than exact keywords.3MIT