Skip to main content
Glama

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

add_project(path)

Register a project directory; creates the Qdrant collection and starts a full initial index in the background.

remove_project(path)

Deregister and delete the Qdrant collection, SQLite manifest, and registry entry.

list_projects()

Registered projects with file/chunk counts, last-indexed time, and state.

semantic_search(query, project?, limit=8, file_filter?)

The hot path. Always runs a staleness check first; project=None searches all registered projects. Returns file paths, line ranges, symbols, scores, snippets.

index_status(path)

idle | indexing | error + last-pass progress.

reindex_project(path)

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. Use index_status to wait for completion.

  • Staleness check (on every semantic_search / index_status): if the project hasn't been scanned within STALE_TTL seconds (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 / deleted by 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 .gitignore and .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_EXCL lock 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_URL

http://192.168.X.X:11434

Ollama base URL

QDRANT_URL

http://192.168.X.X:6333

Qdrant base URL

EMBED_MODEL

qwen3-embedding:8b

Embedding model

INDEX_ROOT

~/.mcp-code-indexer

State directory

STALE_TTL

60

Seconds between staleness re-scans

EMBED_BATCH

48

Texts per Ollama embed request

UPSERT_BATCH

256

Points per Qdrant upsert

MAX_FILE_BYTES

1048576

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.py

Python 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 tools
add_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.
ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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).

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters2/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observedadd_project
    • First observedindex_status
    • First observedlist_projects
    • First observedreindex_project
    • First observedremove_project
    • First observedsemantic_search

TDQS

A4.1/5.0

Scored across 6 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness5/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers