lucerna
Guide for agents using the lucerna MCP tools to search and navigate a codebase index.
Lucerna — MCP tool guide
Lucerna exposes two tools: search_codebase and get_neighbors.
search_codebase
Hybrid semantic + lexical (BM25) search over the indexed codebase. The primary tool — use it first.
| Parameter | Type | Default | Description |
|---|---|---|---|
query | string | required | Search query |
includeGraphContext | boolean | true | Expand results with related symbols from the knowledge graph |
graphDepth | integer 0–3 | 1 | Hops to follow when expanding graph context |
limit | integer 1–100 | 10 | Max results per page |
offset | integer ≥ 0 | 0 | Results to skip — use for pagination when hasMore is true |
includeContent | boolean | true | Include chunk source code. Set false for metadata-only (filePath, name, type, lines) — much smaller response |
language | string | (all) | Filter by language: typescript, python, rust, go, etc. |
type | string | (all) | Filter by chunk type: function · class · method · interface · type · variable · import · section · file |
filePath | string | (all) | Filter by file path (supports glob patterns) |
Response shape
{
"results": [...],
"total": 15,
"hasMore": true,
"offset": 10
}
| Field | Description |
|---|---|
results | Array of flat result objects (see fields below) |
total | Number of results fetched before pagination (at most offset + limit + 1) |
hasMore | true if more results exist beyond the current page |
offset | Only present when non-zero — the offset used for this page |
warning | Present when indexing is still in progress or semantic search is unavailable — retry in a few seconds |
Each result object has these fields:
| Field | Always present | Description |
|---|---|---|
id | yes | Chunk ID — pass to get_neighbors |
loc | yes | "filePath:startLine-endLine" — e.g. "src/auth/middleware.ts:12-17" |
type | yes | Chunk type: function · class · method · etc. |
score | yes | Relevance score 0–1, rounded to 2 decimal places |
name | when named | Symbol name (function/class/method/heading) |
content | when includeContent: true | Raw source code of the chunk |
metadata | when non-empty | Language-specific extra fields |
get_neighbors
Traverses the knowledge graph for a specific chunk. Use it to explore callers, callees, imports, and other relationships that search_codebase didn't surface directly.
| Parameter | Type | Default | Description |
|---|---|---|---|
chunkId | string | required | The id field from a search_codebase result (top-level, not nested) |
depth | integer 1–3 | 1 | How many hops to traverse |
When to use each tool
search_codebasefirst, always. It already includes graph context by default (includeGraphContext: true). For most questions about the codebase, one call is enough.get_neighborswhen you need to go deeper. If a result looks relevant but you need to understand what calls it, what it calls, or what it imports — fetch its neighborhood explicitly.- Don't call
get_neighborspreemptively on every search result. Use it only when a specific chunk warrants deeper exploration.
Query guidelines
- Mix intent with identifiers.
"JWT token verify session middleware"retrieves better than"where is authentication implemented". Semantic search handles intent; BM25 handles exact names. - Exact symbol lookups: for known identifiers like
UserRepositoryorERR_CONN_RESET, a precise query with the symbol name works best. - Narrow with
typebefore raisinglimit. Filtering tofunctionormethodreduces noise more reliably than increasing the result count. - Use
filePathto scope to a module. When you already know which file or directory is relevant, filter to it.
Best practices
- If results look incomplete, check for a
warningfield in the response — indexing may still be running. - Prefer one well-formed query over multiple narrow ones. The hybrid ranker handles broad queries well.
graphDepth: 2is rarely needed. Start at1; only go deeper if the direct neighborhood is insufficient.- Pagination: when
hasMoreistrue, call again withoffsetincremented bylimitto fetch the next page. Stop whenhasMoreisfalseorresultsis empty. - Token-efficient survey: use
includeContent: falseto locate relevant files first, then read the ones you need with a file-reading tool. Use the defaultincludeContent: truewhen you need to understand the code in a single call.