Library / SDK
python-lsp/python-lsp-server avatar
python-lsp/python-lsp-server

python-lsp-server's setup.py exists so GitHub can find the project

Fork of the python-language-server project, maintained by the Spyder IDE team and the community

2,601 stars252 forksPythonMIT

At a glance

What is it?
python-lsp-server is a Language Server Protocol implementation for Python maintained by the Spyder IDE team, where the real packaging metadata is in pyproject.toml and setup.py is a twelve line stub kept only for GitHub's dependency tracking. The provider list in the README omits Black even though the manifest requires it, four distributions ship it under four package names, and the badges still point at the repository it forked from.
Who is it for?
Install this when you want an editor-neutral Python language server whose linters and formatters come from packages you already trust, and when you would rather configure them from your editor than adopt a closed type checker. Three things to check first.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 70 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 4, 2026, and from our analysis. They are not legal advice.

Editorial analysis

setup.py is a stub kept for GitHub's dependency graph

There is a `setup.py` at the root of this repository and it is not a build script.

The whole file is a shebang, two copyright lines, an import and a call to setup with one argument, and the name is annotated with a comment saying it is there to allow GitHub dependency tracking work.

That is the entire purpose of the file. GitHub's dependency graph looks for a Python project's packaging metadata in the conventional places, and a repository with only a pyproject file confuses some of its tooling. Keeping a minimal setup.py makes the project visible to it without duplicating the real metadata.

The real metadata is in `pyproject.toml`. The package is named `python-lsp-server`, licensed MIT with the licence file listed explicitly, and it requires Python 3.9 or newer. The version is dynamic, which means it is derived from the git tags at build time by a version control aware build backend rather than being written in a file.

Two build requirements are pinned with a floor rather than a ceiling: a setuptools release from 69.0.0, and the version-control-aware plugin for it from 3.4.3. There is a manifest file for what goes into a source distribution, and a changelog, a release document, a security policy and a contributing guide beside them.

The same program has four package names

Installing from a package manager means guessing which name your distribution uses, and the README lists four.

On Debian and the distributions derived from it, including Ubuntu, Pop OS and Linux Mint, the package is called `python3-pylsp` and comes from apt. On Fedora it is called `python3-lsp-server`. On Arch it is called `python-lsp-server`. Alpine is the exception and calls it `py3-lsp-server`.

On the Python side it is `python-lsp-server` from the package index, and there is also a conda-forge package under the same name for Anaconda and Miniconda users.

The README says the server is available in the repositories of every major Linux distribution, and that it is usually called one of two things, which matches what the four examples show: two of them follow the distribution naming convention for a Python 3 package and two use the upstream name.

Whichever route you take, the executable is the same one: `pylsp`, which the README tells you to confirm by running it with the help flag after installing.

The practical catch is version skew. A distribution package is built and frozen by that distribution, so the copy you get from apt is not the copy on the package index, and a plugin requiring a recent release is the first thing to notice the gap.

The manifest requires Black, the provider list never mentions it

The required dependencies are the clearest statement of what the server actually needs.

They are a docstring to Markdown converter, a JSON-RPC implementation, a JSON library, the plugin framework, a backport of the import metadata module for Python below 3.10, Jedi, and Black. Black is in the required list, not in an extra.

The README's provider list says something different. It describes Jedi as the thing providing completions, definitions, hover, references, signature help and symbols, and then lists optional providers: Rope for completions and renaming, Pyflakes, McCabe, pycodestyle, pydocstyle disabled by default, autopep8 and YAPF for formatting with YAPF preferred, flake8 disabled by default, and pylint disabled by default. No Black.

The manifest also lists a package called `whatthepatch` that appears in the YAPF extra and in the everything extra, and that the README never explains.

So the two documents disagree in both directions. A hard dependency is missing from the provider list, and a dependency in an extra is missing from the documentation. Neither is dangerous, but both mean that reading only the README leaves you with an incomplete picture of what gets installed.

One real constraint is worth naming: Jedi is pinned with an upper bound, so versions from 0.17.2 up to but not including 0.21.0. Whatever changed in Jedi after that is not available to this server.

The documented failure is a setuptools error message

There is exactly one failure mode in the README, and it is specific enough to be worth quoting.

If an install fails with an error saying that `install_requires` must be a string or a list of strings, the instruction is to upgrade setuptools and try again:

bash
pip install -U setuptools

That error comes from the packaging tooling rather than from the project, which is why the fix is aimed at the build environment instead of at a version of the server. It is the kind of note that exists because people hit it repeatedly on a particular operating system and nobody found a better place to put it.

The rest of the installation section is the ordinary sequence. Install the base package, which exposes the command on your path, and confirm it with the help flag. Add individual capabilities with the extras syntax, for example a formatting extra by name, or everything at once with the extras name `all`.

The `all` extra is the one to know about, because it pulls in every optional linter and formatter at once, and the section on configuration explains why having all of them is not always what you want.

Your editor overrides your home directory configuration

Configuration arrives from the client, which is your editor, and the precedence order is stated once and is not the one most people expect.

Overall configuration is computed first from user configuration in the home directory, then overridden by configuration passed in by the language client, then overridden again by configuration discovered in the workspace.

So the order from weakest to strongest is your home directory settings, then your editor's settings, then the files in the project. The middle entry is the surprising one. Settings that live in the editor's configuration, which many people set once and forget about, override the files in their home directory.

The server also reads the configuration of the underlying tools, and the README names where it looks. pycodestyle is discovered in a configuration directory under the home path, in `setup.cfg`, in `tox.ini` and in a `pycodestyle.cfg` file. flake8 is discovered in a `.flake8` file, in `setup.cfg` and in `tox.ini`.

The worked example for changing which style errors pycodestyle ignores shows all three layers in use: the ignore list goes into the home directory configuration file, the same list is set as a plugin configuration value passed in from the editor, and the same list goes into `setup.cfg` at the project root.

The options themselves are documented in a separate configuration document in the repository, with the flake8 and pycodestyle documentation linked for their own settings.

flake8 cannot be switched on without switching three things off

The default configuration sources are pycodestyle and pyflakes, and moving to flake8 is a three step change with a reason attached.

The reason is duplication. flake8 bundles pycodestyle, mccabe and pyflakes, so leaving those three enabled while enabling flake8 produces the same messages twice in the editor.

The steps are therefore: disable pycodestyle, mccabe and pyflakes by setting their enabled configuration values to false, using the plugin-prefixed path for each; set the flake8 enabled value to true; and change the configuration sources setting, passed in from the client, to a list containing only flake8.

That third step is the one people miss. Enabling the plugin without switching the source list means the server is still reading its defaults from the other two tools, so the duplication does not go away.

Note what the same paragraph reveals about the architecture. The plugin names in those settings are the same optional providers from the installation section, addressed by a dotted path that looks like a settings namespace rather than a Python import path, and the configuration sources list is the switch that decides which of those tools' own config files the server reads.

It is a tidy design for a tool that wraps four linters, and it is the sort of thing that costs an afternoon the first time and is invisible afterwards.

Three formatters can be installed into the same session

The installation section offers two formatters and the manifest adds a third.

autopep8 and YAPF are both listed as providers for code formatting, with YAPF preferred over autopep8. That preference is a disambiguation rule rather than a conflict resolution, because the sentence does not say what happens if both are installed, and both will be enabled if both are present, since the enabling condition is that the dependency is found.

Black is in the required dependencies, so it is present in every install whether or not it is wanted as the formatter here. The README's own list of third party plugins includes a Black plugin, provided as a separate package, which is a different thing from the Black library being a hard dependency.

So a default install has three formatting tools available and no documented arbitration between them. The safest arrangement is to install the one you want as an extra and leave the others out, but the README does not say that.

The plugin mechanism itself is documented properly, though. Plugins are separate packages listed by name, covering type checking with a checker, import sorting, Black formatting, deprecated API detection, extended refactoring through Rope, and fast linting with a Rust based linter. There is a cookiecutter template for writing your own, and the README asks you to file an issue if you need help doing so.

The badges point at the repository it forked from

Three details at the top of the file tell you the project's history.

The badges link to a repository under a different organisation name entirely, the one this project forked from, and the licence badge links to a licence file in that same old repository. The links inside the documentation are correct and point at the current repository, on a branch named `develop` rather than `master`.

So the health badges and the licence link are stale in a way that is harmless but real. Following the licence badge from the current repository lands in a different project's file.

The second detail is the copyright headers carried in both packaging files, which credit a technology company for 2017 to 2020 and then the language server contributors from 2021. That matches the description on the repository page, which describes the project as a fork of the older language server project, maintained by the Spyder IDE team and the community.

The third is the release cadence. Three recent tags, 1.14.0 in December 2025, 1.13.2 in November 2025 and 1.13.1 in August 2025, with the last push to the branch on 2026-07-27 and the repository not archived. Version numbers come from tags at build time, which is why there is no version string to find in the packaging files.

Editorial conclusion

Install this when you want an editor-neutral Python language server whose linters and formatters come from packages you already trust, and when you would rather configure them from your editor than adopt a closed type checker. Three things to check first. Which formatter ends up in the loop, because autopep8, YAPF and Black can all be installed at once and the README prefers one pair without preventing the third. Which linter set is active, because the default pycodestyle and pyflakes overlap with flake8 and produce duplicate messages unless three settings are changed. And whether your distribution's package is current, since the same program is called python3-pylsp on Debian, python3-lsp-server on Fedora, python-lsp-server on Arch and py3-lsp-server on Alpine, and those packages move on their own schedule.

Frequently asked questions

what is python lsp server

A Python 3.9 and later implementation of the Language Server Protocol, maintained by the Spyder IDE team and the community as a fork of the older python-language-server project. Jedi supplies completions, definitions, hover, references, signature help and symbols, and further linters and formatters are added as plugins.

how to install python lsp server

With pip install python-lsp-server, which exposes the pylsp command on your path, and then pip install -U setuptools if the install fails with an install_requires error. Individual capabilities come from extras such as python-lsp-server[yapf], and there is a python-lsp-server[all] extra. Distribution packages exist under several different names.

jedi vs python lsp server

Jedi is a component, not an alternative. The server requires Jedi to provide completions, definitions, hover, references, signature help and symbols, and it is pinned to versions from 0.17.2 up to but not including 0.21.0. The server is the process your editor talks to over the protocol; Jedi is one of the engines inside it.

python lsp server vs python language server

This project is the continuation. The repository describes itself as a fork of the python-language-server project, and the packaging files carry copyright for that project up to 2020 followed by the language server contributors from 2021. The badges at the top of the README still point at the older repository.

What is an LSP server?

A separate program that speaks the Language Server Protocol so an editor can ask a language about the code being edited. Configuration for this one is passed in by the client, which means your editor, and the README gives the precedence order as user configuration in the home directory, then client configuration, then configuration discovered in the workspace.

Official sources

  1. Issues
  2. License: MIT
  3. python-lsp/python-lsp-server on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/python-lsp-python-lsp-server.svg)](https://hysenlabs.com/projects/python-lsp-python-lsp-server)