How to Add Custom File Extensions for Unsupported Types in codebase-memory-mcp
Map any unknown file extension to a supported language by adding an extra_extensions object to your global config.json or per-project .codebase-memory.json file.
The codebase-memory-mcp engine natively recognizes 158 programming languages, silently ignoring files with unrecognized extensions during the discovery phase. To include these files in the knowledge graph and enable tools like search_graph and trace_path to operate on them, you must explicitly declare how custom extensions map to known language IDs.
Why Custom File Extensions Are Ignored
During the discover phase, the engine scans the filesystem and queries the language resolver for a CBMLanguage ID. If the extension is absent from the built-in table, the resolver cannot determine which Tree-sitter grammar to apply, causing the file to be skipped entirely. This prevents binary or irrelevant files from entering the index, but it also blocks legitimate source files using non-standard or template-specific extensions.
Configuration File Locations and Precedence
The engine loads extension mappings from JSON files in two distinct scopes. Project-level settings always override global settings for the same extension key.
Global Configuration (All Projects)
Create or edit the file at:
$XDG_CONFIG_HOME/codebase-memory-mcp/config.json
If XDG_CONFIG_HOME is unset, the engine falls back to:
~/.config/codebase-memory-mcp/config.json
Per-Project Configuration
Create a file named .codebase-memory.json in your repository root. This file takes precedence over the global configuration for that specific project.
Configuration Merging Logic
In src/discover/userconfig.c, the function cbm_userconfig_load() orchestrates the loading sequence. It first calls load_config_file() on the global path, then on the project path. After both files are parsed, a deduplication pass removes any global entry that shares the same extension key as a project entry, ensuring local settings always win.
The extra_extensions Schema
The parsing routine parse_extra_extensions() (lines 166-176 in src/discover/userconfig.c) validates entries with strict rules:
- The root JSON must be an object.
- The key
"extra_extensions"must contain an object value. - Each extension key must start with a dot (
.). - The language value is matched case-insensitively via
lang_from_string(); unknown languages trigger a warning and are ignored. - Valid mappings are stored in a dynamically-grown
cbm_userext_tarray.
Practical Configuration Examples
Global Mapping for Common Template Extensions
Add mappings that apply to every repository on your system:
// ~/.config/codebase-memory-mcp/config.json
{
"extra_extensions": {
".blade.php": "php",
".mjs": "javascript",
".twig": "html"
}
}
Per-Project Overrides
Create a .codebase-memory.json in your repository root to override global settings or define project-specific extensions:
// .codebase-memory.json
{
"extra_extensions": {
".mytmpl": "html",
".xyz": "python"
}
}
Only this repository will recognize .mytmpl and .xyz files; other projects continue to use the global configuration.
Verify Your Configuration
After saving the configuration file, restart the MCP server or run any MCP command to trigger a reload. Confirm the extensions are recognized by examining the graph schema:
codebase-memory-mcp cli get_graph_schema
Alternatively, search for symbols residing within custom extension files:
codebase-memory-mcp cli search_graph '{"label":"Function","name_pattern":"MyFunc"}'
How the Engine Processes Your Mappings
Before indexing begins, the discover pipeline consults the extra_extensions table populated by the user-config loader. When encountering a file with a custom extension, the resolver checks this table after failing the built-in lookup. If a match exists, the file is parsed with the corresponding Tree-sitter grammar and participates in Hybrid-LSP type resolution, making it fully available to all subsequent MCP tooling.
The validation logic implemented in src/discover/userconfig.c appears as follows:
/* Simplified excerpt from src/discover/userconfig.c */
static int parse_extra_extensions(yyjson_val *root,
cbm_userext_t **entries, int *count,
const char *source_label) {
yyjson_val *extra = yyjson_obj_get(root, "extra_extensions");
if (!extra || !yyjson_is_obj(extra)) return 0;
yyjson_obj_iter iter;
yyjson_obj_iter_init(extra, &iter);
yyjson_val *key;
while ((key = yyjson_obj_iter_next(&iter)) != NULL) {
const char *ext = yyjson_get_str(key);
const char *lang = yyjson_get_str(yyjson_obj_iter_get_val(key));
if (!ext || !lang || ext[0] != '.') continue;
CBMLanguage l = lang_from_string(lang);
if (l == CBM_LANG_COUNT) continue;
// store the mapping …
}
return 0;
}
Summary
codebase-memory-mcpsupports 158 built-in languages; unrecognized extensions are ignored by default.- Add custom mappings via the
extra_extensionsobject in~/.config/codebase-memory-mcp/config.json(global) or.codebase-memory.json(project-level). - Project settings override global settings for identical extensions as implemented in
cbm_userconfig_load(). - Extensions must start with a dot and map to valid language names recognized by
lang_from_string(). - Changes take effect immediately after restarting the MCP server; no recompilation is required.
Frequently Asked Questions
Can I map a custom extension to any language name?
The language value must correspond to a supported language identifier in the engine. The parser uses lang_from_string() to validate the mapping case-insensitively. If you provide an unknown language string, the entry is skipped and a warning is logged to stderr.
Do I need to rebuild the MCP server after editing the configuration?
No. The configuration is read at runtime by cbm_userconfig_load() in src/discover/userconfig.c. Simply restart the MCP server or trigger any MCP command to reload the configuration and apply your new mappings.
What happens if I define the same extension in both global and project files?
The per-project .codebase-memory.json takes precedence. The deduplication logic in cbm_userconfig_load() removes conflicting global entries after both files are parsed, ensuring repository-specific settings always win.
Where can I find the list of supported language names?
Refer to the docs/CONFIGURATION.md file in the repository or examine the lang_from_string() implementation in the source code to see the valid identifiers for the 158 supported languages.
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 →