delver - Local-First Code Intelligence MCP Server and CLI
delver is a local-first code-intelligence library, CLI, and MCP server for AI agents and developers.
It parses your codebase with tree-sitter, stores symbols and relationships in a local SQLite graph (WAL + FTS5), resolves cross-file call/type/import edges with a deterministic 3-tier algorithm, ranks repository structure with PageRank, and exposes everything to agents over MCP stdio plus a human-usable CLI.
Same tree + same code = byte-identical index and tool output. No LLM calls anywhere in the pipeline. No summaries. Only what the AST actually says.
Version: 0.1.0. Python 3.12+. Managed by uv. Entry point: delver = "delver.cli:main".
Table of contents
- What this does
- Why it stands out
- Requirements
- Install
- Uninstall
- Commands reference (with examples)
- MCP tools reference (with examples)
- Supported languages
- How it works (for contributors)
- Development and tests
- Troubleshooting
- License
1. What this does
Typical flow:
delver init # index once
delver explore "..." # ask about code, get source grouped by file + call path
delver node <symbol> # symbol details, caller/callee trail
delver callers ... # who calls it, with file:line
delver install # wire the MCP server into Claude / OpenCode / Cursor
What you get:
- A real symbol graph, not grep. Functions, methods, classes, structs, interfaces, traits, enums, type aliases, fields, properties, variables, constants, imports, components, routes. Edges: contains, calls, imports, exports, extends, implements, references, type_of, returns, instantiates, overrides, decorates.
- Cross-file resolution. Import-based resolution first (most precise), then same-file definitions, then a conservative global fallback. Chained
receiver.method()calls resolve via known receiver types with a supertype walk (depth 5). When nothing distinguishes candidates, the reference stays unresolved. A wrong edge is treated as worse than no edge. - Agent-first outputs.
delver_exploreis the primary tool: one call returns verbatim line-numbered source of the relevant symbols grouped by file plus the call path among them.delver_nodereads one file or one symbol. The rest (search,callers,callees,impact,repo_map,files,status) answer narrow questions without extra reads. - Token-budget aware. Adaptive output budgets by repo size (13K/18K/24K total caps), per-file caps, skeletonization (signatures-only for off-spine files), container outlines instead of concatenated method bodies, overload packing, and a line-folded repo map that fits
max_tokens. - Repo map. PageRank over the definition/reference graph with focus-file and mentioned-identifier boosts, rendered as a folded tree (kept lines with a vertical-bar marker, collapsed regions as an ellipsis marker) with 100-char line truncation.
- Hybrid search. FTS5 exact search by default. Optional local embedding re-rank of the FTS5 top-50 via FastEmbed. The model is never auto-downloaded; without it you get pure FTS5 plus a one-line note.
- CLI parity. Every graph query available over MCP is also available as
delver <subcommand>for humans and scripts.
Recoverable conditions ("project not indexed", "symbol not found", "file not in index") return success-shaped text with guidance. Only real malfunctions surface as errors.
2. Why it stands out
Strengths only (no head-to-head claims). Each point is implemented behavior, not marketing:
- Local-first and private. The index lives outside your repo under
~/.delver/indexed-db/(Windows:%USERPROFILE%\.delver\indexed-db\). Your repo stays clean. No code leaves the machine for indexing. No API keys. - Deterministic, AST-derived. Extraction comes from tree-sitter grammars, not LLM summarization. Re-indexing unchanged code gives the same node IDs (
<language>:<relpath>:<kind>:<qualified_name>) and the same output. - Multi-language with exact extractors. 12 language dictionaries plus tsx/jsx aliases plus HTML, plus yaml/properties key-only leaves. Each has explicit AST node-type mappings and behavioral hooks (method classification, receiver types, visibility, async/static/const, import/package extraction, C/C++/C# pre-parse blanking for macros and directives).
- Resolution with confidence, not guessing. Import-resolved symbols short-circuit at 0.90-0.95 confidence. Qualified names, same-file preference, function-as-value rules, proximity narrowing, and word-overlap fallback each have fixed confidence values. Ambiguous names (50+ candidates) stay unresolved.
- Method-on-type works. Return types and declared variable types are normalized into the index so
obj.method()binds toType::method, including inherited methods via extends/implements edges. - Budget engine prevents context blowups. Larger repos get more calls (1/2/3/4/5 by file count), never a bigger single response. Responses are cut at file-section boundaries under the cap and never tell the agent to use Read/Grep; they steer to another
delver_exploreordelver_nodeand label returned source as already read. - Secret-safe by default. Config/data leaves (yaml/properties) are summarized by key only. Values are never stored in the index and never printed.
- Safe transport and storage. Pure stdio via FastMCP. Zero HTTP servers, zero ports, zero SSE, zero daemons, zero file watchers. Staleness is on-demand mtime+size delta sync before every query.
- Surgical installer. Auto-detects Claude Code, OpenCode, and Cursor. Writes only the
delverentry, preserves sibling servers, comments, and formatting (including JSONC comments/trailing commas for OpenCode). Re-runs are byte-equal no-ops (unchanged). Uninstall reverses install exactly and prunes emptied wrappers/files/dirs. - Operational safety. Filesystem-root and home-directory guard on index/destructive commands. Absolute binary paths in installed MCP entries. WAL mode check with a warning when the filesystem silently refuses WAL. Corrupt JSON configs are backed up before rewrite.
3. Requirements
- Python 3.12 or newer.
uvfor install and runs.- Supported OS: Windows, Linux/WSL, macOS.
- Disk locations used (all outside indexed repos):
- Index DB:
~/.delver/indexed-db/<hash>_<slug>.db(Windows:%USERPROFILE%\.delver\indexed-db\...), plus-wal/-shmsidecars. - Embedding models:
~/.delver/models/. - Tree-sitter grammar cache:
~/.delver/ts-cache/.
- Index DB:
Dependencies (from pyproject.toml): fastmcp, tree-sitter, tree-sitter-language-pack, networkx, grep-ast, fastembed, numpy. Dev group: pytest.
4. Install
4.1 Install the package
From the repo root:
uv sync
This creates the venv and installs delver with the delver console script.
Verify:
uv run delver --help
You should see all subcommands: init index sync status uninit explore node callers callees impact repo-map files search install uninstall serve.
4.2 Index a project
cd /path/to/your-project
uv run delver init
Or from anywhere:
uv run delver init /path/to/your-project
What happens:
- Scans the project root, skipping
.git/,node_modules/,.venv//venv/,dist//build//target//__pycache__/,.delver/, lockfiles, binaries, minified files, and files over 1 MB. - Parses each recognized file with tree-sitter, inserts nodes/edges/imports, collects unresolved refs.
- Runs the 3-tier + chained-call resolution pass.
- Prints a tree summary: files indexed, node count, edge count, elapsed time.
init is idempotent. Re-running prints "Already initialized" with a hint to use index or sync.
Other lifecycle commands:
uv run delver status
uv run delver sync
uv run delver index
statusshows files/nodes/edges, DB size, journal mode, pending unresolved refs, last sync time, and the DB path.syncdoes an mtime/size delta sync only and prints added/updated/removed counts (or "Already up to date").indexforces a full re-extract of every file, then resolves.
All project paths are optional and default to the current directory. Global --path also works:
uv run delver --path /path/to/your-project status
Safety: init, index, sync, and uninit refuse filesystem roots (/ , C:\) and the bare user home directory with exit code 2.
4.3 Install the MCP server into your agents
Zero flags = detected agents + global scope (project repos stay clean):
uv run delver install
Explicit selection:
uv run delver install --agents claude,opencode,cursor --location global
uv run delver install --agents claude --location local
uv run delver install --local
uv run delver install --agents claude --auto-allow
Flags:
--agents: comma-separated subset ofclaude,opencode,cursor. Default: all detected agents. Non-interactive.--location:global(default) orlocal.--localis shorthand for--location local.--auto-allow: Claude only. Appendsmcp__delver__*allow entries tosettings.json.
Where entries go:
- Claude Code:
- Global:
~/.claude.jsonundermcpServers.delver = {type: stdio, command: <abs path>, args: [serve]}. - Local:
<root>/.mcp.json(the only project-level file Claude Code reads; stale legacy entries are migrated out on install and uninstall). - Permissions (opt-in):
~/.claude/settings.json(global) or<root>/.claude/settings.json(local).
- Global:
- OpenCode:
- Config dir is
$XDG_CONFIG_HOME/opencodeif set, else~/.config/opencodeon every platform. Local: project root. - File selection: existing
opencode.jsoncwins, else existingopencode.json, else create.jsonc. - Entry under
mcp(notmcpServers):{mcp: {delver: {type: local, command: [<abs path>, serve], enabled: true}}}with$schemaseeded for new files. Comments and trailing commas survive round-trips. Legacy%APPDATA%/opencodeentries are swept on global install/uninstall.
- Config dir is
- Cursor:
- Global:
~/.cursor/mcp.json. Local:<root>/.cursor/mcp.json. SamemcpServersshape as Claude plus--pathinjection (Cursor launches with the wrong cwd and no root URI): local installs get the absolute project path, global installs get${workspaceFolder}. Final args:["serve", "--path", <pathArg>]. Restart Cursor after changes.
- Global:
Report vocabulary per file: created, updated, unchanged (byte-identical re-run, file untouched), removed, not-found.
After install, the server runs over stdio. Manual check:
uv run delver serve
Send a JSON-RPC initialize message over stdin to smoke-test; expect a JSON-RPC initialize response and no port binds.
4.4 Enable semantic re-rank (optional, one-time)
Pure FTS5 is the default. To enable hybrid embedding re-rank:
uv run delver search "login session" --semantic --download
This downloads the embedding model (default bge-small-en-v1.5) into ~/.delver/models/ and exits after printing the path (or continues with the query if one was given). Later runs:
uv run delver search "login session" --semantic
Without a downloaded model, --semantic degrades to pure FTS5 with a one-line success-shaped note. It never auto-downloads.
5. Uninstall
Reverse order: remove agent configs first, then optionally delete the index.
Remove MCP entries:
uv run delver uninstall
- Without
--agents, uninstall sweeps all three targets (reportsnot-foundharmlessly) so it covers agents that are no longer detectable but still have config entries. - With
--agents, only that subset is touched:uv run delver uninstall --agents cursor --location global. --location/--localselect scope the same way as install.- Every write is paired: injected keys removed, emptied wrappers (
mcpServers/mcp) pruned, empty files deleted, empty config dirs pruned. Sibling servers and unrelated keys are never touched.
Delete the index for a project:
uv run delver uninit
uv run delver uninit -y
uv run delver unindex -y /path/to/project
- Prompts
[!] This will permanently delete the Delver index for <root>. Continue? (y/N)unless-y/--yesis given.unindexis an alias. - Deletes every DB file/sidecar for the project by hash-prefix glob (covers both current hybrid names and legacy hash names) plus strips the
delverentry from local agent configs in that project. - Prints
[OK] Removed Delver index for <path>, or a warning when nothing was found (idempotent, exit 0). - Other projects' DBs are untouched.
Full removal from a machine: run uninstall (global scope) for each project you installed, run uninit per indexed root, then delete the package checkout. The only leftovers would be ~/.delver/ caches you may delete manually.
6. Commands reference (with examples)
Global: delver [--path <root>] <command> [args] [project]. The trailing project positional overrides --path; both default to . (cwd).
Lifecycle
| Command | What it does | Example |
|---|---|---|
init [path] |
Create DB, run full index + resolution, print files/nodes/edges | delver init / delver init ./my-app |
index [path] |
Force full re-extract of every file, then resolve | delver index |
sync [path] |
mtime delta sync only; prints added/updated/removed | delver sync |
status [path] |
Files/nodes/edges, DB size, journal mode, pending refs, last sync, DB path | delver status |
uninit [path] [-y] (alias unindex) |
Delete index DB + sidecars + local config entries | delver uninit -y |
Examples:
delver init
# T Initializing Delver
# * Scanning files -- 411 found
# * Parsing code -- done
# * Resolving references -- done
# - Done (with bullet: Indexed 411 files (... nodes, ... edges in ...s))
delver status
# Project: D:\projects\my-app
# Files: 411 Nodes: 10023 Edges: 18979 Unresolved (pending): 0
# DB: C:\Users\you\.delver\indexed-db\d2b9342d_D_projects_my-app.db (... bytes)
# Journal mode: wal
# Last sync: ...
delver sync
# T Syncing Delver ... Already up to date (0 files modified)
delver uninit -y
# [OK] Removed Delver index for D:\projects\my-app
Query
| Command | What it does | Example |
|---|---|---|
explore <query...> |
Primary. Whole-tail query. Prints budget-capped markdown with source grouped by file + flow/blast-radius | delver explore "sync delta indexer" |
node <symbol> [--code] |
Symbol details (signature, location, caller/callee trail). --code adds full body |
delver node sync_delta / delver node UserService --code |
search <query> [--kind] [--limit] [--semantic] [--download] |
Quick symbol name lookup, locations only | delver search login --kind function --limit 10 |
callers <symbol> |
Caller list with file:line | delver callers sync_delta |
callees <symbol> |
Callee list with file:line | delver callees loginUser |
impact <symbol> [--depth N] |
Reverse-edge BFS blast radius | delver impact AuthService --depth 2 |
repo-map [--tokens N] [--focus F...] |
PageRank-ranked folded repo map | delver repo-map --tokens 1024 --focus src/auth.ts |
files [--pattern G] [--subpath D] [--format tree|flat|grouped] |
Indexed file tree with language + symbol counts | delver files --pattern "src/**/*.ts" --format tree |
Notes:
exploretakes the whole tail as the query (free-text allowed). Parse happens before argparse, so quote multi-word queries:delver explore "AuthService loginUser session-manager".nodedefaults to signature + docstring + trail (no body). Containers (class/interface/struct/enum) with--codereturn a structural outline (member names + signatures + line numbers), never concatenated bodies. Ambiguous names return every matching definition packed under a char budget (12000 chars, hard cap 16 rendered, 20 listed).- File mode note:
delver_nodefile view renders<n><tab><line>(cat -n style), default 2000 lines, 38000 char budget, with pagination note and a one-line blast-radius header (used by N files: ...). search --kindaccepts:function, method, class, interface, type, variable, route, component.repo-map --tokensdefaults to 1024.--focusboosts the files you are already working with.
Setup
| Command | What it does | Example |
|---|---|---|
install [--agents ...] [--location ...] [--local] [--auto-allow] |
Detect agents, write MCP configs | delver install --agents claude,opencode --location global |
uninstall [--agents ...] [--location ...] [--local] |
Reverse install exactly | delver uninstall --location local |
serve |
Start FastMCP stdio server | delver serve |
7. MCP tools reference (with examples)
All tools accept optional projectPath to query a second indexed project. All are read-only. Every read runs the mtime delta sync first.
| # | Tool | Role | CLI equivalent |
|---|---|---|---|
| 1 | delver_explore |
PRIMARY. Call first for almost any question or before an edit. Bag of symbol/file names or natural language. Returns verbatim source grouped by file + call path. maxFiles clamped 1..20; effective default comes from the budget engine (4/5/8 by repo size) |
delver explore |
| 2 | delver_node |
SECONDARY. File mode (Read-equivalent with offset/limit) or symbol mode (body + caller/callee trail). includeCode defaults false |
delver node |
| 3 | delver_search |
Quick symbol lookup, locations only. Optional kind, limit (default 10), semantic (default false) |
delver search |
| 4 | delver_callers |
Who calls <symbol>, with file:line |
delver callers |
| 5 | delver_callees |
What <symbol> calls |
delver callees |
| 6 | delver_impact |
Blast radius of changing <symbol> (BFS over reverse edges, depth default 2) |
delver impact |
| 7 | delver_repo_map |
PageRank-ranked folded repo map. maxTokens default 1024, focusFiles, mentionedIdents, forceRefresh |
delver repo-map |
| 8 | delver_files |
Indexed file tree with language + symbol counts. path, pattern, format (tree/flat/grouped), includeMetadata, maxDepth |
delver files |
| 9 | delver_status |
Index health: files/nodes/edges/DB size/journal mode | delver status |
Agent guidance baked into outputs: explore output never tells the agent to use Read; it steers to another delver_explore or delver_node and says "treat returned source as already Read".
Minimal MCP config shapes (command is the absolute delver binary on your machine):
Claude (~/.claude.json):
{
"mcpServers": {
"delver": { "type": "stdio", "command": "C:\\path\\to\\delver.EXE", "args": ["serve"] }
}
}
OpenCode (~/.config/opencode/opencode.jsonc):
{
// your comments survive install/uninstall
"$schema": "https://opencode.ai/config.json",
"mcp": {
"delver": { "type": "local", "command": ["C:\\path\\to\\delver.EXE", "serve"], "enabled": true }
}
}
Cursor (~/.cursor/mcp.json, global):
{
"mcpServers": {
"delver": { "command": "C:\\path\\to\\delver.EXE", "args": ["serve", "--path", "${workspaceFolder}"] }
}
}
Prefer delver install over hand-editing; it resolves the absolute path, picks the right file, and keeps formatting.
8. Supported languages
| Language key | Grammar | Extensions |
|---|---|---|
| python | python | .py, .pyi |
| typescript | typescript | .ts |
| tsx | tsx | .tsx |
| javascript | javascript | .js, .mjs, .cjs |
| jsx | jsx | .jsx |
| rust | rust | .rs |
| c | c | .c, .h |
| cpp | cpp | .cc, .cpp, .cxx, .hpp, .hh, .h++, .cu, .cuh, .metal |
| java | java | .java |
| csharp | c_sharp | .cs |
| go | go | .go |
| php | php | .php |
| ruby | ruby | .rb, .erb |
| lua | lua | .lua |
| html | html | .html, .htm |
| config leaves | n/a | .yml, .yaml, .properties, .ini (key-only nodes) |
Skipped always: binaries, .git/, node_modules/, venvs, dist//build//target/, __pycache__/, .delver/, lockfiles, minified *.min.js, files over 1 MB.
Node kinds: file, module, class, struct, interface, trait, protocol, function, method, property, field, variable, constant, enum, enum_member, type_alias, namespace, parameter, import, export, route, component.
Edge kinds: contains, calls, imports, exports, extends, implements, references, type_of, returns, instantiates, overrides, decorates.
9. How it works (for contributors)
files -> ExtractionOrchestrator (py-tree-sitter) -> SQLite (nodes/edges/files)
|
v
ReferenceResolver (Tier 1 imports -> Tier 2 same-file -> Tier 3 global)
|
v
Graph queries (callers/callees/impact) + FTS5 search
|
v
MCP tools (delver_*) + CLI + repo map
Package layout:
delver/
cli.py # argparse CLI
server.py # FastMCP instance + tool registration
types.py # NodeKind, EdgeKind vocabularies
db/
schema.sql # DDL (nodes, edges, files, unresolved_refs, FTS, metadata)
connection.py # PRAGMA order, WAL check, db_path_for, sidecar cleanup
indexer.py # mtime delta sync engine
queries.py # prepared statements for tools
extraction/
orchestrator.py # walk + parse + store
extractors.py # language dictionaries + hooks
languages.py # language key -> grammar + extension map
resolution/
__init__.py # 3-tier resolver
name_matcher.py
import_resolver.py
chained_calls.py # receiver-type bridges
tools/
__init__.py # 9 tool handlers + register_tools
budgets.py # get_explore_budget / get_explore_output_budget
render.py # node/file/folding renderers
repomap/
__init__.py # PageRank + folded tree + bounded cache
search/
__init__.py # hybrid FTS5 + FastEmbed re-rank
installer/
__init__.py # detect/run_install/run_uninstall orchestrator
targets/ # claude.py, opencode.py, cursor.py
tests/ # pytest suite, one file per phase
Key invariants (violations are bugs):
- Transport is pure stdio. No ports, no SSE, no daemons.
- Stateless execution. No watchers; every query runs
sync_deltafirst. - DB never lives inside the indexed repo.
- MCP tools are
delver_*. CLI isdelver <subcommand>. - Determinism. Same tree = same index and output.
- Recoverable conditions are success-shaped text, never errors.
- Explore output never suggests Read/Grep.
- All shipped source is ASCII. Fold glyphs are emitted at runtime via escapes.
Budgets (repo size -> per-call caps): total 13K/18K/24K/24K/24K chars, per-file 3800/3800/6500/7000/7000, gap 7/8/12/15/15 lines, header/edge caps 5/6/10/15/15. Larger tiers never get a smaller per-file cap. Larger repos get more calls (1/2/3/4/5 at <500/<5k/<15k/<25k/>=25k files), never a bigger single response.
10. Development and tests
uv sync
uv run pytest delver/tests/ -q
uv run delver --help
Full suite must be green before any phase is considered done. Test files map to build phases: test_skeleton.py, test_db.py, test_extraction.py / test_resolution.py, test_tools.py, test_repomap.py, test_installer.py.
Terminal hygiene for contributions: report exit codes plus one-line summaries; on failure show at most the relevant lines.
11. Troubleshooting
Project not indexed. Run: delver init- you queried before indexing. Rundelver init [path], then retry.Symbol not found: X- no node with that name exists. Trydelver search Xfor close matches, or check--kind/--limit.No callers found for X.- symbol exists but has no incoming calls/references edges.WARNING: journal mode is '...' (expected 'wal')- the filesystem (network mount, WSL /mnt) silently kept the prior mode. Reads still work; concurrent reads may block.- Semantic search falls back to FTS5 with a one-line note - the model is not under
~/.delver/models/. Rundelver search --semantic --downloadonce (opt-in). Error: Safety check blocked operation on system root or user home(exit 2) - run from inside a project directory or pass a specific project path.Cancelled - nothing was deleted.- you declined theuninitprompt. Re-run with-yfor scripts.- Unparseable agent JSON - the installer backs it up to
<path>.backupbefore any rewrite; fix or restore the backup and re-run. - Cursor does not see the server - restart Cursor after MCP changes take effect.
12. License
MIT. See root pyproject.toml (license = { text = "MIT" }) and the repository LICENSE if present.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file delver_codebase_mcp-0.1.1.tar.gz.
File metadata
- Download URL: delver_codebase_mcp-0.1.1.tar.gz
- Upload date:
- Size: 243.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2c5ab8262c8a7ec0f4067d5497bc013e8b91b48813b505886a2e33583eab1a68
|
|
| MD5 |
8d9b88ce9d24b60480c27a8c244ed64e
|
|
| BLAKE2b-256 |
ea04de936e5f10441af282809ef7106bffc8bf550e2bf09a9aca006e32e6bd29
|
File details
Details for the file delver_codebase_mcp-0.1.1-py3-none-any.whl.
File metadata
- Download URL: delver_codebase_mcp-0.1.1-py3-none-any.whl
- Upload date:
- Size: 263.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67c68c63954624db8ea98297e1d1f3f110bd7694dcffec30bb4d0940c0679363
|
|
| MD5 |
b7cfea9a15e8dc19cac04f1e1a39719d
|
|
| BLAKE2b-256 |
659e0d42bc413c83765bcb1e197443f9ad0f3f5abc653f8f645720620d66fe20
|