Expose additional LSP operations: diagnostics, codeAction, rename
Feature Request
The built-in LSP tool currently exposes 9 operations:
goToDefinition, findReferences, hover, documentSymbol, workspaceSymbol, goToImplementation, prepareCallHierarchy, incomingCalls, outgoingCalls
These are excellent for code navigation, but the LSP protocol has ~40+ capabilities, and several high-value ones are missing. Adding them would significantly improve Claude's ability to understand, validate, and refactor code — especially in typed languages like Java, TypeScript, C#, and Rust.
Requested Operations (by impact)
1. textDocument/diagnostic (pull diagnostics)
Why: Lets Claude check if code compiles and see errors/warnings without running a full build. Currently, the only way to know if a change broke something is to run mvn compile or equivalent — which is slow and noisy. Diagnostics from the LSP are instant since the server is already analyzing the code in the background.
Use case: After editing a Java file, Claude could immediately check "did I break anything?" without a build round-trip.
2. textDocument/codeAction
Why: LSP code actions are context-aware fixes and refactorings: auto-fix imports, implement interface methods, extract variable/method, convert to lambda, etc. These are operations Claude currently does manually (and sometimes gets wrong — e.g., guessing import paths instead of letting the language server resolve them).
Use case: Claude edits a file, a diagnostic shows a missing import → code action resolves the correct fully-qualified import automatically.
3. textDocument/rename
Why: LSP rename is semantic — it understands type hierarchies, updates imports, handles overrides, and renames across the entire workspace. Currently Claude has to use Grep-based find-and-replace, which is fragile (can miss references, rename unrelated symbols with the same name, or break imports).
Use case: Renaming a method on an interface correctly propagates to all implementing classes and call sites.
4. textDocument/signatureHelp (lower priority)
Why: Shows exact parameter types and documentation for a method call. Useful when Claude is writing a call to an API it hasn't read yet.
5. textDocument/typeDefinition (lower priority)
Why: Navigates from a variable to its type declaration (vs goToDefinition which goes to the variable's definition). Useful for understanding what type a variable holds without hovering.
Context
- These operations are language-agnostic — they'd benefit all LSP-enabled plugins (Java/jdtls, TypeScript, Python/pyright, Go/gopls, Rust/rust-analyzer, etc.)
- The LSP server is already running and maintaining full project state — these capabilities are "free" to expose since the server already computes them
ENABLE_LSP_TOOL=1suggests the tool is still maturing, so this seems like a natural next step
Environment
- Claude Code CLI (latest)
- Using jdtls-lsp plugin (Eclipse JDT.LS 1.57.0)
7 Comments
+1 — diagnostics and rename are the big ones for Go development. gopls already computes them, just need the LSP tool to expose the operations.
+1 to add an official "rename" tool, in particular.
I currently use the "rename_symbol" tool from my own revise-mcp server but would love a first-party implementation in Claude Code or its LSP server.
FWIW, VS Code Copilot Agent somewhat recently - in VS Code 1.110 (February 2026) - added its own official "rename" tool.
+1 for rename and codeAction. I have an Intelephense Premium license specifically for these features, but Claude Code's LSP tool only exposes 9 operations. rename would be especially valuable — it's symbol-aware and safer than grep+edit for refactoring. Currently there's no built-in way to leverage paid LSP features like this.
I have implemented a MCP server that LSP plugins can use to automatically provide tools for missing unimplemented features, which were perplexingly left out by the developers for reasons we cannot explain. Since Anthropic does not communicate clearly, it seems that this is done by a products management or marketing team, for example creating an artificial release as "We shipped enhanced support for LSP!" I have implemented a LSP plugin using
tyfor python which uses the MCP shim.Using this shim, LSP plugins can ship with a cc hook that forbids the builtin
LSPtool and replace the output with a redirection banner requesting Claude to use our powerful interface.This provides the rename tool. The tools also do not require passing line:col arguments which is simply incorrect for this interface context. Instead, Claude provides a line number and a text match. The MCP plugin fetches the correct
Features
---
Over the course of this implementation, Claude Opus 4.7 itself said that the builtin support is 'trash', no holding back or hedging. This is shocking since this can scale capabilities dramatically and is the first thing a harness needs. Perhaps it would reveal that the previous models were more useful than previously thought, and that the new model is not their "most capable yet" but rather "evaluated on a more capable harness."
I am understandingly upset. The Anthropic developers repeatedly do not address low-hanging fruits, and when we bring up those things, it's all crickets. We could implement it ourselves, but the harness is closed source, even though this isn't a moat and is all basic plumbing. This is a symptom of a much more serious problem happening at this company and nobody seems to notice. Again, these are things that Anthropic must address, otherwise we are left to assume the most basic explanation.
Thank you
+1 for rename,
So weird it's not already supported
Ran into this trying to figure out why the official
ruby-lspplugin produces zero diagnostics in Claude Code. Did a full out-of-process investigation; the relevant bit for this thread:ruby-lsp 0.26.9 (current latest) ships exactly one outbound
textDocument/publishDiagnosticscall in the entire codebase. It's intext_document_did_close, where it sends an empty array to clear stale diagnostics for the closing file. That's the whole push surface. Same on main HEAD. Everything else, edits, opens, saves, lives behindtextDocument/diagnostic(pull).Confirmed by writing a small LSP JSON-RPC stdio driver and pointing it at a Ruby file with 11 deliberate rubocop offenses (LineLength 200+ chars, ParameterLists with 8 args, single-letter param names):
didOpen+ 15s listening window: zero notificationsdidChange+ 15s listening window: zero notificationstextDocument/diagnostic(pull): all 11 offenses come back, severity + ranges + autocorrect data intactThis is intentional. Shopify/ruby-lsp#242 (merged August 2022) deliberately switched from push to pull-only. The PR title is literally "Let clients pull diagnostics instead of pushing on edits." Rationale was performance: pull decouples diagnostics from didChange and lets the client debounce.
When someone hit the same wall with Nova in Shopify/ruby-lsp#1873,
@vinistock(ruby-lsp maintainer) was direct:NeoVim users hit it too; the official ruby-lsp docs now point them at a community plugin (
pull_diags.nvim) to add pull support on the client side.So any LSP server that's migrated to pull-only since LSP 3.17 (March 2022) is invisible to Claude Code's diagnostic enrichment today. ruby-lsp is the most prominent one, list is growing. Implementing this feature request is the only realistic path forward for those servers, since upstream has been clear they're not adding push back.
Happy to share the driver script if it's useful for repro.
Drove the same JSON-RPC stdio driver against gopls, typescript-language-server, and rust-analyzer to see how widely the missing-diagnostics gap actually applies. LSP 3.17 added pull diagnostics alongside push, so any of these servers could be on either side.
It's a mixed bag.
gopls v0.22.0 (go1.26.1) is push-comprehensive.
publishDiagnosticsfires on didOpen, didChange, and didSave.diagnosticProviderisn't advertised, buttextDocument/diagnosticactually works anyway (returnskind: "", which is off-spec, but the items come back). Push and pull carry the same content. Claude Code's existing receive-push path works fine here.typescript-language-server 5.2.0 (bundled tsserver 6.0.3) is push-only. Fires
publishDiagnosticson didOpen and didChange.textDocument/diagnosticreturns-32601 Unhandled method. Pull doesn't exist here at all. Push content is complete (all 8 TS errors withsource: "typescript", codes 2322/2345/6133). Claude Code is fine here too.rust-analyzer 0.3.2904 (2026-05-17) is the interesting one. It advertises both push and pull, both work, but they carry different content.
Drove it against a tiny cargo crate with:
use std::collections::HashMap;(unused import)fn BadlyNamed()(non_snake_case)let x: i32 = "not a number";(E0308)fn AnotherBadName(unused_param: i32) -> i32 { unused_param + "oops" }Per-phase counts:
Push channel returned:
rustc:unused_imports,rustc:E0308.Pull channel returned:
rust-analyzer:non_snake_case(x2),rust-analyzer:E0308.Only E0308 shows up in both. Everything else is one-channel-only. A push-receive client gets cargo-check warnings and errors but never sees rust-analyzer's native lints (non_snake_case, dead_code patterns, and friends).
rust-analyzer also fires
workspace/diagnostic/refresh(twice in my run), which is the server telling clients to re-pull. A client that only listens for push silently ignores that and never re-fetches the pull-only diagnostics. So even when push works, you lose freshness on the native lint side.Net of the four servers:
| server | push works? | pull needed? |
|---|---|---|
| ruby-lsp | no | yes, for all diagnostics |
| rust-analyzer | partially | yes, for native lints |
| gopls | yes | no |
| typescript-language-server | yes | no |
Adding pull-diagnostic support to Claude Code:
Worth surveying clangd, pyright/basedpyright, and vtsls at some point too. Happy to share the driver scripts if anyone wants to repro or extend.