LSP MCP (Language Server Protocol Model Context Protocol)

repository·main·Indexed 41 days ago

https://github.com/jonrad/lsp-mcp

An 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.

Tokens
6.2K
Snippets
20
Records
28
Agent score
47%

What's inside LSP MCP

  1. Overview of LSP MCP

    main
    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.
  2. Configure LSP MCP for Claude Desktop using Docker (Recommended)

    main

    To use LSP MCP with Claude Desktop via Docker, modify your claude_desktop_config.json file. 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 -v flag. 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.1

  3. Configure LSP MCP for Claude Desktop using npx

    main

    You 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 --lsp argument. 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"
          ]
        }
      }
    }
  4. Develop with LSP MCP

    main

    The project includes development tools for testing and running the MCP server. Use yarn to 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 help
  5. How LSP tool selection works

    main

    When calling an LSP-based tool, the server determines which LSP client to use based on the following priority:

    1. Explicit LSP ID: If the tool's input schema includes an lsp property (which happens automatically if multiple LSPs are configured), the client can specify the exact lsp ID to use.
    2. File Extension: If no LSP is specified, the server inspects the textDocument.uri of the request and attempts to find an LSP configured for that file extension.
    3. Language Match: If the LSP ID provided doesn't match directly, the server attempts to find an LSP by the provided programming_language.
    4. Default LSP: If no other match is found, the server falls back to the getDefaultLsp() configured in the manager.
  6. Configure LSP mappings in prod.config.json

    main

    The prod.config.json file 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 lsps array 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": []
        }
      ]
    }
  7. Configure LSP MCP via the configuration schema

    main

    The lsp-mcp configuration 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 required lsps array and optional methods and workspace settings.

    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"
    }
  8. Filter supported LSP methods

    main

    You can restrict which LSP methods are supported by adding a top-level methods array 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"]
    }
  9. Configure LSP servers in dev.config.json

    main

    The dev.config.json file allows you to define a list of Language Server Protocol (LSP) servers that the tool can use. Each LSP configuration entry in the lsps array 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., npx or uvx).
    • 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"]
        }
      ]
    }
  10. Retrieve an LSP by ID, language, or extension using LspManager

    main

    The LspManager provides several methods to look up a specific LspClient instance. 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 managed LspClient instances.
    // 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();