LSP MCP (Language Server Protocol Model Context Protocol)
repository·main·Indexed 41 days ago
https://github.com/jonrad/lsp-mcpAn MCP server that bridges LLMs with Language Server Protocols (LSP), providing AI agents with language-aware codebase context. It enables tasks like variable shadowing analysis and execution flow breakdown by exposing LSP capabilities as MCP tools. Supports integration with Claude Desktop, Cursor, and the MCP CLI Client via Docker or npx.
What's inside LSP MCP
- LSP MCP is a Model Context Protocol (MCP) server that exposes Language Server Protocol (LSP) capabilities to LLMs and AI Agents. This allows an AI to gain language-aware context from a codebase, enabling tasks like variable shadowing analysis, execution flow breakdown, and scope isolation checks by leveraging the intelligence of existing language servers.
Configure LSP MCP for Claude Desktop using Docker (Recommended)
mainTo use LSP MCP with Claude Desktop via Docker, modify your
claude_desktop_config.jsonfile. Using Docker is the recommended method. To allow the AI to access your local files, you must mount your local directory into the container using the-vflag. Once mounted, you can ask Claude about files located at the remote path inside the container.```json { "mcpServers": { "lsp": { "command": "docker", "args": ["run", "-i", "--rm", "docker.io/jonrad/lsp-mcp:0.3.1"] } } }Example with volume mounting:
docker run -i --rm -v /local_dir:/remote_dir docker.io/jonrad/lsp-mcp:0.3.1Configure LSP MCP for MCP CLI Client
mainTo use LSP MCP with the MCP CLI Client, follow the same configuration logic as Claude Desktop, but apply the settings to the CLI client's specific configuration file located at~/.llm/config.json.Configure LSP MCP for Claude Desktop using npx
mainYou can run LSP MCP using
npx. Note that Claude Desktop may occasionally report an MCP failure even if the tools are functioning correctly. This method allows you to specify a specific language server via the--lspargument. The example below configures the TypeScript language server.{ "mcpServers": { "lsp": { "command": "npx", "args": [ "-y", "--silent", "git+https://github.com/jonrad/lsp-mcp", "--lsp", "npx -y --silent -p 'typescript@5.7.3' -p 'typescript-language-server@4.3.3' typescript-language-server --stdio" ] } } }Develop with LSP MCP
mainThe project includes development tools for testing and running the MCP server. Use
yarnto install dependencies and the provided CLI commands to interact with the server during development.yarn yarn mcp-cli # Interactive MCP tool for development yarn dev --help # Get CLI helpConfigure LSP MCP for Cursor
mainTo integrate LSP MCP with Cursor, follow the official Cursor MCP documentation. In the Cursor settings, set the
Typetocommandand use the Docker command pattern:docker run -i --rm -v <LOCAL_DIR>:<REMOTE_DIR> jonrad/lsp-mcp:<version>How LSP tool selection works
mainWhen calling an LSP-based tool, the server determines which LSP client to use based on the following priority:
- Explicit LSP ID: If the tool's input schema includes an
lspproperty (which happens automatically if multiple LSPs are configured), the client can specify the exactlspID to use. - File Extension: If no LSP is specified, the server inspects the
textDocument.uriof the request and attempts to find an LSP configured for that file extension. - Language Match: If the LSP ID provided doesn't match directly, the server attempts to find an LSP by the provided
programming_language. - Default LSP: If no other match is found, the server falls back to the
getDefaultLsp()configured in the manager.
- Explicit LSP ID: If the tool's input schema includes an
Configure LSP mappings in prod.config.json
mainThe
prod.config.jsonfile defines how the MCP server maps specific file extensions and language identifiers to Language Server Protocol (LSP) commands. This allows the server to know which language server to invoke when an LLM requests operations on a specific file type.Each object in the
lspsarray represents a language server configuration with the following fields:id: A unique identifier used for logging purposes.extensions: An array of file extensions (e.g.,["ts", "js"]) used to identify which files should trigger this LSP.languages: An array of language keywords (e.g.,["typescript", "javascript"]) that, if provided by the LLM, will trigger the use of this LSP.command: The executable command used to start the language server.args: An array of command-line arguments passed to the command (e.g.,["--stdio"]).
{ "lsps": [ { "id": "typescript", "extensions": ["ts", "tsx", "js", "jsx"], "languages": ["typescript", "javascript"], "command": "typescript-language-server", "args": ["--stdio"] }, { "id": "python", "extensions": ["py"], "languages": ["python", "python2", "python3"], "command": "pylsp", "args": [] } ] }Configure LSP MCP via the configuration schema
mainThe
lsp-mcpconfiguration is defined by a schema that specifies which Language Servers (LSPs) to run and how to interact with them. The configuration object consists of a requiredlspsarray and optionalmethodsandworkspacesettings.Configuration Keys
lsps(Required): An array of LSP server configurations. Each object in the array must contain:id: A unique string identifier for the LSP.extensions: An array of file extensions this LSP handles (e.g.,[".ts", ".js"]).languages: An array of language identifiers (e.g.,["typescript", "javascript"]).command: The executable command to run the LSP.args: An array of command-line arguments for the LSP.
methods(Optional): An array of specific LSP methods to enable. If this key is omitted, all available methods will be enabled.workspace(Optional): The path to the workspace to use for the LSP. Defaults to/if not provided.
{ "lsps": [ { "id": "typescript-language-server", "extensions": [".ts", ".tsx"], "languages": ["typescript"], "command": "typescript-language-server", "args": ["--stdio"] } ], "methods": ["textDocument/definition", "textDocument/hover"], "workspace": "/path/to/project" }Filter supported LSP methods
mainYou can restrict which LSP methods are supported by adding a top-level
methodsarray to the configuration. If this key is omitted, the tool defaults to supporting all available methods. This is useful for limiting the scope of capabilities exposed to the LLM/client.{ "lsps": [...], "methods": ["textDocument/documentSymbol"] }Configure LSP servers in dev.config.json
mainThe
dev.config.jsonfile allows you to define a list of Language Server Protocol (LSP) servers that the tool can use. Each LSP configuration entry in thelspsarray defines how to identify, trigger, and execute a specific language server.Each LSP object supports the following keys:
id: A unique identifier used for logging purposes.extensions: An array of file extensions (e.g.,["ts", "js"]) used to identify which files should be handled by this LSP.languages: An array of language keywords (e.g.,["typescript", "javascript"]). If an LLM specifies one of these keywords as the language, this LSP will be selected.command: The executable command to run (e.g.,npxoruvx).args: An array of command-line arguments passed to the command (e.g.,["--stdio"]).
{ "lsps": [ { "id": "typescript", "extensions": ["ts", "tsx", "js", "jsx"], "languages": ["typescript", "javascript"], "command": "npx", "args": ["-y", "typescript-language-server", "--stdio"] } ] }Retrieve an LSP by ID, language, or extension using LspManager
mainThe
LspManagerprovides several methods to look up a specificLspClientinstance. Note that lookups for IDs, languages, and extensions are case-insensitive (converted to lowercase internally).getLsp(id: string): Returns the client matching the provided ID.getLspByLanguage(language: string): Returns the client that supports the specified language.getLspByExtension(extension: string): Returns the client associated with the specified file extension.getDefaultLsp(): Returns the first client provided during initialization.getLsps(): Returns an array of all managedLspClientinstances.
// Get by ID const lsp = manager.getLsp('pyright'); // Get by language const pythonLsp = manager.getLspByLanguage('python'); // Get by extension const tsLsp = manager.getLspByExtension('.ts'); // Get the default const defaultLsp = manager.getDefaultLsp();