Skip to content

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

Closed
Wolfvin wants to merge 1 commit into
mainfrom
feat/issue-9-cypher-engine-v2
Closed

feat(graph): Cypher-subset query engine -- query-graph command + MCP tool (closes #9)#151
Wolfvin wants to merge 1 commit into
mainfrom
feat/issue-9-cypher-engine-v2

Conversation

@Wolfvin

@Wolfvin Wolfvin commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Closes #9

Catatan: Race condition dengan PR #149. Saya claim issue ini pada 2026-07-01T11:56:55Z (~14 detik setelah claim comment worker lain di 11:56:41Z). Saat saya cek issue state sebelum claim, belum ada comment apapun. PR ini competing approach dengan PR #149 — BOS putuskan.

Summary

Implementasi Cypher-subset graph query engine sesuai issue #9 "minimal viable" scope. Agents dapat ekspresikan pertanyaan struktural dalam satu query ekspresif sebagai pengganti chaining 3-5 trace + impact + context tool calls (estimasi 60-80% reduction in tool calls per issue #9).

Supported Cypher subset

  • Clauses: MATCH, WHERE, RETURN, LIMIT
  • Predicates: =, !=, <, >, <=, >=, CONTAINS, IS NULL, IS NOT NULL, EXISTS { pattern }, NOT EXISTS { pattern }, AND, OR, NOT
  • Node labels: Function, Class, File, Module, Route, Type, Interface (+ aliases: method, component)
  • Edge types: CALLS, IMPORTS, DEFINES, INHERITS, IMPLEMENTS, USES_TYPE
  • Read-only — write clauses (CREATE/SET/DELETE/MERGE/REMOVE/DROP/INSERT/UPDATE/DETACH) ditolak dengan error jelas
  • Default LIMIT 100, hard cap 1000 untuk prevent runaway queries

Example queries (dari issue #9)

MATCH (f:Function)-[:CALLS]->(g) WHERE f.name = 'handleRequest' RETURN g.name, g.file
MATCH (c:Class)-[:INHERITS]->(p) WHERE p.name = 'BaseModel' RETURN c.name
MATCH (f:Function) WHERE NOT EXISTS { ()-[:CALLS]->(f) } RETURN f.name  -- dead code

Architecture

  • scripts/cypher_query_engine.py — Tokenizer + recursive-descent parser + AST-to-SQL translator + executor. All user-supplied literals parameterized (? placeholders). Identifiers validated against allow-lists at parse time. Correlated EXISTS subqueries translate to SQL EXISTS with WHERE correlation (not redundant JOIN).
  • scripts/commands/query_graph.py — CLI command dengan --explain flag (shows translated SQL without executing). Registered as query-graph.
  • scripts/mcp_server.py — Static MCP tool definition query-graph dengan full description + query/workspace/explain parameters. Tool name codelens_query_graph.
  • tests/test_cypher_query.py — 66 tests: tokenizer, parser validation, SQL translation (placeholder/param count verification), end-to-end execution against test database, error handling, CLI command, MCP tool registration, SQL injection safety.

Security

  • All string/number literals in WHERE predicates passed as SQL parameters (? placeholders) — no string interpolation
  • Identifiers (var names, prop names) validated against allow-lists at parse time
  • Node labels validated against _LABEL_TO_NODE_TYPE map at parse time
  • Edge types validated against _VALID_EDGE_TYPES set at parse time
  • Write clauses rejected with clear "read-only" error
  • SQL injection test case included in test suite

Files

  • scripts/cypher_query_engine.py — new (~700 lines: tokenizer + parser + translator + executor)
  • scripts/commands/query_graph.py — new (CLI command wrapper)
  • scripts/mcp_server.py — modified (43 lines added: static tool definition)
  • tests/test_cypher_query.py — new (66 tests)
  • README.md, SKILL.md, SKILL-QUICK.md, skill.json, pyproject.toml, scripts/graph_model.py — updated by sync_command_count.py --apply (command count 69 -> 70, MCP tools 67 -> 68)

Verified

  • 66/66 cypher query tests pass
  • 185/185 pass on focused subset (test_cypher_query + test_command_count + test_command_registry + test_version_consistency + test_cli + test_codelens + test_graph_model + test_graph_incremental), 35 skipped (optional deps), 0 failed
  • CLI: codelens query-graph --explain produces correct SQL + params
  • End-to-end: all 3 issue [FEATURE] Cypher-like graph query engine for MCP tool query_graph #9 example queries return expected results against test database (6 nodes, 3 edges)
  • SQL injection test: 'x'; DROP TABLE graph_nodes; --' safely handled (table not dropped)

Acceptance criteria status (from issue #9)

  • MATCH, WHERE, RETURN, LIMIT clauses
  • Node labels + edge types
  • Basic predicates: =, CONTAINS, IS NULL, NOT EXISTS
  • Read-only (no write clauses)
  • MCP tool query_graph registered (as codelens_query_graph)
  • CLI command query-graph registered
  • 66 tests covering parser + translator + executor + error handling + security

…tool (closes #9)

Issue #9 — Cypher-like graph query engine for MCP tool query_graph.

Agents can now express structural questions in a single expressive query
instead of chaining trace + impact + context tool calls. One query replaces
3-5 tool calls for typical structural questions (estimated 60-80% reduction
in tool calls for structural questions per issue #9).

Supported Cypher subset (per issue 'minimal viable' scope):
- Clauses: MATCH, WHERE, RETURN, LIMIT
- Predicates: =, !=, <, >, <=, >=, CONTAINS, IS NULL, IS NOT NULL,
  EXISTS { pattern }, NOT EXISTS { pattern }, AND, OR, NOT
- Node labels: Function, Class, File, Module, Route, Type, Interface
- Edge types: CALLS, IMPORTS, DEFINES, INHERITS, IMPLEMENTS, USES_TYPE
- Read-only (no CREATE/SET/DELETE/MERGE clauses)
- Default LIMIT 100, hard cap 1000 to prevent runaway queries

Example queries (from issue #9):
  MATCH (f:Function)-[:CALLS]->(g) WHERE f.name = 'handleRequest' RETURN g.name, g.file
  MATCH (c:Class)-[:INHERITS]->(p) WHERE p.name = 'BaseModel' RETURN c.name
  MATCH (f:Function) WHERE NOT EXISTS { ()-[:CALLS]->(f) } RETURN f.name  -- dead code

Architecture:
- scripts/cypher_query_engine.py: tokenizer + recursive-descent parser +
  AST-to-SQL translator + executor. All user-supplied literals are
  parameterized (? placeholders) -- no SQL injection. Identifiers (var
  names, prop names, labels, edge types) validated against allow-lists
  at parse time. Correlated EXISTS subqueries translate to SQL EXISTS
  with WHERE correlation (not redundant JOIN).
- scripts/commands/query_graph.py: CLI command with --explain flag
  (shows translated SQL without executing). Registered as 'query-graph'.
- scripts/mcp_server.py: static MCP tool definition 'query-graph' with
  full description, query/workspace/explain parameters. Tool name
  codelens_query_graph (hyphens to underscores).
- tests/test_cypher_query.py: 66 tests covering tokenizer, parser
  validation, SQL translation (placeholder/param count), end-to-end
  execution against test database, error handling, CLI command,
  MCP tool registration.

Security:
- All string/number literals in WHERE predicates are passed as SQL
  parameters (? placeholders) -- no string interpolation into SQL.
- Identifiers (variable names, property names) validated against
  allow-lists (_NODE_PROPERTIES, _EDGE_PROPERTIES) at parse time.
- Node labels validated against _LABEL_TO_NODE_TYPE map at parse time.
- Edge types validated against _VALID_EDGE_TYPES set at parse time.
- Write clauses (CREATE/SET/DELETE/MERGE/REMOVE/DROP/INSERT/UPDATE/DETACH)
  rejected with clear 'read-only' error.
- SQL injection test case included in test suite (test_sql_injection_safe).

Command count: 69 -> 70 (query-graph added). sync_command_count.py --apply
updated README.md, SKILL.md, SKILL-QUICK.md, skill.json, pyproject.toml,
scripts/graph_model.py. MCP tools: 67 -> 68 (55 static + 13 dynamic).

Verified:
- 66/66 cypher query tests pass
- 185/185 pass on focused subset (test_cypher_query + test_command_count +
  test_command_registry + test_version_consistency + test_cli + test_codelens
  + test_graph_model + test_graph_incremental), 35 skipped (optional deps)
- CLI: 'codelens query-graph --explain' produces correct SQL + params
- End-to-end: all 3 issue #9 example queries return expected results
  against test database with 6 nodes + 3 edges
@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.

@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

@Wolfvin

Wolfvin commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

Closing as duplicate — #149 has better implementation (68 tests vs 66, cleaner error handling via structured dicts, better file headers). Merge #149 instead.

@Wolfvin Wolfvin closed this Jul 3, 2026
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