codebase-memory-mcp-pro-knowledge-graph

v2026.09.25

Community fork of codebase-memory-mcp with incremental-reindex fixes — pure-C knowledge-graph MCP server for AI code exploration

GitHub
Install command
npx skhub add reason-machines/codebase-memory-mcp-pro-knowledge-graph
Markdown
SKILL.md

codebase-memory-mcp-pro Knowledge Graph

Skill by ara.so — MCP Skills collection.

Overview

codebase-memory-mcp-pro is a community fork of DeusData/codebase-memory-mcp that provides a pure-C knowledge graph MCP server for AI code exploration. It indexes codebases using tree-sitter AST analysis across 158 languages, building a persistent graph of functions, classes, call chains, and cross-file references.

Key improvements in this fork:

  • Incremental-reindex correctness — preserves inbound cross-file CALLS edges; editing a file no longer orphans calls into its symbols
  • Enhanced explore tool — single-call blast-radius analysis with callers, neighbors, inline hotspot flags, and line-numbered source
  • Swift type fidelity — struct/enum/actor are distinct graph labels; enum cases extracted as EnumCase nodes
  • Cypher aggregation fix — non-aggregate functions mixed with aggregates now group correctly
  • detect_changes blast radius — depth parameter produces transitive caller impact analysis

The fork ships no prebuilt binaries — you build from source to get all integrated fixes.

Installation

Build from Source

# Clone the fork
git clone https://github.com/win4r/codebase-memory-mcp-pro.git
cd codebase-memory-mcp-pro

# Build (first build compiles 158 tree-sitter grammars — takes a few minutes)
./scripts/build.sh
# → build/c/codebase-memory-mcp (reports version: dev)

# Install to PATH
cp build/c/codebase-memory-mcp ~/.local/bin/

# Add as stdio MCP server (available in all projects)
claude mcp add codebase-memory -s user -- ~/.local/bin/codebase-memory-mcp

Iterative rebuilds (much faster after first build):

make -j -f Makefile.cbm cbm

Verify Integration

Confirm the integrated fixes are live:

# Index a repository
codebase-memory-mcp cli index_repository '{"repo_path":"/path/to/repo"}'

# Test PR #465 — node properties survive WITH aggregation
codebase-memory-mcp cli query_graph '{
  "project": "<name>",
  "query": "MATCH (a)-[:CALLS]->(b) WITH b, count(a) AS c RETURN b.file_path, c LIMIT 1"
}'
# Non-empty file_path means you're running the cherry-picked build

⚠️ Do not run codebase-memory-mcp update — it pulls upstream and overwrites the integrated build. Use ./scripts/build.sh to update instead.

Core MCP Tools

The server exposes 15 MCP tools. Key tools in this fork:

explore (Fork Enhancement)

One-call blast-radius analysis — returns callers, neighbors, and line-numbered source:

// AI agent invocation
{
  "name": "explore",
  "arguments": {
    "project": "my-project",
    "symbol_name": "processOrder",
    "include_source": true,
    "max_callers": 20,
    "max_neighbors": 10
  }
}

Returns:

  • Blast radius: attributed callers + inline fan-in hotspot flags
  • Neighbors: 1-hop callees + same-file siblings
  • Source: verbatim line-numbered code grouped by file
  • Cypher escape-hatch: optional cypher_query parameter for custom graph traversal

index_repository

Build the knowledge graph:

{
  "name": "index_repository",
  "arguments": {
    "repo_path": "/path/to/repo",
    "project_name": "my-project"  // optional, defaults to dir name
  }
}

Incremental re-index (fork fix: preserves cross-file CALLS edges):

# Edit files, then re-run index_repository
# Inbound calls to edited symbols are preserved

query_graph

Execute Cypher queries against the knowledge graph:

{
  "name": "query_graph",
  "arguments": {
    "project": "my-project",
    "query": "MATCH (f:Function)-[:CALLS]->(g:Function) WHERE f.file_path =~ '.*service.*' RETURN f.name, g.name, g.file_path LIMIT 10"
  }
}

Common patterns:

// Find all callers of a function
MATCH (caller)-[:CALLS]->(target:Function)
WHERE target.name = 'processPayment'
RETURN caller.name, caller.file_path

// Functions with most callers (hotspots)
MATCH (caller)-[:CALLS]->(target)
WITH target, count(caller) AS fan_in
WHERE fan_in > 5
RETURN target.name, target.file_path, fan_in
ORDER BY fan_in DESC

// Call chain between two symbols
MATCH path = shortestPath(
  (a:Function {name: 'handleRequest'})-[:CALLS*..10]->(b:Function {name: 'saveToDatabase'})
)
RETURN [n in nodes(path) | n.name] AS call_chain

// Dead code detection (no inbound calls)
MATCH (f:Function)
WHERE NOT ()-[:CALLS]->(f)
  AND f.visibility = 'public'
RETURN f.name, f.file_path

// Swift enum cases (fork feature)
MATCH (e:Enum)-[:CONTAINS]->(case:EnumCase)
WHERE e.name = 'AppError'
RETURN case.name, case.line_start

Fork fix: Aggregations now group correctly:

// This returns one row per edge type (not collapsed into one row)
MATCH (a)-[r]->(b)
RETURN type(r), count(*) AS edge_count

detect_changes

Detect modified files and impacted symbols:

{
  "name": "detect_changes",
  "arguments": {
    "project": "my-project",
    "since": "HEAD~5",  // fork fix: honors since parameter
    "depth": 2          // fork feature: transitive caller blast radius
  }
}

Fork enhancement: depth parameter produces transitive caller blast radius:

  • impacted_symbols includes callers up to depth hops
  • Each symbol tagged with hop (0 = changed, 1+ = caller) and transitive flag
  • impacted_count deduplicated across hops

Example response:

{
  "changed_files": ["src/payment/processor.ts"],
  "impacted_symbols": [
    {
      "name": "processPayment",
      "file_path": "src/payment/processor.ts",
      "hop": 0,
      "transitive": false
    },
    {
      "name": "handleCheckout",
      "file_path": "src/checkout/handler.ts",
      "hop": 1,
      "transitive": true
    },
    {
      "name": "completeOrder",
      "file_path": "src/order/service.ts",
      "hop": 2,
      "transitive": true
    }
  ],
  "impacted_count": 12
}

trace_path

Find call paths between two symbols:

{
  "name": "trace_path",
  "arguments": {
    "project": "my-project",
    "from_symbol": "handleRequest",
    "to_symbol": "saveToDatabase",
    "max_depth": 10
  }
}

get_code_snippet

Retrieve source code with line numbers:

{
  "name": "get_code_snippet",
  "arguments": {
    "project": "my-project",
    "file_path": "src/utils/validator.ts",
    "start_line": 45,
    "end_line": 60
  }
}

Fork fix: Returns valid UTF-8 (handles non-UTF-8 source files gracefully).

Swift Enhancements (Fork)

Distinct Type Labels

Stock upstream lumps Swift struct/enum/actor as Class. This fork emits distinct labels:

// Find all Swift structs
MATCH (s:Struct)
WHERE s.file_path =~ '.*\\.swift$'
RETURN s.name, s.file_path

// Find all actors
MATCH (a:Actor)
RETURN a.name

// Enum with cases
MATCH (e:Enum)-[:CONTAINS]->(case:EnumCase)
WHERE e.name = 'NetworkError'
RETURN case.name

Enum Case Extraction

Enum cases (including multi-name case a, b, c lines) are extracted as EnumCase nodes:

// Source
enum Status {
    case pending, processing  // Multi-name case
    case completed(Date)
    case failed(Error)
}
// Query
MATCH (e:Enum {name: 'Status'})-[:CONTAINS]->(case:EnumCase)
RETURN case.name
// Returns: pending, processing, completed, failed

Static Method Dedup Fix

Fork fix: An enum's static func is no longer double-emitted as both Method and Function nodes.

CLI Usage

The binary supports both MCP stdio mode (for agents) and direct CLI invocation:

# MCP stdio mode (agent communication)
codebase-memory-mcp

# Direct CLI tool invocation
codebase-memory-mcp cli <tool_name> '<json_args>'

# Examples
codebase-memory-mcp cli index_repository '{"repo_path": "/path/to/repo"}'

codebase-memory-mcp cli query_graph '{
  "project": "my-project",
  "query": "MATCH (f:Function) RETURN f.name LIMIT 5"
}'

codebase-memory-mcp cli explore '{
  "project": "my-project",
  "symbol_name": "parseConfig",
  "include_source": true
}'

Configuration

MCP Server Configuration

Add to ~/.config/claude/claude_desktop_config.json (or agent-specific config):

{
  "mcpServers": {
    "codebase-memory": {
      "command": "/home/user/.local/bin/codebase-memory-mcp",
      "args": [],
      "env": {}
    }
  }
}

Environment Variables

# Optional: custom database location
export CBM_DB_PATH=/path/to/custom/db

# Optional: log level (debug, info, warn, error)
export CBM_LOG_LEVEL=info

Project-Specific Configuration

Create .codebase-memory.json in repository root:

{
  "exclude_paths": [
    "node_modules",
    "vendor",
    "build",
    "dist",
    ".git",
    "*.test.ts"
  ],
  "include_extensions": [
    ".ts", ".tsx", ".js", ".jsx",
    ".py", ".go", ".rs", ".c", ".cpp", ".swift"
  ],
  "max_file_size_kb": 1024
}

Real-World Patterns

Pattern 1: Impact Analysis Before Refactoring

// 1. Find the function
const exploreResult = await explore({
  project: "my-api",
  symbol_name: "validateUser",
  include_source: true,
  max_callers: 50
});

// 2. Check blast radius
const callerCount = exploreResult.callers.length;
const hasHighFanIn = callerCount > 10;

// 3. Query transitive impact
const impactResult = await query_graph({
  project: "my-api",
  query: `
    MATCH (caller)-[:CALLS*1..3]->(target:Function)
    WHERE target.name = 'validateUser'
    RETURN DISTINCT caller.name, caller.file_path
  `
});

// 4. Make informed decision
if (hasHighFanIn) {
  // High-risk refactor: write comprehensive tests first
} else {
  // Low-risk: proceed with confidence
}

Pattern 2: Dead Code Detection

// Find public functions with no callers
const deadCode = await query_graph({
  project: "my-api",
  query: `
    MATCH (f:Function)
    WHERE NOT ()-[:CALLS]->(f)
      AND f.visibility = 'public'
      AND f.file_path =~ '.*src/.*'
    RETURN f.name, f.file_path, f.line_start
    ORDER BY f.file_path
  `
});

// Cross-reference with exports
const exports = await query_graph({
  project: "my-api",
  query: `
    MATCH (m:Module)-[:EXPORTS]->(f)
    RETURN f.name, m.file_path
  `
});

// Candidates for deletion: deadCode NOT IN exports

Pattern 3: Incremental Re-index Workflow

#!/bin/bash
# safe-refactor.sh

# 1. Index current state
codebase-memory-mcp cli index_repository '{"repo_path": "."}'

# 2. Snapshot call graph
codebase-memory-mcp cli query_graph '{
  "project": "my-api",
  "query": "MATCH (a)-[:CALLS]->(b {name: \"targetFunc\"}) RETURN a.name, a.file_path"
}' > before.json

# 3. Make changes
vim src/core/target.ts

# 4. Re-index (fork: preserves inbound CALLS edges)
codebase-memory-mcp cli index_repository '{"repo_path": "."}'

# 5. Verify call graph integrity
codebase-memory-mcp cli query_graph '{
  "project": "my-api",
  "query": "MATCH (a)-[:CALLS]->(b {name: \"targetFunc\"}) RETURN a.name, a.file_path"
}' > after.json

# 6. Compare
diff before.json after.json

Pattern 4: Architecture Documentation

// Generate module dependency graph
const modules = await query_graph({
  project: "my-api",
  query: `
    MATCH (m1:Module)-[:IMPORTS]->(m2:Module)
    RETURN m1.file_path AS from, m2.file_path AS to
  `
});

// Detect circular dependencies
const cycles = await query_graph({
  project: "my-api",
  query: `
    MATCH path = (m:Module)-[:IMPORTS*2..10]->(m)
    RETURN [n in nodes(path) | n.file_path] AS cycle
    LIMIT 10
  `
});

// Find architectural layers (no upward imports)
const layers = await query_graph({
  project: "my-api",
  query: `
    MATCH (m:Module)
    WHERE m.file_path =~ '.*/domain/.*'
      AND NOT (m)-[:IMPORTS]->(:Module {file_path: ~'.*/infrastructure/.*'})
    RETURN m.file_path AS clean_domain_module
  `
});

Troubleshooting

Issue: "No such project"

Cause: Project not indexed or wrong name.

# List indexed projects
codebase-memory-mcp cli query_graph '{
  "project": "any",
  "query": "MATCH (p:Project) RETURN p.name"
}'

# Re-index with explicit name
codebase-memory-mcp cli index_repository '{
  "repo_path": "/path/to/repo",
  "project_name": "exact-name"
}'

Issue: Incremental re-index loses edges (upstream bug)

Solution: You're running stock upstream, not the fork. Rebuild from source:

cd codebase-memory-mcp-pro
./scripts/build.sh
cp build/c/codebase-memory-mcp ~/.local/bin/

Verify integration:

codebase-memory-mcp cli query_graph '{
  "project": "test",
  "query": "MATCH (a)-[:CALLS]->(b) WITH b, count(a) AS c RETURN b.file_path, c LIMIT 1"
}'
# Non-empty file_path = fork build

Issue: Cypher query returns unexpected single row

Cause: Aggregation bug in upstream (fixed in fork).

// This should return one row per edge type
MATCH (a)-[r]->(b)
RETURN type(r), count(*)
// Upstream: collapses into single row
// Fork: groups correctly by type(r)

Rebuild from fork source if you're seeing this.

Issue: Swift enums/structs labeled as Class

Solution: Fork emits distinct labels. Query with specific types:

// Fork
MATCH (s:Struct) RETURN s.name

// Upstream workaround (not recommended)
MATCH (s:Class)
WHERE s.kind = 'struct'  // Property may not exist
RETURN s.name

Issue: Build fails on macOS with libgit2 ≥ 1.8

Solution: Already fixed in fork (PR #512 integrated). If still failing:

brew info libgit2  # Check version
# Ensure you're building from fork, not upstream
git remote -v  # Should show win4r/codebase-memory-mcp-pro
./scripts/build.sh

Issue: UTF-8 errors in get_code_snippet

Solution: Fixed in fork (PR #526). Rebuild from source.

Issue: detect_changes ignores since parameter

Solution: Fixed in fork (PR #464). Rebuild from source.

Advanced: Custom Cypher Patterns

Find HTTP Route Handlers

MATCH (route:Route)-[:HANDLED_BY]->(handler:Function)
WHERE route.method = 'POST'
RETURN route.path, handler.name, handler.file_path
ORDER BY route.path

Cross-Service Call Analysis

MATCH (caller:Function)-[:HTTP_CALL]->(route:Route)
WHERE caller.file_path =~ '.*service-a/.*'
  AND route.service = 'service-b'
RETURN caller.name, route.path, route.method

Complexity Analysis

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

Ownership Mapping (by directory)

MATCH (f:Function)
WITH split(f.file_path, '/')[0..3] AS module, count(f) AS function_count
RETURN module, function_count
ORDER BY function_count DESC

Integration with AI Agents

Claude Code / Cursor

// ~/.config/claude/claude_desktop_config.json
{
  "mcpServers": {
    "codebase-memory": {
      "command": "/home/user/.local/bin/codebase-memory-mcp"
    }
  }
}

Aider

# .aider.conf.yml
mcp:
  servers:
    - name: codebase-memory
      command: /home/user/.local/bin/codebase-memory-mcp

Generic MCP Client

import { MCPClient } from '@modelcontextprotocol/sdk';

const client = new MCPClient({
  command: '/home/user/.local/bin/codebase-memory-mcp',
  args: []
});

await client.connect();

const result = await client.callTool('explore', {
  project: 'my-api',
  symbol_name: 'processOrder'
});

console.log(result);

Performance Notes

  • Linux kernel (28M LOC, 75K files): 3 minutes to index
  • Average repository: milliseconds
  • Graph queries: <1ms for simple patterns, <100ms for complex traversals
  • Memory: RAM-first pipeline with LZ4 compression; memory released after indexing

Contributing to the Fork

This is a community fork tracking upstream. To contribute:

  1. Upstream PRs first: Submit fixes to DeusData/codebase-memory-mcp
  2. Fork-specific enhancements: Submit PRs to win4r/codebase-memory-mcp-pro
  3. Integration requests: Open an issue if an upstream PR should be cherry-picked into the fork

License

MIT License (unchanged from upstream). See LICENSE.

All credit for the original engine: DeusData. This fork exists to integrate fixes faster than upstream merge cycles.

Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.25

Published

Sep 25, 2026

Category

Uncategorized

License

NOASSERTION

Source path

skills/codebase-memory-mcp-pro-knowledge-graph

Default branch

main

Latest commit

329e67c

Tree SHA

01fd22f