# How to Extend Codebase Memory MCP: A Complete Customization Guide

> Learn how to extend codebase memory MCP by adding Tree-sitter grammars, registering JSON-RPC tools, configuring file extensions, or creating custom extraction passes for enhanced analysis. Get the complete customization guide.

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

---

**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:

```c
// 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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/cbm.c) where the `cbm_load_grammars` function iterates over the array:

```c
// 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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/scripts/build.sh):

```bash

# 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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/scripts/build.sh), then verify the new language is indexed:

```bash

# 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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/docs/TOOL_SPEC.md) or a new specification file:

```json
{
  "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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/cbm.c) by querying the SQLite-backed graph directly:

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

```c
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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/scripts/cli.c):

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

```bash
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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/.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`:

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

```

Or use a per-project [`.codebase-memory.json`](https://github.com/DeusData/codebase-memory-mcp/blob/main/.codebase-memory.json) file at the repository root, which overrides global settings. See [`docs/CONFIGURATION.md`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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/`:

```c
// 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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/cbm.c) where other extractors like `extract_calls` are called:

```c
// 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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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:

```bash
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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/cbm.c), and updating [`scripts/build.sh`](https://github.com/DeusData/codebase-memory-mcp/blob/main/scripts/build.sh).
- **New MCP tools** need a handler function in [`internal/cbm/cbm.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/cbm.c), registration in the `cbm_tools` table, and optional CLI wrapping in [`scripts/cli.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/scripts/cli.c).
- **File extension mapping** works through JSON configuration ([`.codebase-memory.json`](https://github.com/DeusData/codebase-memory-mcp/blob/main/.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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/cbm.c) and [`scripts/build.sh`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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`](https://github.com/DeusData/codebase-memory-mcp/blob/main/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.