index_project
Registers projects and rebuilds the graph once, after explicit user approval. Pass every project in one call: a rebuild costs the whole corpus. It never writes inside the source projects.
Arguments
Section titled “Arguments”| Argument | Type | Default | Meaning |
|---|---|---|---|
projects | array of objects | none | The batch to register and index. Each entry requires name, path and languages, and accepts nothing else. This is the form to use. |
name | string | none | Single-project form: the repository identifier. |
path | string | none | Single-project form: the repository directory. Absolute, ~-prefixed, or relative to the working directory of the server process. |
languages | array of strings | none | Single-project form: the languages to index. |
confirmed | boolean or null | null | Approval from a client that cannot use MCP elicitation. Only true proceeds. |
Naming both forms in one request is rejected with INVALID_ARGUMENT, because two
selectors can disagree and there is nothing to decide between them. Naming
neither is rejected the same way.
The accepted languages values are the supported language vocabulary, and
nothing else:
go, typescript, javascript, ts, js, rust, rsValues are lowercased and trimmed. A duplicate in one entry, an empty string, or a word outside the list is rejected before anything is written.
Answers
Section titled “Answers”Nothing, in the sense the other ten tools do. It registers the projects it is given in the repository registry, rebuilds the complete canonical graph once, and publishes the result as a new generation. On success it reports the generation and snapshot it published together with the per-language counters of the pass. It is the only mutating tool on the surface.
Consent
Section titled “Consent”It refuses without explicit approval. A client that declares the MCP elicitation
capability is asked directly, and the request proceeds only when the user
accepts. A client that does not implement elicitation must obtain approval itself
and then send confirmed: true; sending it without having asked is a lie the
server cannot detect.
Called without either, it fails:
PERMISSION_REQUIRED: user approval is required; confirm the operation before setting confirmed=trueAn elicitation the user declines fails with PERMISSION_DENIED. An elicitation
the client cannot deliver fails with PERMISSION_REQUIRED.
The prompt names what approval covers: the project and its path for a single project, or the count and every name for a batch. Approving “11 projects” without seeing which ones is not approval.
Example
Section titled “Example”{ "name": "index_project", "arguments": { "name": "kivgraph", "path": "/Users/adria/Documents/programacion/projects/kivgraph", "languages": ["go"] }}PERMISSION_REQUIRED: user approval is required; confirm the operation before setting confirmed=trueCorpus: snapshot 30 of two repositories, kivgraph and mole. The captured
call sent no confirmed and the client declared no elicitation capability, so
the refusal is the whole response.
The batch form, which is the one to send:
{ "name": "index_project", "arguments": { "projects": [ { "name": "kivgraph", "path": "/Users/adria/Documents/programacion/projects/kivgraph", "languages": ["go", "typescript"] }, { "name": "mole", "path": "/Users/adria/Documents/programacion/projects/mole", "languages": ["go", "typescript"] } ], "confirmed": true }}Pass every project in one call
Section titled “Pass every project in one call”This is not a style preference. A rebuild resolves cross-repository edges over the complete fact set, so there is no cheaper unit than the whole corpus: adding one project costs exactly what adding eleven costs. Calling the tool once per project pays that full cost once per project and throws away every result but the last, because only the newest generation is published.
Eleven projects registered one call at a time cost eleven rebuilds for one useful graph. Registered together they cost one.
The whole batch is registered before anything is built. If the index or the rebuild then fails, the prior registry is restored and the previous generation stays published.
When it is available
Section titled “When it is available”The tool exists only on a configured serve route. Without a configured indexer
it is not registered at all, so the read-only server cannot gain filesystem or
storage access by accident.
It is also the only tool registered when no generation has been published yet.
That is how a client with no graph builds its first one: the server completes the
handshake, publishes index_project alone, and the other ten appear once a
generation exists. See Troubleshooting.
Registering the same project twice
Section titled “Registering the same project twice”Indexing a project that is already registered is not a conflict. The caller asked for that repository to be in the graph, and it is.
- A project already registered with the same directory is reindexed without touching the registry. An identical request changes nothing on disk at all.
- A change of
languagesfor the same directory replaces the entry, and theexclusionson file survive it. The request cannot express exclusions, and dropping them would silently widen the index to directories that were excluded on purpose. - Only a name already held by a different directory is a real conflict,
because then nothing can decide which of the two repositories the name means.
The error names the registered path:
project "mole" is already registered at "/repos/mole": choose another name or remove that entry.
Names are compared exactly, and a name is an identifier: ., .. and anything
containing a path separator are rejected. The rust: namespace is reserved for
the providers Kivgraph derives from the toolchain and cannot be taken.
Progress
Section titled “Progress”A full rebuild takes minutes on a large registry, while an MCP client applies its own timeout to the call, thirty seconds in some, and cancels work that is progressing fine.
A request that carries a progressToken gets notifications/progress for every
unit of work: the phase, the repository and a detail. A client that honours them
waits for as long as the work reports. Without a token no progress callback is
installed at all, so the index does not pay for a channel nobody reads.
Progress counts up and never repeats a value, as the protocol requires. A notification that cannot be delivered is dropped rather than failing the index.
The pass itself runs as a child process — index --full --json — and the server
forwards the progress it reports. That is what keeps the peak of an index out of
the process answering queries; see Indexing.
Limits
Section titled “Limits”- It never writes inside the source projects. It writes the repository registry and the Kivgraph state directory; the checkouts it reads are left untouched.
- One index runs at a time inside a process. An
index_projectand a resynchronisation cannot overlap, and across processes a lock elects the single writer: the loser does not wait, because a rebuild lasting minutes would look like a hang. - A failure is reported as
INDEXING_FAILEDwith the observed cause in the message: a module that needs a newer toolchain, a path that is not a repository, a dependency the module cache does not hold. pathmust exist and be a directory. A relative path is resolved against the working directory of the server process, which is the client’s choice, not yours; prefer an absolute path.- Rust is indexed through an external
rust-analyzer scipprocess and needs it configured. See Configuration. - It publishes a new generation, so every cursor issued from the previous one
expires with
CURSOR_SNAPSHOT_EXPIRED.