Auth-Failure-Protokoll für autonome Figma-MCP-Läufe
status: "NEEDS_REAUTH"). Kein Polling, kein Retry-Loop, kein stilles Weitermachen mit gecachten Daten.
Kontext
Der Skill figma-autonomous-implementer (.claude/skills/figma-autonomous-implementer/) läuft nach einer einzigen User-Bestätigung der Slice-Liste headless durch fünf Phasen (Auth-Probe → Decompose → Implement-per-Slice → Visual-Verify-per-Slice → PR-Open). In mindestens drei dieser Phasen ist die Figma-MCP-Verbindung Pflicht-Quelle:
- Phase 1 (Auth-Probe via
whoami). - Phase 2 (Decompose) —
get_metadata,get_design_context,get_variable_defs. - Phase 4 (Visual-Verify) —
get_screenshotfür die Frame-Baseline pro Breakpoint.
Die Figma-MCP-Auth läuft im Hintergrund über den Claude.ai-Connector und kann zwischen Aufrufen unbemerkt ablaufen (Token-Expiry, Cookie-Verlust, Connector-Fehlkonfiguration). Der Fehlertext im MCP-Tool-Result enthält dann konsistent eine der Substrings expired, 401, session, unauthenticated oder unauthorized — aber das exakte Wording schwankt zwischen Connector-Versionen und Endpoints.
In der Vergangenheit haben autonome MCP-Konsumenten in solchen Fällen drei Anti-Pattern gezeigt:
- Retry-Loop ohne Cap — der Loop drehte minutenlang Auth-Fehler im Kreis, bis der User abbrach. Kontext-Verbrauch hoch, Erkenntniswert null.
- Backoff-Loop mit zunehmender Pausenzeit — kosmetisch besser, aber der eigentliche Trigger (User muss neu autorisieren) wurde nie an die Oberfläche gebracht.
- Stilles Weiterlaufen mit gecachten Inputs — der Skill ignorierte den Fehler und arbeitete mit veralteten oder unvollständigen Figma-Daten weiter. Resultat: Slices, die gegen ein Schatten-Bild gebaut wurden.
Im Solcom-Repo existiert bereits ein etabliertes Gegen-Pattern im .claude/agents/solcom-figma-reviewer.md-Reviewer-Agent (Sektion „Fallback-Fetch via Figma-MCP"):
„Pre-Flight für eigene Calls:whoamieinmal, dann gezielt nachladen. Beim Fehlerfall (z. B. „session expired"): nicht retry-loopen, inresidual_risksmelden und an Caller zurück."
Das gibt die Richtung vor, ist aber für den Reviewer-Kontext formuliert (Reviewer hat einen Caller, der die Reauth selbst ausführen kann). Der figma-autonomous-implementer hat keinen Caller — er kommuniziert direkt mit dem User. Es braucht ein maschinenlesbares, smoke-test-bares Auth-Failure-Protokoll.
Entscheidung
Bei Figma-MCP-Auth-Failure bricht der figma-autonomous-implementer nach maximal zwei Versuchen ab und gibt eine einzige strukturierte JSON-Message mit status: "NEEDS_REAUTH" aus. Kein dritter Versuch, kein Polling, kein User-Prompt mit der Frage „soll ich nochmal?".
Das Protokoll hat fünf Bestandteile:
1. Trigger-Substrings (eindeutig auth, kein anderer Fehlertyp)
Der Skill klassifiziert einen Fehler als Auth-Failure genau dann, wenn der Roh-Text der MCP-Tool-Antwort (case-insensitive) eine der folgenden Substrings enthält:
expired 401 session unauthenticated unauthorized
Andere Fehler (timeout, 429, 503, generische Netzwerkfehler ohne Auth-Substring) sind nicht Auth-Failure — sie laufen in den parallelen NEEDS_FIGMA_TRANSPORT-Pfad, das ist Domäne des Skills, nicht dieses ADRs.
2. Retry-Cap: genau zwei Versuche
- Versuch 1 ist der Original-Aufruf, der den Trigger-Substring lieferte.
- Versuch 2 wird nach 1 Sekunde Pause ausgeführt — mit demselben Tool und denselben Parametern.
- Liefert Versuch 2 wieder einen Auth-Substring → sofort Abbruch, JSON-Output, Lauf beenden. Keine dritte Chance, kein exponentielles Backoff.
Begründung 2-statt-3: ein dritter Versuch fügt keine Information hinzu, die ein zweiter nicht schon liefert. Drei Versuche kosten doppelten Wartetask, ohne den NEEDS_REAUTH-Pfad zu verbessern.
3. Output-JSON-Schema (Pflicht-Felder, fixe Reihenfolge)
{
"status": "NEEDS_REAUTH",
"service": "figma-mcp",
"attempts": 2,
"trigger": "<wörtlicher Auszug aus dem Fehlertext, max 200 Zeichen>",
"instruction": "Figma-MCP-Verbindung im Claude.ai-Connector neu autorisieren, dann denselben /figma-autonomous-implement-Aufruf wiederholen."
}
status— fixierter StringNEEDS_REAUTH. Ein anderer Wert ist Schema-Verstoß.service— fixierter Stringfigma-mcp. Falls weitere MCP-Server den Pfad nutzen, kommen weitere Werte hinzu.attempts— Integer, der Wert beim Abbruch (typisch2). Nie0, nie>2für diesen Skill.trigger— wörtlicher Substring-Auszug aus dem Fehlertext, gekappt auf 200 Zeichen. Kein Paraphrasing.instruction— der eine Satz, was der User zu tun hat.
Der Smoke-Test (smoke/run.sh) parst dieses JSON mit jq und prüft die fünf Pflichtfelder + status === "NEEDS_REAUTH".
4. Single-Message-Discipline
Der Skill gibt genau eine Message mit dem JSON aus, dann beendet er den Lauf. Keine nachfolgende Erklärung, keine zweite Message mit Tipps, keine AskUserQuestion mit Optionen. Das JSON ist parse-fähig — Sekundärtext wäre Rauschen für Skript-Wrapper.
5. Resume-Pfad
Nach erfolgter Reauth ruft der User denselben Aufruf erneut. Der Skill startet bei Phase 1, nicht in der Mitte. Zwischen Auth-Verlust und Reauth kann sich am Figma-Frame etwas geändert haben; ein Mid-Resume mit gecachten Decomp-Daten würde gegen einen veralteten State bauen.
Rejected alternatives
Drei Versuche statt zwei rejected
Auth-Tokens drehen nicht in Sekunden ihre Gültigkeit hin und her. Drei Versuche fügen eine Sekunde Wartezeit hinzu, aber keine echte Recovery-Wahrscheinlichkeit. Plus: der Smoke-Test-Schwellwert wird unschärfer.
Exponentielles Backoff (1s → 2s → 4s → …) rejected
Verzögert nur den Anti-Pattern „User wartet, bis er endlich erfährt, dass er reauthen muss". Auth-Failures sind kein Rate-Limit-Problem, das Pause helfen würde.
AskUserQuestion-Prompt im Loop rejected
„Auth ist abgelaufen — soll ich's nochmal versuchen?" — Verworfen aus zwei Gründen: verletzt die Single-Allowed-Prompt-Discipline des Skills; die Antwort ist immer dieselbe (Reauth + Retry), also ist die Frage Konversations-Theater.
Auto-Reauth via OAuth-Refresh-Token rejected
Der Claude-Code-Connector steuert den Refresh-Pfad zentral. Ein Skill-eigener Refresh würde den Connector-Zustand desynchronisieren. Der Reauth-Pfad ist UI-getrieben (User klickt im Connector-Dialog), nicht skript-getrieben.
Stilles Weitergehen mit dem letzten gültigen Decomp-Output rejected
Nach Auth-Verlust kann der Skill nicht mehr garantieren, dass get_screenshot (Phase 4) einen aktuellen Frame liefert. Visual-Verify gegen einen Schatten-Frame ist schlechter als gar kein Visual-Verify, weil es scheinbar grünes Verifikations-Theater liefert.
Eigene Status-Werte pro Tool (AUTH_FAILED_WHOAMI, …) rejected
Die User-Action ist immer dieselbe (im Connector reauthen). Die Tool-Granularität gehört in trigger als Roh-Beweis, nicht in einen aufgeblähten Status-Enum-Raum.
Strukturlose Freitext-Message rejected
„Ich konnte nicht auf Figma zugreifen, bitte reauthenticate" — nicht maschinen-parsbar. Der Smoke-Test könnte nur grep'pen, was fehleranfällig ist; ein Skript-Wrapper könnte den Output gar nicht abfangen.
Skill bei Auth-Failure stumm beenden ohne JSON rejected
Der User hätte keine Diagnose, was passiert ist. Ein stummer Exit würde sich nicht von einem normalen Lauf-Ende unterscheiden lassen.
Consequences
- Vorhersehbare Failure-Surface. Jeder autonome Lauf des Skills hat genau zwei Outcomes für Auth-Failure-Pfade: NEEDS_REAUTH-JSON oder normaler Lauf. Smoke-Test + CI-Wrapper können beide Pfade sauber unterscheiden.
- Smoke-test-bares Schema. Der Smoke-Test in
smoke/run.shprüft die fünf Pflichtfelder und das fixestatus-Wording mitjq. Das schützt gegen Schema-Drift. - Mirror-Konsistenz mit
solcom-figma-reviewer. Beide Komponenten folgen demselben „nicht retry-loopen, melden"-Prinzip. Bei zukünftigen MCP-Konsumenten lässt sich das Schema 1:1 übertragen. - False-Positive-Risiko bei Substring-Match. Wenn ein Figma-MCP-Fehler den String
sessionaus Versehen in einem nicht-auth-Kontext enthält, würde er fälschlich als NEEDS_REAUTH klassifiziert. Bewusste Restbedingung — Recovery-Aufwand für den User ist niedrig genug. - Resume-Aufwand. Der volle Re-Run aus Phase 1 nach Reauth dupliziert die Decomposition (Phase 2). Bei großen Frames ist das ~30 Sekunden Verlust. Akzeptabel, weil Mid-Resume gegen veraltete Daten schlechter ist.
- Kein automatischer Auth-Heartbeat zwischen Phasen. Der Skill probt Auth nur in Phase 1. Wenn die Session zwischen Decomposition und Visual-Verify abläuft, fängt der Skill den Failure beim ersten fehlschlagenden Tool ab.
- Erweiterungs-Pfad. Ein zweites NEEDS_*-Status (
NEEDS_FIGMA_TRANSPORT,NEEDS_DECOMPOSITION_REVISION,SLICE_FAILED) lebt im Skill selbst, nicht in diesem ADR. Wenn die Familie wächst und ein gemeinsames Schema braucht, ist das ein eigener ADR mit höherer Nummer.