Du richtest gerade einen MCP-Server für Claude Code oder Claude Desktop ein, kopierst eine Config aus der Doku – und stolperst über diesen Befehl:
{
"mcpServers": {
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"]
}
}
}
uvx. Kein pip install, kein python -m venv, kein „erst mal die requirements.txt anlegen". Einfach uvx irgendwas, und es läuft.
Wenn du aus der Java- oder Node-Welt kommst, kennst du das Gefühl: Python-Tooling hatte über Jahre den Ruf, fummelig zu sein. Virtualenvs, die man vergisst zu aktivieren. Drei verschiedene Wege, Pakete zu installieren, je nachdem welches Tutorial du gerade liest. Genau dieses Problem hat uv sich vorgenommen – und ist dabei so gut geworden, dass es inzwischen quasi der Standard-Weg ist, Python-basierte MCP-Server zu starten.
Schauen wir uns an, was uv eigentlich ist, warum es bei MCP-Setups überall auftaucht, und wie du es in deinen eigenen Python-Projekten einsetzt.
Was ist uv überhaupt?
uv ist ein Python-Paket- und Projektmanager, entwickelt von Astral – dem Team hinter Ruff, dem Linter, der in den letzten Jahren ähnlich schnell die Python-Welt erobert hat. Geschrieben ist uv in Rust, und genau das ist der Hauptgrund für seinen Erfolg: Geschwindigkeit, die in der Python-Welt bisher unüblich war.
Das eigentlich Bemerkenswerte an uv ist aber nicht nur die Performance, sondern dass es ein einziges Tool für Aufgaben ist, für die du vorher fünf verschiedene Tools gebraucht hast:
| Aufgabe | Bisheriges Tool | Mit uv |
|---|---|---|
| Pakete installieren | pip | uv pip / uv add |
| Virtuelle Umgebungen | venv / virtualenv | uv venv (automatisch) |
| Dependency-Locking | pip-tools | uv lock |
| Projekt- & Dependency-Management | poetry | uv (pyproject.toml) |
| Tools isoliert ausführen | pipx | uvx |
| Python-Versionen verwalten | pyenv | uv python |
Du installierst also nicht mehr fünf Tools mit fünf unterschiedlichen Konfigurationsdateien und fünf unterschiedlichen mentalen Modellen – du installierst uv.
Zum Geschwindigkeitsversprechen: uv löst Dependency-Installationen typischerweise 10- bis 100-mal schneller auf als pip. Das liegt an drei Dingen zusammen: der Rust-Implementierung, einem globalen Cache (ein Paket wird systemweit nur einmal heruntergeladen, danach nur noch verlinkt) und massiver Parallelisierung beim Download. Bei einem kleinen Projekt merkst du das kaum – aber bei einem Monorepo mit mehreren Services und hunderten Dependencies ist der Unterschied zwischen “Kaffee holen” und “weiterarbeiten”.
Warum uvx der Star bei MCP-Servern ist
Wenn du schon mal einen Node-basierten MCP-Server eingerichtet hast, kennst du npx: Statt ein Paket global zu installieren, lädst du es einmal herunter, führst es aus und lässt den Rest hinter dir. Genau das ist uvx für die Python-Welt – nur dass es vorher schlicht kein gutes Äquivalent dazu gab.
Schau dir noch mal die Config von oben an:
{
"mcpServers": {
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"]
}
}
}
Was hier im Hintergrund passiert: uvx mcp-server-fetch lädt das Paket mcp-server-fetch aus PyPI, baut dafür eine ephemere, isolierte Umgebung (gecached, damit der zweite Start sofort geht) und führt das darin enthaltene Kommando aus. Du brauchst keine global installierten Python-Pakete, keine Versionskonflikte zwischen verschiedenen MCP-Servern, kein „welches Python ist das gerade".
Der Unterschied zum klassischen Weg
Ohne uv sähe das Setup für denselben MCP-Server so aus:
# Anti-Pattern: der klassische Weg
git clone https://github.com/example/mcp-server-fetch
cd mcp-server-fetch
python -m venv .venv
source .venv/bin/activate
pip install -e .
python -m mcp_server_fetch
Sechs Schritte, ein aktiviertes venv, das du nicht vergessen darfst – und in der Claude-Config müsstest du den vollen Pfad zum Python-Interpreter im venv hinterlegen. Fehleranfällig, und auf einem zweiten Rechner fängst du wieder bei null an.
Mit uvx wird daraus eine Zeile, die überall gleich funktioniert – ob auf deinem Mac, in einem Docker-Container oder auf dem Rechner eines Kollegen:
uvx mcp-server-fetch
Genau diese Eigenschaft – ein Befehl, keine Vorbereitung, reproduzierbar – ist der Grund, warum praktisch jede MCP-Server-Dokumentation inzwischen uvx als empfohlenen Weg zeigt. MCP-Server sind kleine, oft kurzlebige Tools, die du ausprobierst, austauschst oder nur gelegentlich brauchst. Genau für dieses Nutzungsmuster ist uvx gebaut.
uv im Projekt-Alltag: Anti-Pattern vs. Best Practice
Anti-Pattern: der venv-pip-requirements-Tanz
So sieht der klassische Start eines Python-Projekts aus – wahrscheinlich kennst du das genau so:
mkdir my-project && cd my-project
python -m venv .venv
source .venv/bin/activate # unter Windows: .venv\Scripts\activate
pip install requests pandas
pip freeze > requirements.txt
python main.py
Das Problem ist nicht, dass das nicht funktioniert. Das Problem ist alles, was schiefgehen kann, ohne dass du es merkst:
- Du vergisst
source .venv/bin/activatein einem neuen Terminal-Tab und installierst Pakete plötzlich global. pip freeze > requirements.txtschreibt auch alle transitiven Dependencies mit exakten Versionen rein – ein Update vonpandasreicht, und die Datei ist ein einziger Diff-Krieg.requirements.txtunterscheidet nicht zwischen “das brauche ich zum Entwickeln” (Tests, Linter) und “das brauche ich in Produktion”.
Best Practice: uv init, uv add, uv run
Mit uv sieht derselbe Start so aus:
uv init my-project
cd my-project
uv add requests pandas
uv run main.py
Was hier passiert:
uv initlegt ein neues Projekt an – mitpyproject.toml,.python-versionund einer Grundstruktur. Kein leeres Verzeichnis, sondern ein Projekt mit Standardkonfiguration.uv add requests pandasinstalliert die Pakete und trägt sie in diepyproject.tomlein und schreibt eineuv.lock-Datei mit exakt aufgelösten Versionen – automatisch, in einem Schritt.uv run main.pyführt das Skript in der projekteigenen virtuellen Umgebung aus. Du musst nichts aktivieren – uv erkennt das.venv-Verzeichnis im Projekt und nutzt es einfach.
Die pyproject.toml sieht danach so aus:
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"requests>=2.32.0",
"pandas>=2.2.0",
]
Dev-Dependencies (Tests, Linter) trennst du sauber ab:
uv add --dev pytest ruff
Das Killer-Feature: Skripte mit Inline-Dependencies
Richtig praktisch wird es bei einzelnen Skripten, die du mal eben ausführen willst, ohne ein ganzes Projekt aufzusetzen. uv unterstützt PEP 723 – Dependencies werden direkt im Skript als Kommentar deklariert:
# script.py
# /// script
# dependencies = [
# "requests<3",
# "rich",
# ]
# ///
import requests
from rich import print
resp = requests.get("https://api.github.com/repos/astral-sh/uv")
print(resp.json())
Ausführen mit:
uv run script.py
uv liest den Kommentarblock, baut sich im Hintergrund eine passende, gecachte Umgebung und führt das Skript aus – ganz ohne venv, ohne pip install, ohne dass du irgendetwas vorbereiten musst. Genau dasselbe Prinzip, das uvx für MCP-Server nutzt, nur eben für deine eigenen Skripte.
Pro-Tipps / Warnungen
Pro-Tipp:
uv.lockgehört ins Git-RepoDie
uv.lock-Datei ist das Äquivalent zupackage-lock.json(npm) oderpoetry.lock. Sie fixiert nicht nur die Versionen deiner direkten Dependencies, sondern der gesamten Abhängigkeitskette – exakt, inklusive Hashes. Committest du sie mit, installiertuv syncauf jedem Rechner (und in jeder CI-Pipeline) garantiert dieselben Versionen. Lässt du sie weg, verlierst du genau den Vorteil, den du mit uv gerade gewonnen hast: reproduzierbare Builds.
Pro-Tipp: Migration ohne Big Bang – das
uv pip-InterfaceDu musst nicht von heute auf morgen dein ganzes Projekt auf
pyproject.tomlunduv addumstellen. uv bringt ein Drop-in-kompatiblespip-Interface mit:uv venv uv pip install -r requirements.txt uv pip compile requirements.in -o requirements.txtDas ist exakt dieselbe Syntax wie bei pip, läuft aber mit der uv-Geschwindigkeit. Damit kannst du bestehende Projekte schrittweise umstellen – erst die Installation beschleunigen, später (wenn überhaupt) auf den vollen Projekt-Workflow mit
uv add/uv runwechseln.
Achtung: Python-Versionen nicht doppelt verwalten
uv kann Python-Versionen selbst installieren und verwalten –
uv python install 3.12lädt eine eigenständige Python-Version herunter, unabhängig von deinem System-Python. In Kombination mit einer.python-version-Datei im Projekt sorgt das dafür, dassuv runimmer die richtige Version nutzt.Die Falle: Wenn du zusätzlich noch
pyenvaktiv hast, konkurrieren beide Tools um dieselbe Aufgabe – und du verbringst deine Zeit damit, herauszufinden, welches Tool gerade “gewonnen” hat. Entscheide dich für eines. Für neue Projekte istuv pythonder pragmatischere Weg, weil es direkt in den Rest des Workflows integriert ist.
Fazit
uv ist eines dieser Tools, die du nicht aktiv suchst – du stolperst darüber, weil sie sich leise in den Workflows etablieren, die du sowieso schon nutzt. Bei dir war es uvx in einer MCP-Server-Config. Bei jemand anderem ist es vielleicht ein GitHub-Repo, dessen README plötzlich uv sync statt pip install -r requirements.txt zeigt.
Das eigentlich Interessante daran: uv löst keine neuen Probleme. Pakete installieren, virtuelle Umgebungen verwalten, Versionen pinnen – das konnte Python alles vorher schon. uv macht es nur so einfach und schnell, dass die ganzen kleinen Workarounds, an die du dich gewöhnt hattest, plötzlich überflüssig sind. Das ist kein Sprung nach vorne, sondern eher das Aufräumen eines Werkzeugkastens, der über 15 Jahre gewachsen ist.
Wenn dein nächstes Python-Projekt ansteht – oder du das nächste Mal requirements.txt tippst – probier stattdessen uv init und uv add. Der Umstieg dauert keine fünf Minuten, und du wirst den venv-Tanz nicht vermissen.
