# How to Query Graph Data Directly from the Store Module in Codebase-Memory-MCP

> Query graph data directly from the store module in Codebase-Memory-MCP using the low-level C API. Access node lookup, edge traversal, BFS, and full-text search.

- Repository: [Martin Vogel/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)
- Tags: how-to-guide
- Published: 2026-07-05

---

**Yes, you can query graph data directly from the store module using the low-level C API exposed in [`src/store/store.h`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/store/store.h) and [`src/store/store.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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 using `cbm_search_params_t` for 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.

```c
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:

```c
/* 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:

```c
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:

```c
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, &params, &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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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.h`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/store/store.h) without requiring RPC or UI layers.
- Use **`cbm_store_open_path_query`** for 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_bfs`** enables efficient depth-bounded graph traversal via optimized SQLite queries.
- **`cbm_store_search`** supports 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.