How to Extend Codebase Memory MCP: A Complete Customization Guide

To extend codebase memory MCP, you can add new Tree-sitter grammars for language support, register new JSON-RPC tools in the C source, configure custom file extensions in JSON configs, or create custom extraction passes for specialized analysis.

The DeusData/codebase-memory-mcp repository provides a static-analysis engine that builds a knowledge graph from your repository using vendored Tree-sitter grammars and a C-based indexing pipeline. Extending this Model Context Protocol (MCP) server allows you to parse additional languages, expose custom tools to AI agents, or extract specialized code relationships beyond the default call graphs and imports.

Extend Codebase Memory MCP by Adding New Language Support

Adding support for a new programming language requires implementing a Tree-sitter grammar and registering it within the core engine.

Creating the Grammar File

Start by copying an existing grammar as a template. Create a new C file under internal/cbm/ that wraps your Tree-sitter parser:

// internal/cbm/grammar_mydsl.c
#include "tree_sitter/api.h"
#include "cbm.h"

extern const TSLanguage *tree_sitter_mydsl(void);

const CBMGrammar grammar_mydsl = {
    .name = "mydsl",
    .language = tree_sitter_mydsl(),
    .file_exts = { ".mydsl", NULL },
};

Reference the existing grammar_python.c and other grammar files in internal/cbm/ for the complete implementation pattern.

Registering the Grammar in cbm.c

Add your grammar to the master list in internal/cbm/cbm.c where the cbm_load_grammars function iterates over the array:

// internal/cbm/cbm.c
extern const CBMGrammar grammar_mydsl;

static const CBMGrammar *all_grammars[] = {
    &grammar_c, 
    &grammar_cpp, 
    &grammar_python,
    &grammar_mydsl, 
    NULL
};

Updating the Build Script

Ensure the new source file is compiled by modifying scripts/build.sh:


# Add grammar_mydsl.c to the $GRAMMAR_SRCS variable

GRAMMAR_SRCS="$GRAMMAR_SRCS internal/cbm/grammar_mydsl.c"

The build script typically pulls all grammar_*.c files automatically, but manual addition ensures your custom location is included.

Testing Your New Language

Re-compile the binary using scripts/build.sh, then verify the new language is indexed:


# Create a test file

echo "foo = 1" > example.mydsl

# Index the repository

codebase-memory-mcp index_repository --repo-path .

# Verify in the graph

codebase-memory-mcp query_graph --project example \
  --query "MATCH (f:File) WHERE f.name ENDS WITH '.mydsl' RETURN f.name"

How to Add New MCP Tools to Codebase Memory

Custom tools expose new JSON-RPC methods that AI agents can invoke to query your codebase.

Defining the Tool Schema

Document your tool's interface in docs/TOOL_SPEC.md or a new specification file:

{
  "name": "list_deprecated_functions",
  "description": "Returns functions marked with @deprecated",
  "params": { "project": "string" },
  "result": { "functions": ["string"] }
}

Implementing the Handler Function

Implement the logic in internal/cbm/cbm.c by querying the SQLite-backed graph directly:

static YYJSON_VAL *handle_list_deprecated_functions(CBMServer *srv,
                                                     YYJSON_VAL *args) {
    const char *project = yyjson_obj_get_str(args, "project");
    sqlite3_stmt *stmt;
    const char *sql = "SELECT name FROM Function WHERE deprecated = 1 "
                     "AND project = ?";
    
    sqlite3_prepare_v2(srv->db, sql, -1, &stmt, NULL);
    sqlite3_bind_text(stmt, 1, project, -1, SQLITE_STATIC);
    
    YYJSON_VAL *arr = yyjson_arr_new(srv->arena);
    while (sqlite3_step(stmt) == SQLITE_ROW) {
        const char *name = (const char *)sqlite3_column_text(stmt, 0);
        yyjson_arr_add_str(arr, name);
    }
    sqlite3_finalize(stmt);
    
    return yyjson_obj_new(srv->arena, "functions", arr);
}

Reference existing handlers like handle_get_architecture in the same file for the complete pattern.

Registering the Tool in the Tool Table

Add your handler to the cbm_tools array:

static const CBMTool cbm_tools[] = {
    { "get_architecture", handle_get_architecture },
    { "list_deprecated_functions", handle_list_deprecated_functions },
    { NULL, NULL }
};

Adding CLI Support

Optionally expose the tool via command line by updating scripts/cli.c:

else if (strcmp(tool, "list_deprecated_functions") == 0) {
    printf("%s\n", run_cli_tool("list_deprecated_functions", args_json));
}

After rebuilding, invoke the tool:

codebase-memory-mcp cli list_deprecated_functions --project my-repo

Map Custom File Extensions Without Recompiling

For languages already supported by Tree-sitter, you can map non-standard extensions (like .blade.php for PHP or .mjs for JavaScript) through configuration files rather than C code.

Add entries to the global config at ~/.config/codebase-memory-mcp/config.json:

{
  "extra_extensions": {
    ".blade.php": "php",
    ".mjs": "javascript",
    ".mydsl": "mydsl"
  }
}

Or use a per-project .codebase-memory.json file at the repository root, which overrides global settings. See docs/CONFIGURATION.md for the complete schema.

Create Custom Extraction Passes for Advanced Analysis

Beyond standard call graphs and imports, you can extract domain-specific relationships like environment variable usage or security-sensitive function calls.

Writing the Extractor Module

Create a new C module under internal/cbm/:

// internal/cbm/extract_env_accesses.c
#include "cbm.h"

void extract_env_accesses(CBMFileResult *res, const char *source) {
    // Walk the Tree-sitter AST, look for Identifier nodes named "process.env"
    // Emit an edge: (Function)-[:READS_ENV]->(EnvVar)
    // Implementation using tree-sitter API...
}

Hooking into the Indexing Pipeline

Invoke your extractor from the main indexing logic in internal/cbm/cbm.c where other extractors like extract_calls are called:

// Inside the file processing loop
extract_calls(res, source);
extract_imports(res, source);
extract_env_accesses(res, source);  // Your custom pass

Update docs/SCHEMA.md or the runtime schema builder to include the new READS_ENV edge type. After recompiling and re-indexing, query your custom relationships:

codebase-memory-mcp query_graph --project myproj \
  --query "MATCH (f:Function)-[:READS_ENV]->(e) RETURN f.name, e.name"

Summary

  • New language support requires creating a grammar_*.c file, registering it in internal/cbm/cbm.c, and updating scripts/build.sh.
  • New MCP tools need a handler function in internal/cbm/cbm.c, registration in the cbm_tools table, and optional CLI wrapping in scripts/cli.c.
  • File extension mapping works through JSON configuration (.codebase-memory.json or global config) without requiring recompilation.
  • Custom extraction passes involve writing new extract_*.c modules and hooking them into the indexing pipeline in cbm.c.

All extensions compile into a single static binary, maintaining the zero-dependency architecture that makes codebase memory MCP lightweight for AI coding agents.

Frequently Asked Questions

Do I need to know C to extend codebase memory MCP?

Yes, most extensions require C programming knowledge. Adding new languages, MCP tools, or extraction passes involves modifying files like internal/cbm/cbm.c and scripts/build.sh. However, mapping custom file extensions to existing languages only requires editing JSON configuration files, which needs no C knowledge.

Can I add runtime dependencies when extending the MCP?

No, the architecture prohibits runtime dependencies. According to the DeusData/codebase-memory-mcp source code, all extensions must be compiled into the single static binary. This design preserves the zero-dependency guarantee, meaning you cannot rely on external interpreters, shared libraries, or runtime package managers.

How do I query custom edges added by extraction passes?

Use the standard Cypher query interface via query_graph. After adding a custom extraction pass that creates edges like READS_ENV, query them using the MATCH clause: MATCH (f:Function)-[:READS_ENV]->(e) RETURN f.name, e.name. The graph schema updates automatically when you add new edge types to the extraction logic.

Will custom extensions break the single-binary architecture?

No, provided you follow the compilation workflow. All extensions—whether new grammars, tools, or analysis passes—are statically linked into the codebase-memory-mcp binary via scripts/build.sh. As long as you add your C files to the build script and recompile, the result remains a single, self-contained executable with no external dependencies.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →