← All publications

LSP for AI Coding Agents: The Protocol Your Agent Isn't Using Yet

Introduction

Your agent guesses. It matches names as text and hopes the right line was in what it read. A language server replaces the guessing with code intelligence, because it parsed your code and knows.

For almost a year now I have been working as an AI Enablement Lead at a product company, and I am responsible for research and AI adoption among software developers and QA. On our codebase LSP cut the agent’s token usage by 16-22% and its execution time by 30-40%. Everything below rests on my own tests and on an independent benchmark from CircleCI.

What LSP is

LSP (Language Server Protocol) is a standardized protocol for communication between a code editor and a server that analyzes the source code and provides information about it.

Before it appeared in 2016, every smart editor feature had to be written again for every language. You want proper Python in VS Code, someone sits down and writes a plugin. You want the same thing in Vim, everything starts from scratch, because the API there is different. In Emacs, from scratch again. Ten editors for twenty languages, that is two hundred separate plugins, and their quality is very different.

LSP removed this nonsense with a single agreement. The language team writes one program (pyright for Python, gopls for Go, rust-analyzer for Rust), the editor team writes one wrapper, and after that everything works with everything.

How LSP got into the LLM world

The first well-known paper at the intersection of LSP and LLM appeared in June 2023 at Microsoft Research (arXiv 2306.10763).

Back then AI was still bad at software development, and there was one key problem. When an LLM types code and accesses an object, for example an instance of a class, it has no way at all to find out which methods this object actually has, if its definition sits in a neighboring file. There was nowhere to look. The model of that time simply typed text from left to right, with no tools, with no way to find something and open it. Functions and tool calls appeared in the API on June 13, 2023, in exactly the same month as this paper, and the first proper agents were still almost a year away.

This is exactly the point where the model started to hallucinate, making up something that looks like the truth. Imagine that developers had their IDE with IntelliSense taken away, were put into Notepad, and had the rest of the project files locked away. And here you are typing user. and trying to remember how it was: username? email? or maybe name after all?

The researchers started thinking about how to solve this problem, and they came up with this idea.

The model types code not in words but in tokens, and at every step it picks the next one from a list of candidates. At the moment when it puts a dot after the object, the generation is paused and the language server is asked which members this object really has. The list that comes back does not go into the model, it goes into the wrapper around it, and the wrapper simply crosses out of the candidates all the names that do not exist in the project. The model then picks from what is left, so it physically cannot type a method that does not exist.

Generation stops right after envTypeEnum., where the model has to pick a member name it cannot see. The language server answers with the members that exist on that type, among them getDescription(). TD-3 then typed getName() and SC typed getDesc(), neither of which is in that list, while the run with Monitor-Guided Decoding typed getDescription() and later ListResult.of() instead of the invented ListResult.success()

This approach was called Monitor-Guided Decoding. In Java the compilation rate went up by 19-25%, and there was no need to retrain the model for it.

This is the first well-known paper where the language server does not just feed the model context, but limits it. And the side product turned out to be more important than the experiment itself: to call the servers from Python, the authors wrote the multilspy library. This is exactly what solid-lsp later grew out of, inside Serena, which is the most popular LSP tool for agents (27 thousand stars at the time of writing). So the chain is direct: research from 2023 gave a library, the library gave the agent tooling of 2025-2026.

How it works

By default, an LLM works with your code as plain text, and it cannot do even a basic “go to definition”. For the agent to find the definition of an object, it has to use plain text search and collect the information it needs with the grep tool.

Modern models already do this well enough and they do not overload the context. For example Opus 5, when it looks for the definition of some object, does not read the whole file at once but finds only what it needs. But if the project is big and the dependencies are complex, this can take more tokens, more time, and in some situations it can also lead to errors.

LSP, in turn, gives the agent access to the language server, and behind that server there is a semantic model of the project, and the LLM gets a large number of tools for more flexible and more precise navigation through the code. This is especially visible on weaker models (the study below will confirm this).

Without LSP the agent sees four text matches for getUser and cannot tell which one is the definition. With LSP it gets the one true definition at user.ts:12 and the same-named method on admin is excluded by scope

LSP does not replace grep, it only extends what the LLM can do.

Why so few people talk about LSP

Even though the first use of LSP together with an LLM was in 2023, native LSP in the big agents has existed only since December 2025 (Claude Code and Kiro CLI). Only half a year has passed since then, and because of that it does not have any big independent studies or benchmarks. This approach is still new, and all the attention goes to other trendy directions like agentic development and context engineering.

In my opinion, LSP already has big potential, and in the next few years we will see it become one of the main pillars of agentic development.

Interesting fact: MCP, which is already used everywhere, was inspired by LSP during its development.

MCP takes some inspiration from the Language Server Protocol, which standardizes how to add support for programming languages across a whole ecosystem of development tools. In a similar way, MCP standardizes how to integrate additional context and tools into the ecosystem of AI applications. Source

Advantages

Besides the “go to definition” mentioned above, LSP also provides tools like these:

Diagnostics - the language server itself returns errors and warnings after every edit: types, missing imports, syntax. There is no need to run a compiler or a linter. For an agent this matters. If it made a mistake itself, it sees the mistake in the same turn and fixes it, without waiting for the user or for CI. For big projects and complex tasks this gives a big boost in productivity, because a build can take ~10-15 minutes.

Find all references - all the uses of a symbol. textDocument/references. A grep by name will give you matches in comments, in strings, in fields with the same name in other classes, and it will miss re-exports and aliases. LSP returns exactly the places that the compiler counts as references to this symbol. This is the key operation for “what will break if I change this”.

Document symbols - the table of contents of a file: classes, methods, fields, their nesting and their boundaries. textDocument/documentSymbol. A cheap replacement for reading the whole file.

Call hierarchy - call chains in both directions: who calls this function (incoming) and who it calls (outgoing). callHierarchy/incomingCalls / outgoingCalls. This is a trace several levels deep in one call. By hand the agent would build it with a dozen greps, losing branches on callbacks and virtual dispatches.

Hover / type info at a position - the actual type of an expression at a specific point. textDocument/hover. It is irreplaceable where the type is inferred and not written: var, generics, LINQ chains, the return of a factory. Grep physically cannot answer this question.

If you have worked in mobile development and know how long a project can take to build (compiling styles and views, bindings, translation resources), you will understand why diagnostics is one of the things I love about the Language Server Protocol. It lets the agent find the error right away instead of waiting for another build.

And this is not the full list of features. But availability can vary depending on the language and the environment. So always read the documentation before you use it.

Disadvantages

Of course, LSP does not fix everything, and it is not a solution to every problem. It also has certain downsides in use. Let’s look at them in more detail.

The main downside you should know about is that in some situations the search can be incomplete. LSP is responsible only for what the compiler sees, inside one language and one project. So everything where the name of your class or method lives as a string passes it by: creating a type by name through reflection, class names in configs and in logger settings, tables and columns in raw SQL and stored procedures, string routes that the frontend calls. All of this lives next to the code, but it is not a direct reference to a symbol.

In such cases the agent can ask LSP, find 12 places and not find another 5 that grep would have found. At the same time it does not know that it missed something, because the answer was clean (and hedging with grep may not work in this case).

With grep the situation would be like this: 40 matches with noise, the agent looks through them and decides on each one. Slower, more expensive, but accurate.

At this point you may think “I would rather wait and pay a bit more, but grep will handle everything and I will get a better result”. However, grep gets it wrong more often, and it does it at random.

With grep the agent can find 800 matches, read 30 of them and drop the rest because of the context limit, not because of their meaning.

During my tests LSP and grep showed the same accuracy of results, that is, the main worry did not come true. The independent study from CircleCI, in fact, found that LSP was more accurate in its results than grep (more details below).

My experience with the Language Server Protocol

I first tried to connect LSP to Claude Code in January 2026, a month after official support appeared. Back then it worked slowly, not efficiently, and it even froze from time to time. It usually hung on the very first indexing of the project, which is big and has a lot of dependencies. Half a year has passed since then, a large number of bugs were fixed, and I decided to give it a second chance.

I want to warn you right away that how effective LSP is depends on many things: your model, the effort of the model, the programming language, the context of the task, the size of the project and things like that. Also, support for the protocol is still under active development and things can change.

I ran a small study where LSP showed good results.

Setup:

  • Product: a huge codebase (about 20 solutions and 100 projects)
  • External dependencies: NuGet packages, .dll libraries written in C++, API specifications
  • Language: C# / .NET 10
  • Model: Opus 5 / Effort: Max
  • Methodology: a research task and a reference question, 50 independent agent runs.

Token savings with LSP over 50 agent runs on a .NET codebase: 15.8% on a research task, 22.5% on a reference question, and 32.5% on the same task with an extra instruction in CLAUDE.md

Token usage went down by about 16-22%, and execution time went down by 30-40%. At the same time the accuracy of the answers did not suffer. LSP and grep solved the tasks equally correctly.

Extra instructions in CLAUDE.md cut token usage even more.

Unfortunately I cannot show my CLAUDE.md notes, because they contain company secrets. In short, they describe where to look for the original source of an API contract (the OpenAPI specification), since searching the compiled type gives you nothing. This is exactly the case where LSP by default can give a worse result than grep, but with the right instruction the problem is solved.

CircleCI benchmark, June 24, 2026 - LSP vs. grep

Let’s look at a very fresh study from CircleCI about how LSP works with Claude Code.

Setup: the Vue.js core repository, ~149K lines of TypeScript. The models are Opus 4.8 and Sonnet 4.6. Three “find all references” tasks with a known ground truth: trigger (11 places), track (20), effect (260). They measured time, cost, tool output tokens and how complete the found references were.

LSPgrep
Total across the six tasks$1.88$2.03
Opus 4.8, total$1.22$1.26
Sonnet 4.6, total$0.66$0.77
Task effect (260 places), Opus$0.50$0.62
Task effect, Sonnet$0.24$0.29

Sonnet 4.6:

  • Execution time: went down by ~34% (the same as in my tests).
  • Tokens: went down by ~33% (the context rots more slowly)
  • Cost: went down by ~14% (in the actual bill)
  • Accuracy: LSP did not miss a single time. The LLM on plain grep, in the runs where it was wrong, found 9 references out of 11 for trigger and 249 out of 260 for effect.

Opus 4.8: the difference with grep is not so strong, except for the same drop in token usage of ~30%. Execution time turned out to be even a little bit longer.

According to the results of the study:

  • Accuracy went up, LSP was more accurate than grep on Sonnet. On Opus both configurations found everything
  • The money saving is ~7% on average (Sonnet 14%, Opus 3%)
  • Token usage went down by 30-33% (both models)
  • Execution time went down by ~34% on Sonnet and went up by about 2% on Opus

Source: https://circleci.com/blog/claude-code-lsp/

LSP can show great results on a weaker model, and on a stronger one it roughly breaks even (not counting the lower token usage). Also do not forget to take care of the places in the code that LSP does not cover (for example XAML bindings in MAUI or API contracts) with an instruction in CLAUDE.md. Then the agent will know that in some situations it is better to use a combination of tools (grep + LSP).

Where LSP will be more effective

As you have already seen, how effective LSP is depends a lot on your environment, and here is my checklist of where it will be the most useful:

  • Big project / Monolith
  • Names that often repeat, “Service”, “Handler”, “Item” and so on.
  • A strongly typed language, for example Java, C#, Go, Rust
  • Long compilation / heavy CI
  • A high level of abstraction: interfaces, DI, abstract factories

Which agents already support LSP

ToolLSPWhenHow it works
Kiro CLI (AWS)Yesv1.22, December 11, 202518 languages out of the box, no setup needed
Claude Code (Anthropic)Yesv2.0.74, end of December 2025The tool is built in, servers are installed as plugins: 11 official ones plus your own through .lsp.json
OpenCodeYes, but turned off202530+ preinstalled servers with auto-install, turned on with the lsp: true flag
Qwen CodeExperimental2026Only under the --experimental-lsp flag
GitHub Copilot CLIPartlyApril 22, 2026External LSP servers plus C++ in public preview, needs compile_commands.json
OpenAI Codex CLINoOnly through MCP bridges. The request for native LSP is one of the most upvoted in the repository (issue #8745)
Google (Gemini CLI, Antigravity)NoRequests #2465 and #6690 are open, Gemini CLI was retired on June 18, 2026
Any agent through MCPYes2025Serena and similar bridges, 40+ languages, works where there is no native support

How to connect LSP

The setup is very quick, I will show it with C# and Claude Code as an example.

In Claude Code the tool itself is already built in, and the language server is installed separately, one per language.

First we install the server, it is an ordinary dotnet tool:

dotnet tool install --global csharp-ls

Then we turn on the official plugin and reload the plugins:

/plugin install csharp-lsp@claude-plugins-official
/reload-plugins

That’s it, from now on the agent will go to the server on its own. The plugin works on top of csharp-ls, which is Roslyn under the hood, so it understands .NET Core, .NET Framework, and solutions with several projects. For other languages the scheme is the same, only the package and the name of the plugin change, you can see the list through /plugin. If the language you need is not in the marketplace, the server is written by hand in .lsp.json.

Keep in mind that on a big codebase the first run is not instant: the server needs to load the solution and build an index, and only after that do the answers become fast.

Conclusion

LSP is already a powerful tool in agentic development, it can raise accuracy, cut token usage (and the price of use) and also make the agent work faster. Many modern agents already have LSP support, but you need local setup to turn it on.

Whether you should use LSP or not depends on your project, your stack and your model. Its support and development are actively continuing and getting better. So you should definitely pay attention to it.

Thank you for reading the article to the end. I will be glad to hear about your experience with LSP, whether it helped you increase your effectiveness or slowed your agents down instead.

Discussion