MCP-Server — Doku-Lookup im Editor
Artikel 7 · Serie: Agentic Coding mit Claude Code
v0.6 funktioniert. Drei Visualisierungen, ein Datensatz, ein Switcher. An diesem Punkt entsteht eine andere Art von Problem: jede Erweiterung bringt Libraries ins Spiel, die Claude Code aus dem Gedächtnis kennt, aber vielleicht nicht in ihrer aktuellen Version. Das ist kein Vorwurf, sondern ein strukturelles Problem. Wer shadcn/ui einführen will, bekommt von einem Sprachmodell mit Trainings-Cutoff möglicherweise Prop-Signaturen aus einer älteren Version. Wer Tailwind 4 nutzt, bekommt vielleicht Tailwind-3-Syntax. Das Werkzeug dagegen heißt MCP.
Was MCP ist und was es nicht ist
MCP steht für Model Context Protocol. Ein MCP-Server ist ein externer Prozess, den Claude Code zur Laufzeit ansprechen kann, um Daten zu lesen, APIs aufzurufen oder Werkzeuge auszuführen. Im Unterschied zu einem Skill definiert ein MCP-Server nicht, wie eine Aufgabe anzugehen ist, sondern was für externe Fähigkeiten verfügbar sind.
Der Unterschied in der Praxis: ein Skill sagt Claude Code „bei einer Parser-Aufgabe diese Schritte ausführen". Ein MCP-Server sagt Claude Code „wenn du aktuelle Doku zur D3-Library brauchst, frag mich". Der Skill beschreibt Ablauf und Strategie. Der MCP-Server liefert Daten oder führt Aktionen aus.
Zwei MCP-Server kommen in Art 7 zum Einsatz:
- Context7: holt aktuelle Library-Dokumentation zu Tausenden von Packages direkt in den Editor-Kontext. Claude kann fragen, ohne zu raten.
- Playwright: steuert einen echten Browser. Für Art 8 vorbereitet, hier nur installiert.
Plan-File für Art 7
Task 1 (sequenziell): .mcp.json einrichten
Context7 und Playwright als stdio-Server konfigurieren.
Die Datei kommt ins Repo, damit alle, die das Projekt klonen, dieselbe MCP-Konfiguration bekommen.
Task 2 (nach Task 1): shadcn/ui einführen
npx shadcn init, dann Tabs, Button und Card hinzufügen.
App.tsx migrieren: selbstgebauten Switcher durch shadcn-Tabs ersetzen.
Task 3 (parallel zu Task 2): chart-builder Skill
Wissen aus den drei bestehenden Charts verdichten.
Skill ruft Context7 für aktuelle D3-Doku auf.
Task 1: .mcp.json ins Repo
Der erste Schritt ist die einfachste Datei:
Erstelle eine .mcp.json im Repo-Root.
Zwei Server: Context7 für Library-Doku und Playwright für Browser-Steuerung.
Die Datei soll ins Repo, nicht in eine globale User-Konfiguration.
Das Ergebnis:
{
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
},
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp@latest"]
}
}
}
Wichtig: die Datei gehört ins Repo. Wer MCP-Server nur in ~/.claude.json einträgt, hat sie auf seinem eigenen Rechner, aber andere Projektmitglieder, neue Entwicklungsumgebungen oder CI sehen nichts davon. .mcp.json im Repo-Root ist die richtige Stelle.
.playwright-mcp/ kommt in .gitignore, da der Playwright-Server dort Session-Artefakte ablegt, die nicht ins Versionssystem gehören.
Was Context7 konkret macht
Vor der shadcn/ui-Migration stellen wir Context7 kurz unter Beweis. Der Prompt:
Ich will shadcn/ui in ein Vite-Projekt mit Tailwind 4 einführen.
Bitte hol dir über Context7 die aktuelle Installationsanleitung.
Claude Code ruft dann mcp__context7__resolve-library-id auf, sucht die aktuelle shadcn-Library-ID, und holt anschließend mit mcp__context7__query-docs die relevanten Abschnitte. Was zurückkommt, ist die Doku der tatsächlich installierten Version, nicht das, was zum Trainings-Zeitpunkt gültig war.
Das Ergebnis in unserem Fall: shadcn läuft unter Tailwind 4 mit dem -b radix-Flag, nicht mit einer Legacy-Konfiguration. Ohne Context7-Lookup wäre hier Raten angesagt gewesen.
Context7 ist kein Ersatz für IDE-Autocomplete bei stabilen APIs. Für Array.prototype.map oder useState ist es Overkill. Sinnvoll wird es dort, wo Claude erfahrungsgemäß rät: neue Major-Versionen, Libraries mit häufigen API-Brüchen, Plugin-spezifische Konfiguration.
Task 2: shadcn/ui einführen
shadcn/ui ist keine NPM-Library im üblichen Sinne. Es gibt kein npm install @shadcn/ui. Stattdessen kopiert eine CLI die Komponenten-Quellen direkt ins Projekt. Die Komponenten werden mit-versioniert, lassen sich anpassen und gehören dem Projekt.
Führe shadcn/ui in web/ ein: npx shadcn init.
Füge dann Tabs, Button und Card hinzu.
Migriere App.tsx: der selbstgebaute Switcher mit Tailwind-Buttons kommt raus,
stattdessen kommen shadcn-Tabs rein.
Nach npx shadcn@latest init und dem Hinzufügen der Komponenten:
npx shadcn@latest add button
npx shadcn@latest add tabs
npx shadcn@latest add card
liegen in web/src/components/ui/ drei fertige Komponenten, die sofort importiert werden können. shadcn legt außerdem src/lib/utils.ts mit dem cn()-Hilfs-Helper an, der clsx und tailwind-merge zusammenführt.
Die Migration von App.tsx ist ein direkter Austausch. Die bisherigen manuell gestylten Buttons:
<nav role="tablist" className="inline-flex rounded-md border ...">
{VARIANTS.map((v) => (
<button role="tab" aria-selected={variant === v.key}
className={`px-4 py-1.5 ${variant === v.key ? "bg-stone-900 text-white" : "..."}`}
>
{v.label}
</button>
))}
</nav>
werden durch shadcn-Komponenten ersetzt:
<Tabs value={variant} onValueChange={(v) => setVariant(v as Variant)}>
<TabsList>
<TabsTrigger value="sunburst" data-testid="switch-sunburst">Sunburst</TabsTrigger>
<TabsTrigger value="sankey" data-testid="switch-sankey">Sankey</TabsTrigger>
<TabsTrigger value="treemap" data-testid="switch-treemap">Treemap</TabsTrigger>
</TabsList>
<TabsContent value="sunburst"><Sunburst titel={data.titel} /></TabsContent>
<TabsContent value="sankey"><Sankey titel={data.titel} /></TabsContent>
<TabsContent value="treemap"><Treemap titel={data.titel} /></TabsContent>
</Tabs>
Der Unterschied: shadcn-Tabs bringen Keyboard-Navigation, korrekte ARIA-Attribute und konsistentes Styling ohne zusätzliche Konfiguration. Der Overhead ist minimal, der Gewinn in Accessibility sofort da.
Task 3: chart-builder Skill
Nach drei Visualisierungen steckt im Repo implizites Wissen, das sich nicht wiederholen sollte. Welche Farbkonventionen gelten, wie ein Drill-Down mit focusPath funktioniert, warum <foreignObject> für Text-Umbruch in SVG nötig ist, wie Smoke-Tests für D3-Komponenten aussehen. Dieses Wissen in einen Skill zu verdichten bedeutet: beim nächsten Chart muss niemand die bestehenden Dateien auseinandersuchen.
Erstelle .claude/skills/chart-builder/SKILL.md.
Der Skill soll bei Chart-Anfragen triggern und folgende Konventionen festhalten:
Props-Struktur, Farbschema, shortLabel-Pattern, focusPath-Mechanik, Smoke-Test.
Außerdem: bei D3-API-Fragen soll der Skill Context7 aufrufen.
Der Kern-Workflow im Skill:
- Welcher Chart-Typ? Ist
buildHierarchy()der richtige Dateneinstieg, oder braucht der Chart eine eigene Aggregation? - Context7 für D3-API konsultieren, wenn Unsicherheit besteht.
- Komponente nach Projektkonvention aufbauen, Smoke-Test gleich mit.
- Im App.tsx-Switcher integrieren.
Der Skill referenziert Sunburst.tsx als Referenz für Drill-Down, Treemap.tsx für <foreignObject> und Sankey.tsx für Highlight-Verhalten. Wer das nächste Chart baut, findet dort alle Muster.
Tests anpassen
Die Migration auf shadcn-Tabs bringt eine unerwartete Konsequenz für die Tests. Radix Tabs, auf dem shadcn aufbaut, rendert <TabsContent> inaktiver Tabs standardmäßig nicht ins DOM. Das bedeutet: ein Test, der nach dem Klick auf den Sankey-Tab nach data-testid="sankey" sucht, findet nichts — nicht weil etwas kaputt ist, sondern weil Radix den Inhalt erst beim Aktivieren mounted.
Das ist eigentlich gutes Verhalten: unnötiger DOM-Ballast bleibt draußen. Für Tests heißt es aber: die bisherige Strategie „klick auf Tab, prüf ob Inhalt da ist" greift zu tief in die Rendering-Details ein. Sie testet die shadcn-Implementierung, nicht das eigentliche Verhalten der App.
Die robustere Alternative ist, das zu testen was semantisch entscheidend ist: sind die richtigen Tab-Trigger vorhanden, und ist der richtige als aktiv markiert?
// Default-Tab: Sunburst aktiv
expect(screen.getByTestId("switch-sunburst")).toHaveAttribute("aria-selected", "true");
expect(screen.queryByTestId("sunburst")).toBeInTheDocument();
Das ist kein Kompromiss, sondern der bessere Test: aria-selected ist genau das, was ein Screenreader oder ein Accessibility-Audit prüfen würde. Wenn der falsche Tab aktiv ist, schlägt dieser Test an. Wenn die Visualisierung selbst kaputt ist, haben die Smoke-Tests der Chart-Komponenten ihren Auftritt.
3 Tests grün, Build sauber.
Playwright-MCP als Vorbereitung
Playwright-MCP ist in .mcp.json konfiguriert, aber in Art 7 noch nicht genutzt. Der MCP-Server startet bei Bedarf einen Chromium-Browser, über den Claude Code navigieren, klicken und Screenshots machen kann.
Die Vorkonfiguration macht Sinn, weil der erste Start von Playwright eine Chromium-Installation auslöst. Das besser jetzt zu klären als mitten in einer End-to-End-Test-Session in Art 8.
Stand am Ende dieses Artikels
git clone https://codeberg.org/rotecodefraktion/byhaushalt.git
cd byhaushalt
git checkout v0.7
cd parser && uv run python -m parser.normalize
cd ../web && npm install && npm run dev
Vollständiger Stand unter byhaushalt @ v0.7.
v0.7 enthält: .mcp.json mit Context7 + Playwright, shadcn/ui mit Tabs, Button und Card, App.tsx auf shadcn-Tabs migriert, .claude/skills/chart-builder/SKILL.md. 22 Tests grün, 3 xfail.
cd parser && uv run pytest -v
cd web && npm run test
# 22 passed, 3 xfailed
Wie es weitergeht
Artikel 8 behandelt End-to-End-Tests mit Playwright-MCP. Claude Code steuert den Browser direkt, findet Selektoren, prüft ob Visualisierungen korrekt rendern, und schreibt die E2E-Specs aus einer Markdown-Beschreibung. Die Grundlage dafür ist der Playwright-MCP-Server, der in Art 7 schon konfiguriert wurde.
Wie shadcn/ui mit Context7 eingeführt wurde und was der chart-builder-Skill leistet, steht hier. Den Aufbau des Worktree-Setups zeigt Artikel 6. Subagents und das Datenmodell beschreibt Artikel 5.