# Hybrid LSP Type Resolution in codebase-memory-mcp: A Complete Technical Guide

> Master hybrid LSP type resolution in codebase-memory-mcp. This guide details the Tree-sitter engine that unifies JavaScript, TypeScript, JSX, and TSX parsing for seamless cross-language symbol resolution and CBM lookups.

- Repository: [Martin Vogel/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)
- Tags: deep-dive
- Published: 2026-07-12

---

**The hybrid LSP type resolver in codebase-memory-mcp combines JavaScript, TypeScript, JSX, and TSX parsing into a single Tree-sitter-based engine that resolves symbols across mixed-language projects using a unified type-info cache and the CBM infrastructure for cross-file lookups.**

The codebase-memory-mcp project implements a sophisticated Language Server Protocol (LSP) server capable of handling multiple JavaScript-family dialects through one unified resolution system. This article examines the hybrid LSP type resolution architecture that enables accurate symbol resolution across JavaScript, TypeScript, JSX, and TSX files in a single pass.

## What Is Hybrid LSP Type Resolution?

Hybrid LSP type resolution refers to the architecture in `codebase-memory-mcp` that merges parsing rules for plain JavaScript, TypeScript, JSX, and TSX into a single resolver. Instead of maintaining separate parsers for each syntactic variant, the system uses Tree-sitter's TypeScript grammar to handle all four languages simultaneously. This approach registers every symbol—including declarations, imports, exports, and JSX component usages—into a centralized type-info cache that serves LSP clients with accurate type information regardless of the source file extension.

## Core Implementation in ts_lsp.c

The heart of the hybrid resolver lives in [`internal/cbm/lsp/ts_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp/ts_lsp.c). This file implements the request handling logic that bridges Tree-sitter parsing with the CBM (Codebase Memory) infrastructure.

### Unified Grammar Processing

The resolver initializes a Tree-sitter parser configured for TypeScript, which inherently understands JSX and TSX syntax nodes. When processing a file, the system calls `ts_parser_new()` and sets the language to `tree_sitter_typescript()`, enabling a single parser instance to handle JavaScript-family source code without switching grammars.

After parsing, the resolver walks the syntax tree to construct a symbol table via `build_symbol_table()`. This traversal captures identifiers, their scopes, and inferred types—including JSX component props—regardless of whether the source is vanilla JavaScript or TypeScript with JSX.

### Cross-File Resolution

The hybrid resolver leverages the CBM infrastructure to resolve symbols defined in separate modules. When encountering an import statement, the system invokes `cbm_load_file()` to dynamically parse dependency files. This allows the resolver to handle scenarios where a `.tsx` file imports a `.js` module, maintaining type consistency across language boundaries.

The `cbm_load_file` routine integrates with the type-info cache, ensuring that symbols loaded from external files are available for subsequent queries without re-parsing.

## Standard Library Integration

Generated stub files provide pre-populated type information for built-in APIs. Located in `internal/cbm/lsp/generated/`, files such as [`python_stdlib_data.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/python_stdlib_data.c), [`go_stdlib_data.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/go_stdlib_data.c), and [`cpp_stdlib_data.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/cpp_stdlib_data.c) contain type definitions for standard libraries.

Before responding to LSP requests, the hybrid resolver merges these standard-library stubs with project-specific types. This ensures that calls to standard APIs are correctly typed regardless of whether the project uses JavaScript or TypeScript variants.

## Practical Code Examples

Below are implementations showing how the hybrid resolver handles LSP requests and testing scenarios.

### Handling Definition Requests

The entry point for hybrid resolution appears in `ts_lsp_handle_request`, defined in [`internal/cbm/lsp/ts_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp/ts_lsp.c):

```c
static void ts_lsp_handle_request(cbmlsp_server *srv,
                                   const char *method,
                                   const json_t *params) {
    if (strcmp(method, "textDocument/definition") == 0) {
        const char *uri = json_string_value(json_object_get(params, "uri"));
        const char *position = json_string_value(json_object_get(params, "position"));
        
        /* 1. Parse the file using the shared TypeScript grammar */
        TSParser *parser = ts_parser_new();
        ts_parser_set_language(parser, tree_sitter_typescript());
        TSTree *tree = ts_parser_parse_string(parser, NULL,
                                              source_content, source_len);
        
        /* 2. Build symbol table from the syntax tree */
        SymbolTable *symtab = build_symbol_table(tree);
        
        /* 3. Resolve definition location (may cross file boundaries) */
        Location loc = resolve_definition(symtab, uri, position);
        
        /* 4. Return response to LSP client */
        cbmlsp_respond(srv, method, location_to_json(loc));
    }
}

```

This function demonstrates the hybrid approach: one parser handles all JavaScript variants, while `resolve_definition` manages cross-file lookups through the CBM infrastructure.

### Testing Hybrid Resolution

The test suite in [`tests/test_ts_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/tests/test_ts_lsp.c) validates JSX component resolution:

```c
static void test_jsx_component_resolution(void) {
    const char *src =
        "import React from 'react';\n"
        "export const Button = (props) => <button>{props.label}</button>;\n"
        "export const App = () => <Button label=\"Hi\"/>;\n";

    /* Load source into virtual file */
    cbm_file *f = cbm_load_virtual_file("App.tsx", src);
    
    /* Resolve definition for Button component inside JSX */
    Location loc = ts_lsp_resolve_definition(f, "App.tsx", line=4, col=15);
    
    /* Verify location points to the export statement */
    assert(loc.line == 2);
}

```

This test verifies that the hybrid resolver correctly identifies component definitions within JSX syntax, treating TSX and JavaScript imports uniformly.

## Benefits of the Hybrid Approach

The hybrid LSP type resolution system offers several advantages for language server implementations:

- **Single Parser Maintenance**: By utilizing Tree-sitter's TypeScript grammar for all JavaScript-family languages, the codebase eliminates redundant parser implementations. Updates to the grammar automatically propagate to JSX and TSX handling.

- **Consistent Type Information**: Users receive accurate completions and go-to-definition behavior across mixed-language projects, such as React applications combining `.js`, `.ts`, and `.tsx` files.

- **Extensible Architecture**: Adding support for additional JavaScript-derived dialects requires only minor grammar adjustments rather than entirely new resolver implementations.

- **Cross-Language Resolution**: The integration with `cbm_load_file` enables seamless symbol resolution across module boundaries, even when importing files written in different dialects.

## Summary

- **Hybrid LSP type resolution** in codebase-memory-mcp unifies JavaScript, TypeScript, JSX, and TSX processing through a single Tree-sitter parser located in [`internal/cbm/lsp/ts_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp/ts_lsp.c).
- The resolver constructs symbol tables via `build_symbol_table()` and handles cross-file lookups using the `cbm_load_file` infrastructure.
- Standard library type information from generated files like [`python_stdlib_data.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/python_stdlib_data.c) augments project-specific types before LSP responses are sent.
- The architecture reduces maintenance overhead while providing consistent type information across mixed-language codebases.
- Integration occurs through [`internal/cbm/lsp_all.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp_all.c), which aggregates all resolver modules for the final `cbm_lsp` binary.

## Frequently Asked Questions

### How does the hybrid resolver handle different JavaScript dialects without separate parsers?

The resolver uses Tree-sitter's TypeScript grammar, which inherently includes rules for JSX and TSX syntax. By calling `tree_sitter_typescript()` in `ts_parser_new()`, the system parses JavaScript, TypeScript, JSX, and TSX files using the same grammar tree, eliminating the need for dialect-specific parsers while maintaining accurate syntax recognition.

### What mechanism enables cross-file symbol resolution in the hybrid LSP system?

Cross-file resolution works through the CBM infrastructure's `cbm_load_file` function. When the resolver encounters an import statement, it dynamically loads and parses the referenced file, caching the results in the type-info cache. This allows symbols defined in `.js` modules to be resolved from `.tsx` files and vice versa.

### Where is the hybrid LSP type resolution logic integrated into the build system?

All LSP-related source files are compiled together via [`internal/cbm/lsp_all.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp_all.c), which includes the individual resolver modules including [`ts_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/ts_lsp.c). This aggregated compilation unit produces the `cbm_lsp` binary, exposing the standard LSP JSON-RPC interface to clients.

### How does the resolver provide type information for standard library functions?

The system merges auto-generated stub files located in `internal/cbm/lsp/generated/`—such as [`python_stdlib_data.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/python_stdlib_data.c), [`go_stdlib_data.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/go_stdlib_data.c), and [`cpp_stdlib_data.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/cpp_stdlib_data.c)—with project-specific symbol tables. These stubs pre-populate the type-info cache with standard library definitions, ensuring accurate typing for built-in API calls across all supported JavaScript variants.