Blog
Mein MCP-Server hatte in dreieinhalb Monaten null Nutzer
Kein Login, kein Konto, sofort loslegen. Klang nach der nutzerfreundlichen Entscheidung und war der Grund, warum niemand den Server benutzt hat. Was ich falsch verstanden habe und wie die Trennung in zwei Produkte das gelöst hat.
14. August 2026
Am 10. August habe ich zum ersten Mal nachgezählt, wer unseren Academy-MCP-Server eigentlich benutzt. Das Ergebnis: null ausgestellte API-Keys, null Fortschritts-Einträge, null Zertifikate. In dreieinhalb Monaten.
Der Server war nicht kaputt. Der Container war healthy, die Tools antworteten, die Doku stand auf npm. Er hat exakt das getan, wofür ich ihn im April gebaut habe. Nur hat ihn niemand gebraucht.
## Die Entscheidung, die im April richtig aussah
Alle unsere anderen öffentlichen MCP-Server laufen über OAuth 2.1 mit PKCE. Beim Academy-Server bin ich bewusst davon abgewichen und habe einen einfachen Bearer-Token genommen: Du holst dir im Dashboard einen Key, trägst ihn als Umgebungsvariable ein, fertig.
Die Begründung damals war reine Reibungsrechnung. OAuth ist mehr Bauarbeit, ein Key ist in zwei Minuten drin. Klang nach der freundlichen Variante.
Sie war es nicht. Ein Key aus einem fremden Dashboard heißt: Website aufmachen, einloggen, Knopf finden, kopieren, in eine Konfigurationsdatei schreiben, Client neu starten. Sechs Schritte, davon fünf außerhalb des Tools, in dem du gerade arbeitest. OAuth heißt: im Client auf Verbinden klicken, im Browser bestätigen, zurück. Ich habe den Weg gebaut, der für mich als Entwickler einfacher war, und ihn dann für nutzerfreundlich gehalten.
Das ist der Teil, den ich mir gemerkt habe. "Weniger Bauarbeit" und "weniger Aufwand für den Nutzer" fühlen sich beim Planen identisch an, und sie sind es fast nie.
## Der eigentliche Fehler lag eine Ebene tiefer
Auch das war noch nicht der Kern. Der Server lieferte den kompletten Kurstext anonym aus. Ohne Konto, ohne Key, sofort.
Damit gab es keinen einzigen Grund, sich anzumelden. Fortschritt, Quiz, Wiederholung, Zertifikat lagen hinter einer Hürde, an der direkt daneben eine offene Tür stand. Wer den Server anschloss, bekam sowieso alles, was er wollte.
Ich hatte eine Zugangshürde als reines Reibungsproblem behandelt. Sie ist aber auch die Antwort auf die Frage, wofür dein Produkt eigentlich da ist. Ein Ding, das anonym alles rausgibt und angemeldet ein bisschen mehr, ist kein Produkt mit zwei Stufen. Es ist ein Produkt, das sich selbst überflüssig macht.
## Zwei Produkte statt einem halben
Die Lösung war nicht mehr Auth, sondern eine saubere Trennung.
Das npm-Paket `mcp-academy` ist ab jetzt die Bibliothek. Der volle Kurs ist eingebacken, kein Konto, kein Netz nötig, MIT-lizenziert. Wer nur lesen will, ist genau hier richtig und soll sich nirgends anmelden müssen. Das war die Variante, vor der ich am meisten Respekt hatte, weil sie sich nach Umsatzverzicht anfühlt. Tut sie nicht: Es gab vorher schlicht keinen Umsatz, den man hätte verzichten können.
Der gehostete Connector auf `mcp.studiomeyer.academy` ist der Kurs. Er verlangt seit v0.4.0 immer einen Login, wahlweise Google, Discord oder Magic-Link, und liefert dafür Fortschritt, Quiz, Wiederholungen, Zertifikate und den Tutor. Also genau die Dinge, die ohne Konto technisch gar nicht funktionieren können, weil sie sich etwas über dich merken müssen.
Diese Trennung hat die Frage aufgelöst, an der ich vier Monate vorbeigelaufen bin. Vorher war es ein Ding, das beides halb konnte. Jetzt sind es zwei, die je eine Sache ganz können.
## Was beim Umbau schiefging
Den OAuth-Layer habe ich nicht neu geschrieben, sondern wörtlich aus einem Schwester-Server kopiert. Er sitzt im Container, nicht in der Next.js-App, damit die Website-Anmeldung unberührt bleibt. Identität ist die verifizierte E-Mail-Adresse, also ein Konto für Website und Connector statt zweier getrennter Nutzerlisten.
Beim Kopieren habe ich fast zwei Schwächen der Vorlage mitgeschleppt.
Die erste: Die Kennung, mit der ein Token seine Familie erkennt, lag nur im Arbeitsspeicher. Nach jedem Deploy ist die weg, und damit ist der Server blind für genau die Angriffe, gegen die dieser Mechanismus da ist. Läuft im Test sauber durch, weil du im Test nicht deployst.
Die zweite: Beim Einlösen des Codes wurde die Rücksprung-Adresse nicht mit der verglichen, mit der der Code ausgestellt wurde. Beides ist jetzt gefixt, aber die Lehre ist unangenehm: Wenn du Code kopierst, kopierst du auch die Fehler, die im Original nie aufgefallen sind. Eine Vorlage, die seit Monaten produktiv läuft, ist kein Beweis für Korrektheit. Sie ist nur ein Beweis dafür, dass noch niemand danach gesucht hat.
Zwei Review-Runden haben zusammen 20 Befunde ergeben. Vier davon waren Folgefehler unserer eigenen Korrekturen aus Runde eins. Das ist inzwischen ein so verlässliches Muster, dass ich ab der zweiten Runde ausdrücklich danach frage.
## Was ich nächstes Mal anders mache
Die Zahl anschauen. Nicht das Monitoring, die Nutzung. Kein Healthcheck der Welt sagt dir, dass niemand dein Produkt benutzt, weil aus Sicht des Servers alles bestens ist. Dreieinhalb Monate sind ziemlich lang für "ist mir nie aufgefallen".
Und beim nächsten Auth-Design zuerst die unbequeme Frage stellen: Was genau bekommt jemand, der sich anmeldet, das er ohne Anmeldung nicht bekommt? Wenn die Antwort "ein bisschen mehr Komfort" lautet, wird sich niemand anmelden. Dann ist nicht der Login-Knopf das Problem, sondern der Zuschnitt dahinter.
Wenn du gerade selbst einen MCP-Server baust: Die Auth-Grundlagen stecken in [MCP-Auth](/levels/6/06-mcp-auth), der praktische Weg in [MCP-Server-Auth mit OAuth 2.1](/playbooks/mcp-server-auth-mit-oauth-2-1). Für die Frage, wie dein Server überhaupt zu Nutzern kommt, ist [Deployment und Distribution](/levels/6/04-deployment-und-distribution) der bessere Startpunkt als noch eine Runde Feature-Bau. Die offizielle Autorisierungs-Spezifikation liegt unter [modelcontextprotocol.io](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization).