You don’t want to write a Language Server Protocol client

Posted 2023/01/19

It is known that the best way to get a right answer is to write the wrong answer on the stalls in the CS department and wait for someone to correct you. I just spent two hours trying to get pyright’s language server to do anything at all, so now I’m taking out my pocket knife and starting to scratch.

The Language Server Protocol is Microsoft’s (now open) answer to abstracting code completion, type checking, etc. across languages without custom VSCode plugins for each. It’s a good goal! And the fact that it’s open in theory means that other editors can use the same language servers and get type checking in arbitrary languages by just writing a LSP client.

In practice… VSCode is the only serious client of the protocol. langserver.org has a relatively unimpressive list of clients, and as far as I can tell, none of them besides VSCode use the protocol as their primary interface for code completion, syntax highlighting, etc. Sourcegraph, an early adopter of LSP, even deprecated their LSP support in 2021. Contrary to my intuition, clients are hard to write (that’s all I wanted to do!) but servers are easy. Which makes sense if you think of LSP as basically just VSCode’s plugin API. Writing VSCode is hard! Writing a silly little plugin is easy. Now just call the silly little plugin a “server” and confuse the heck out of everyone.

Further confusing the server vs client distinction, one of the most used language servers can’t be started without an already-listening client!. More. The client is the always-running thing, and the server is the thing that is occasionally started up when needed. Very intuitive. Further further confusing things, as soon as you connect to a server, there’s a whole complicated initialization protocol that weighs more heavily on the client than the server, and then the server is likely to follow up by hammering you with even more “hey did you know I also support this capability!” messages. It’s a lot!

In further further further practice, I suspect that a lot of language servers have only ever tested integration with VSCode and only support other clients by accident. The language server for pyright (Microsoft’s own (excellent) python type checker) didn’t even support being used as a server for years until someone else came along and implemented it. That’s not meant to bag on pyright, but more to illustrate how seriously even MS devs take other clients.

Basically, if you think “Hey! I want to quickly query pyright (or Codex). I see they have LSP server implementations! Let’s just use that protocol!” then you will attempt to write an LSP client and you will be sad and unfulfilled. If you think “Hey! I want to add functionality to VSCode.” then you’re about to write a LSP server and you will be happy.

Anyway all I wanted to do was run pyright on a series of functions without paying the startup overhead for each function. If all this is horribly confused and actually that’s easy to do from pytest, I’ve left plenty of space in this bathroom stall (twitter).