Skip to content

feat(query-graph): Cypher-subset graph query engine + MCP tool (closes #9)#149

Merged
Wolfvin merged 1 commit into
mainfrom
feat/issue-9-query-graph
Jul 3, 2026
Merged

feat(query-graph): Cypher-subset graph query engine + MCP tool (closes #9)#149
Wolfvin merged 1 commit into
mainfrom
feat/issue-9-query-graph

Conversation

@Wolfvin

@Wolfvin Wolfvin commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Closes #9

Summary

Agents currently must chain multiple MCP tools (trace → impact → context) to answer structural questions. This PR adds a single expressive query language — an openCypher subset — that replaces 3-5 tool calls with one.

What changed

New files:

  • scripts/query_graph_engine.py — Pure-Python Cypher-subset parser + SQL compiler + executor. Zero external deps. Read-only (no CREATE/DELETE/MERGE).
  • scripts/commands/query_graph.py — CLI command codelens query-graph.
  • tests/test_query_graph.py — 68 tests.

Modified:

  • scripts/mcp_server.py — added query-graph to _TOOL_DEFINITIONS.
  • Doc/metadata files — command count synced 69→70, MCP static 54→55.

Supported Cypher subset (MVP per issue #9 spec)

MATCH (var:Label)-[:EDGE_TYPE]->(var2)
WHERE var.property = 'value'
WHERE var.name CONTAINS 'substr'
WHERE var.file IS NULL
WHERE NOT EXISTS { ()-[:CALLS]->(var) }   -- dead code
RETURN var.name, var2.file
LIMIT 10

Clauses: MATCH, WHERE, RETURN, LIMIT
Predicates: =, !=, <, >, <=, >=, CONTAINS, IS NULL, IS NOT NULL, NOT EXISTS { pattern }, AND, OR
Node labels: function, class, file, module, route, type, interface (case-insensitive — PascalCase normalized to lowercase)
Edge types: CALLS, IMPORTS, DEFINES, INHERITS, IMPLEMENTS, USES_TYPE
Edge syntax: -[:TYPE]->, <-[:TYPE]-, -[:TYPE]- (undirected)
Anonymous nodes: () matches any node (used in NOT EXISTS)

Example queries from issue #9

-- 1. What does handleRequest call?
MATCH (f:Function)-[:CALLS]->(g) WHERE f.name = 'handleRequest' RETURN g.name, g.file

-- 2. Dead code (functions with no callers)
MATCH (f:Function) WHERE NOT EXISTS { ()-[:CALLS]->(f) } RETURN f.name

-- 3. Class inheritance
MATCH (c:Class)-[:INHERITS]->(p:Class) RETURN c.name, p.name

Design decisions

  • Pure Python, zero deps. No external Cypher library needed. The parser is a simple recursive-descent parser (~200 lines). The SQL compiler translates patterns to JOINs on graph_nodes + graph_edges.
  • Read-only. No CREATE/DELETE/MERGE — safe for CI.
  • Correlated subqueries for NOT EXISTS. The dead-code pattern (NOT EXISTS { ()-[:CALLS]->(f) }) compiles to a correlated SQL subquery that references the outer query's node via shared variable names.
  • Labels case-insensitive. Cypher convention is PascalCase (Function, Class) but graph_model stores lowercase. Labels are normalized to lowercase at parse time.
  • Anonymous nodes (). Valid in Cypher — matches any node. Used in NOT EXISTS patterns where the caller side is unbound.
  • Default edge type CALLS. When no type is specified (-[]-> or -->), CALLS is assumed (most common query).
  • Defensive errors. Parse/compile/DB errors return structured error dicts ({status: error, error: parse_error, message: ...}), not exceptions. validate_query() checks syntax without touching the DB.

Test results

  • 68/68 new tests in tests/test_query_graph.py pass:
    • TestTokenizer (8) — strings, brackets, arrows, comments, errors
    • TestParser (19) — nodes, edges, WHERE predicates, LIMIT, RETURN *, errors
    • TestValidateQuery (3) — syntax-only validation
    • TestExecuteSingleNode (10) — MATCH, WHERE, LIMIT, RETURN *, AND/OR
    • TestExecuteWithEdges (4) — CALLS right/left, INHERITS, multi-hop
    • TestNotExists (2) — dead-code detection + positive EXISTS
    • TestErrorHandling (6) — parse errors, missing DB, missing tables, echo
    • TestCliCommandRegistration (4) — registration, help, --validate, --limit
    • TestMcpToolRegistration (4) — schema, required fields, description
    • TestFileHeaders (2) — @WHO/@WHAT/@PART/@entry
    • TestIssueSpecExamples (3) — all three examples from issue [FEATURE] Cypher-like graph query engine for MCP tool query_graph #9 spec
  • No regressions: 442 passed, 40 skipped, 0 failed in safe-to-run test subset.
  • test_command_count.py passes — counts are in sync.
  • test_command_registry.py passes — query-graph auto-registers.
  • Pre-existing failure in test_universal_grammar_loader (tree-sitter-zig env) unchanged.

Non-breaking

  • New command + new MCP tool — additive. No existing command touched.
  • Command count synced via sync_command_count.py --apply.
  • No dependency changes.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

…#9)

Agents currently must chain multiple MCP tools (trace -> impact -> context)
to answer structural questions. This adds a single expressive query language
—an openCypher subset — that replaces 3-5 tool calls with one.

New files:
- scripts/query_graph_engine.py — pure-Python Cypher-subset parser +
  SQL compiler + executor. Zero external deps. Read-only (no CREATE/DELETE).
  Supported clauses: MATCH, WHERE, RETURN, LIMIT.
  Supported predicates: =, !=, <, >, <=, >=, CONTAINS, IS NULL, IS NOT NULL,
  NOT EXISTS { pattern }, AND, OR.
  Node labels: function, class, file, module, route, type, interface
  (case-insensitive — PascalCase convention normalized to lowercase).
  Edge types: CALLS, IMPORTS, DEFINES, INHERITS, IMPLEMENTS, USES_TYPE.
  Edge syntax: -[:TYPE]->, <-[:TYPE]-, -[:TYPE]- (undirected).
  Anonymous nodes () supported (matches any node — used in NOT EXISTS).
  Default edge type is CALLS when none specified.
  Correlated subqueries for NOT EXISTS (dead-code detection pattern).
  Defensive: parse/compile/DB errors return structured error dicts, not
  exceptions. validate_query() checks syntax without touching the DB.
- scripts/commands/query_graph.py — CLI command 'codelens query-graph'.
  --validate flag for syntax-only check. --limit CLI flag overrides query
  LIMIT. Auto-registered via commands/__init__.py.
- tests/test_query_graph.py — 68 tests covering tokenizer, parser, SQL
  compilation, executor, error handling, CLI registration, MCP tool schema,
  file headers, and all three example queries from issue #9 spec.

Modified:
- scripts/mcp_server.py — added 'query-graph' to _TOOL_DEFINITIONS (static
  schema with query, limit, validate params; description includes examples
  from issue #9).
- README/SKILL/SKILL-QUICK/pyproject.toml/skill.json/graph_model.py —
  command count synced 69->70, MCP static 54->55 via
  sync_command_count.py --apply.

Test results: 68/68 new tests pass. 442 passed / 40 skipped / 0 failed in
safe-to-run test subset. No regressions. Pre-existing failures in
test_universal_grammar_loader (tree-sitter-zig env) unchanged.
@sonarqubecloud

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

@Wolfvin Wolfvin deleted the feat/issue-9-query-graph branch July 3, 2026 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Cypher-like graph query engine for MCP tool query_graph

1 participant