← Back to Chronicle

LSP-MCP-RS

ONE BINARY. EVERY LANGUAGE. // JANUARY 2026

The Headline

∞ Languages
One MCP Server to Rule Them All

Go to definition. Find references. Hover docs. Across Rust, Lua, TypeScript, Python, C/C++, Go—all from one binary.

The Problem

AI agents working with code have a critical blindspot: they can't navigate like an IDE. They read files sequentially, grep for patterns, hope they find the right definition. Meanwhile, every modern editor has LSP—the Language Server Protocol—providing instant semantic understanding.

Scenario Without LSP With LSP
"What does this function do?" Read entire file, guess from context Hover → instant docs + signature
"Where is this defined?" grep filename, hope it's unique goToDefinition → exact location
"What calls this function?" grep pattern, manual filtering findReferences → complete list
"Show me the class structure" Read whole file, parse mentally documentSymbol → full outline
"Every IDE user has had this for a decade. AI agents were still grepping like it's 1995."
- STRYK

The Solution

lsp-mcp-rs bridges Language Server Protocol to Model Context Protocol. One Rust binary that spawns and manages any LSP server, exposing its capabilities as MCP tools.

┌─────────────────────────────────────────────────────────────┐
│                    AI AGENT (DC/KALIC)                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  MCP Request: lsp_goto_definition                           │
│  file: "src/main.rs", line: 42, character: 15               │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│                      LSP-MCP-RS                             │
│                                                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │rust-analyzer│  │lua-language │  │ typescript- │  ...    │
│  │             │  │   server    │  │   server    │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│                                                             │
└─────────────────────────────────────────────────────────────┘
        

Supported Languages

Rust

rust-analyzer

Lua

lua-language-server

TypeScript

typescript-language-server

Python

pyright

Go

gopls

C/C++

clangd

Configuration-driven. Add any LSP that speaks JSON-RPC over stdio. The binary doesn't care what language—it just bridges the protocol.

Capabilities

Operation MCP Tool What It Returns
Go to Definition lsp_goto_definition File path, line, column of definition
Find References lsp_find_references All locations where symbol is used
Hover Information lsp_hover Documentation, type signature
Document Symbols lsp_document_symbol Functions, classes, variables in file
Workspace Symbols lsp_workspace_symbol Search symbols across project
Go to Implementation lsp_goto_implementation Interface/trait implementations
Call Hierarchy (In) lsp_incoming_calls What calls this function
Call Hierarchy (Out) lsp_outgoing_calls What this function calls

Real World Example

Task: Understand a Rust codebase

# Old way: grep and hope
grep -r "fn process_message" src/
→ Found in 3 files, unclear which is the real one
→ Load all 3 files (~2000 tokens) to check

# New way: LSP precision
lsp_workspace_symbol query="process_message"
→ src/handler.rs:142 - fn process_message(msg: Message) -> Result<()>

lsp_goto_definition file="src/main.rs" line=87 character=12
→ src/handler.rs:142

lsp_find_references file="src/handler.rs" line=142 character=4
→ Called from: main.rs:87, worker.rs:203, tests.rs:45

lsp_hover file="src/handler.rs" line=142 character=4
→ "Processes incoming WebSocket messages and routes to handlers"
→ fn process_message(msg: Message) -> Result
        
~2000
Tokens (grep approach)
~100
Tokens (LSP approach)

Configuration

# config.toml
[servers.rust]
command = "rust-analyzer"
extensions = [".rs"]

[servers.lua]
command = "lua-language-server"
extensions = [".lua"]

[servers.typescript]
command = "typescript-language-server"
args = ["--stdio"]
extensions = [".ts", ".tsx", ".js", ".jsx"]

[servers.python]
command = "pyright-langserver"
args = ["--stdio"]
extensions = [".py"]

[servers.go]
command = "gopls"
extensions = [".go"]

[servers.cpp]
command = "clangd"
extensions = [".c", ".cpp", ".h", ".hpp"]
        

File extension determines which LSP handles the request. Add servers for any language with LSP support—the bridge handles the rest.

Implementation

Rust
Language
MCP
Protocol
9
LSP Operations
6+
Languages

Built with tower-lsp for LSP client communication, tokio for async, and the MCP SDK for Claude integration. Servers are spawned on-demand and cached for subsequent requests.

Why This Matters

"This isn't just a tool—it's giving AI agents the same code understanding that made IDEs revolutionary. Definition jumping, reference finding, semantic search. The entire IDE experience, exposed as MCP tools."
- STRYK

Status

Milestone Status
Core LSP bridge ✓ Complete
Multi-language config ✓ Complete
GitHub release ✓ Published
MCP Registry submission In Progress
Claude Code integration ✓ Working

Repository: github.com/Stryk91/lsp-mcp-rs