The Language Server Protocol, or how Microsoft solved an infinite grid
Somewhere in the VS Code team’s Zurich office, sometime in late 2015, someone drew a grid on a whiteboard. The rows were programming languages. The columns were editors. Each cell was a plugin that would need to be written, shipped, and kept alive — autocomplete, go-to-definition, error highlighting, all of it — for every combination of row and column. Nobody counted the cells. Nobody needed to.
The team was Microsoft’s Zurich lab, led by Erich Gamma — one of the four authors of the 1994 book Design Patterns, and therefore a man with a particular interest in pattern-matching his way out of a problem. They had already integrated two language servers into VS Code: OmniSharp for C#, which spoke HTTP with JSON, and the TypeScript language server, which spoke JSON over stdin/stdout in a format borrowed from the V8 debugger protocol. Neither spoke the other’s language. Two integrations had been enough to see the grid for what it was.
What they built instead was the Language Server Protocol, announced on June 27, 2016 in a joint statement with Red Hat and Codenvy. The idea was minimal by design: one standard that any language server could speak and any editor could understand. An editor sends messages — the user opened this file, the cursor is at line 23, character 4, what completions are available here? — and the language server replies with structured data. The editor does not need to understand Python’s import system. The Python server does not need to know what VS Code’s UI looks like. They share only the envelope.
The protocol runs on JSON-RPC, with headers modeled on HTTP, and it operates at the editor’s level of abstraction, not the language’s. It passes document URIs and cursor positions — not abstract syntax trees or compiler symbols. Microsoft’s own documentation notes that this was the decisive design choice: it is far easier to standardize “line 23, character 4” across every language than to agree on what a type declaration looks like in Go versus Haskell.
The first full adopter outside Microsoft was the PowerShell extension — not a glamorous debut for a universal standard, but PowerShell had a long and unhappy history of poor editor support, and the extension worked. Then the Rust toolchain. Then Java. Then virtually everything else. By the early 2020s, what had been an M×N problem was M+N: write one language server, and it runs inside every editor that speaks the protocol.
The reason LSP held where previous attempts at editor-tooling standards had not was that Gamma’s team refused to standardize the thing that would have been hardest to standardize: the language model itself. A Python server can represent its internal understanding of Python any way it likes, as long as it can respond to “go to definition” with a URI and a line number. Agreeing on the message format while leaving the interpretation alone kept the spec small enough to actually adopt.
Today Neovim, Emacs, Zed, JetBrains, and VS Code all speak LSP for most of their language intelligence. The editors look entirely different. The servers were written in different decades, in different countries, by teams that have never met. They all use the same envelope.
Sources
- Language Server Protocol — Wikipedia — Overview, timeline, the M×N complexity problem, and how LSP became the norm for language intelligence tools by the early 2020s.
- Language Server Protocol Overview — Microsoft Learn — The full origin story: OmniSharp and TypeScript server integration, the JSON-RPC design rationale, and why operating at the editor’s level of abstraction made the spec adoptable.
- Red Hat, Codenvy and Microsoft Collaborate on Language Server Protocol — Red Hat press release — The June 27, 2016 public announcement confirming date and collaborators.