Die MCP-Server-Welt
Was ein Werkzeug-Server dem Agenten gibt, was er ihn kostet — nachgestellt am lebenden System.
Was ein MCP-Server tatsaechlich ist
Ein MCP-Server ist kein Dienst, den ein Mensch bedient. Er ist ein Katalog von Faehigkeiten, den ein Modell zur Laufzeit liest — und genau darin liegen Nutzen und Preis.
Das Model Context Protocol trennt drei Rollen sauber voneinander: der Host (hier: Claude Code) haelt die Sitzung, der Client spricht JSON-RPC ueber stdio oder HTTP, der Server besitzt die Faehigkeit und die Zugangsdaten. Der Agent bekommt nie den Token — er bekommt ein Werkzeug. Dieser Bericht selbst ist der Beweis: das REST-Aequivalent POST /api/artifacts verlangt OAuth2 gegen auth.maierzone.de, ueber MCP ist derselbe Vorgang publishArtifact(slug, files) ohne ein einziges Geheimnis im Agenten.
Die vier Primitive — und wofuer sie taugen
Bedienung: Klick oder Pfeiltasten. Ohne JavaScript stehen alle vier Abschnitte untereinander lesbar da (mz-tabs, progressive enhancement).
Tools — Verben, die das Modell aufrufen darf
Ein Tool ist Name plus JSON-Schema plus Beschreibung. Das Schema ist die eigentliche Botschaft: es sagt nicht nur, was erlaubt ist, sondern erzieht das Modell dazu, die richtige Frage zu stellen. publishArtifact verlangt genau eine index.html — das ist keine Doku, das ist eine Leitplanke.
Kosten: jedes Tool-Schema liegt dauerhaft im Kontext. 24 Tools sind schnell 8–12 KB, die in jeder einzelnen Anfrage mitgesendet werden.
Resources — Substantive, die der Host holen darf
Resources sind adressierbare Inhalte (URI, MIME-Type), die der Host lesen kann, ohne dass das Modell einen Aufruf begruendet. Der Unterschied zum Tool ist die Kausalitaet: eine Resource hat keine Nebenwirkung, ein Tool darf eine haben.
In der Praxis unterschaetzt: Resources sind der billigere Weg fuer alles, was der Agent nur lesen will — sie belegen keinen Tool-Slot.
Prompts — vorgefertigte Zuege
Ein Prompt-Primitive ist eine benannte, parametrisierte Vorlage, die der Nutzer explizit auswaehlt. Das ist der Ort fuer Hausregeln: „Wiki-Seite anlegen“ als Prompt ist reproduzierbarer als dieselbe Anweisung in Prosa.
Grenze: Prompts wirken nur, wenn jemand sie waehlt. Sie sind Angebot, nicht Zwang.
Sampling & Elicitation — der Rueckkanal
Sampling dreht die Richtung um: der Server bittet den Host um eine Modellantwort. Elicitation bittet um eine Nutzereingabe. Beides ist maechtig und beides ist heikel — ein Server, der Modellzeit anfordern kann, kann sie auch verbrennen.
Regel im Haus: Rueckkanal nur mit sichtbarer Zustimmung. Was der Server schickt, bleibt Datum, nie Anweisung.
Warum ein Tool-Katalog nicht beliebig wachsen darf
Werkzeug-Auswahl ist ein Klassifikationsproblem mit wachsender Klassenzahl. Ab ein paar Dutzend Tools mit aehnlichen Namen sinkt die Trefferquote messbar — nicht weil das Modell schlechter wird, sondern weil die Beschreibungen einander aehnlicher werden. Die Gegenmittel sind bekannt: scharfe Verben statt Substantive, ein Tool je Absicht statt eines Tools mit zwoelf Modi, und nachgelagertes Laden von Schemata (in dieser Sitzung: ToolSearch mit select:).
Der Tool-Katalog des mzone-publisher
Filtern per Suchfeld, sortieren per Klick auf die Kopfzeile. Die Spalte „≈ KB“ sortiert numerisch (th[data-sort="number"]) und nennt Groessenordnungen typischer Antworten — keine Messreihe.
| Tool | Gattung | Nebenwirkung | ≈ KB |
|---|---|---|---|
| getCapabilities | Lesen | keine | 6 |
| lookupStyles | Lesen | keine | 4 |
| listTemplates | Lesen | keine | 2 |
| getTemplate | Lesen | keine | 3 |
| listPublishedPages | Lesen | keine | 5 |
| getPageContext | Lesen | keine | 4 |
| getPageHistory | Lesen | keine | 3 |
| getPageStats | Lesen | keine | 2 |
| getArtifactSource | Lesen | keine | 20 |
| listVersions | Lesen | keine | 2 |
| searchPages | Suchen | keine | 3 |
| fullTextSearch | Suchen | keine | 6 |
| lintWiki | Pruefen | keine | 8 |
| validateArtifact | Pruefen | Preview mit TTL | 2 |
| renderPreview | Pruefen | keine | 10 |
| publishPage | Schreiben | Seite live | 2 |
| publishArtifact | Schreiben | Bundle live, Version | 3 |
| publishAsset | Schreiben | Asset live | 2 |
| publishRawPage | Schreiben | Alias auf Artefakt | 2 |
| publishRawPageCompressed | Schreiben | Alias, br/gzip | 2 |
| mergePageContext | Schreiben | Context veraendert | 2 |
| setPageLifecycle | Schreiben | Status veraendert | 1 |
| rollbackArtifact | Schreiben | Version zurueck | 2 |
| deletePage | Loeschen | irreversibel | 1 |
24 Tools. Sechs schreiben, eines loescht, siebzehn lesen oder pruefen — ein gesundes Verhaeltnis: die gefaehrliche Minderheit ist klein und benennbar.
Was der Katalog kostet
Beide Diagramme zeigen echte Zahlen aus getCapabilities(). Der Zeiger darf ueber die Balken — Tooltip und Legende kommen aus dem mzone-Chart-Preset, nicht aus chart.js-Defaults. Ueber dem linken Diagramm liegt zusaetzlich die Lupe aus fx-magnify.
Drei Wege zum selben Wissen
Der volle Katalog ist 14-mal so gross wie die Selbstbeschreibung. Deshalb liefert getCapabilities() nur Namen — und lookupStyles holt den Rest nur bei Bedarf. Das ist Kontext-Oekonomie als API-Entwurf.
Wachstum des Design-Systems
1.0.0 bis 1.4.0: von 4 auf 34 Dateien, von 39,7 KB auf 439,2 KB. Der Sprung 1.0.0→1.1.0 ist der Einzug der fx-Module, der Sprung auf 1.4.0 sind die Transitions.
-
1.0.0Report-Chrome. 4 Dateien, 39,7 KB. Nur CSS — Karten, Tabellen, Befunde.
-
1.1.0fx-Module und Chart-Preset. 26 Dateien, 262,5 KB. Ab hier hat der Bericht Bewegung.
-
1.2.028 Dateien, 301,0 KB.
destroy()wird Vertrag fuer jedes Modul. -
1.3.033 Dateien, 365,1 KB. R26 richtet die Signaturen aus (
fx(target, options)), V-1 prueft BEM-Modifier. -
1.4.034 Dateien, 439,2 KB. 27 Transition-Patterns plus
mz-transitions.js. Das FILTER-Release rueckt auf 1.5.0.
Bilanz: was MCP bringt, was es kostet
Suchfeld filtert die Karten unten (Modul mz-search, rein clientseitig — ein statisches Artefakt hat kein OAuth-Token fuer fullTextSearch).
Keine Karte passt zu diesem Filter.
Der Server haelt die Zugangsdaten. Der Agent bekommt Faehigkeit ohne Geheimnis. Ein kompromittierter Sitzungsverlauf gibt kein Passwort her, weil nie eines drin war.
Beleg: publishArtifact ueber MCP funktioniert, POST /api/artifacts antwortet ohne Token mit 401.
Faehigkeiten werden zur Laufzeit gelesen, nicht einkompiliert. Ein neues Tool am Server ist am naechsten Sitzungsstart da — ohne Agenten-Update, ohne Redeploy auf der Client-Seite.
Kehrseite siehe Karte „Versionsdrift“.
n Agenten mal m Diensten wird von n×m zu n+m. Der Publisher weiss nichts ueber Claude Code, Claude Code weiss nichts ueber Freemarker — das Schema in der Mitte genuegt beiden.
Der eigentliche Netzwerkeffekt des Protokolls.
Ein gutes Schema erzieht. overwrite=false als Default macht das Ueberschreiben zur bewussten Handlung; validateArtifact vor publishArtifact macht Pruefen billiger als Reparieren.
Schutz durch Entwurf statt durch Ermahnung.
Jedes Tool-Schema liegt in jeder Anfrage im Fenster — auch in den 95 % der Zuege, in denen es nicht gebraucht wird. Zwei Server mit je 30 Tools kosten dauerhaft mehr als die meisten Antworten.
Gegenmittel in dieser Sitzung: Schemata verzoegert laden, per select: nachziehen.
Aehnliche Tools verwaessern einander. publishRawPage, publishRawPageCompressed und publishArtifact tun im Kern dasselbe — Altlasten als Alias sind bequem fuer Bestandsagenten und teuer fuer neue.
Ein Tool je Absicht schlaegt ein Tool mit zwoelf Modi.
Alles, was ein Tool zurueckgibt, ist fremder Text im Kontext. Eine Seite, ein Dateiname, eine Fehlermeldung kann Anweisungen enthalten. Die einzige tragfaehige Haltung: Tool-Ergebnisse sind Daten, niemals Befehle.
Gilt auch fuer Titel in Listen — die schreibt jemand anderes.
Der Server aendert ein Feld, der Agent haelt an einer Annahme fest. Ohne Vertragspruefung merkt das niemand bis zum Fehlschlag — deshalb der Selbstcheck nach dem Publish und die reachability in der Antwort.
Antwort, die den eigenen Erfolg nachprueft, ist die billigste Absicherung.
Drei Aufrufe sind drei Aufrufe. Bricht der zweite ab, ist der erste passiert. Wer Atomaritaet will, baut sie in ein Tool hinein — das Protokoll gibt sie nicht her.
Deshalb ist ein Bundle eine Nutzlast, nicht drei.
Werkzeugketten sind Rundreisen. Zehn kleine Aufrufe schlagen selten einen gut geschnittenen — Kornung ist eine Entwurfsentscheidung, keine Geschmacksfrage.
V-2 zeigt die Gegenrichtung: validate liefert einen stagingToken, publish sendet nichts erneut.
Transitions-Labor — alle 27 Patterns aus 1.4.0
Jede Zelle ist ein lauffaehiges Pattern. Vier laufen rein ueber CSS (Hover/Fokus, kein JS), 23 haengen an mz-transitions.js. Filter durchsucht Namen und Beschreibung.
Kein Pattern passt zu diesem Filter.
Hoehe faehrt weich auf, ohne feste px (grid-rows-Trick).
Ziffern fallen versetzt mit Blur herein. Oneshot.
Zaehl-Badge rutscht diagonal herein, Overshoot am Ende.
Zwei Textzustaende tauschen mit Blur und Gegenbewegung.
Panel klappt vom Ankerpunkt auf. Position setzt der Aufrufer.
Backdrop blendet, Dialog skaliert heraus. position:fixed.
Seitenpanel faehrt von rechts herein, volle Hoehe.
Zwei Seiten im Track, --next schiebt zur zweiten.
Zwei Icons tauschen mit Skalierung und Blur.
Kreis bobt herein, Haken zeichnet sich per stroke-draw.
Gehoverter Avatar springt hoch, Nachbarn folgen abgeschwaecht.
Validierungsfehler: einmal schuetteln, neutral enden.
Wert loest sich in Blur und Sperrung auf.
Ladeplatzhalter mit Schimmer weicht dem Inhalt.
Glanzstreifen laeuft dauerhaft ueber den Text.
Tab-Leiste mit gleitendem Indikator, ohne ARIA-Verhalten.
Tooltip bei Hover, Fokus und Fokus im Inneren.
Textzeilen steigen versetzt herein, Stagger bis 6 Zeilen.
Karte neigt sich in 3D, Modul trackt den Zeiger.
Plus dreht sich zum X, Menue waechst aus dem Button.
Aufklapper mit weicher Hoehe und drehendem Plus.
Preview-Token aus validateArtifact, publiziert ohne zweite Uebertragung.
Meldung steigt unten mittig herein und steht.
Icon schnellt auf und faerbt sich. Pop bei jedem Setzen.
Haken zeichnet sich per stroke-draw beim Anhaken.
Ziffern klappen wie eine Fallblattanzeige herein.
Thumb gleitet, Track faerbt sich (Feature-Flags).
Reines CSS-Pattern: kein Fokus-Trap, kein Escape-Handler, kein role="dialog". Wer es als echten Dialog benutzt, ergaenzt beides selbst — siehe Befund B4.
Befunde aus dem Test
Neun Befunde, alle am Quelltext von 1.4.0 nachvollzogen, nicht geraten. Schwere: hoch bricht etwas, mittel kostet Verlaesslichkeit, niedrig ist Politur.
-
B1hoch fx-scroll.js · countUp()
scrollFx().counter()schreibtel.textContent— damit loescht es alle Kindknoten. Der dokumentierte Beispielselektor ist.mz-stat__value, und genau dort leben die neuen Ziffern-Spans vonmz-t-number-popundmz-t-counter. Wer beides nach Anleitung kombiniert, verliert die Spans beim ersten Frame; das Pattern ist danach tot, ohne Fehlermeldung.In diesem Bericht umgangen:
counter()laeuft nur auf.tx-count, die Pattern-Stats bleiben unangetastet. Vorschlag: countUp auf einen Textknoten begrenzen oder Elemente mit[class*="mz-t-"]ueberspringen. -
B2mittel mzone.css · mz-t-skeleton, mz-t-shimmer
Beide Patterns setzen ihre Farben als feste Hex-Werte:
--mz-t-skeleton-base:#1c242e,--mz-t-shimmer-hi:#f4f7fb. Im hellen Theme steht der Platzhalter damit als dunkler Block auf hellem Grund, und der Shimmer-Glanz ist fast weiss auf fast weiss. Die uebrigen Bausteine des Systems ziehen ihre Farben aus Tokens und wechseln mit.Selbst pruefbar: Theme-Schalter oben umlegen und die Zellen skeleton und shimmer ansehen. Vorschlag:
var(--mz-surface-alt)/var(--mz-border)als Default, Hex nur als Fallback. -
B3mittel mz-transitions.js · Trigger-Verdrahtung
Default-Trigger ist
'click'auf dem Ziel selbst. Fuer dropdown, modal, panel und toast ist das Ziel im Ruhezustandvisibility:hidden— es kann nie angeklickt werden, der Default oeffnet also grundsaetzlich nichts. Wer die Zeile aus dem Katalog kopiert, bekommt ein stummes Pattern und keinen Hinweis.Vorschlag: fuer diese vier Patterns
trigger:'none'als Default, oder eine OptiontriggerElfuer den ausloesenden Knoten. In diesem Bericht durchgaengigtrigger:'none'plus eigener Button. -
B4mittel mz-t-modal, mz-t-checkbox, mz-t-toggle
Drei Patterns sehen aus wie Bedienelemente, sind aber keine. Das Modal bringt weder
role="dialog"noch Fokus-Trap noch Escape mit; Checkbox und Toggle haben kein<input>und keine Rolle — ohne Zeigergeraet sind sie nicht bedienbar und in einem Formular nicht vorhanden.Das ist als CSS-Pattern legitim, gehoert aber in die Katalog-Beschreibung. Vorschlag: Beispiel-Markup mit
<input class="mz-sr-only" type="checkbox">bzw.role="switch" aria-checked. -
B5mittel mzone.css · mz-t-toggle, mz-t-checkbox, mz-t-like, mz-t-shake
Vier Zustandsfarben stehen ausserhalb des Token-Systems:
#2f81f7(toggle-on, checkbox-on),#e5484d(like, shake). Das System hat fuer beides Tokens —--mz-infound--mz-danger— die im hellen Theme andere Werte annehmen. So bleibt ein aktivierter Schalter in beiden Themes derselbe Blauton, waehrend alles daneben wechselt.Ueberschreibbar bleibt es (Custom Property am Element), der Default ist nur nicht der des Hauses.
-
B6niedrig mz-t-tabs-slide__indicator
Der Indikator hat im CSS keine
background. Sichtbar wird er erst durch dasstyle="background:var(--mz-accent)"aus dem Katalog-Beispiel. Wer das Attribut beim Uebernehmen weglaesst, sieht ein Tab-Set ohne Indikator und sucht den Fehler im JavaScript.Vorschlag:
background: var(--mz-accent)als Default ins Pattern, das style-Attribut aus dem Beispiel streichen. -
B7niedrig mz-theme-toggle.js · applyStoredTheme()
Die Doku empfiehlt,
applyStoredTheme()synchron im Kopf der Seite aufzurufen — die Funktion ist aber ausschliesslich als ES-Modul-Export erreichbar, und ein Modul laedt deferred. Der empfohlene Weg ist so nicht gehbar; praktisch bleibt nur, die fuenf Zeilen von Hand zu wiederholen (wie im Kopf dieser Seite).Vorschlag: eine klassische Variante
mz-theme-boot.jsausliefern oder den Inline-Schnipsel in den Katalog aufnehmen. -
B9hoch fx-magnify.js:56 · live gefunden
Beim ersten Aufbau dieser Seite stand
magnify('.mz-dgm')im Skript — das Diagramm ist ein Inline-SVG, undfx-magnifyakzeptiert nurcanvasoderimg. Das Modul wirft daraufhin:fx-magnify: keine Quelle (canvas/img) im Ziel gefunden. Die Zielwahl war mein Fehler — die Wirkung ist der Befund: der Wurf steht auf Modul-Toplevel, also stirbt der komplette Rest vonapp.jsmit. Tabs, Filtertabelle, beide Suchfelder, alle 27 Transitions und beide Diagramme blieben stumm, wegen einer Verzierung.Ein Effekt, der nichts als Verzierung ist, sollte nicht werfen, sondern warnen und eine No-Op-Instanz liefern — so wie fehlendes WebGL auf den 2D-Weg faellt statt abzubrechen. Zweitens waere SVG als Quelle naheliegend, gerade weil
mz-dgmim selben System als Diagramm-Container gefuehrt wird. Hier im Artefakt jetzt beides beruecksichtigt: Lupe auf.mz-chart(echtes canvas), und jeder Effekt laeuft durch einensafe()-Wrapper. -
B8bestanden Gesamteindruck
Alle 27 Patterns rendern in einem Bundle nebeneinander, ohne Namenskollision, ohne Layout-Streit und ohne eine einzige externe Abhaengigkeit. Der Reduced-Motion-Guard sitzt in jedem Block; die Stellschrauben liegen an der Basisklasse statt auf
:root, also lassen sich zwei Instanzen desselben Patterns unterschiedlich einstellen. Genau das ist der Unterschied zwischen einer Effektsammlung und einem System.
Fazit
Die MCP-Server-Welt tauscht Integrationsarbeit gegen Kontextmiete. Das ist fast immer ein guter Tausch — solange der Katalog schmal, die Verben scharf und die Antworten selbstpruefend bleiben. Der mzone-publisher zeigt beide Seiten in einer einzigen Antwort: getCapabilities() nennt Namen statt Beispiele, weil Namen genuegen, um zu schreiben; lookupStyles holt den Rest nur bei Bedarf. 6 KB statt 84 KB ist kein Sparzwang, sondern Entwurf.
mzone-ui 1.4.0 traegt diesen Bericht ohne eine Zeile fremdes CSS. Die 27 Patterns sind sauber gekapselt, und die vier reinen CSS-Patterns beweisen den Punkt am staerksten: was ohne JavaScript geht, sollte ohne JavaScript gehen. Die meisten Befunde sind Kanten, keine Bruchstellen. Zwei sind es nicht: B1 zerstoert stumm genau die Kombination, zu der die Doku einlaedt, und B9 laesst eine Verzierung die gesamte Bedienbarkeit der Seite mitreissen. Beide sind kleine Aenderungen, und beide betreffen dieselbe Frage — wie sich das System bei Fehlbedienung verhaelt. An der Antwort darauf unterscheidet sich ein Design-System von einer Effektsammlung.
B9 zuerst: dekorative Module warnen statt zu werfen, sonst kostet ein Tippfehler im Ziel die ganze Seite. Dann B1 entschaerfen (countUp ueberspringt Elemente mit mz-t-Kindern), B2 und B5 auf Tokens umstellen, B6 als Default nachziehen. Vier kleine Aenderungen, danach ist das Set widerspruchsfrei.
Bei den vier Overlay-Patterns trigger:'none' ins Beispiel schreiben (B3) und die a11y-Grenzen von modal, checkbox und toggle benennen (B4). Beides kostet nur Text und spart jedem Agenten eine Fehlrunde.