Skip to main content
Glama
martin-delivered

Figma Storybook Component Matching MCP Server

Figma → Storybook Component Matching MCP Server

Goal

Create a remote MCP server. The goal is to receive Figma design nodes as input, match them with our team's React components (registered in Storybook), and generate usage code examples.

LLM (Claude) should be able to handle requests like the following through this MCP:

  • "Analyze this Figma URL"

  • "Tell me how to implement this Figma node with our components"

  • "Show me 3 candidate components"

Tech Stack

  • Runtime: Cloudflare Workers

  • Language: TypeScript (strict mode)

  • MCP: Using @modelcontextprotocol/sdk + agents packages

  • Transport: Streamable HTTP, endpoint is /mcp

  • Validation: zod

  • Build/Deploy: wrangler

  • Target Framework: React (JSX output for code generation)

Authentication (Option A: Bearer Token)

  • All MCP requests require the header Authorization: Bearer <token>

  • Compare with env.MCP_AUTH_TOKEN, return 401 if mismatch

  • Authentication failure should return a clear error message ({"error": "invalid_token"})

Environment Variables (defined in wrangler)

  • FIGMA_TOKEN: Figma Personal Access Token (stored by the server)

  • STORYBOOK_URL: Storybook base URL (e.g., https://storybook.example.com)

  • MCP_AUTH_TOKEN: Token for client authentication

  • COMPONENT_IMPORT_PREFIX: Import path for code generation (default @/components)

Manage local development via .dev.vars and production via wrangler secret put. Keep only dummy placeholders in wrangler.toml.

Tools to Expose

1. get_figma_node

Description: Receives a Figma URL and returns core information about the node in a refined format.

Input (zod):

{
  url: string  // Figma 노드 URL (예: https://www.figma.com/file/XXX/...?node-id=1%3A2)
}

Operation:

  1. Parse fileKey and nodeId from the URL (decode ?node-id=1%3A21:2)

  2. Call Figma API: GET https://api.figma.com/v1/files/{fileKey}/nodes?ids={nodeId}

    • Header: X-Figma-Token: {env.FIGMA_TOKEN}

  3. Extract only the following from the response (Figma responses are too verbose, so refine them):

    • Node name (name)

    • Node type (type: FRAME, INSTANCE, TEXT, ...)

    • If it's a component, component name (componentIdcomponentName)

    • Styles: background color, border, border radius, padding, layout mode (autolayout direction), gap

    • If text, characters and font information

    • Child structure: only names/types of child nodes at 1 level depth (no recursion, to avoid excessive length)

    • Component variables/variants information (if any)

Output: A refined JSON object containing the above information.

Errors: Distinguish between URL parsing failure, Figma API 4xx/5xx, token expiration, etc., and return error messages.

2. get_figma_subtree

Description: Recursively fetches the entire tree of a node (for analyzing entire pages/frames).

Input:

{
  url: string,
  maxDepth?: number  // 기본 3, 너무 깊으면 토큰 폭발
}

Operation: Similar to get_figma_node but recurses children up to maxDepth. Each child is also in a refined format.

3. list_stories

Description: Returns a list of components from our Storybook.

Input: None (or { filter?: string } for searching)

Operation:

  1. Fetch ${env.STORYBOOK_URL}/index.json

  2. (Fallback on failure) Try ${env.STORYBOOK_URL}/stories.json

  3. Extract only entries with type: "story" from the entries object (exclude docs pages)

  4. Convert to the following format:

{
  id: string,
  componentName: string,  // title에서 마지막 "/" 뒤 부분 (예: "Forms/Button" → "Button")
  storyName: string,      // name 필드
  fullTitle: string,      // 원본 title
  tags: string[]
}[]

Caching: In-memory cache the response for 5 minutes (no need for KV, use a simple variable). Since Workers instances are short-lived, do not set a long duration.

4. get_story_details

Description: Detailed information for a specific story (props, args).

Input:

{ storyId: string }

Operation:

  1. Find the ID in index.json

  2. If possible, extract argTypes from ${STORYBOOK_URL}/stories.json or ID-based metadata

  3. Clean up props signature:

{
  id: string,
  componentName: string,
  description?: string,
  props: {
    name: string,
    type: string,
    required: boolean,
    description?: string,
    defaultValue?: any
  }[]
}

If argTypes cannot be retrieved, set props as an empty array and add note: "argTypes unavailable".

5. match_figma_to_components

Description: Returns candidate components that match Figma node data, along with scores (Core Tool).

Input:

{
  figmaNode: <get_figma_node 출력 형식>,
  topK?: number  // 기본 3
}

Operation:

  1. Fetch all components using list_stories

  2. Calculate matching score for each component:

    • Name Similarity (weight 0.5): Figma node name vs componentName

      • Exact match: 1.0

      • Case-insensitive match: 0.9

      • Inclusion: 0.6

      • Levenshtein distance-based: 0~0.5

    • Structure Matching (weight 0.3): Infer child patterns

      • Figma children are only text → add "Button", "Label" candidates

      • Icon + text → add "Button", "Tag", "Chip" candidates

      • Multiple card-like children → add "List", "Grid" candidates

    • Tag Matching (weight 0.2): Storybook story tags contain keywords from the Figma node name

  3. Return top K (default 3):

{
  storyId: string,
  componentName: string,
  score: number,  // 0~1
  reasons: string[]  // 왜 매칭됐는지 사람이 읽을 수 있게
}[]

Exclude matches with a score below 0.3 (filter out meaningless matches).

6. generate_component_usage

Description: Generates React JSX code examples using matched components + Figma node information.

Input:

{
  storyId: string,
  figmaNode: <get_figma_node 출력 형식>
}

Operation:

  1. Get props signature using get_story_details

  2. Attempt to map Figma node text, styles, and variant information to props

    • Figma text → children or label prop

    • Figma variant name → matching prop value

  3. Generate JSX code string

Output:

{
  code: string,        // <Button variant="primary">Click me</Button>
  importStatement: string,  // import { Button } from "@/components/Button"
  notes: string[]      // 매핑 추측이나 빠진 정보 안내
}

Import path is based on environment variable env.COMPONENT_IMPORT_PREFIX (default value "@/components").

Project Structure

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.md

Implementation Requirements

  1. Type Safety: Explicitly define zod schemas for all tool inputs and output types.

  2. Error Handling:

    • Figma 401 → "Figma token expired/invalid"

    • Figma 404 → "Node not found"

    • Storybook fetch failure → Clear message

    • All errors must be returned in a format the MCP can understand.

  3. Logging: Use console.log for tool call start/end, and console.error for errors. Visible in Workers dashboard.

  4. Testing: Unit test core logic (URL parsing, matching scores, normalization logic) with vitest.

  5. Update README:

    • What the tool does

    • Environment variable explanation

    • Local execution (npm run dev)

    • Deployment (npm run deploy)

    • How to connect to Claude Desktop / Claude.ai

    • Input/output examples for each tool

Workflow (Proceed while reporting step-by-step)

Phase 1: Setup

  • Project initialization, dependency installation

  • Create wrangler.toml, tsconfig.json

  • Verify empty MCP server responds at /mcp (0 tools is OK)

Phase 2: Authentication

  • Bearer token validation middleware

  • Verify 401 on calls with invalid tokens

Phase 3: Figma Tools

  • figma/url-parser.ts + unit tests

  • figma/client.ts (actual API calls)

  • figma/normalizer.ts (response refinement)

  • Register get_figma_node tool

  • Verify operation with actual Figma URL

Phase 4: Storybook Tools

  • storybook/client.ts (index.json fetch + caching)

  • Register list_stories, get_story_details

Phase 5: Matching

  • matching/scorer.ts + unit tests

  • Register match_figma_to_components

Phase 6: Code Generation

  • codegen/react.ts

  • Register generate_component_usage

Phase 7: Finalization

  • Add get_figma_subtree

  • Write README

  • Provide .dev.vars.example

After each phase, report briefly: "I did this, and I will do this next."

Notes

  • Cloudflare Workers only support a subset of Node.js APIs. fs, child_process, etc., are not available. Write based on fetch.

  • Use the latest stable version of @modelcontextprotocol/sdk.

  • MCP standards change quickly, so follow the latest patterns in the agents package.

  • Do not build everything at once; verify phase by phase.

  • Keep code clear; comments only for business logic (like matching scores).

Start

Please start with Phase 1.

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • The Figma MCP server brings Figma design context directly into your AI workflow.

  • MCP server for AI access to SmartBear tools, including BugSnag, Reflect, Swagger, PactFlow, QTM4J.

  • Connect AI coding agents to Anima Playground, Figma, and your design system.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/martin-delivered/storybook-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server