How to Query Graph Data Directly from the Store Module in Codebase-Memory-MCP
Yes, you can query graph data directly from the store module using the low-level C API exposed in src/store/store.h, which provides functions for node lookup, edge traversal, BFS searches, and full-text search without requiring higher-level RPC or UI layers.
The store module in Codebase-Memory-MCP serves as the foundational SQLite-backed interface for all graph operations. Located in src/store/store.h and src/store/store.c, this module exposes a comprehensive query surface that allows direct C-level access to the knowledge graph. You can bypass higher-level abstractions and execute efficient read-only queries against the underlying database.
Core Query API Overview
The store module organizes its query capabilities into distinct categories for nodes, edges, traversal, and vector search. All functions operate directly on the SQLite database and return dynamically allocated results that require explicit memory management.
Node Lookup Functions
You can locate nodes using multiple identifier strategies:
cbm_store_find_node_by_id– Fetch a node by its internal SQLite row ID.cbm_store_find_node_by_qn– Find a node by project and qualified name (QN).cbm_store_find_nodes_by_name– Exact-match name lookup scoped to a project.cbm_store_find_nodes_by_label– Return all nodes of a given label (e.g., "Function").cbm_store_find_nodes_by_file– Locate nodes defined in a specific file path.cbm_store_find_nodes_by_file_overlap– Get nodes overlapping a specific line range (useful for "jump to definition").cbm_store_find_nodes_by_qn_suffix– Find nodes whose qualified name ends with a specific suffix.
Edge Lookup and Traversal
For relationship analysis, the module provides targeted edge retrieval:
cbm_store_find_edges_by_source– Retrieve all outgoing edges from a node.cbm_store_find_edges_by_target– Retrieve all incoming edges to a node.cbm_store_find_edges_by_source_type– Filter outgoing edges by type (e.g., "CALLS").cbm_store_find_edges_by_type– Return all edges of a given type within a project.cbm_store_bfs– Execute a breadth-first search from a start node with depth limits, direction controls, and edge-type filters.
Advanced Search and Vector Similarity
Beyond exact lookups, the store supports complex search patterns:
cbm_store_search– Full-text and property search across nodes and edges usingcbm_search_params_tfor regex patterns, file globs, and degree filtering.cbm_store_vector_search– Cosine-similarity based nearest-neighbor lookup on stored AI vectors.
Practical Usage Examples
Opening a Read-Only Store
Always use cbm_store_open_path_query to ensure the database remains immutable during queries. This function guarantees that the underlying SQLite connection is opened in read-only mode.
cbm_store_t *store = cbm_store_open_path_query("/path/to/project.db");
if (!store) {
fprintf(stderr, "Unable to open store: %s\n", cbm_store_error(NULL));
exit(1);
}
Finding Nodes and Traversing Edges
This workflow demonstrates looking up a node by qualified name and retrieving its outgoing "CALLS" relationships:
/* Find node by qualified name */
cbm_node_t node;
int rc = cbm_store_find_node_by_qn(store, "myproject", "my_pkg.MyClass.my_method", &node);
if (rc == CBM_STORE_OK) {
printf("Node ID: %" PRId64 "\n", node.id);
}
/* Retrieve outgoing CALLS edges */
cbm_edge_t *edges = NULL;
int edge_cnt = 0;
rc = cbm_store_find_edges_by_source_type(store, node.id, "CALLS", &edges, &edge_cnt);
if (rc == CBM_STORE_OK) {
for (int i = 0; i < edge_cnt; ++i) {
printf("Calls %s (edge ID %" PRId64 ")\n", edges[i].target_id, edges[i].source_id);
}
cbm_store_free_edges(edges, edge_cnt);
}
Executing Breadth-First Search
Use cbm_store_bfs for efficient graph traversal without manual recursion:
cbm_traverse_result_t bfs;
rc = cbm_store_bfs(store, node.id, "outbound",
(const char *[]) { "CALLS" }, 1,
3, /* max depth */
100, /* max results */
&bfs);
if (rc == CBM_STORE_OK) {
printf("BFS visited %d nodes.\n", bfs.visited_count);
cbm_store_traverse_free(&bfs);
}
Using the Advanced Search API
The search function automatically builds SQLite predicates from regex and glob hints:
cbm_search_params_t params = {
.project = "myproject",
.label = "Function",
.name_pattern = ".*Handler$", /* regex on name */
.file_pattern = "*.go", /* glob on file_path */
.relationship = "CALLS",
.direction = "outbound",
.min_degree = 2,
.limit = 20,
.case_sensitive = false,
.exclude_labels = (const char*[]) { "Test", NULL },
};
cbm_search_output_t out;
int rc = cbm_store_search(store, ¶ms, &out);
if (rc == CBM_STORE_OK) {
for (int i = 0; i < out.count; ++i) {
printf("%s (%s) – in:%d out:%d\n",
out.results[i].node.name,
out.results[i].node.qualified_name,
out.results[i].in_degree,
out.results[i].out_degree);
}
cbm_store_search_free(&out);
}
Memory Management Requirements
All "find" functions in src/store/store.h return dynamically allocated arrays. You must free these buffers using the corresponding helper functions to avoid memory leaks:
cbm_store_free_nodes– Release arrays returned by node lookup functions.cbm_store_free_edges– Release edge arrays.cbm_store_traverse_free– Release BFS traversal results.cbm_store_search_free– Release search output structures.
Always pair query calls with their respective free functions before closing the store connection.
Summary
- The store module provides direct C-level access to graph data through
src/store/store.hwithout requiring RPC or UI layers. - Use
cbm_store_open_path_queryfor safe read-only database access. - Query functions cover node lookup (by ID, name, label, file), edge retrieval (by source, target, type), and complex search patterns.
cbm_store_bfsenables efficient depth-bounded graph traversal via optimized SQLite queries.cbm_store_searchsupports regex, glob patterns, and degree filtering for advanced discovery.- Always free allocated memory using the appropriate
cbm_store_free_*helper functions after processing results.
Frequently Asked Questions
Is the store module thread-safe for direct queries?
The store module uses SQLite as its backend, so thread safety depends on SQLite's configuration and the specific build options used in Codebase-Memory-MCP. For concurrent access, use separate cbm_store_t handles per thread or ensure proper SQLite serialization mode is enabled in the connection.
How do I perform a read-only query without modifying the database?
Always invoke cbm_store_open_path_query instead of the general open function. This guarantees the underlying SQLite connection is opened in read-only mode, preventing any accidental writes to the knowledge graph while querying.
What is the difference between cbm_store_find_node_by_qn and cbm_store_find_nodes_by_name?
cbm_store_find_node_by_qn searches for a single node using its fully qualified name (e.g., "my_pkg.MyClass.method") within a specific project, while cbm_store_find_nodes_by_name performs an exact-match search on the short name only (e.g., "method") and returns all matching nodes across the project scope.
Do I need to manually free memory after calling query functions?
Yes, all query functions return dynamically allocated arrays that you must free explicitly. Use cbm_store_free_nodes for node arrays, cbm_store_free_edges for edge arrays, and cbm_store_search_free for search results to prevent memory leaks.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →