Graph Data Model in Codebase-Memory-MCP: Node Labels and Edge Types Explained
Codebase-Memory-MCP represents source code as a property graph where typed nodes represent code entities (functions, classes, variables) and typed edges represent relationships (calls, inherits, references), defined in TypeScript interfaces for visualization and analysis.
Codebase-Memory-MCP transforms your source code repository into a navigable graph structure that powers its web-based visualization interface. Understanding this graph data model is essential for developers who want to extend the tool, build custom queries, or integrate the MCP server with other systems. The model is formally defined in graph-ui/src/lib/types.ts and implemented by the Python backend indexing engine.
Core Components of the Graph Data Model
The graph data model consists of three primary TypeScript interfaces that define how code entities and their relationships are structured, aggregated, and transported.
GraphNode Structure and Node Labels
The GraphNode interface, defined at lines 3-16 in graph-ui/src/lib/types.ts, represents a concrete code entity with both semantic and visual properties.
Each node includes:
- Positional data:
x,y, andzcoordinates for 3D graph layout - Entity metadata:
name,qualified_name,file_path,start_line, andend_line - Visual attributes:
color,size, andstatus(using theNodeStatustype) - Analytics:
in_callscount tracking incoming references
The label field (line 8) encodes the entity type as a string, enabling the UI to color-code nodes and display human-readable badges. Valid node labels include:
functionclassmoduleenumvariabletype_aliasimport
GraphEdge Structure and Relationship Types
The GraphEdge interface, defined at lines 39-44 in graph-ui/src/lib/types.ts, connects two nodes via directed relationships.
Each edge contains:
source: The ID of the originating nodetarget: The ID of the destination nodetype: A string specifying the relationship kind (line 42)
Valid edge types include:
calls– Function invocationsreferences– Variable or symbol usageinherits– Class inheritance relationshipscontains– Parent-child containment (e.g., methods within a class)exports– Module export relationshipsimports– Import dependencies
The UI uses the type field to render different line styles and colors for each relationship category.
SchemaInfo and GraphData Containers
Two additional interfaces manage graph metadata and transport:
SchemaInfo (lines 76-80) provides aggregated statistics about the graph composition:
node_labels: Array of objects tallying count per label typeedge_types: Array of objects tallying count per relationship typetotal_nodesandtotal_edges: Aggregate counts
GraphData (lines 62-68) serves as the top-level payload sent to the frontend:
nodes: Array ofGraphNodeobjectsedges: Array ofGraphEdgeobjectstotal_nodes: Count for pagination and progress tracking- Optional
linked_projectsandmissed_graphsections for multi-project views
Backend Implementation and Data Flow
The Python backend implements this graph data model through a multi-stage pipeline:
-
AST Extraction: The backend walks the abstract syntax tree of each indexed file, creating a
GraphNodefor every discovered entity. -
Relationship Mapping: For each detected relationship (e.g., a function calling another function), the backend emits a
GraphEdgewith the appropriatetypestring. -
Schema Aggregation: During indexing, the system builds a
SchemaInfoobject that tallies node labels and edge types for statistical reporting. -
Serialization: All nodes, edges, and schema information serialize as JSON conforming to the
GraphDatainterface. -
Transport: The data travels via the RPC endpoint
/api/graphto the frontend. -
Rendering: The
useGraphDatahook (located ingraph-ui/src/hooks/useGraphData.ts) consumes the payload, rendering nodes at their coordinates and styling connections according to theirtype.
The CLI entry point in pkg/pypi/src/codebase_memory_mcp/_cli.py drives this indexing process, while pkg/pypi/src/codebase_memory_mcp/graph_builder.py contains the core logic for AST traversal and graph construction.
Practical Code Examples
The following TypeScript examples demonstrate how to construct valid graph data structures conforming to the model:
// Building a minimal graph with two functions and a call relationship
import {
GraphNode,
GraphEdge,
GraphData,
NodeStatus,
} from "./lib/types";
const fnA: GraphNode = {
id: 1,
x: 0,
y: 0,
z: 0,
label: "function",
name: "foo",
file_path: "src/foo.py",
qualified_name: "module.foo",
start_line: 10,
end_line: 14,
size: 5,
color: "#ffcc00",
status: "normal",
in_calls: 0,
};
const fnB: GraphNode = {
id: 2,
x: 200,
y: 0,
z: 0,
label: "function",
name: "bar",
file_path: "src/bar.py",
qualified_name: "module.bar",
start_line: 20,
end_line: 25,
size: 6,
color: "#66ccff",
status: "normal",
in_calls: 1,
};
const callEdge: GraphEdge = {
source: fnA.id, // foo calls bar
target: fnB.id,
type: "calls",
};
const graph: GraphData = {
nodes: [fnA, fnB],
edges: [callEdge],
total_nodes: 2,
};
// Consuming schema statistics returned by the backend
interface SchemaInfo {
node_labels: { label: string; count: number }[];
edge_types: { type: string; count: number }[];
total_nodes: number;
total_edges: number;
}
const schema: SchemaInfo = {
node_labels: [
{ label: "function", count: 342 },
{ label: "class", count: 87 },
{ label: "module", count: 12 },
],
edge_types: [
{ type: "calls", count: 590 },
{ type: "inherits", count: 73 },
{ type: "references", count: 210 },
],
total_nodes: 441,
total_edges: 873,
};
Summary
- GraphNode entities carry positional coordinates, metadata, and a
labelfield identifying the code entity type (function, class, variable, etc.). - GraphEdge connections specify relationship semantics through the
typefield (calls, inherits, references, etc.). - SchemaInfo aggregates node and edge statistics for UI dashboards and filtering controls.
- The GraphData interface serves as the canonical transport format between the Python backend and TypeScript frontend.
- All type definitions reside in
graph-ui/src/lib/types.ts, with line-specific references toGraphNode(3-16),GraphEdge(39-44),GraphData(62-68), andSchemaInfo(76-80).
Frequently Asked Questions
What are the valid node labels in Codebase-Memory-MCP?
According to the GraphNode interface in graph-ui/src/lib/types.ts, the label field accepts strings identifying code entity types. Common values include function, class, module, enum, variable, type_alias, and import. The UI uses these labels to apply color-coding and display badges for each node.
How does the backend determine edge types?
The Python backend analyzes AST relationships during indexing. When it detects a function call, it creates a GraphEdge with type: "calls"; for inheritance relationships, it uses type: "inherits"; for variable usage, type: "references". These type strings are defined at line 42 of the types file and consumed by the frontend to style connection lines.
What is the purpose of SchemaInfo?
SchemaInfo provides a statistical summary of the entire graph, defined at lines 76-80 in graph-ui/src/lib/types.ts. It counts occurrences of each node label and edge type, enabling the web UI to display distribution charts, filtering options, and project health metrics without loading the full node list.
How is graph data transported between backend and frontend?
The backend serializes nodes and edges into JSON conforming to the GraphData interface (lines 62-68). This payload includes the complete nodes and edges arrays plus a SchemaInfo object. The data travels via the /api/graph RPC endpoint and is consumed by the useGraphData React hook in the frontend for rendering.
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 →