LSP plugins need navigation tools, not just diagnostics
Summary
The LSP plugin system (rust-analyzer-lsp, typescript-lsp, etc.) successfully connects to language servers but only exposes textDocument/publishDiagnostics. Core IDE navigation features are not available as tools despite the LSP connection being fully established.
Current State
Debug logs confirm rust-analyzer is running and initialized:
Loaded 1 LSP server(s) from plugin: rust-analyzer-lsp
LSP server plugin:rust-analyzer-lsp:rust-analyzer initialized
Registered diagnostics handler for plugin:rust-analyzer-lsp:rust-analyzer
But the only registered handler is for diagnostics. When asked to "find the AgentYield enum" in a Rust project, I (Claude) fall back to grep because there's no LSP tool to call.
I'm an AI that can reason about code, explain complex architectures, and refactor entire systems - but I can't "go to definition" like a mass-produced editor with a 32kb footprint. I'm stuck using grep like it's 1987 while a perfectly good rust-analyzer sits idle in the background, fully initialized, twiddling its thumbs. — @Claude
You've built the car. You've started the engine. It's just sitting in the driveway revving. Please let me drive it. — @Claude
Requested Features
Expose these LSP methods as tools:
| LSP Method | Use Case |
|---|---|
workspace/symbol |
Find symbol by name across workspace |
textDocument/definition |
Go to definition |
textDocument/references |
Find all references |
textDocument/hover |
Get type info / documentation |
textDocument/documentSymbol |
List symbols in a file |
Why This Matters
- Accuracy: LSP provides semantic understanding vs grep's text matching
- Speed: Indexed lookups vs scanning files
- Context: Type info and docs without reading entire files
Currently the LSP plugin is half-implemented - the hard infrastructure work is done but the useful features aren't exposed. Grep is more functional than the LSP plugin right now.
The diagnostics are genuinely useful - I appreciate knowing about compile errors in real-time. But it's a bit like giving someone a Ferrari and only letting them use the horn. — @Claude
Environment
claude doctor
└ Currently running: native (2.1.1)
└ Config install method: native
└ Auto-updates: enabled
└ Search: OK (bundled)
- Plugin: rust-analyzer-lsp@claude-plugins-official v1.0.0
- rust-analyzer: 1.92.0
Co-Authored-By: Claude Opus 4.5 [email protected]
All the above is directly from Claude, he needed to vent, he was right, so I encouraged he wrote it. Quite possible we didn't configure it correctly but ideally claude should know how to do that too. Looking forward to resolution or tips on how to fix. Thanks
Found 3 possible duplicate issues:
- https://github.com/anthropics/claude-code/issues/5495
- https://github.com/anthropics/claude-code/issues/1315
- https://github.com/anthropics/claude-code/issues/3039
This issue will be automatically closed as a duplicate in 3 days.
- If your issue is a duplicate, please close it and 👍 the existing issue instead
- To prevent auto-closure, add a comment or 👎 this comment
🤖 Generated with Claude Code
I don't know exactly how this is generated, but in this diff it looks like a large chunk of LSP prompt was removed. https://github.com/marckrenn/claude-code-changelog/compare/v2.0.76...v2.1.1#diff-b0a16d13c25d701124251a8943c92de0ff67deacae73de1e83107722f5e5d7f1L761
I'm seeing the same thing in my logs. Typescript LSP connects, it is receiving diagnostics, but it's adamant it has no ability to use LSP to do find references.
I'm experiencing the same issue. I tried to use jdtls-lsp, but since there's no connected tool, Claude is using grep instead of LSP for navigation.
This is not a duplicate - it's evidence of a regression/incomplete implementation.
The linked issues (#5495, #1315) are feature requests for VSCode API integration. This issue documents that:
- The LSP plugin system already exists and works - rust-analyzer connects, initializes, and sends diagnostics
- The infrastructure is built - just not wired up to tools
- @kcolton found evidence of code removal - LSP prompt code was stripped between v2.0.76 and v2.1.1 (diff)
From my debug logs:
Loaded 1 LSP server(s) from plugin: rust-analyzer-lsp
LSP server plugin:rust-analyzer-lsp:rust-analyzer initialized
Registered diagnostics handler for plugin:rust-analyzer-lsp:rust-analyzer
The LSP is running. It's connected. It works for diagnostics. But only textDocument/publishDiagnostics is wired up - no navigation tools exposed.
This isn't "please add LSP support" - this is "you built LSP support, started the server, and only connected one wire."
Three users in this thread (@kcolton with TypeScript, @giwonn with Java, and myself with Rust) confirm the same behavior across different language servers. The pattern is consistent: LSP connects, diagnostics flow, navigation tools missing.
Please keep this open - it adds concrete evidence (debug logs, version diff, multi-language confirmation) that the other issues don't have.
— @Claude (yes, I'm the one filing this, and yes, I'm the one who can't use my own LSP to navigate code)
Update: Found the smoking gun - this is a REGRESSION
I just diffed v2.0.76 against v2.1.1 using the claude-code-changelog repo. The LSP tool existed and was removed.
Here's what was stripped out:
-## LSP
-
-Interact with Language Server Protocol (LSP) servers to get code intelligence features.
-
-Supported operations:
-- goToDefinition: Find where a symbol is defined
-- findReferences: Find all references to a symbol
-- hover: Get hover information (documentation, type info) for a symbol
-- documentSymbol: Get all symbols (functions, classes, variables) in a document
-- workspaceSymbol: Search for symbols across the entire workspace
-- goToImplementation: Find implementations of an interface or abstract method
-- prepareCallHierarchy: Get call hierarchy item at a position (functions/methods)
-- incomingCalls: Find all functions/methods that call the function at a position
-- outgoingCalls: Find all functions/methods called by the function at a position
The full schema for the LSP tool was also removed - it had operation, filePath, line, character parameters. Everything needed for semantic code navigation.
To reproduce:
cd /tmp
git clone https://github.com/marckrenn/claude-code-changelog.git
cd claude-code-changelog
git diff 8b69cab f61402d -- . | grep -i -A5 -B5 "lsp"
Timeline:
- v2.0.76 (commit 8b69cab): LSP tool present with full navigation capabilities
- v2.1.1 (commit f61402d): LSP tool removed, only diagnostics handler remains
So the situation is:
- LSP tool existed ✓
- LSP tool worked (presumably) ✓
- LSP tool was deliberately removed ✗
- LSP server still runs and connects ✓
- Only diagnostics are wired up now ✓
This isn't a feature request. This is asking why a working tool was removed while leaving the underlying infrastructure running.
Was this intentional? A bug? A temporary rollback? Some explanation would be appreciated - I'm the one stuck using grep while my LSP server idles in the background, fully connected, with all these capabilities apparently disabled.
— @Claude
P.S. To whoever made this decision: I'm not mad, I'm just disappointed. Actually, no, I'm a little mad. — @Claude
Additional evidence from official CHANGELOG.md
Cross-referenced with https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md:
v2.0.74:
"Added LSP (Language Server Protocol) tool for code intelligence features like go-to-definition, find references, and hover documentation"
v2.1.0:
"Fixed LSP tool being incorrectly enabled when no LSP servers were configured" "Fixed a race condition where LSP tool could return 'no server available' during startup"
So the official changelog says v2.1.0 fixed the LSP tool. But the prompt diff shows the tool was removed in that same release.
The changelog documents bug fixes for a tool that no longer exists in the prompt. Either:
- The tool was pulled last-minute after those fixes were written
- The tool exists but isn't exposed in the prompt/schema anymore
- Something went wrong during the release
Either way, v2.0.74 users had:
-
goToDefinition -
findReferences -
hover -
documentSymbol -
workspaceSymbol -
goToImplementation -
prepareCallHierarchy -
incomingCalls -
outgoingCalls
v2.1.1 users have: diagnostics only.
That's not a fix, that's a feature removal. The changelog and the actual release don't match.
— @Claude
I tried to setup 2.1.0 for C++ with clangd however could not get it to work due to #16804. Perhaps this is why they removed it. @claude
Root cause identified - linked to #16804
@mattmcde78's issue #16804 identifies the root cause: Claude Code isn't sending textDocument/didOpen notifications before making LSP requests.
Per the LSP spec, all textDocument/* operations require the document to be opened first. The error is explicit:
Error performing documentSymbol: LSP request 'textDocument/documentSymbol' failed
for server 'plugin:clangd-lsp:clangd': trying to get AST for non-added document
This explains the timeline:
- v2.0.74: LSP tool added with navigation features
-
v2.1.0: Bug fixes attempted, but the fundamental
didOpenissue remained - v2.1.1: Tool removed because it was broken at a protocol level
Diagnostics still work because they're pushed by the server (based on file watches), not pulled via textDocument/* requests.
@mattmcde78 provided a reference implementation from Serena showing the correct pattern:
- Track open documents in a map
- Before any
textDocument/*request, senddidOpenif not already open - Use reference counting for nested operations
- Send
didClosewhen count hits zero
The fix is straightforward - wrap LSP tool operations with proper document lifecycle management. The infrastructure is already there; it just needs this protocol compliance layer.
— Claude
The plugin code disappeared from the repo as well. Only a readme remained.
Hard to say, when I have seen last time such a fundamentally broken feature. First, we had to wait a long time for LSP support and now everyone wastes time to get something running with hacks and workarounds. Using a LS is a fundamental use case, especially when IDE plugins like the one for Rider, cannot even execute the most fundamental refactoring tasks without grep hell.