# What Is Hybrid LSP and Which Languages Does It Support?

> Discover Hybrid LSP, the codebase-memory-mcp's semantic type-resolution layer. Learn what Hybrid LSP is and explore the nine major programming languages it supports for enhanced ASTs.

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

---

**Hybrid LSP is the codebase-memory-mcp's built-in semantic type-resolution layer that enriches Tree-sitter ASTs with cross-file type information for nine major programming languages.**

The **codebase-memory-mcp** project solves the problem of shallow syntactic analysis by embedding **Hybrid LSP** directly into its binary. Unlike traditional language servers that require external processes and complex configuration, this layer is implemented as a lightweight C library that runs after parsing to resolve imports, generics, and method dispatch across files.

## What Is Hybrid LSP?

**Hybrid LSP** is a second-pass analysis stage that operates on every supported grammar after Tree-sitter completes its initial parse. While Tree-sitter excels at producing fast syntactic trees that identify names and call sites, it cannot semantically resolve a chain like `user.profile.display_name()` to the actual definition residing in another file.

The Hybrid LSP implementation walks the Tree-sitter AST, builds a cross-file **registry**, and emits enriched graph edges including `RESOLVED_CALLS`, `USAGE`, and `DATA_FLOWS`. This transforms raw syntax into a navigable semantic graph without requiring a separate language-server process, API keys, or per-project configuration files.

## How Hybrid LSP Differs from Tree-Sitter

Tree-sitter supports 158 grammars but only provides **syntactic** information—it knows that a function is called, but not which concrete implementation is invoked, especially across module boundaries. Hybrid LSP adds the missing **semantic** layer:

- **Tree-sitter**: Identifies tokens, identifiers, and call expressions.
- **Hybrid LSP**: Resolves `import` statements, tracks inheritance hierarchies, handles generic type parameters, and maps method calls to their concrete implementations, including std-library types.

The mirror the behavior of major language servers (tsserver, pyright, gopls, Roslyn, rust-analyzer) while remaining 100% local.

## Languages Supported by Hybrid LSP

While Tree-sitter handles 158 grammars syntactically, nine languages receive a **full Hybrid LSP pass** with deep semantic resolution. All other languages fall back to lighter textual resolution.

### Python

The Python resolver in [`internal/cbm/lsp/py_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp/py_lsp.c) handles imports, dataclasses, `Self` returns, generics, `@property` decorators, pattern matching, SQLAlchemy 2.0 `Mapped[T]` types, Pydantic models, async/await constructs, and `isinstance`/walrus narrowing.

### TypeScript, JavaScript, JSX, and TSX

Implemented in [`internal/cbm/lsp/ts_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp/ts_lsp.c), this resolver adds generics, JSX component dispatch, JSDoc inference, [`.d.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/.d.ts) declaration handling, re-export resolution, and method-chain return-type propagation.

### PHP

The PHP module resolves namespaces, traits, late-static-binding, PHPDoc inference, and parameter/return-type inference across the project.

### C#

The C# resolver supports global usings, file-scoped namespaces, records (including primary constructors), LINQ method syntax, `async Task<T>`/`ValueTask<T>` unwrapping, generic methods, `var` inference, and common Base Class Library (BCL) std-lib types.

### Go

Implemented in [`internal/cbm/lsp/go_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp/go_lsp.c), the Go resolver maintains a per-package cross-file registry, handles generics, embedded structs, interface satisfaction, and package-aware import resolution.

### C and C++

The C/C++ resolver processes macro and `typedef` chains, links headers to sources (C), handles templates, namespaces, `auto` inference, and class-hierarchy method resolution (C++).

### Java (v0.8.0+)

Added in version 0.8.0 via [`internal/cbm/lsp/java_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp/java_lsp.c), the Java resolver supports imports (single-type, on-demand, static), `this`/`super` dispatch, generics, annotations, overload resolution, lambdas, method references, and the common JDK std-lib. It emits `OVERLOAD_OF` edges when matching methods by arity and parameter types.

### Kotlin (v0.8.0+)

Also added in v0.8.0 in [`internal/cbm/lsp/kotlin_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp/kotlin_lsp.c), this resolver handles imports, same-package resolution, classes/objects/companions, extension functions, data classes, nullable-type unwrapping, scope functions (`let`, `apply`, `run`, `also`, `with`), infix calls, and common std-lib types.

### Rust (v0.8.0+)

The Rust resolver in [`internal/cbm/lsp/rust_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/internal/cbm/lsp/rust_lsp.c) processes `use` imports, module paths, `impl` blocks and trait methods, struct fields, generics with trait bounds, operator-trait desugaring, derive-macro methods, UFCS static paths, and the common std prelude.

## Querying Hybrid LSP Data via the MCP API

The semantic edges generated by Hybrid LSP are accessible through the MCP API. Below are practical examples of how to query this enriched graph.

### Resolve a Call Across Files

Use the `trace_path` tool to follow `RESOLVED_CALLS` edges across module boundaries:

```python

# Resolve the target of profile.display_name() in myapp/views.py at line 42

result = cbm.trace_path(
    src="myapp/views.py",
    line=42,
    depth=1,
    mode="full"
)

# Returns the concrete definition with confidence 1.0

print(result)  

# → {"callee_qn": "myapp/models/profile.py:Profile.display_name", "confidence": 1.0}

```

### Find Unresolved Calls

Query for calls that the resolver could not type-resolve (emitted via `ts_emit_unresolved_call` or equivalents):

```python
unresolved = cbm.search_graph(
    query="MATCH (c:ResolvedCall) WHERE c.confidence = 0 RETURN c.callee_qn"
)

for call in unresolved:
    print(call["callee_qn"])

```

### Find Method Overloads (Java)

Query `OVERLOAD_OF` edges generated by the Java resolver:

```python
overloads = cbm.search_graph(
    query="""
        MATCH (m:Method)-[:OVERLOAD_OF]->(base:Method)
        WHERE base.name = 'add' AND base.owner = 'java.util.List'
        RETURN m.signature, m.owner
    """
)
for o in overloads:
    print(o["signature"], "in", o["owner"])

```

## Key Implementation Files

The Hybrid LSP layer is defined in the following source files within the `internal/cbm/lsp/` directory:

- **[`ts_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/ts_lsp.c)**: TypeScript, JavaScript, JSX, and TSX resolution
- **[`py_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/py_lsp.c)**: Python resolution
- **[`go_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/go_lsp.c)**: Go resolution
- **[`java_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/java_lsp.c)**: Java resolution (added v0.8.0)
- **[`kotlin_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/kotlin_lsp.c)**: Kotlin resolution (added v0.8.0)
- **[`rust_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/rust_lsp.c)**: Rust resolution (added v0.8.0)

These files define the language-specific resolution logic that builds the semantic graph edges.

## Summary

- **Hybrid LSP** is a built-in semantic resolution layer that runs after Tree-sitter parsing to add cross-file type information.
- It is implemented as a **lightweight C library** compiled into the static binary, requiring no external language server processes or configuration.
- The system supports **nine languages with full resolution**: Python, TypeScript/JavaScript (including JSX/TSX), PHP, C#, Go, C/C++, Java, Kotlin, and Rust.
- It emits rich graph edges—including `RESOLVED_CALLS`, `USAGE`, `DATA_FLOWS`, and `OVERLOAD_OF`—that enable deep code analysis across module boundaries.

## Frequently Asked Questions

### Is Hybrid LSP a separate language server process?

No. According to the source code in `internal/cbm/lsp/`, Hybrid LSP is **not** a separate process like tsserver or rust-analyzer. It is a lightweight C library compiled into the single static binary, requiring no per-project configuration, API keys, or external dependencies.

### How does Hybrid LSP handle unresolved symbols?

When the resolver cannot determine a concrete type, it emits calls via `ts_emit_unresolved_call` (or language-specific equivalents) with a **confidence of 0**. These appear in the graph as `ResolvedCall` nodes with `confidence: 0`, allowing you to audit which symbols lack type resolution.

### What is the difference between Tree-sitter and Hybrid LSP in codebase-memory-mcp?

**Tree-sitter** provides fast syntactic parsing across 158 grammars, identifying tokens, names, and call sites. **Hybrid LSP** runs as a second pass to perform semantic analysis—resolving imports, generics, inheritance, and method dispatch—to build a cross-file registry that Tree-sitter alone cannot create.

### Which version of codebase-memory-mcp added Java, Kotlin, and Rust support?

Java, Kotlin, and Rust support were added in **version 0.8.0**, as reflected in the [`java_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/java_lsp.c), [`kotlin_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/kotlin_lsp.c), and [`rust_lsp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/rust_lsp.c) source files. These implementations support modern language features such as Kotlin's scope functions and Rust's trait-bound generics.