Skip to main content
Glama
bernard357
by bernard357

duckdb-codegraph

A frugal, embeddable code-graph building block for agentic systems — tree-sitter impact analysis and structure explanation over a local DuckDB file, no external service.

duckdb-codegraph is a python package that exposes the actual structure of a codebase to a local agent, in 3 steps:

  1. analyze a folder of source files with tree-sitter and extract nodes and edges

  2. store that graph in a single DuckDB database baked next to your agent

  3. answer impact, explain, and report questions with a local function call

Where duckdb-vectors answers "what text is semantically near this query", duckdb-codegraph answers "what code is affected if this symbol or file changes" and "what is the structure of this code". The must-be-reliable deliverable is impact: a transitive reverse-dependency set over the edge graph, with every best-effort edge flagged rather than silently dropped.

SDK entry point

Open a store against a local .duckdb file and query it. Open read-only in the serving path, when the index is a frozen artifact baked into the container:

from duckdb_codegraph import CodeGraphStore

store = CodeGraphStore(db_path="codegraph.duckdb", read_only=True)

result = store.impact("payments.charge.Charge")
for hit in result.affected:
    print(hit.distance, hit.resolution, hit.node.qualified_name)

explanation = store.explain("payments.charge.Charge")
report = store.report()

impact returns the affected set with per-node distance and resolution; explain returns a node's defines/fan-in/fan-out/bases/subclasses; report introspects the index.

store.index(folder) is incremental-by-default: a full rebuild runs when the database is empty or you pass rebuild=True, and otherwise only changed, added, and deleted files are reconciled by comparing each file's stored etag against a freshly computed one (the compute_etag content fingerprint). The global cross-file resolution is re-run so edges that bound to a changed file are re-resolved; a no-change re-index is a no-op. The incremental result is identical to a full rebuild of the same on-disk state.

from duckdb_codegraph import CodeGraphStore

store = CodeGraphStore(db_path="codegraph.duckdb")

store.index("./my-project")              # full build on an empty database
store.index("./my-project")              # incremental re-index (etag-driven)
store.index("./my-project", rebuild=True)  # force a full rebuild

Related MCP server: capability-os

Indexing from the CLI

$ duckdb-codegraph index ./my-project --db codegraph.duckdb   # incremental by default
$ duckdb-codegraph index ./my-project --db codegraph.duckdb --rebuild  # full rebuild

The index verb is incremental-by-default: it runs a full build when the database is empty and reconciles only changed, added, and deleted files on a re-run. Pass --rebuild to force a full rebuild.

MCP tool

duckdb-codegraph mcp is an MCP-over-stdio server exposing three read-only tools:

  • impact(target, …) — transitive reverse-dependency set for a symbol or file.

  • explain(target, …) — structural neighbourhood of a symbol or file.

  • report() — introspects the index: database path, schema version, languages, and node/edge counts.

An MCP client spawns duckdb-codegraph mcp as a child process in the same container and talks to it over stdin/stdout; stdio is a same-container transport, not a network protocol.

The server also serves over Streamable HTTP, selected with --transport http:

$ duckdb-codegraph mcp                                   # stdio (default)
$ duckdb-codegraph mcp --transport http                  # http on 127.0.0.1:8000/mcp
$ duckdb-codegraph mcp --transport http --host 127.0.0.1 --port 8000

HTTP binds loopback 127.0.0.1:8000 at path /mcp by default; pass --host and --port to override. Serving stays strictly read-only over both transports, and both expose the identical impact, explain, and report tools with the same JSON-object shapes. The HTTP transport is the groundwork that will later let a client index a repository in a separate sandbox (for example a GitHub repository); that remote / sandbox indexing is future work this transport enables, not something shipped here.

Setup for working on the package itself

Requirements:

  • Python 3.12+

  • uv (Python env and builds)

Shell commands:

$ make setup     # install the Python toolchain into a local venv
$ make test      # run the test suite
$ make lint      # ruff, mypy, markdownlint

The Makefile is the toolbox

Drive common tasks through make; do not call the underlying tools directly:

  • make - list common targets

  • make setup — check and install the development toolchain

  • make lint / make format — check / apply ruff, mypy, markdownlint.

  • make test — run the pytest suite.

  • make self-test — capability evidence: index the package's own source with duckdb-codegraph and run a sequence of labelled requests (list files, list functions, change-impact traversal, cross-module symbol context, index overview, most-depended-upon hotspots), each printing a result and asserting a structural fact. Dogfoods the tool on a real multi-module codebase, distinct from the hermetic make test suite.

  • make build — build the wheel and sdist (version from the git tag via hatch-vcs).

Project structure

duckdb-codegraph/
├── src/duckdb_codegraph/   # the package
│   ├── store.py            # the CodeGraphStore API
│   ├── indexer.py          # folder → DuckDB graph index
│   ├── cli.py              # the duckdb-codegraph CLI (incl. the mcp verb)
│   ├── mcp_server.py       # the MCP-over-stdio server
│   ├── config.py           # Settings / DUCKDB_CODEGRAPH_* env
│   ├── models.py           # Node / Edge / ImpactResult pydantic models
│   ├── etag.py             # compute_etag content fingerprint
│   └── extractors/         # pluggable extractors (python, javascript/typescript)
├── tests/                  # pytest suite
├── pyproject.toml          # metadata, deps, tag-driven version (hatch-vcs)
└── Makefile                # the task toolbox

Releases are tag-driven: the version comes from the git vYYMMDD tag, and pushing a tag publishes to PyPI.

Configuration

Settings resolve with the precedence: explicit argument > DUCKDB_CODEGRAPH_* environment variable > default.

Setting

Argument

Environment variable

Default

Database path

db_path

DUCKDB_CODEGRAPH_DB_PATH

codegraph.duckdb

Indexed source root

root

DUCKDB_CODEGRAPH_ROOT

None

Read-only

read_only

DUCKDB_CODEGRAPH_READ_ONLY

false

Pointers

License

MIT.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Enables read-only querying of a local repository through a deterministic tree-sitter symbol and edge graph, exposing keyword search with exact file:line hits, regex text search, per-file symbol skeletons, caller/callee traversal, and directory-level maps of clusters, hubs, and hotspots over stdio.
    10
    51 npm
    1
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Serves an AI coding agent a searchable index of a codebase's existing capabilities and past incidents, so it can find and reuse what already exists before writing new code. Also exposes blast-radius analysis for shared code and lets the agent reindex the knowledge base, all via local retrieval with no model calls or API keys.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Serves a repository's code knowledge graph over stdio (MCP) so coding agents can look up symbols, trace callers and callees, compute blast radius, list file symbols, run hybrid lexical-plus-graph search, and get citation-grounded answers from file:line evidence instead of guessing from text chunks. All tools work offline straight from the graph, with prose synthesis only when an OpenAI-compatible LLM endpoint is configured.
    15
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents and reviewers to query a deterministic code dependency graph for callers, routes, pages, tables, and config with file:line evidence instead of grepping. One server can serve many indexed graphs, supporting cross-repository impact analysis.
    1,680 PyPI
    4
    MIT