Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DeusData/codebase-memory-mcp/llms.txt

Use this file to discover all available pages before exploring further.

The query_graph tool executes a read-only openCypher subset directly against the SQLite knowledge graph. It is the most powerful way to perform structural analysis — multi-hop traversals, aggregations, dead-code detection, hotspot ranking, inheritance queries, and cross-service HTTP call mapping — all in a single call that returns results in under 1ms for typical pattern queries. Anything that requires joining multiple pieces of structural information (callers + depth + file path, for instance) is best expressed as a Cypher query rather than a sequence of search_graph calls.
Run get_graph_schema first to see which node labels and edge types are present in your project. This prevents writing queries for labels or relationships that don’t exist in the current index.

Supported Clauses

MATCH

The primary pattern-matching clause. Multiple MATCH clauses in one query act as joins.
MATCH (f:Function)-[:CALLS]->(g:Function)
RETURN f.name, g.name
LIMIT 20
OPTIONAL MATCH works like a left outer join — nodes with no match are returned with null properties:
MATCH (c:Class)
OPTIONAL MATCH (c)-[:INHERITS]->(parent:Class)
RETURN c.name, parent.name

WHERE

Filter expressions support:
OperatorExample
Equality / comparisonf.name = 'main', f.line > 100
Not equalf.name <> 'test'
Boolean logicAND, OR, XOR, NOT
Set membershipf.name IN ['main', 'init']
String predicatesCONTAINS, STARTS WITH, ENDS WITH
Null checksIS NULL, IS NOT NULL
Regex matchf.name =~ '.*Handler.*'
Label testn:Function
Existence subqueryEXISTS { (f)<-[:CALLS]-() }
The EXISTS { ... } subquery supports single-hop existence patterns. It is especially useful for dead-code detection: WHERE NOT EXISTS { (f)<-[:CALLS]-() } finds functions with zero callers.

WITH

WITH pipes results between query stages and allows filtering mid-query:
MATCH (f:Function)
WITH f, size((f)<-[:CALLS]-()) AS caller_count
WHERE caller_count > 5
RETURN f.name, caller_count
ORDER BY caller_count DESC

RETURN, ORDER BY, SKIP, LIMIT, DISTINCT

Standard result control. DISTINCT deduplicates before returning:
MATCH (f:Function)-[:CALLS*1..3]->(g:Function)
RETURN DISTINCT g.name
ORDER BY g.name
SKIP 10
LIMIT 50

UNWIND

Expands a list into individual rows:
UNWIND ['ProcessOrder', 'CancelOrder'] AS fn_name
MATCH (f:Function {name: fn_name})
RETURN f.name, f.file

UNION / UNION ALL

Combine results from two queries. UNION deduplicates; UNION ALL keeps all rows:
MATCH (f:Function {name: 'ProcessOrder'})
RETURN f.name, f.file
UNION
MATCH (m:Method {name: 'ProcessOrder'})
RETURN m.name, m.file

CASE

Conditional expressions in RETURN or WITH:
MATCH (f:Function)
RETURN f.name,
  CASE
    WHEN f.cyclomatic > 10 THEN 'complex'
    WHEN f.cyclomatic > 5  THEN 'moderate'
    ELSE 'simple'
  END AS complexity_tier

Patterns

Node patterns

(n)                      -- any node
(n:Function)             -- node with label Function
(n:Function {name: 'f'}) -- node with label and property
(n:Class|Interface)      -- label alternation: Class or Interface

Relationship patterns

(a)-[:CALLS]->(b)        -- directed edge
(a)<-[:CALLS]-(b)        -- reverse direction
(a)-[:CALLS|ASYNC_CALLS]->(b)  -- type alternation
(a)-[r]->(b)             -- capture edge in variable r

Variable-length paths

(a)-[:CALLS*1..3]->(b)   -- 1 to 3 hops
(a)-[:CALLS*]->(b)       -- any number of hops (use with LIMIT)
(a)-[:CALLS*3]->(b)      -- exactly 3 hops
Unbounded variable-length paths (* with no upper limit) can be slow on large graphs. Always add a depth cap like *1..5 or combine with LIMIT.

Aggregation Functions

FunctionDescription
count(n)Count rows
count(DISTINCT n.name)Count distinct values
sum(n.line)Sum numeric property
avg(n.cyclomatic)Average
min(n.line)Minimum
max(n.line)Maximum
collect(n.name)Collect values into a list

Scalar Functions

Graph metadata

labels(n), type(r), id(n), keys(n), properties(n)

Type conversion

toLower(s), toUpper(s), toString(v), toInteger(s), toFloat(s), toBoolean(s)

String manipulation

size(s), length(s), trim(s), ltrim(s), rtrim(s), reverse(s), substring(s, start, length), replace(s, search, replacement), left(s, n), right(s, n)

Utility

coalesce(a, b, ...) — returns first non-null value

Unsupported Features

The following are not supported and will fail with a clear unsupported … error (not silent empty results):
  • Write clauses: CREATE, SET, DELETE, MERGE
  • CALL (stored procedures)
  • CALL { ... } IN TRANSACTIONS
  • List literals: [1, 2, 3]
  • Map literals: {key: value}
  • List comprehensions: [x IN list WHERE ...]
  • Path functions: shortestPath(), allShortestPaths()
  • Query parameters: $param

Example Queries

1. Find all functions calling a specific function

MATCH (caller:Function)-[:CALLS]->(f:Function {name: 'ProcessOrder'})
RETURN caller.name, caller.file

2. Dead code detection

Finds functions with zero inbound calls, excluding main and entry points:
MATCH (f:Function)
WHERE NOT EXISTS { (f)<-[:CALLS]-() }
AND NOT f.name STARTS WITH 'main'
RETURN f.name, f.file
LIMIT 20

3. Inheritance hierarchy

MATCH (c:Class)-[:INHERITS]->(parent:Class)
RETURN c.name, parent.name
ORDER BY parent.name

4. Find all HTTP routes

MATCH (r:Route)
RETURN r.name, r.file, r.method
ORDER BY r.method

5. Variable-length call traversal (depth 1–3)

MATCH (f:Function {name: 'main'})-[:CALLS*1..3]->(g:Function)
RETURN DISTINCT g.name

6. Cross-service HTTP calls

MATCH (caller:Function)-[:HTTP_CALLS]->(route:Route)
RETURN caller.name, route.name

7. Find classes implementing an interface

MATCH (c:Class)-[:IMPLEMENTS]->(i:Interface {name: 'Repository'})
RETURN c.name

8. Top 10 most-called functions (hotspots)

MATCH (f:Function)<-[:CALLS]-()
RETURN f.name, count(*) AS call_count
ORDER BY call_count DESC
LIMIT 10

9. High-complexity functions (cyclomatic > 10)

MATCH (f:Function)
WHERE f.cyclomatic > 10
RETURN f.name, f.file, f.cyclomatic
ORDER BY f.cyclomatic DESC
LIMIT 20

10. Functions with hidden O(n²) patterns

MATCH (f:Function)
WHERE f.transitive_loop_depth >= 3 OR f.linear_scan_in_loop >= 1
RETURN f.qualified_name, f.transitive_loop_depth, f.linear_scan_in_loop
ORDER BY f.transitive_loop_depth DESC

Using query_graph

Pass your Cypher string as the query parameter along with the project name:
{
  "query": "MATCH (f:Function)<-[:CALLS]-() RETURN f.name, count(*) AS call_count ORDER BY call_count DESC LIMIT 10",
  "project": "myapp"
}
From the CLI:
codebase-memory-mcp cli query_graph '{
  "query": "MATCH (f:Function)-[:CALLS]->(g:Function {name: \"ProcessOrder\"}) RETURN f.name, f.file",
  "project": "myapp"
}'
With max_rows to cap output:
codebase-memory-mcp cli query_graph '{
  "query": "MATCH (c:Class)-[:INHERITS]->(p:Class) RETURN c.name, p.name",
  "project": "myapp",
  "max_rows": 50
}'
query_graph has a hard ceiling of 100,000 rows. For broad queries, add LIMIT directly in the Cypher. For paginated browsing of large result sets, use search_graph with offset / limit instead.

Multi-Project Stores

When multiple repositories are indexed under the same store, always include the project parameter to scope your query. Omitting it will return an error. Use list_projects to find exact project names:
codebase-memory-mcp cli list_projects
Then pass the name in every query:
{
  "query": "MATCH (r:Route) RETURN r.name, r.method ORDER BY r.method",
  "project": "payments-service"
}

Build docs developers (and LLMs) love