Skip to content

LSP Configuration

What Is LSP?

Language Server Protocol (LSP) is a standardised communication protocol between an editor (the client) and a language-specific analysis process (the server). The same protocol powers diagnostics in VS Code, Neovim, JetBrains — and Claude Code.

┌────────────┐                       ┌──────────────────┐
│ Claude Code │  ←── JSON-RPC ───→   │  Language Server  │
│  (client)   │     over stdio       │ (pyright, ts-ls)  │
└────────────┘                       └──────────────────┘

The client sends notifications like "file opened", "file changed". The server analyses the code in the background and pushes back diagnostics (errors, warnings), plus responds to queries like "go to definition" or "find all references". The server doesn't care who the client is — it reads JSON from stdin and writes JSON to stdout.

Since Claude Code v2.0.74, the CLI has a built-in LSP client that can launch and manage language servers directly in the terminal — no IDE required. After every file edit Claude makes, the language server re-analyses the changed file and reports errors automatically. Claude sees them in the same turn and can fix issues before moving on.


Why It Matters

Without LSP With LSP
Errors discovered only when you run pyright or tsc manually Errors caught immediately after each file edit
Claude relies on its own knowledge of your types Pyright validates against actual type stubs and your real code
Type mismatches, wrong arguments, missing imports slip through Claude sees and fixes them in the same turn
Refactoring requires manual verification LSP acts as a safety net — broken references surface instantly

Beyond diagnostics, the LSP also gives Claude code navigation: go-to-definition, find-references, hover information, and workspace symbol search. When you ask "where is this function used?", the LSP provides precise answers instead of grep-based guesses.


Using LSP During Development

LSP diagnostics are automatic — you don't invoke them. After every file edit, the language server runs in the background and reports issues. If Claude introduces a type error, it notices and fixes it in the same turn.

Tips for getting the most out of it:

  • Let Claude self-correct — After an edit, if diagnostics appear, Claude fixes them without being told. Trust the feedback loop.
  • Ask to "fix all diagnostics" — After a batch of changes, ask Claude to sweep remaining type errors. No separate uv run pyright pass needed.
  • Use it as a commit gate — If Ctrl+O shows zero diagnostics after edits, the code is type-clean.
  • Be more aggressive with refactoring — Rename a type, change a function signature, restructure a module. The LSP catches every broken reference that Claude might otherwise miss.

What LSP does NOT replace

LSP handles type checking and code intelligence only. It does not replace ruff for linting/formatting, does not catch runtime errors, and only analyses files that Claude has touched or that you point it to.


TypeScript / Next.js Projects

How it works

typescript-language-server is a global binary that acts as the LSP server. It automatically reads your project's local node_modules/typescript, so it always uses the exact TypeScript version your project pins — no per-project configuration needed.

Setup (once per machine)

npm install -g typescript-language-server typescript

Every TypeScript/JavaScript project works after this. The typescript already in your devDependencies is used automatically.

Verify

# Binary is available
which typescript-language-server
typescript-language-server --version

# Server starts when Claude Code opens (from project root)
claude --debug 2>&1 | grep -i "lsp\|typescript-language"
# Look for: LSP server 'typescript' started (pid XXXXX)

PATH issue? If which fails after a successful install:

npm config get prefix   # find where npm puts global installs (e.g. /usr/local)
# Add to ~/.zshrc or ~/.bashrc:
export PATH="$(npm config get prefix)/bin:$PATH"

Test it's working

Open any .ts file with a type error and ask Claude:

What type errors are in this file? List them with line numbers. Don't fix anything.

With LSP active Claude reports exact tsc diagnostics with line numbers. Without it, it can only infer issues by reading the file.


Python / FastAPI Projects

Two binaries — critical distinction

The pyright npm package ships two separate binaries:

Binary Purpose Accepts --stdio?
pyright CLI type-checker — runs and exits No
pyright-langserver LSP server — long-running, speaks LSP protocol Yes

The sq-dev plugin uses pyright-langserver. Running pyright --stdio will not work — pyright is a CLI tool that does not accept LSP protocol messages.

How it works

pyright-langserver runs as a global tool. When it starts, it walks up the directory tree from the file being edited to find pyproject.toml or pyrightconfig.json, then uses that configuration to locate the virtual environment and understand your installed packages.

Setup (once per machine)

npm install -g pyright

This installs both pyright (the CLI type-checker) and pyright-langserver (the LSP binary) globally via npm — same mechanism as typescript-language-server.

Verify

# Both binaries are available
which pyright-langserver
which pyright
pyright --version   # pyright-langserver has no --version flag; use pyright instead

# Server starts when Claude Code opens (from project root)
claude --debug 2>&1 | grep -i "lsp\|pyright"
# Look for: LSP server 'python' started (pid XXXXX)

PATH issue? If which fails after a successful install:

npm config get prefix   # find where npm puts global installs (e.g. /usr/local)
# Add to ~/.zshrc or ~/.bashrc:
export PATH="$(npm config get prefix)/bin:$PATH"

Test it's working

Open any .py file and ask Claude:

What type errors does Pyright report in this file? List them with line numbers. Don't fix anything.

With LSP active Claude reports real Pyright diagnostics. Without it, it can only spot issues it infers by reading the code.


Monorepo / Non-Standard Project Layout

By default pyright-langserver walks up from the edited file to find pyproject.toml. If your project root and your Python source are in different directories (e.g. a monorepo where Python code lives in core/), pyright needs an explicit configuration to find the right venv and source paths.

Create a pyrightconfig.json at the root of the directory you open Claude Code from:

{
  "include": [
    "core/app",
    "core/tests"
  ],
  "venvPath": "core",
  "venv": ".venv",
  "pythonVersion": "3.12"
}
Field Value
include Paths to analyse (relative to pyrightconfig.json)
venvPath Directory that contains the .venv folder
venv Name of the venv folder (almost always .venv)
pythonVersion Must match what you use in pyproject.toml

Commit pyrightconfig.json to the repo — everyone on the team benefits.

TypeScript monorepos

typescript-language-server handles monorepos automatically via tsconfig.json project references. No extra configuration is needed.


Integrating LSP in Custom Marketplaces

If you maintain a custom Claude Code marketplace and want to bundle LSP servers inside your plugins, there are two mechanisms. The first is reliable; the second is a fallback.

This is how the Anthropic official marketplace does it. Define LSP servers directly in the plugin entry inside marketplace.json:

{
  "name": "my-plugin",
  "description": "My team's developer tools",
  "source": "./plugins/my-plugin",
  "version": "1.0.0",
  "category": "development",
  "strict": false,
  "lspServers": {
    "pyright": {
      "command": "pyright-langserver",
      "args": ["--stdio"],
      "extensionToLanguage": {
        ".py": "python",
        ".pyi": "python"
      }
    },
    "typescript": {
      "command": "typescript-language-server",
      "args": ["--stdio"],
      "extensionToLanguage": {
        ".ts": "typescript",
        ".tsx": "typescriptreact",
        ".js": "javascript",
        ".jsx": "javascriptreact"
      }
    }
  }
}

Claude Code reads lspServers from the marketplace manifest when the plugin is installed. The plugin directory itself only needs a LICENSE and README.md — no additional config files.

Option 2: .lsp.json in the plugin directory (fallback)

Place a .lsp.json file inside the plugin's install directory:

{
  "pyright": {
    "command": "pyright-langserver",
    "args": ["--stdio"],
    "extensionToLanguage": {
      ".py": "python",
      ".pyi": "python"
    }
  }
}

This mechanism is picked up by Claude Code's plugin loader, but it has a known race condition: the LSP Server Manager sometimes initialises before plugins finish loading, causing .lsp.json configs to never register. For this reason, always prefer Option 1.

Best practice: use both

The sq-dev plugin defines lspServers in the marketplace manifest and keeps a .lsp.json in the plugin directory as a belt-and-suspenders approach. If either mechanism fails, the other provides coverage.

Key requirements

  • The language server binary must be globally installed (e.g. via npm install -g). Claude Code spawns the language server as a child process outside any virtual environment, so binaries inside .venv/bin/ won't be found.
  • Each lspServers entry needs: command (the binary name), extensionToLanguage (maps file extensions to language IDs). Optional fields: args, env, settings, initializationOptions, startupTimeout, workspaceFolder.
  • Multi-purpose plugins work fine — a single plugin can bundle skills, MCP servers, agents, and LSP servers together. The lspServers key sits alongside other plugin fields in the manifest.

For the full plugin configuration reference, see the official docs on plugins.


Troubleshooting

Symptom Cause Fix
Executable not found: typescript-language-server Global npm install missing npm install -g typescript-language-server typescript
Executable not found: pyright-langserver npm install -g pyright not run npm install -g pyright
pyright-langserver not in PATH after install npm global bin not in PATH Add export PATH="$(npm bin -g):$PATH" to shell profile
LSP starts but no Python diagnostics Pyright can't find venv Add pyrightconfig.json at project root (see above)
LSP starts but wrong Python version Wrong venv path in config Check venvPath and venv in pyrightconfig.json
Plugin LSP not activating lspServers missing from marketplace manifest Add the lspServers key to the plugin entry in marketplace.json (see above)
Plugin LSP intermittent Race condition with .lsp.json fallback Add lspServers to the marketplace manifest as the primary mechanism
Plugin errors in /plugin tab Plugin cache outdated /plugin update sq-dev@sartiq-marketplace

General debug steps:

  1. Run claude --debug 2>&1 | grep -i lsp — check for startup errors
  2. Confirm the language server binary is globally installed (which pyright-langserver should return a path outside .venv/)
  3. Confirm you started Claude Code from the project root (not a subdirectory)
  4. Confirm you restarted Claude Code after setup — LSP servers initialise at session start, not mid-session

Quick Reference

# TypeScript — once per machine
npm install -g typescript-language-server typescript

# Python — once per machine
npm install -g pyright

# Verify binaries
which typescript-language-server
which pyright-langserver

# Check servers started (run from project root)
claude --debug 2>&1 | grep -i lsp

# Force plugin cache refresh after an update
/plugin update sq-dev@sartiq-marketplace