feat(core): port server/tools_query.py to backend-neutral queries#20
Merged
Conversation
Fourth step of the Kuzu -> DuckDB migration. The most-used MCP tool
file (symbol_lookup, find_callers, find_callees, imports_of,
search_symbols, subgraph) now uses backend-neutral helpers. Both
backends answer these MCP tools identically.
What lands:
- codegraph/core/protocol.py: three new GraphDB methods covering the
query patterns in tools_query.py.
- find_nodes(label, where=..., contains=..., return_fields=...,
limit=...) -> list[dict]
Used by symbol_lookup + search_symbols. Both exact match (=) and
substring (CONTAINS / LIKE) supported; multi-field substrings get
OR'd, so search_symbols on TFResource matches when either name or
type contains the query.
- find_neighbors(edge_type, src_key=..., dst_key=..., src_where=...,
dst_where=..., return_src=..., return_dst=..., return_edge=...)
-> list[dict]
Used by find_callers, find_callees, imports_of, who_imports. Result
rows are flattened to {src_<field>: ..., dst_<field>: ...,
edge_<field>: ...} so the caller can pick what they need without
every tool reaching into Kuzu's "table.field" shape.
- reach_via_edge(edge_type, start_key, max_depth=..., return_fields=...)
-> list[dict]
Used by subgraph at depth > 1. Backed by Cypher's `*1..n` path
syntax on Kuzu and a recursive CTE on DuckDB.
- codegraph/core/db_kuzu.py + db_duckdb.py: all three helpers
implemented on both backends. Edge tables in DuckDB use composite
JOINs (e.g. `FROM edge_calls e, function a, function b WHERE
e.from_id = a.id AND e.to_id = b.id`) so anchoring on either side
and filtering by neighbor fields uses the same SQL shape.
- codegraph/server/tools_query.py: every conn.execute() call gone,
the _rows import gone. Each of the six MCP tools (symbol_lookup,
find_callers, find_callees, imports_of, search_symbols, subgraph)
goes through one or two GraphDB helper calls and translates the
result dicts into the tool's JSON payload.
- tests/test_core/test_graph_helpers.py: 18 new parametrized tests
covering find_nodes (where + contains + multi-field OR + limit),
find_neighbors (anchor on src, anchor on dst via where, edge props),
and reach_via_edge (single hop + two-hop).
End-to-end verification on a 3-function 2-file repo:
Kuzu:
symbol_lookup helper -> /tmp/.../a.py
find_callers helper -> [caller, wrapper]
imports_of /b.py -> [{ /a.py, 'helper' }]
DuckDB (CGH_DB=duckdb):
symbol_lookup helper -> /tmp/.../a.py
find_callers helper -> [caller, wrapper]
imports_of /b.py -> [{ /a.py, 'helper' }]
Identical results. 292 tests pass (was 274 + 18 new = 292).
What's NOT in this PR (next migration PRs):
- tools_viz.py (19 Cypher queries — bigger file, dedicated PR)
- tools_arch.py (3 queries)
- tools_docs.py (6 queries)
- analysis/{context_builder,dead_code}.py (5 queries)
- cli/commands_monitor.py (12 stats queries — separate task #10)
- federation.py (kuzu-direct opens — task #11)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fourth PR in the Kuzu → DuckDB migration. The most-used MCP tool file (`symbol_lookup`, `find_callers`, `find_callees`, `imports_of`, `search_symbols`, `subgraph`) now uses backend-neutral helpers. Both backends return identical results for these tools.
What lands
End-to-end verification
3-function 2-file repo with `a.py` defining `helper` + `caller`, `b.py` importing helper:
Test count
274 → 292 (+18 new parity tests).
Not in this PR (follow-ups)