← Back to Blog

The 2-Minute Claude Code Upgrade You're Probably Missing: LSP

Right now, every Claude Code user is running without LSP. That means every time you ask "where is processPayment defined?", Claude Code does what you'd do with a terminal. It greps. It searches text patterns across your entire codebase, reads through dozens of files, and tries to figure out which match is the actual definition.

It works. But it's slow, it's fuzzy, and on large codebases it regularly misses or gets confused. Search for User in a real project and you get 847 matches across 203 files: class definitions, variable names, comments, imports, CSS classes, SQL columns. The thing you actually wanted? Buried somewhere in the middle. Claude Code has to read through each match to narrow it down. That takes 30-60 seconds. Sometimes longer.

There's a feature that changes this entirely. It's called LSP, the Language Server Protocol. It's not enabled by default. It's not prominently documented. The setup requires a flag discovered through a GitHub issue, not the official docs. But once it's on, the same query ("where is processPayment defined?") returns the exact file and line number in 50 milliseconds. Not 30 seconds. Fifty milliseconds. With 100% accuracy.

That's not an incremental improvement. That's a category change in how Claude Code navigates your code.

TL;DR

Claude Code ships without LSP enabled. Enabling it gives Claude the same code intelligence your IDE has: go-to-definition, find references, type info, real-time error detection. From my debug logs: ~50ms per query vs 30-60s with grep. Two minutes of setup. Jump to setup →

What You're Currently Running

By default, Claude Code navigates your codebase with text search tools: Grep, Glob, and Read. It's the same as having a very fast developer with grep and find at a terminal. Smart pattern matching, but fundamentally just matching text.

The core problem: grep treats code as text. But code is not text. It has structure, meaning, and relationships. When you ask "where is getUserById defined?", you want the one function definition, not the 50 places that call it plus the 12 comments that mention it. Grep can't tell the difference. LSP can.

What LSP Actually Is

Before 2016, every code editor had to build its own language support from scratch. VS Code needed a Python plugin. Vim needed a separate Python plugin. Emacs, Sublime, Atom — each one reinventing the same work. Twenty editors times fifty languages meant a thousand separate implementations, most of them incomplete.

Before LSP: M × N VS Code Vim Emacs Sublime Python TypeScript Go Rust 4 × 4 = 16 plugins With LSP: M + N VS Code Vim Emacs Claude Code LSP Protocol Pyright ts-server gopls rust-analyzer 4 + 4 = 8 implementations

In 2016, Microsoft had an insight: separate the language intelligence from the editor. Create a protocol, a standard way for any editor to talk to any language server. The editor says "where is this symbol defined?" in JSON-RPC. The language server (a separate process that deeply understands one language) answers.

That's LSP. It turned a thousand-implementation problem into a seventy-implementation one. And it's why your VS Code Python experience is exactly as good as your Neovim Python experience — they're both talking to Pyright.

The Performance Gap

Here's the thing nobody talks about: AI coding assistants had the exact same problem that editors had before LSP. Without it, Claude Code does text search. Grep, Glob, Read. It works. But the cost is measured in seconds per query, multiplied by dozens of queries per task. It adds up fast.

Without LSP grep -r "User" 847 matches 203 files Filter & read each file... ~30-60 seconds maybe correct With LSP goToDefinition JSON-RPC user-service.ts line 42 ~50ms · 100% accurate ~900× faster, guaranteed accuracy

What Claude Code Gets from LSP

LSP gives Claude Code two categories of superpowers: things that happen automatically and things it can actively request.

Passive: Self-Correcting Edits

This is the most valuable part, and most people don't even realize it's happening. After every file edit, the language server pushes diagnostics: type errors, missing imports, undefined variables. Claude Code sees these immediately and fixes them in the same turn, before you ever see the error.

1 You ask Claude: "Add email param" 2 Claude edits createUser() 3 LSP detects 3 errors in call sites 4 Claude fixes all 3 0 errors ✓ All 4 steps happen in a single turn — before you see the result. No manual iteration. No "oops, I missed a call site." It just works.

Think about what this means in practice. You ask Claude to add an email parameter to createUser(). Claude edits the function signature. The language server instantly reports 3 errors at three call sites that now have the wrong number of arguments. Claude sees the errors, finds all three call sites, and fixes them. You get the result with zero errors on the first try.

Without LSP, Claude would edit the function, hand you the result, you'd try to compile, see 3 errors, paste them back to Claude, and iterate. With LSP, that entire loop collapses into one step.

Active: On-Demand Code Intelligence

Beyond automatic diagnostics, Claude Code can explicitly ask the language server questions:

You don't need to use these operations explicitly. Just ask Claude Code naturally. "Where is authenticate defined?", "find all usages of UserService", "what type is response?" It routes to the right LSP operation automatically.

Setting It Up

Here's the full setup. It takes about 2 minutes, and you only do it once.

Prerequisites

Step 1: Enable the LSP Tool

This is the part that trips people up. You need to add a flag to your Claude Code settings:

Add this to your ~/.claude/settings.json:

"ENABLE_LSP_TOOL": "1"
Heads up

ENABLE_LSP_TOOL is not officially documented as of February 2026. It was discovered via GitHub Issue #15619 as a community workaround. It may change or become unnecessary in future versions. I also recommend adding export ENABLE_LSP_TOOL=1 to your shell profile (~/.zshrc on macOS, ~/.bashrc on Linux) as a fallback.

Step 2: Install the Language Server

Install the binary for each language you work with. These are the same language servers your IDE uses. LSP is universal.

Language Plugin Install Command
Python pyright-lsp npm i -g pyright
TypeScript/JS typescript-lsp npm i -g typescript-language-server typescript
Go gopls-lsp go install golang.org/x/tools/gopls@latest
Rust rust-analyzer-lsp rustup component add rust-analyzer
Java jdtls-lsp brew install jdtls
C/C++ clangd-lsp brew install llvm
C# csharp-lsp dotnet tool install -g csharp-ls
PHP php-lsp npm i -g intelephense
Kotlin kotlin-lsp GitHub releases
Swift swift-lsp Included with Xcode
Lua lua-lsp GitHub releases

Step 3: Install and Enable the Plugin

First, update the marketplace catalog:

claude plugin marketplace update claude-plugins-official

Then install the plugin for your language:

claude plugin install pyright-lsp Python
claude plugin install typescript-lsp TypeScript/JS
claude plugin install gopls-lsp Go
claude plugin install rust-analyzer-lsp Rust
claude plugin install jdtls-lsp Java
claude plugin install clangd-lsp C/C++
claude plugin install csharp-lsp C#
claude plugin install php-lsp PHP
claude plugin install kotlin-lsp Kotlin
claude plugin install swift-lsp Swift
claude plugin install lua-lsp Lua

Verify it's installed and enabled:

claude plugin list
The #1 gotcha

A plugin can be installed but disabled. A disabled plugin won't register its LSP server at startup. If claude plugin list shows Status: disabled, run claude plugin enable <name> and restart Claude Code.

To be safe, I also explicitly set them to true in ~/.claude/settings.json:

{
  "ENABLE_LSP_TOOL": "1",
  "enabledPlugins": {
    "pyright-lsp@claude-plugins-official": true,
    "typescript-lsp@claude-plugins-official": true,
    "gopls-lsp@claude-plugins-official": true
  }
}

This single issue — plugins installed but not enabled — accounts for most "LSP isn't working" problems.

Step 4: Restart Claude Code

LSP servers initialize at startup. After installing plugins, you need a full restart. Then verify by asking Claude: "What type is [some variable]?" — if it uses the LSP hover operation instead of reading the file, you're good.

What Happens at Startup

Here's something I found interesting while digging through debug logs. When Claude Code starts, all enabled LSP servers launch simultaneously. They don't wait for you to open a file.

From my actual debug logs (4 language servers enabled):

# From ~/.claude/debug/ — session on Feb 23, 2026

05:53:56.216  [LSP MANAGER] Starting async initialization
05:53:56.573  Total LSP servers loaded: 4
05:53:56.757  gopls initialized          (+0.5s)
05:53:56.762  typescript initialized     (+0.5s)
05:53:56.819  pyright initialized        (+0.6s)
05:54:04.791  jdtls initialized          (+8.6s)
              Index is warm — all LSP operations now ~50ms

Two things stand out. First, the Java server takes ~8 seconds because of JVM warmup — this is normal, not a bug. Second, servers start indexing your entire project immediately. They scan all files of their language type, build symbol tables, and resolve dependencies. By the time you ask your first question, the index is already warm.

This means goToDefinition, findReferences, and hover work for any symbol in your project — not just files you've opened. The language server has already seen everything.

Using It in Practice

You don't need to learn any new commands. Just talk to Claude Code the way you normally would:

You say... Claude uses...
"Where is authenticate defined?" goToDefinition
"Find all usages of UserService" findReferences
"What type is response?" hover
"What functions are in auth.ts?" documentSymbol
"Find the PaymentService class" workspaceSymbol
"What implements AuthProvider?" goToImplementation
"What calls processPayment?" incomingCalls
"What does handleOrder call?" outgoingCalls

The real power shows up in refactoring sessions. When you're renaming a method, adding a parameter, or changing a return type, LSP ensures Claude finds every reference and updates them correctly — not the "grep found 47 out of 52 actual usages" situation.

You can also press Ctrl+O to see diagnostics pushed by LSP servers. This shows you what the language servers are seeing in real time.

The Gotchas

I hit most of these so you don't have to.

Issue Cause Fix
LSP tool not available at all ENABLE_LSP_TOOL not set Add to settings.json, restart
"Plugin not found in any marketplace" Stale marketplace catalog claude plugin marketplace update claude-plugins-official
Plugin installed but disabled Not enabled after install claude plugin enable <name> + restart
"Executable not found in $PATH" Binary not installed or not in PATH Install binary, verify with which <binary>
"No server available" Race condition during startup Restart Claude Code, wait for servers to initialize
"Total LSP servers loaded: 0" in logs Plugins installed but all disabled Enable plugins, restart

Debug Checklist

When things aren't working:

  1. Check the binary is installed: which pyright-langserver (or whatever binary your language needs)
  2. Check plugin status: claude plugin list — look for Status: enabled
  3. Check debug logs at ~/.claude/debug/latest — search for "Total LSP servers loaded: N" where N should be > 0

Every Claude Code session you run without LSP is a session where every "find this definition" takes 30-60 seconds instead of 50ms. Where every refactor misses call sites that a language server would have caught instantly. Where errors that LSP would have surfaced and auto-fixed slip through to your review.

The setup is two minutes. The feature flag is one line in your settings. The performance difference is not subtle — it's the gap between text search and semantic code intelligence. The same gap that made IDEs better than Notepad, except now it's making your AI assistant better at its job.

If you're already using Claude Code, enable LSP. You'll feel it on the very first query.