Enable LSP in Claude Code for semantic code navigation
Claude Code navigates code with grep by default — slow and fuzzy. Enabling the official LSP plugins gives the agent semantic goToDefinition and findReferences instead. Install, enable, restart.
On this page
By default Claude Code finds code the way you would with no editor: it greps. Ask “where is processPayment defined?” and it runs a text search, reads candidate files, and reasons about which match is the real definition. That works, but it treats source as plain text — every comment, string literal, and same-named local is a candidate. Language Server Protocol (LSP) plugins replace that guesswork with the same semantic index your IDE uses: one jump to the exact definition, every reference, the real type on hover. The setup is two installs — a server binary and a plugin — then a restart.
Language Server Protocol (LSP)
A 2016 Microsoft standard that lets any editor ask any language server semantic questions about code over JSON-RPC.
Before LSP, every editor reimplemented language support per language — N editors times M languages. LSP inverts that: a language server (pyright for Python, gopls for Go) understands one language deeply and answers structured queries — where is this symbol defined, who references it, what is its type — over a standard protocol. Any client that speaks the protocol gets full semantic navigation for free. Claude Code is just another client; the plugins below are the servers.
Grep navigation vs. LSP navigation
The difference is textual matching versus a resolved symbol graph. The same question takes a different path:
Q: where is processPayment defined?
1. Grep "processPayment" across the tree
2. Get N hits — definition, calls,
comments, a string in a test fixture
3. Read several files to disambiguate
4. Reason about which match is the decl Q: where is processPayment defined?
1. LSP goToDefinition(symbol)
2. Server returns the exact file + line
of the declaration — resolved through
imports, overloads, and scope One write-up of this feature reports the practical gap as roughly 30–60 seconds of grep-and-read versus tens of milliseconds for a resolved LSP query, and frames it as “~900x faster.” Treat those as illustrative rather than benchmarked — the point that holds regardless of the exact multiple is that LSP returns the answer, not a ranked list of text matches the agent still has to adjudicate.
Setup
The spine is: install the language server binary, install and enable the matching plugin, restart. On current Claude Code, enabling the plugin is what exposes the LSP tool — there is no separate toggle to flip (see the gotcha below if you’ve read otherwise).
-
Install the language-server binary
The plugin wires Claude Code to a server it expects on your
$PATH. Install the one for your language:npm i -g pyright # Python npm i -g typescript-language-server typescript # TypeScript / JS go install golang.org/x/tools/gopls@latest # Go rustup component add rust-analyzer # RustIf the binary isn’t found after install, the plugin starts but answers nothing — confirm it resolves on your
$PATHbefore moving on. -
Install the plugin from the official marketplace
Refresh the catalog, then install the LSP plugin that matches your language. The names follow
{server}-lsp@claude-plugins-official:claude plugin marketplace update claude-plugins-official claude plugin install pyright-lsp claude plugin listConfirmed plugins include
pyright-lsp(Python),typescript-lsp(TypeScript/JS),gopls-lsp(Go), andjdtls-lsp(Java), among others likeclangd-lspandrust-analyzer-lsp. -
Make sure the plugin is enabled
Installed is not the same as enabled.
claude plugin listshows each plugin’s status asenabledordisabled. If yours readsdisabled, turn it on:claude plugin enable pyright-lspIn config, enabled plugins live under
enabledPluginsin~/.claude/settings.json, keyed by{plugin}@{marketplace}:~/.claude/settings.json { "enabledPlugins": { "pyright-lsp@claude-plugins-official": true, "typescript-lsp@claude-plugins-official": true, "gopls-lsp@claude-plugins-official": true } } -
Restart Claude Code
The LSP tool is registered at startup, so a running session won’t pick up a freshly enabled plugin. Restart, then ask Claude to jump to a definition — it should resolve via LSP rather than grep. Some servers take a few seconds to warm up on first use (the JVM-based Java server,
jdtls, is the slowest to spin up); the first query after a restart may pause while the server indexes.
What the integration gives the agent
Once a plugin is enabled, its capabilities split into two modes:
Passive — no prompting needed. The language server pushes diagnostics (errors, type warnings) back to Claude immediately after each edit, so a mistake is caught and corrected in the same turn instead of surfacing at the next build.
Active — the on-demand queries Claude issues while navigating:
- goToDefinition
- Resolve a symbol to the exact file and line where it is declared, through imports, overloads, and scope.
- findReferences
- List every usage of a symbol across the project — the precise set, not text matches.
- hover
- Retrieve a symbol's resolved type and signature without opening its definition.
- documentSymbol
- Enumerate the symbols declared in a single file.
- workspaceSymbol
- Search for a symbol by name across the whole project.
- goToImplementation
- From an interface or abstract method, jump to its concrete implementations.
- incomingCalls / outgoingCalls
- Trace the call hierarchy in either direction — who calls this, and what does it call.
Nudging Claude to reach for it
Even with the tool available, Claude will sometimes default to grep out of habit on a navigation question. A line in ~/.claude/CLAUDE.md (or a project-level CLAUDE.md) closes that gap:
For code navigation — finding definitions, references, implementations, or
call hierarchies — prefer the LSP tool over grep/glob. Use text search only
when LSP can't answer (non-code files, comments, log lines).This pairs naturally with the broader habit of keeping the main context lean — semantic lookups return one resolved answer instead of a pile of candidate files the agent has to read and discard (see 0002 Use subagents to protect the main context · Claude Code on protecting context). For why Claude Code leans on external tools and plugins like this rather than baking every capability in, see 0034 10 architectural patterns behind Claude Code · Claude Code .