Adding Custom Language Servers
Relevant source files
The following files were used as context for generating this wiki page:
The lsp-mcp-server acts as a bridge between the Model Context Protocol (MCP) and various Language Server Protocol (LSP) implementations. While the project includes built-in support for standard languages like TypeScript, Python, and Rust, it is designed to be extensible, allowing users to add custom language servers via configuration files. This extensibility ensures that semantic code intelligence—such as go-to-definition, hover information, and workspace symbols—can be applied to any language with an available LSP implementation.
Sources: CLAUDE.md:1-10, src/index.ts:515-530
Configuration Structure
Custom language servers are defined within a JSON configuration file. The server logic merges user-defined configurations with built-in defaults, where user-defined servers with the same id as a built-in server will override the default.
Configuration File Locations
The system searches for configuration files in the following order of priority:
.lsp-mcp.json(Current Working Directory)lsp-mcp.json(Current Working Directory)$XDG_CONFIG_HOME/lsp-mcp/config.json~/.lsp-mcp.json(Home Directory)
Sources: src/config.ts:37-55, src/config.ts:72-88
Server Configuration Schema
Each server entry in the servers array must adhere to the LSPServerConfig interface.
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier (e.g., "typescript", "ruby"). |
extensions | string[] | List of file extensions the server handles (e.g., [".rb", ".rake"]). |
languageIds | string[] | Language IDs as defined by the LSP specification. |
command | string | The binary or command used to start the language server. |
args | string[] | Arguments passed to the command. |
env | Record<string, string> | Optional environment variables for the server process. |
rootPatterns | string[] | Patterns to identify the project root (e.g., ["Gemfile", ".git"]). |
Sources: src/types.ts:111-135, src/config.ts:93-112
Architecture of Server Integration
When a tool request is made for a specific file, the ConnectionManager identifies the appropriate server based on the file extension and workspace root.
The diagram shows the logic within the ConnectionManager to route file-based requests to the correct LSP client instance.
Sources: src/services/connection-manager.ts:60-90, CLAUDE.md:23-28
Initialization Process
Once the configuration is validated, the LSPClientImpl handles the low-level process spawning and JSON-RPC handshake.
- Spawning: The server process is started using
node:child_process.spawnwithshell: falsefor security. - Handshake: An
initializerequest is sent containing therootUriand client capabilities. - Capabilities: The server responds with its supported features (e.g.,
definitionProvider,hoverProvider), which are stored in the client instance.
Sources: src/services/lsp-client.ts:117-150, src/services/lsp-client.ts:250-280
Lifecycle and Reliability
Custom servers benefit from the built-in lifecycle management features of the ConnectionManager.
Automatic Restart Policy
If a language server process exits unexpectedly (crashes), the manager attempts to restart it using exponential backoff.
- Max Attempts: 3 attempts.
- Window: 5 minutes.
- Backoff: Base delay of 1000ms multiplied by $2^{(attempt-1)}$.
Sources: src/services/connection-manager.ts:246-285, CLAUDE.md:94-98
Resource Management
To conserve system resources, servers are subject to an idle timeout. If no requests are received for a specific server instance within the idleTimeout period (default 30 minutes), the ConnectionManager shuts down the process.
Sources: src/services/connection-manager.ts:327-345, src/types.ts:152-155
Data Flow for a Custom Server Request
The following sequence diagram illustrates how a request for a custom language (e.g., Ruby) is handled from the MCP layer down to the spawned LSP process.
This diagram shows the interaction between managers and the specialized LSP client during the first request for a custom language file.
Sources: src/services/connection-manager.ts:60-80, src/services/document-manager.ts:86-105, CLAUDE.md:46-56
Summary
Adding custom language servers to the lsp-mcp-server involves defining the server's command, file extensions, and root patterns in a JSON configuration file. The architecture ensures that these servers are lazily loaded, automatically managed for reliability, and integrated into the same diagnostic and document management pipeline as built-in servers. This allows developers to extend the intelligence of Claude Code to any proprietary or niche language that supports the LSP protocol.
Sources: src/config.ts:117-130, CLAUDE.md:120-125