How the Cypher Query Engine Works in codebase-memory-mcp: OpenCypher Support Explained

The Cypher query engine in codebase-memory-mcp is a read-only interpreter that translates a subset of OpenCypher into SQLite SQL, executing it against the internal knowledge-graph store through a four-stage pipeline of lexing, parsing, planning, and execution.

The cypher query engine provides a lightweight, self-contained query layer for the cbm_store knowledge graph in the DeusData/codebase-memory-mcp repository. Unlike full Neo4j implementations, this engine deliberately restricts operations to read-only graph analysis, converting pattern matching and aggregation expressions into executable SQL statements.

Four-Stage Query Processing Pipeline

The engine processes queries through a strict pipeline implemented primarily in src/cypher/cypher.c.

Lexer: Tokenizing the Input

The lexer scans input strings and produces a token stream containing identifiers, literals, operators, and punctuation. It handles string escaping, numeric literals, comments, and two-character tokens such as !=, <=, and ...

Key implementation resides in src/cypher/cypher.c at lines 68-124.

Parser: Building the Abstract Syntax Tree

A recursive-descent parser constructs an abstract syntax tree (AST) for MATCH patterns, WHERE clauses, and RETURN specifications. The parser detects unsupported clauses early and validates syntax against the read-only subset.

Implementation spans lines 329-782 in src/cypher/cypher.c.

Planner: Generating SQL

The planner walks the AST and produces equivalent SQL SELECT statements. It maps node variables to columns (name, qn, label, file) and edge variables to columns (name, qn, label), generating necessary joins and filters for the SQLite backend.

Executor: Running Against SQLite

The executor sends generated SQL to the SQLite-backed cbm_store via cbm_exec_query in src/store/store.c, returning result sets to the caller.

Supported OpenCypher Features

The cypher query engine supports a practical read-only subset of OpenCypher optimized for code analysis.

MATCH Patterns

  • Node syntax: (n:Label) with optional variable names
  • Relationship syntax: -[:TYPE*min..max]-> with hop ranges
  • Label alternation: :A|B|C parsed as pipe-separated lists (stored as "A|B|C" and split during matching; see parse_node() around line 560)
  • Hop ranges: *2..5 for specific depths; * alone translates to 1..0 (where 0 signals no upper bound)

Example:

const char *cypher = "MATCH (n:Class|Interface)-[:CALLS*1..3]->(m) "
                     "WHERE n.name CONTAINS \"Get\" "
                     "RETURN n.name, COUNT(m) AS calls "
                     "ORDER BY calls DESC LIMIT 10";

WHERE Filters

Supported operators include:

  • Logical: AND, OR, XOR, NOT
  • Comparison: =, <>, >, <, >=, <=
  • String: CONTAINS, STARTS WITH, ENDS WITH
  • Null checking: IS NULL, IS NOT NULL
  • List membership: IN
  • Label tests: n:Label

RETURN Clause

Supports scalar expressions, aggregate functions (COUNT, SUM, AVG, MIN, MAX, COLLECT), DISTINCT, and string functions (toLower, toUpper, toString). Multi-argument scalar functions include coalesce, substring, replace, left, and right.

Function handling distinguishes three groups via is_aggregate_tok(), is_string_func_tok(), and is_multiarg_func_call() around lines 1292-1302.

Ordering and Pagination

Full support for ORDER BY ... ASC|DESC, SKIP, and LIMIT.

EXISTS Predicate

Limited to single-hop patterns: (var)-[:TYPE]->().

Example:

const char *cypher2 = "MATCH (e) "
                      "WHERE EXISTS { (e)-[:EXTENDS]->() } "
                      "RETURN e.name, "
                      "       CASE WHEN e.is_public THEN \"public\" ELSE \"private\" END AS visibility, "
                      "       toUpper(e.name) AS upper_name";

Property Access and CASE Expressions

Standard node.prop syntax for stored properties and simple CASE ... END expressions.

Variable Limits

Hard-coded constants in src/foundation/limits.h define CYP_MAX_VARS = 16 for node variables and 8 edge variables maximum per query.

Explicitly Unsupported Features

The engine rejects write and schema-altering operations through unsupported_clause_error() (lines 815-838 in src/cypher/cypher.c):

  • CREATE, DELETE, DETACH, SET, REMOVE, MERGE
  • YIELD, CALL (stored procedures)
  • FOREACH, MANDATORY MATCH
  • DROP, CONSTRAINT

These generate clear error messages such as "unsupported Cypher feature: CREATE clause (write operations not supported)".

Architectural Implementation Details

The expression tree (cbm_expr_t) is built recursively in src/cypher/cypher.c, allowing straightforward evaluation or SQL translation. Label alternation is stored as a single string "A|B|C" and split during pattern matching.

The engine maintains strict boundaries through constants defined in src/foundation/limits.h, ensuring predictable memory usage during query processing.

Practical Code Examples

Multi-hop analysis with label alternation:

const char *cypher = "MATCH (n:Class|Interface)-[:CALLS*1..3]->(m) "
                     "WHERE n.name CONTAINS \"Get\" "
                     "RETURN n.name, COUNT(m) AS calls "
                     "ORDER BY calls DESC LIMIT 10";

Using scalar functions and CASE expressions:

const char *cypher2 = "MATCH (e) "
                      "WHERE EXISTS { (e)-[:EXTENDS]->() } "
                      "RETURN e.name, "
                      "       CASE WHEN e.is_public THEN \"public\" ELSE \"private\" END AS visibility, "
                      "       toUpper(e.name) AS upper_name";

Filtering with IN lists and IS NULL:

const char *cypher3 = "MATCH (c) "
                      "WHERE c.type IN [\"class\", \"enum\"] AND c.deprecated IS NULL "
                      "RETURN c.name, c.type";

Key Source Files

File Role
src/cypher/cypher.h Public API for lexing, parsing, and execution
src/cypher/cypher.c Full lexer, parser, AST construction, and query planning
src/store/store.c SQLite-backed store receiving generated SQL via cbm_exec_query
src/foundation/limits.h Engine constants including CYP_MAX_VARS
src/cli/cli.c CLI wrapper exposing the query_graph command

Summary

  • The cypher query engine implements a four-stage pipeline: lexer, parser, planner, and executor.
  • It translates OpenCypher into SQLite SQL for read-only graph queries against cbm_store.
  • Supports MATCH patterns with label alternation and hop ranges, WHERE filters, RETURN with aggregates, and ORDER BY/LIMIT.
  • Explicitly blocks all write operations (CREATE, DELETE, SET, etc.) via unsupported_clause_error().
  • Hard limits include 16 node variables and 8 edge variables per query.
  • Core implementation resides in src/cypher/cypher.c with storage delegation to src/store/store.c.

Frequently Asked Questions

Does the codebase-memory-mcp Cypher engine support write operations?

No. The engine is explicitly read-only and rejects CREATE, DELETE, SET, REMOVE, MERGE, and DETACH clauses. The unsupported_clause_error() function in src/cypher/cypher.c (lines 815-838) detects these constructs and returns clear error messages indicating that write operations are not supported.

What is the maximum depth for relationship hop ranges?

The engine supports arbitrary hop ranges using syntax like *2..5. The unbounded * operator translates to 1..0 internally, where 0 signals no upper bound. However, practical limits depend on the underlying SQLite performance and the cbm_store indexing.

How does the engine handle multiple labels in MATCH patterns?

Label alternation such as :Class|Interface is parsed into a single pipe-separated string (e.g., "Class|Interface") and stored as such. During execution, this string is split and evaluated as a label test. This implementation is found in parse_node() around line 560 of src/cypher/cypher.c.

Which aggregate functions are available in RETURN clauses?

The engine supports COUNT, SUM, AVG, MIN, MAX, and COLLECT. These are identified by is_aggregate_tok() around line 1292 in src/cypher/cypher.c, alongside string functions like toLower and toUpper, and multi-argument functions such as coalesce and substring.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →