Figma Storybook Component Matching MCP Server
Figma → Storybook Komponenten-Matching MCP-Server
Ziel
Erstellung eines Remote-MCP-Servers. Das Ziel ist es, Figma-Designknoten als Eingabe zu erhalten, sie mit den React-Komponenten unseres Teams (registriert in Storybook) abzugleichen und Anwendungsbeispiele für den Code zu generieren.
Die LLM (Claude) sollte über dieses MCP folgende Anfragen verarbeiten können:
"Analysiere diese Figma-URL"
"Sag mir, wie ich diesen Figma-Knoten mit unseren Komponenten implementieren kann"
"Zeige mir 3 Komponenten-Kandidaten"
Tech-Stack
Runtime: Cloudflare Workers
Sprache: TypeScript (strict mode)
MCP: Verwendung der Pakete
@modelcontextprotocol/sdk+agentsTransport: Streamable HTTP, Endpunkt ist
/mcpValidierung: zod
Build/Deployment: wrangler
Ziel-Framework: React (JSX-Ausgabe bei der Codegenerierung)
Authentifizierung (Option A: Bearer-Token)
Alle MCP-Anfragen erfordern den Header
Authorization: Bearer <token>Abgleich mit
env.MCP_AUTH_TOKEN, bei Nichtübereinstimmung Rückgabe von 401Authentifizierungsfehler liefern eine klare Fehlermeldung (
{"error": "invalid_token"})
Umgebungsvariablen (definiert in wrangler)
FIGMA_TOKEN: Figma Personal Access Token (wird vom Server gespeichert)STORYBOOK_URL: Storybook-Basis-URL (z. B.https://storybook.example.com)MCP_AUTH_TOKEN: Token für die Client-AuthentifizierungCOMPONENT_IMPORT_PREFIX: Import-Pfad bei der Codegenerierung (Standard@/components)
Für die lokale Entwicklung .dev.vars verwenden, für die Produktion wrangler secret put. In wrangler.toml nur Dummy-Platzhalter belassen.
Bereitzustellende Tools
1. get_figma_node
Beschreibung: Empfängt eine Figma-URL und gibt die Kerninformationen des Knotens in bereinigter Form zurück
Eingabe (zod):
{
url: string // Figma 노드 URL (예: https://www.figma.com/file/XXX/...?node-id=1%3A2)
}Ablauf:
Parsen von
fileKeyundnodeIdaus der URL (?node-id=1%3A2→ dekodiert zu1:2)Aufruf der Figma-API:
GET https://api.figma.com/v1/files/{fileKey}/nodes?ids={nodeId}Header:
X-Figma-Token: {env.FIGMA_TOKEN}
Extraktion nur der folgenden Daten (die Figma-Antwort ist zu ausführlich, daher Bereinigung):
Knotenname (
name)Knotentyp (
type: FRAME, INSTANCE, TEXT, ...)Bei Komponenten: Komponentenname (
componentId→componentName)Stil: Hintergrundfarbe, Rahmen, Border-Radius, Padding, Layout-Modus (Auto-Layout-Richtung), Gap
Bei Text:
charactersund SchriftinformationenKind-Struktur: Nur Name/Typ der Kindknoten bis zu einer Tiefe von 1 (keine Rekursion, wird sonst zu lang)
Informationen zu Komponenten-Variablen/Varianten (falls vorhanden)
Ausgabe: Ein bereinigtes JSON-Objekt mit den oben genannten Informationen
Fehler: Unterscheidung zwischen URL-Parsing-Fehler, Figma-API 4xx/5xx, Token-Ablauf usw. mit entsprechenden Fehlermeldungen
2. get_figma_subtree
Beschreibung: Ruft den gesamten Baum eines Knotens rekursiv ab (zur Analyse ganzer Seiten/Frames)
Eingabe:
{
url: string,
maxDepth?: number // 기본 3, 너무 깊으면 토큰 폭발
}Ablauf: Ähnlich wie get_figma_node, aber rekursives Abrufen der Kinder bis maxDepth. Jedes Kind ebenfalls im bereinigten Format.
3. list_stories
Beschreibung: Gibt die Komponentenliste unseres Storybooks zurück
Eingabe: Keine (oder { filter?: string } für die Suche)
Ablauf:
Fetch von
${env.STORYBOOK_URL}/index.json(Fallback bei Fehler) Versuch mit
${env.STORYBOOK_URL}/stories.jsonExtraktion nur der Einträge mit
type: "story"aus dementries-Objekt (Docs-Seiten ausschließen)Konvertierung in folgendes Format:
{
id: string,
componentName: string, // title에서 마지막 "/" 뒤 부분 (예: "Forms/Button" → "Button")
storyName: string, // name 필드
fullTitle: string, // 원본 title
tags: string[]
}[]Caching: In-Memory-Caching der Antwort für 5 Minuten (KV nicht erforderlich, einfache Variable). Da Workers-Instanzen kurzlebig sind, nicht zu lange ansetzen.
4. get_story_details
Beschreibung: Detaillierte Informationen zu einer bestimmten Story (Props, Args)
Eingabe:
{ storyId: string }Ablauf:
Suche der entsprechenden ID in
index.jsonFalls möglich, Extraktion der argTypes aus
${STORYBOOK_URL}/stories.jsonoder ID-basierten MetadatenBereinigung der Prop-Signatur:
{
id: string,
componentName: string,
description?: string,
props: {
name: string,
type: string,
required: boolean,
description?: string,
defaultValue?: any
}[]
}Falls argTypes nicht abgerufen werden können, Props als leeres Array zurückgeben und stattdessen note: "argTypes unavailable" hinzufügen.
5. match_figma_to_components
Beschreibung: Gibt Komponenten-Kandidaten, die mit den Figma-Knotendaten übereinstimmen, zusammen mit einem Score zurück (Kern-Tool)
Eingabe:
{
figmaNode: <get_figma_node 출력 형식>,
topK?: number // 기본 3
}Ablauf:
Abrufen aller Komponenten über
list_storiesBerechnung des Matching-Scores für jede Komponente:
Namensähnlichkeit (Gewichtung 0.5): Figma-Knotenname vs.
componentNameExakte Übereinstimmung: 1.0
Übereinstimmung ohne Berücksichtigung von Groß-/Kleinschreibung: 0.9
Teilmenge: 0.6
Basierend auf Levenshtein-Distanz: 0~0.5
Struktur-Matching (Gewichtung 0.3): Ableitung von Kind-Mustern
Figma-Kind ist nur Text → Kandidaten "Button", "Label" +
Icon + Text → Kandidaten "Button", "Tag", "Chip" +
Mehrere Karten-ähnliche Kinder → Kandidaten "List", "Grid" +
Tag-Übereinstimmung (Gewichtung 0.2): Storybook-Story-Tags enthalten Schlüsselwörter aus dem Figma-Knotennamen
Rückgabe der Top K (Standard 3):
{
storyId: string,
componentName: string,
score: number, // 0~1
reasons: string[] // 왜 매칭됐는지 사람이 읽을 수 있게
}[]Matching-Scores unter 0.3 werden ausgeschlossen (Filterung irrelevanter Übereinstimmungen).
6. generate_component_usage
Beschreibung: Generiert ein React-JSX-Codebeispiel mit der gematchten Komponente + Figma-Knoteninformationen
Eingabe:
{
storyId: string,
figmaNode: <get_figma_node 출력 형식>
}Ablauf:
Abrufen der Prop-Signatur über
get_story_detailsVersuch, Text, Stil und Varianteninformationen des Figma-Knotens auf Props abzubilden
Figma-Text →
childrenoderlabelPropFigma-Variantenname → passender Prop-Wert
Generierung des JSX-Code-Strings
Ausgabe:
{
code: string, // <Button variant="primary">Click me</Button>
importStatement: string, // import { Button } from "@/components/Button"
notes: string[] // 매핑 추측이나 빠진 정보 안내
}Der Import-Pfad basiert auf der Umgebungsvariable env.COMPONENT_IMPORT_PREFIX (Standardwert "@/components").
Projektstruktur
figma-storybook-mcp/
├── src/
│ ├── index.ts # Worker 진입점, 인증 미들웨어, MCP 라우팅
│ ├── mcp.ts # MyMCP 클래스 (도구 등록)
│ ├── auth.ts # Bearer 토큰 검증
│ ├── figma/
│ │ ├── client.ts # Figma REST API 호출
│ │ ├── url-parser.ts # URL → fileKey + nodeId
│ │ └── normalizer.ts # Figma 응답 → 정제된 형식
│ ├── storybook/
│ │ ├── client.ts # index.json fetch + 캐싱
│ │ └── types.ts
│ ├── matching/
│ │ ├── scorer.ts # 매칭 점수 계산
│ │ └── name-similarity.ts # Levenshtein 등
│ ├── codegen/
│ │ └── react.ts # JSX 코드 생성
│ └── types.ts # 공통 타입
├── tests/
│ ├── url-parser.test.ts
│ ├── normalizer.test.ts
│ └── scorer.test.ts
├── wrangler.toml
├── .dev.vars.example # 실제 .dev.vars는 gitignore
├── package.json
├── tsconfig.json
├── vitest.config.ts
└── README.mdImplementierungsanforderungen
Typsicherheit: Alle Tool-Eingabe-Zod-Schemata und Ausgabe-Typen müssen explizit definiert sein
Fehlerbehandlung:
Figma 401 → "Figma-Token abgelaufen/ungültig"
Figma 404 → "Knoten nicht gefunden"
Storybook-Fetch fehlgeschlagen → Klare Nachricht
Alle Fehler müssen in einem für MCP verständlichen Format zurückgegeben werden
Logging:
console.logfür Start/Ende von Tool-Aufrufen, Fehler überconsole.error. Sichtbar im Workers-DashboardTests: Unit-Tests für Kernlogik mit vitest (URL-Parsing, Matching-Score, Normalisierungslogik)
README-Aktualisierung:
Was das Tool macht
Erklärung der Umgebungsvariablen
Lokale Ausführung (
npm run dev)Deployment (
npm run deploy)Anleitung zur Verbindung mit Claude Desktop / Claude.ai
Beispiele für Ein-/Ausgabe jedes Tools
Arbeitsablauf (Berichterstattung in Phasen)
Phase 1: Setup
Projektinitialisierung, Installation der Abhängigkeiten
Erstellung von
wrangler.toml,tsconfig.jsonÜberprüfung, ob der leere MCP-Server auf
/mcpantwortet (auch mit 0 Tools OK)
Phase 2: Authentifizierung
Middleware zur Überprüfung des Bearer-Tokens
Überprüfung von 401 bei Aufrufen mit ungültigem Token
Phase 3: Figma-Tools
figma/url-parser.ts+ Unit-Testsfigma/client.ts(tatsächliche API-Aufrufe)figma/normalizer.ts(Bereinigung der Antwort)Registrierung des
get_figma_node-ToolsÜberprüfung der Funktion mit einer echten Figma-URL
Phase 4: Storybook-Tools
storybook/client.ts(index.json fetch + Caching)Registrierung von
list_stories,get_story_details
Phase 5: Matching
matching/scorer.ts+ Unit-TestsRegistrierung von
match_figma_to_components
Phase 6: Codegenerierung
codegen/react.tsRegistrierung von
generate_component_usage
Phase 7: Abschluss
Hinzufügen von
get_figma_subtreeErstellung der README
Bereitstellung von
.dev.vars.example
Nach jeder Phase kurz berichten: "Das habe ich erledigt, als Nächstes mache ich das."
Hinweise
Cloudflare Workers unterstützen nur einen Teil der Node.js-API.
fs,child_processetc. funktionieren nicht. Auf Basis vonfetchschreibenAktuelle stabile Version von
@modelcontextprotocol/sdkverwendenDa sich der MCP-Standard schnell ändert, den neuesten Mustern des
agents-Pakets folgenNicht alles auf einmal bauen, sondern phasenweise validieren
Code klar halten, Kommentare nur für Geschäftslogik (wie Matching-Scores)
Start
Bitte beginne mit Phase 1.
Related MCP Connectors
The Figma MCP server brings Figma design context directly into your AI workflow.
Serves your design system and coding standards to coding agents, so they stop guessing.
Build and manage your design system with AI: tokens, themes, components, icons, Figma and code.
Live React design-system APIs, patterns, and code validation so AI agents build real UI, not slop.