Skip to main content
Glama

code-indexer

Semantic code index over Ollama + Qdrant, with two entry points over the same core (code_indexer.core): an MCP stdio server (code-indexer-mcp) for agent use, and a one-shot CLI (code-indexer) for shell/scripts. The MCP server 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.

Installation (CLI)

From the repo directory, install both executables as editable uv tools (on PATH in ~/.local/bin, edits to the checkout take effect immediately):

uv tool install -e .

This installs code-indexer (and the optional code-indexer-mcp server executable). Verify with code-indexer list-projects.

Related MCP server: ollqd

CLI

code-indexer add-project /path/to/repo [--name myproject]
code-indexer lookup-project /path/to/repo
code-indexer list-projects
code-indexer semantic-search "auth token refresh" --project /path/to/repo --limit 8 [--json]
code-indexer find-symbol FileTransferSession [--symbol-type class]
code-indexer find-definition main
code-indexer find-references QTimer --relationship calls
code-indexer get-code-context src/session.hpp --start-line 40 --end-line 80
code-indexer index-status /path/to/repo
code-indexer reindex-project /path/to/repo
code-indexer remove-project /path/to/repo
code-indexer watch /path/to/repo [--duration 300] [--background]   # optional inotify watcher
code-indexer watch --all                            # watch all registered projects

Every subcommand accepts --skip-stale-check to skip the staleness probe / incremental index pass on that invocation (startup-cost opt-out; there is no daemon on the default path). CLI subcommands and MCP tools map 1:1 to core operations.

find-symbol, find-definition, find-references, and get-code-context accept both --project X and --name X for the project argument (path, slug, or registered custom name).

watch (optional, opt-in)

code-indexer watch [PATH...] | --all [--duration T] [--background] runs a long-lived event-based watcher: project roots are watched recursively with Linux inotify (the watchdog Observer library, opt-in watch dependency-group — the MCP server and one-shot commands never import it). A file event schedules an incremental pass after a quiet period of WATCH_DEBOUNCE seconds (default 3 — the old poll tick is now the debounce; the env alias WATCH_QUIET_PERIOD is accepted and wins). A burst of events coalesces into at most one pass per quiet period, and an event burst that changes no content costs a hash scan only — zero embedding, zero Qdrant traffic.

  • Self-heal sweep: a full staleness pass for every watched project runs every WATCH_SWEEP_INTERVAL seconds (default 300 s) even with zero events, healing anything inotify missed.

  • Degradation: without watchdog installed, or if inotify watch descriptors are exhausted (OSError scheduling the recursive watches), the watcher falls back to quiet-period polling (one hash scan per project per quiet tick) — correctness is never lost, only latency.

  • Self-write suppression: events under the index root, .git paths, and editor temp files (.swp, ~, .tmp, ...) are filtered; the watcher's own manifest/registry writes never trigger a pass.

  • Moved/deleted dirs: directory delete/move events dirty the project (a wholesale file-set change), so deletions are purged on the next pass.

  • --duration T bounds the watcher's life (exit 0 after T seconds; 0 or omitted = forever; applies to background mode too). SIGINT/SIGTERM exit 0; the kernel flock is released automatically.

  • Multiple projects are served round-robin: repeatable path/slug/name args, or --all for every registered project (registry order). Never combine paths with --all.

  • --background daemonizes (double-fork + setsid), writes the daemon PID to <INDEX_ROOT>/watch.pid guarded by an flock on that file (a second watcher is refused while a live one holds it — the flock, not the pid, is the liveness test), and redirects stdout/stderr to <INDEX_ROOT>/watch.log. --foreground (default) keeps the inherited stdio and normal output and does not take the pidfile. A stopped watcher leaves no live lock or PID residue (the pidfile is unlinked only after the flock is released).

  • Opt-in and never a prerequisite: without a watcher, one-shot commands behave exactly as before (STALE_TTL probe per invocation).

Tools (MCP)

Tool

Description

add_project(path, name)

Register a project directory; creates the Qdrant collection and starts a full initial index in the background. Idempotent: re-adding an already-registered path returns the current index status summary (state, files, chunks, last_indexed) and does NOT spawn a re-index — only nonexistent paths error. Optional name picks the collection name yourself (idx_<name>, sanitized to [A-Za-z0-9_-], 1-64 chars, collision-checked) instead of the auto hash slug.

lookup_project(path)

Check registration without side effects: returns one line with path, slug, custom name, Qdrant collection name (idx_<slug>), state, files, chunks, last_indexed — or not registered: <path>. Normalizes paths (tilde, relative, trailing slash; symlink matched via real path). Use this instead of guessing via add_project idempotency.

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. project accepts a path, a slug, or a registered custom name. Returns file paths, line ranges, symbols, scores, snippets.

index_status(path)

idle | indexing | error + last-pass progress.

reindex_project(path)

Force a full rebuild.

find_symbol(name, project?, symbol_type?)

Look up symbols by name in the manifest symbol index (no semantic search). Exact AST-first, capped substring fallback. symbol_type: function|method|class|struct|enum|namespace.

find_definition(name, project?)

Where a symbol is declared (exact name match only, no substring).

find_references(name, project?, relationship?, limit=25)

Textual references TO a symbol (all confidence=heuristic). relationship: calls|inherits|includes|references.

get_code_context(file, project?, start_line?, end_line?, symbol?, context_lines?)

Retrieve ONLY the relevant source lines — by line range (start_line+end_line) or via a symbol (symbol), padded by context_lines.

MCP project parameters accept a path, slug, or registered custom name (equivalent to the CLI's --project X / --name X). There is no MCP watch tool: a watcher makes no sense inside an MCP server that is already long-lived — watch is CLI-only.

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 processes (multiple agents, CLI + server) are safe — per-project flock lock files (fcntl.flock(LOCK_EX|LOCK_NB); BlockingIOError reports "indexing in progress"; the kernel releases the lock automatically when a process dies, so there is no stale-lock stealing and lock files are permanent), WAL-mode SQLite with busy_timeout, idempotent point IDs. Two processes indexing the same project at once is wasteful, not corrupting: the flock serializes them to exactly one pass.

Upgrading from mcp-code-indexer

Upgrading from the old mcp-code-indexer repo/server: run code-indexer add for each project; existing idx_* collections are reused, no reindex required. The default state directory moved from ~/.mcp-code-indexer to ~/.code-indexer — the new registry starts empty (an undocumented reset, not a migration), so re-registering with the same custom names (--name) that the old projects used reattaches to the already-existing Qdrant collections. Re-run reindex-project once per old project to populate its symbol index (pre-schema-v2 manifests have no symbol rows).

State layout

$INDEX_ROOT/               (default ~/.code-indexer)
├── registry.db            # path -> slug mapping (SQLite, WAL)
├── <slug>.lock            # per-project lock
├── <slug>/manifest.db     # per-project file manifest (SQLite, WAL)
├── watch.pid              # flock-guarded watcher PID file (--background only)
└── watch.log              # watcher daemon stdout/stderr (--background only)

Qdrant holds one collection per project: idx_{slug} where slug is an 8-hex hash of the absolute path — or idx_<name> when the project was registered with a custom name.

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

~/.code-indexer

State directory

STALE_TTL

60

Seconds between staleness re-scans

WATCH_DEBOUNCE

3

watch quiet period (s) between an event burst and its pass

WATCH_QUIET_PERIOD

alias for WATCH_DEBOUNCE (wins when both set)

WATCH_SWEEP_INTERVAL

300

watch periodic full staleness sweep (s)

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": {
    "code-indexer": {
      "command": "uv",
      "args": [
        "--directory", "/path/to/code-indexer",
        "run", "code-indexer"
      ],
      "env": {
        "OLLAMA_URL": "http://192.168.X.X:11434",
        "QDRANT_URL": "http://192.168.X.X:6333"
      }
    }
  }
}

Performance note

Embedding throughput depends on the Ollama host: measured ~1.2 docs/s with GPU passthrough (8B model, 4096-dim, batch 48) vs ~0.17 docs/s CPU-only. The first index of a large repo is the slow part (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 code-indexer-mcp                  # run the stdio MCP server
uv run code-indexer list-projects        # one-shot CLI (no daemon)
uv run pytest                            # unit + concurrency tests
# (old dev/audit scripts under scripts/ were removed with the rename; the
# live e2e coverage now lives in tests/, scripts/live_smoke.py in vector-memory)

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