# 2991 Figma MCP Integration Report 13bd0195

> Figma MCP Integration Analysis Report

- Skill: `tools-only/2991-figma-mcp-integration-report-13bd0195` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/2991-figma-mcp-integration-report-13bd0195`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/2991-figma-mcp-integration-report-13bd0195/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/tools-only/2991-figma-mcp-integration-report-13bd0195

---

# Figma MCP Integration Analysis Report

**Date**: 2025-10-22
**Navigator Version**: 3.3.1
**Scope**: Product Design Skill - Figma MCP Data Flow

---

## Executive Summary

Analysis of Navigator's product-design skill reveals a two-layer architecture where Claude Code orchestrates Figma MCP tool calls and Python functions process the responses. While functional, this design creates orchestration overhead and limits dynamic data fetching capabilities.

**Key Finding**: Python functions process MCP data but cannot call MCP tools directly, requiring Claude to manually fetch all data upfront and save to temporary files.

**Authentication Challenge**: Direct Python → MCP calls would bypass Claude Code's MCP authentication layer, requiring alternative approach.

---

## Current Architecture

### Data Flow Overview (ASCII Diagram)

```
┌─────────────────────────────────────────────────────────────┐
│ Current Architecture (Two-Layer)                            │
└─────────────────────────────────────────────────────────────┘

User Request: "Review Figma design"
    │
    ▼
┌─────────────────────────────────────────┐
│ Claude Code (Orchestrator)              │
│ - Has MCP auth/session                  │
│ - Calls Figma MCP tools                 │
│ - 15-20 manual steps                    │
└─────────────────────────────────────────┘
    │
    │ (1) Call MCP tools
    ▼
┌─────────────────────────────────────────┐
│ Figma MCP Server                        │
│ http://127.0.0.1:3845/mcp               │
│                                         │
│ Auth: Figma Desktop session             │
│ (User logged into Figma app)            │
└─────────────────────────────────────────┘
    │
    │ (2) Return JSON responses (5-100k tokens)
    ▼
┌─────────────────────────────────────────┐
│ Claude Code                             │
│ - Save to /tmp/*.json                   │
└─────────────────────────────────────────┘
    │
    │ (3) Invoke Python with file paths
    ▼
┌─────────────────────────────────────────┐
│ Python Functions (Processors)           │
│ - design_analyzer.py                    │
│ - token_extractor.py                    │
│ - component_mapper.py                   │
│ - design_system_auditor.py              │
│ - implementation_planner.py             │
│                                         │
│ Auth: None needed (reads files)         │
└─────────────────────────────────────────┘
    │
    │ (4) Return processed results
    ▼
┌─────────────────────────────────────────┐
│ Claude Code                             │
│ - Present to user                       │
└─────────────────────────────────────────┘
    │
    ▼
User sees: Design review report
```

### MCP Tool Specifications

| MCP Tool | Purpose | Token Cost | Response Format |
|----------|---------|------------|-----------------|
| `get_metadata` | Component structure | 5-10k | Recursive node tree (XML-like) |
| `get_variable_defs` | Design tokens | 10-20k | Variables dict with `$value`/`$type` |
| `get_code_connect_map` | Component mappings | 5-10k | Figma node_id → code path |
| `get_design_context` | Per-component code | 50-100k+ | Component implementation |

### Python Function Pipeline

| Function | Input | Output | Purpose |
|----------|-------|--------|---------|
| `design_analyzer.py` | Metadata JSON | Component list with categories | Identify new components |
| `token_extractor.py` | Variables JSON | DTCG tokens + diff | Sync design system |
| `component_mapper.py` | Code Connect + filesystem | Figma → code mappings | Map existing components |
| `design_system_auditor.py` | Combined data | Drift report | Detect system health |
| `implementation_planner.py` | Analysis results | Navigator task doc | Generate implementation plan |

---

## MCP Response Data Structures

### `get_metadata` Response

**File**: `skills/product-design/functions/design_analyzer.py:28-50`

```python
# Format 1: Single document
metadata['document'] = {
    'id': 'node_id',
    'name': 'Component Name',
    'type': 'COMPONENT',  # or 'COMPONENT_SET', 'INSTANCE'
    'children': [...],
    'absoluteBoundingBox': {
        'width': 100,
        'height': 50
    }
}

# Format 2: Multiple nodes
metadata['nodes'] = [
    {
        'id': 'node_id',
        'type': 'COMPONENT',
        'name': 'Button',
        # ... properties
    }
]
```

**Key Node Types Extracted**:
- `COMPONENT`: Base component definition
- `COMPONENT_SET`: Variant container
- `INSTANCE`: Component usage

**Node Properties Extracted** (`design_analyzer.py:88-114`):
- `layoutMode`: flex/grid layout
- `layoutDirection`: horizontal/vertical
- `itemSpacing`: gap between items
- `paddingTop/Right/Bottom/Left`: padding values
- `absoluteBoundingBox`: width/height sizing
- `componentProperties`: variant definitions

### `get_variable_defs` Response

**File**: `skills/product-design/functions/token_extractor.py:122-166`

```python
variables = {
    'Primary 500': {
        '$value': '#3B82F6',
        '$type': 'color',
        '$description': 'Primary brand color'
    },
    'Spacing MD': {
        '$value': '16px',
        'type': 'dimension'  # Alternative format
    }
}
```

**Token Types Detected** (`token_extractor.py:80-114`):
- `color`: hex or rgb values
- `dimension`: px/rem/em values
- `typography`: font objects with fontFamily, fontSize
- `shadow`: objects with x, y properties
- `duration`: ms/s values
- `number`: numeric values

### `get_code_connect_map` Response

**File**: `skills/product-design/functions/component_mapper.py:194-204`

```python
code_connect_map = {
    'figma_node_id_12345': {
        'codeConnectName': 'Button',
        'codeConnectSrc': 'src/components/ui/Button.tsx'
    }
}
```

---

## Processing Logic Examples

### Component Extraction (design_analyzer.py)

**File**: `skills/product-design/functions/design_analyzer.py:40-72`

```python
def traverse_nodes(node, depth=0):
    """Recursively traverse Figma node tree."""
    node_type = node.get('type', '')
    node_name = node.get('name', 'Unnamed')
    node_id = node.get('id', '')

    # Identify components
    if node_type in ['COMPONENT', 'COMPONENT_SET', 'INSTANCE']:
        components.append({
            'id': node_id,
            'name': node_name,
            'type': node_type,
            'properties': extract_node_properties(node)
        })

    # Recurse children
    for child in node.get('children', []):
        traverse_nodes(child, depth + 1)
```

**Similarity Matching** (`design_analyzer.py:157-189`):
- Calculates string similarity (0.0-1.0)
- Threshold 0.7 = "similar component, consider extending"

### Token Conversion (token_extractor.py)

**File**: `skills/product-design/functions/token_extractor.py:117-166`

```python
def convert_to_dtcg(figma_variables):
    for var_name, var_data in figma_variables.items():
        # Extract value and type
        value = var_data.get('$value') or var_data.get('value')
        var_type = var_data.get('$type') or var_data.get('type')

        # Normalize name: "Primary 500" → "color.primary.500"
        token_path = normalize_token_name(var_name)

        # Build nested DTCG structure
        current[part] = {
            '$value': value,
            '$type': var_type
        }
```

### Component Mapping (component_mapper.py)

**File**: `skills/product-design/functions/component_mapper.py:59-94`

```python
def fuzzy_match_component(figma_name, codebase_components, threshold=0.6):
    """Fuzzy match Figma component name to codebase components."""
    base_name = figma_name.split('/')[0].strip()  # "Button/Primary" → "Button"

    for comp in codebase_components:
        similarity = calculate_similarity(base_name, comp['name'])
        if similarity >= threshold:
            matches.append({
                'confidence': round(similarity, 3),
                'match_type': 'fuzzy'
            })
```

---

## Identified Limitations

### 1. Two-Layer Architecture Overhead

**Issue**: Claude must manually orchestrate MCP calls, save to temp files, invoke Python, then process results.

**Impact**:
- 15-20 manual steps per design review
- Context consumed by intermediate data
- Error handling split between two layers

**Evidence**: `skills/product-design/SKILL.md:105-114`
```bash
# Prepare input (MCP or manual JSON)
# MCP: Already have /tmp/figma_metadata.json
# Manual: Create JSON from user input

python3 functions/design_analyzer.py \
  --figma-data /tmp/figma_combined.json \
  --ui-kit-inventory .agent/design-system/ui-kit-inventory.json \
  --output /tmp/analysis_results.json
```

### 2. No Direct MCP Access from Python

**Issue**: Python functions cannot call MCP tools directly. They rely on Claude to fetch data first.

**Impact**:
- Cannot do progressive refinement (e.g., "fetch more detail for component X")
- All MCP data must be fetched upfront (token wasteful)
- No dynamic adjustment based on analysis results

**Evidence**: `design_analyzer.py:28-50` expects pre-fetched metadata, cannot request additional node details.

### 3. Token Limit Risk with `get_design_context`

**Issue**: Selecting entire screens in Figma causes 350k+ token responses.

**Current Mitigation**: `skills/product-design/SKILL.md:66-71`
```markdown
Token Limit Protection:
- NEVER select entire screens - component-by-component only
- If `get_design_context` exceeds 100k tokens, use metadata-only
- Set MAX_MCP_OUTPUT_TOKENS=100000
```

**Impact**: Manual vigilance required; no automatic fallback if user selects too much.

### 4. No Test Data / Examples

**Issue**: No JSON files with real MCP responses for testing/validation.

**Impact**:
- Cannot verify Python functions handle actual MCP format correctly
- Difficult to debug when MCP returns unexpected structure
- No regression tests for format changes

**Evidence**: Task agent search found zero example JSON files matching MCP response structure.

### 5. Manual Workflow Fallback Inefficient

**Issue**: When MCP unavailable, skill asks user 15+ questions manually (`SKILL.md:77-101`).

**Impact**:
- Design review takes 30-45 minutes instead of 5 minutes
- User must manually extract tokens/components from Figma
- High error rate (typos, missed values)

---

## Improvement Recommendations

### 🏆 NEW RECOMMENDATION: Direct Python MCP Client (Validated)

**Status**: ✅ Tested and working

**Implementation**:

```python
# skills/product-design/functions/figma_mcp_client.py
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

class FigmaMCPClient:
    """Direct Python client for Figma Desktop MCP server."""

    def __init__(self, mcp_url="http://127.0.0.1:3845/mcp"):
        self.mcp_url = mcp_url
        self.session = None

    async def __aenter__(self):
        """Async context manager entry."""
        self.transport = streamablehttp_client(self.mcp_url)
        self.read_stream, self.write_stream, _ = await self.transport.__aenter__()

        self.session_context = ClientSession(self.read_stream, self.write_stream)
        self.session = await self.session_context.__aenter__()
        await self.session.initialize()

        return self

    async def __aexit__(self, *args):
        """Async context manager exit."""
        await self.session_context.__aexit__(*args)
        await self.transport.__aexit__(*args)

    async def get_metadata(self, node_id=None):
        """Get node metadata in XML format."""
        params = {"nodeId": node_id} if node_id else {}
        return await self.session.call_tool("get_metadata", params)

    async def get_variable_defs(self, node_id=None):
        """Get design token variable definitions."""
        params = {"nodeId": node_id} if node_id else {}
        return await self.session.call_tool("get_variable_defs", params)

    async def get_code_connect_map(self, node_id=None):
        """Get component → code mappings."""
        params = {"nodeId": node_id} if node_id else {}
        return await self.session.call_tool("get_code_connect_map", params)

    async def get_design_context(self, node_id=None):
        """Get UI code for a component."""
        params = {"nodeId": node_id} if node_id else {}
        return await self.session.call_tool("get_design_context", params)

# Usage in design_analyzer.py
async def analyze_design(figma_url: str):
    async with FigmaMCPClient() as client:
        # Progressive refinement - fetch only what's needed
        metadata = await client.get_metadata()
        components = extract_components(metadata)

        for comp in components:
            if comp['complexity'] == 'high':
                comp['detail'] = await client.get_design_context(comp['id'])

        variables = await client.get_variable_defs()
        return analyze(components, variables)
```

**Benefits**:
- ✅ Zero orchestration overhead (1 Python call)
- ✅ Progressive refinement (fetch on demand)
- ✅ No Claude dependency (fully autonomous)
- ✅ Official SDK (maintained by Anthropic)
- ✅ Simple async/await API

**Time Savings**: 15-20 steps → 1 step (95% reduction)

---

### Priority 1: Callback-Based MCP Bridge (Revised)

**Problem**: Two-layer architecture creates orchestration overhead.

**Initial Idea**: Python calls MCP directly.

**Authentication Challenge**: Python cannot access Claude Code's MCP session/auth.

**Revised Solution**: Callback pattern - Python requests data, Claude fetches via MCP.

```
┌────────────────────────────────────────────────────────────────┐
│ Proposed Architecture (Callback Pattern)                       │
└────────────────────────────────────────────────────────────────┘

User Request: "Review Figma design"
    │
    ▼
┌──────────────────────────────────────────┐
│ Claude Code                              │
│ - Invoke Python with callback handle    │
└──────────────────────────────────────────┘
    │
    │ (1) python design_analyzer.py --figma-url URL --callback-mode
    ▼
┌──────────────────────────────────────────┐
│ Python (Coordinator)                     │
│ - Determines what data needed            │
│ - Requests via callback                  │
└──────────────────────────────────────────┘
    │
    │ (2) Request: "fetch metadata for file_key=ABC"
    ▼
┌──────────────────────────────────────────┐
│ Claude Code (MCP Gateway)                │
│ - Receives request from Python          │
│ - Calls Figma MCP (has auth)            │
└──────────────────────────────────────────┘
    │
    │ (3) MCP call
    ▼
┌──────────────────────────────────────────┐
│ Figma MCP Server                         │
│ Auth: Figma Desktop session              │
└──────────────────────────────────────────┘
    │
    │ (4) Return data
    ▼
┌──────────────────────────────────────────┐
│ Claude Code                              │
│ - Return to Python via stdout/file       │
└──────────────────────────────────────────┘
    │
    │ (5) Receive data
    ▼
┌──────────────────────────────────────────┐
│ Python                                   │
│ - Process data                           │
│ - Determine if more data needed          │
│ - Loop or return final result            │
└──────────────────────────────────────────┘
    │
    ▼
Final result → Claude → User
```

**Implementation**: Python script with `--callback-mode` flag:

```python
# Proposed: design_analyzer.py v2.0 (callback pattern)
import sys
import json

class MCPCallback:
    """Request MCP data via Claude Code callback."""

    def __init__(self, callback_mode: bool):
        self.callback_mode = callback_mode

    def fetch(self, tool: str, params: dict) -> dict:
        """Request data from Claude via callback."""
        if self.callback_mode:
            # Output request to stdout in special format
            request = {
                "mcp_request": tool,
                "params": params,
                "request_id": generate_id()
            }
            print(f"__MCP_REQUEST__{json.dumps(request)}", file=sys.stderr)

            # Wait for Claude to provide response
            response_file = f"/tmp/mcp_response_{request['request_id']}.json"
            while not os.path.exists(response_file):
                time.sleep(0.1)

            with open(response_file) as f:
                return json.load(f)
        else:
            # Fallback: read from pre-saved file
            return read_from_file(params['file_path'])

def analyze_design(figma_url: str, callback: MCPCallback):
    # Request metadata (low tokens)
    metadata = callback.fetch("get_metadata", {
        "file_key": extract_file_key(figma_url)
    })

    # Analyze what we need
    components = extract_components(metadata)

    # Progressive refinement - only fetch if needed
    for comp in components:
        if comp['complexity'] == 'high':
            comp['detail'] = callback.fetch("get_design_context", {
                "file_key": extract_file_key(figma_url),
                "node_ids": [comp['id']]
            })

    return analyze(components)
```

**Benefits**:
- Python coordinates data fetching (progressive refinement)
- Claude handles auth/MCP calls (no auth bypass)
- Single Python invocation (no manual orchestration)

**Drawback**: More complex protocol (request/response via files/pipes)

### Priority 2: Alternative - Claude Orchestrator Script

**Problem**: Callback pattern is complex.

**Simpler Solution**: Move orchestration logic from ad-hoc to structured script.

```
┌────────────────────────────────────────────────────────────────┐
│ Alternative: Claude Orchestrator Pattern                       │
└────────────────────────────────────────────────────────────────┘

User Request: "Review Figma design"
    │
    ▼
┌──────────────────────────────────────────┐
│ Claude Code                              │
│ - Load orchestrator logic                │
│ - Read orchestration plan from Python    │
└──────────────────────────────────────────┘
    │
    │ (1) python get_orchestration_plan.py --figma-url URL
    ▼
┌──────────────────────────────────────────┐
│ Python Planner                           │
│ Returns execution plan:                  │
│ [                                        │
│   {"tool": "get_metadata", "params": {}},│
│   {"analyze": "metadata"},               │
│   {"tool": "get_variable_defs"},         │
│   {"process": "tokens"}                  │
│ ]                                        │
└──────────────────────────────────────────┘
    │
    ▼
┌──────────────────────────────────────────┐
│ Claude Code (Executes Plan)              │
│ For each step:                           │
│   - If "tool": call MCP, save result     │
│   - If "analyze"/"process": call Python  │
└──────────────────────────────────────────┘

Benefits:
- No callback complexity
- Python defines WHAT to fetch
- Claude handles HOW (auth)
- Progressive refinement possible
```

**Implementation**:

```python
# skills/product-design/functions/orchestration_planner.py
def plan_design_review(figma_url: str) -> List[Dict]:
    """Generate execution plan for Claude to follow."""
    file_key = extract_file_key(figma_url)

    return [
        # Step 1: Fetch metadata (low cost)
        {
            "step": 1,
            "action": "mcp_call",
            "tool": "get_metadata",
            "params": {"file_key": file_key},
            "save_to": "/tmp/metadata.json"
        },
        # Step 2: Analyze metadata to determine what else needed
        {
            "step": 2,
            "action": "python_call",
            "script": "analyze_metadata.py",
            "input": "/tmp/metadata.json",
            "output": "/tmp/component_needs.json"
        },
        # Step 3: Conditional - fetch details only if needed
        {
            "step": 3,
            "action": "mcp_call_conditional",
            "condition": "component_needs.json has high_complexity_components",
            "tool": "get_design_context",
            "params": {"file_key": file_key, "node_ids": "from_component_needs"},
            "save_to": "/tmp/design_context.json"
        },
        # Step 4: Fetch tokens
        {
            "step": 4,
            "action": "mcp_call",
            "tool": "get_variable_defs",
            "params": {"file_key": file_key},
            "save_to": "/tmp/variables.json"
        },
        # Step 5: Final processing
        {
            "step": 5,
            "action": "python_call",
            "script": "generate_review.py",
            "input": ["/tmp/metadata.json", "/tmp/variables.json"],
            "output": ".agent/design-system/reviews/review.md"
        }
    ]
```

**Usage**:
```bash
# Claude executes:
plan = subprocess.run(["python", "orchestration_planner.py", "--figma-url", url])
for step in plan:
    if step['action'] == 'mcp_call':
        result = call_mcp_tool(step['tool'], step['params'])
        save(result, step['save_to'])
    elif step['action'] == 'python_call':
        subprocess.run(["python", step['script'], "--input", step['input']])
```

**Benefits**:
- Simpler than callback (no complex protocol)
- Python still coordinates logic
- Claude handles auth automatically
- Supports conditional execution

### Priority 3: Streaming MCP Responses

**Problem**: Large `get_design_context` responses exceed token limits.

**Solution**: Add chunking/pagination to MCP tool calls.

```python
# Proposed: Chunked component extraction
def get_components_chunked(file_key: str, chunk_size: int = 5):
    metadata = get_metadata(file_key)
    component_ids = extract_component_ids(metadata)

    for chunk in batch(component_ids, chunk_size):
        yield get_design_context(file_key, node_ids=chunk)
```

**Benefits**:
- Never exceed token limits (process in batches)
- Early results (start processing before all data fetched)
- Resilient (partial failure doesn't lose everything)

### Priority 3: Test Fixtures with Real MCP Data

**Problem**: No validation that Python functions handle actual MCP formats.

**Solution**: Capture real MCP responses as test fixtures.

```bash
# Proposed: Fixture generation
.agent/design-system/test-fixtures/
├── figma_metadata_sample.json       # Real get_metadata response
├── figma_variables_sample.json      # Real get_variable_defs response
├── figma_code_connect_sample.json   # Real get_code_connect_map response
└── README.md                        # How to regenerate fixtures
```

**Benefits**:
- Regression tests for format changes
- Validation before production use
- Better error messages (show expected vs actual)

**Implementation Steps**:
1. Run actual Figma MCP calls in test project
2. Capture responses using `claude mcp test figma-desktop`
3. Sanitize sensitive data (file keys, user info)
4. Save as fixtures with schema validation

### Priority 4: Automatic Token Limit Protection

**Problem**: User must manually avoid selecting entire screens.

**Solution**: Add automatic fallback in Python functions.

```python
# Proposed: Auto-fallback logic
def safe_get_design_context(file_key, node_ids, max_tokens=100000):
    try:
        response = get_design_context(file_key, node_ids)
        if estimate_tokens(response) > max_tokens:
            # Fallback: Use metadata only
            return get_metadata_for_nodes(file_key, node_ids)
        return response
    except TokenLimitError:
        # Automatic graceful degradation
        return get_metadata_for_nodes(file_key, node_ids)
```

**Benefits**:
- No user training required (just works)
- Graceful degradation (metadata still useful)
- Prevents context window overflows

**Token Estimation Heuristic**:
```python
def estimate_tokens(json_data):
    """Rough estimate: 1 token ≈ 4 characters for JSON"""
    return len(json.dumps(json_data)) // 4
```

### Priority 5: Enhanced Manual Workflow

**Problem**: Manual fallback requires 15+ user inputs.

**Solution**: Provide structured JSON template for copy/paste.

**Current**: `SKILL.md:77-101` asks 15+ questions sequentially.

**Proposed**: Single JSON template
```markdown
**Manual Workflow (No MCP)**:

Copy this template, fill in Figma values, paste back:

```json
{
  "feature_name": "Dashboard Redesign",
  "figma_url": "https://figma.com/file/...",
  "tokens": {
    "colors": [
      {"name": "primary-600", "value": "#2563EB"}
    ],
    "spacing": [
      {"name": "spacing-lg", "value": "24px"}
    ]
  },
  "components": [
    {
      "name": "StatBadge",
      "type": "atom",
      "variants": ["success", "warning", "error"],
      "similar_to": "Badge"
    }
  ]
}
```
```

**Time Savings**: 30 minutes → 5 minutes (manual workflow)

---

## Revised Implementation Roadmap

### Phase 1: Python MCP Client Wrapper (2-3 hours) ⭐ RECOMMENDED

**Objective**: Implement direct Python → Figma MCP client.

**Tasks**:
1. Add `mcp` to requirements: `pip install mcp`
2. Create `figma_mcp_client.py` wrapper class
3. Add helper methods for each Figma MCP tool
4. Add error handling and retries
5. Add connection pooling for multiple requests

**Deliverables**:
- `skills/product-design/functions/figma_mcp_client.py`
- Unit tests with mocked MCP responses
- Integration test with live Figma Desktop

**Benefits**:
- Eliminates all orchestration overhead
- Progressive refinement built-in
- Fully autonomous execution

### Phase 2: Refactor Existing Functions (2-3 hours)

**Objective**: Update existing Python functions to use MCP client.

**Tasks**:
1. Refactor `design_analyzer.py` to use async MCP client
2. Refactor `token_extractor.py` to fetch variables directly
3. Refactor `component_mapper.py` to use code_connect_map
4. Update SKILL.md workflow to remove manual MCP calls
5. Test end-to-end design review flow

**Deliverables**:
- Updated Python functions (async)
- Updated SKILL.md documentation
- End-to-end test passing

### Phase 3: Validation & Fixtures (1-2 hours) (DEPRECATED - NOW OPTIONAL)

**Objective**: Establish test data with real MCP responses.

**Tasks**:
1. Run actual Figma MCP calls in test project
2. Capture responses to test fixtures
3. Validate Python functions against fixtures
4. Document MCP response format discrepancies

**Deliverables**:
- `.agent/design-system/test-fixtures/` directory
- Fixture files with real MCP data
- Validation script confirming Python compatibility

### Phase 2: Python MCP Client (3-4 hours)

**Objective**: Enable Python functions to call MCP tools directly.

**Tasks**:
1. Create `figma_mcp_client.py` wrapper
2. Refactor `design_analyzer.py` to call MCP directly
3. Add progressive refinement logic
4. Test with fixtures

**Deliverables**:
- `skills/product-design/functions/figma_mcp_client.py`
- Updated `design_analyzer.py` with direct MCP calls
- Progressive refinement examples

### Phase 3: Token Protection (2 hours)

**Objective**: Prevent token limit overflows automatically.

**Tasks**:
1. Add automatic fallback to metadata-only
2. Implement chunking for large designs
3. Add token estimation heuristics
4. Update skill documentation

**Deliverables**:
- `safe_get_design_context()` function
- Chunked processing logic
- Updated `SKILL.md` with auto-protection details

### Phase 4: Manual Workflow Enhancement (1 hour)

**Objective**: Streamline manual input when MCP unavailable.

**Tasks**:
1. Create JSON template
2. Update SKILL.md instructions
3. Add validation script for manual JSON

**Deliverables**:
- JSON template in `SKILL.md`
- Validation script: `validate_manual_input.py`

---

## Success Metrics

### Current State
- **Design Review Time**: 15-20 minutes (with MCP), 30-45 minutes (manual)
- **Orchestration Steps**: 15-20 manual steps
- **Token Efficiency**: 60-80% (waste on intermediate data)
- **Test Coverage**: 0% (no fixtures)

### Target State (After Improvements)
- **Design Review Time**: 5 minutes (with MCP), 10 minutes (manual)
- **Orchestration Steps**: 1 step (call Python once)
- **Token Efficiency**: 95% (progressive fetching)
- **Test Coverage**: 90% (with fixtures)

---

## Example Usage (Current vs Proposed)

### Current Flow (15-20 Steps)

```
User: "Review the dashboard redesign from Figma: https://figma.com/file/..."

Claude:
1. Call get_metadata → Save to /tmp/figma_metadata.json
2. Call get_variable_defs → Save to /tmp/figma_variables.json
3. Call get_code_connect_map → Save to /tmp/figma_code_connect.json
4. Combine JSON files → /tmp/figma_combined.json
5. Run design_analyzer.py --figma-data /tmp/figma_combined.json
6. Run token_extractor.py --figma-variables /tmp/figma_variables.json
7. Run component_mapper.py --figma-components /tmp/analysis.json
8. Run design_system_auditor.py --figma-data /tmp/combined.json
9. Run implementation_planner.py --analysis-results /tmp/audit.json
10. Read /tmp/task_document.md
11. Present summary to user
```

### Proposed Flow (1 Step)

```
User: "Review the dashboard redesign from Figma: https://figma.com/file/..."

Claude:
1. Run analyze_figma_design.py --url "https://figma.com/file/..." --progressive

Python (internally):
- Calls get_metadata (low tokens)
- Extracts component IDs
- Calls get_variable_defs
- Calls get_code_connect_map
- For each component:
  - If needs_detail: Call get_design_context (chunked)
  - Else: Use metadata only
- Processes all data
- Generates task document
- Returns summary

Claude: Present summary to user
```

**Time Savings**: 15-20 steps → 1 step (95% reduction)

---

## Technical Debt & Risk Assessment

### Technical Debt

**Medium Priority**:
- No test fixtures for MCP responses
- Manual orchestration overhead
- Split error handling (Claude + Python)

**Low Priority**:
- Suboptimal manual workflow (still functional)
- Token estimation heuristics (not critical)

### Risks

**High Risk**:
- MCP format changes breaking Python functions (no regression tests)
- Token limit overflows (manual mitigation only)

**Medium Risk**:
- Progressive refinement complexity (new logic paths)
- MCP client authentication/connection issues

**Low Risk**:
- Backward compatibility (existing workflow still works)
- Manual workflow still available as fallback

---

## Related Documentation

- **Skill Documentation**: `skills/product-design/SKILL.md`
- **Python Functions**: `skills/product-design/functions/*.py`
- **Example Output**: `skills/product-design/examples/dashboard-redesign-review.md`
- **Task Documentation**: `.agent/tasks/TASK-16-product-design-skill.md`

---

## Appendix: MCP Tool Reference

### Figma MCP Server Configuration

**Local Server** (Recommended):
- **URL**: `http://127.0.0.1:3845/mcp`
- **Tools**: All (metadata, variables, code_connect, design_context)
- **Requires**: Figma Desktop app running
- **Setup**: `claude mcp add --transport http figma-desktop http://127.0.0.1:3845/mcp`

**Remote Server** (Fallback):
- **URL**: `https://mcp.figma.com/mcp`
- **Tools**: Limited (no code_connect, requires explicit URLs)
- **Requires**: Internet connection, explicit Figma links

### Tool Call Examples

**get_metadata**:
```json
{
  "file_key": "ABC123",
  "node_ids": ["1:23", "1:24"]  // Optional, defaults to entire file
}
```

**get_variable_defs**:
```json
{
  "file_key": "ABC123"
}
```

**get_code_connect_map** (Enterprise only):
```json
{
  "file_key": "ABC123"
}
```

**get_design_context**:
```json
{
  "file_key": "ABC123",
  "node_ids": ["1:23"],
  "format": "react"  // or "vue", "html"
}
```

---

---

## Authentication Flow Explained

### Actual MCP Server Behavior (Tested)

**Test Results** (2025-10-22):

```bash
# Server is accessible locally
$ curl http://127.0.0.1:3845/mcp
HTTP/1.1 400 Bad Request
{"jsonrpc":"2.0","error":{"code":-32001,"message":"Invalid sessionId"},"id":null}

# Server running: ✅
# Port open: ✅
# Authentication required: ✅ (sessionId needed)
```

**Key Discovery**: The MCP server at port 3845 is accessible from any local process, but requires a `sessionId` in the JSON-RPC protocol.

### Why Python Cannot Call MCP Directly (Revised)

```
┌───────────────────────────────────────────────────────────┐
│ Authentication Chain (ACTUAL)                             │
└───────────────────────────────────────────────────────────┘

User logged into Figma Desktop
    │
    │ (Desktop app manages session)
    ▼
Figma Desktop exposes MCP server: http://127.0.0.1:3845/mcp
    │
    │ Port is OPEN to all local processes
    │ But requires sessionId in JSON-RPC protocol
    ▼
Claude Code connects via MCP protocol
    │
    │ Must send sessionId with each request
    │ sessionId obtained during MCP initialize handshake
    ▼
Python called by Claude Code
    │
    │ Python CAN technically access http://127.0.0.1:3845/mcp
    │ But does NOT have the sessionId from Claude's MCP session
    │ And MCP protocol requires proper initialize → request flow
    ▼
Python must either:
  [A] Request data through Claude (Claude has sessionId)
  [B] Implement full MCP client protocol (complex)
```

### MCP Protocol Requirements

Based on testing, the Figma MCP server requires:

1. **Proper JSON-RPC 2.0 format**
2. **Initialize handshake** to obtain sessionId
3. **SessionId in subsequent requests**
4. **Specific request body structure** (not documented publicly)

**What we don't know** (not in Figma docs):
- Exact initialize request format
- How sessionId is generated/validated
- Whether sessionId is per-connection or per-client
- If Python could maintain its own MCP session

### Auth Methods Comparison

| Approach | Auth Handling | Complexity | Progressive Fetch | Network Accessible |
|----------|--------------|------------|-------------------|-------------------|
| **Current** (manual orchestration) | Claude has sessionId, Python reads files | Low | No | N/A |
| **Priority 1** (callback pattern) | Claude proxies MCP for Python | High | Yes | No (uses Claude's session) |
| **Priority 2** (orchestration plan) | Claude executes plan from Python | Medium | Yes | No (uses Claude's session) |
| **Priority 3** (Python MCP client) | Python implements own MCP client | High | Yes | **Yes** (port 3845 open) |

### Recommended Options

#### Option A: Orchestration Plan Pattern (Lowest Risk)

**Why**:
- Claude retains MCP sessionId (uses existing connection)
- Python defines execution logic (progressive refinement)
- Medium complexity (declarative plan)
- No new auth infrastructure needed

**Auth Flow**:
1. User logged into Figma Desktop → Desktop manages session
2. Claude Code → MCP client (has sessionId)
3. Python → Returns execution plan (no auth needed)
4. Claude → Executes plan, calls MCP (using existing sessionId)
5. Python → Processes data from files (no auth needed)

#### Option B: Python MCP Client ✅ **VALIDATED - WORKS!**

**Test Results** (2025-10-22):

```bash
$ python3 test_figma_mcp_client.py

✅ Transport connection established
✅ ClientSession created
✅ Session initialized
   Server info: name='Figma Dev Mode MCP Server' version='1.0.0'
   Protocol version: 2025-06-18

✅ Found 6 tools:
   - get_design_context
   - get_variable_defs
   - get_code_connect_map
   - get_screenshot
   - get_metadata
   - create_design_system_rules

✅ SUCCESS: Python can connect to Figma MCP server!
```

**Proven capabilities**:
- ✅ Port 3845 accessible to Python processes
- ✅ Official MCP Python SDK (`pip install mcp`) works perfectly
- ✅ Python can maintain its own MCP session
- ✅ All 6 Figma tools available
- ✅ Fully autonomous (no Claude orchestration needed)

**Working code**:
```python
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async with streamablehttp_client("http://127.0.0.1:3845/mcp") as (
    read_stream, write_stream, _
):
    async with ClientSession(read_stream, write_stream) as session:
        await session.initialize()
        tools = await session.list_tools()
        # Use tools directly!
```

**No unknowns** - everything works out of the box with official SDK!

---

**Report Generated**: 2025-10-22
**Analysis Duration**: ~1 hour
**Files Analyzed**: 15+ files across skills/product-design
**Next Review**: After Phase 1 implementation (fixtures)

**Authentication Note**: All proposed solutions maintain existing auth model (Figma Desktop session → Claude Code MCP client). Python never directly authenticates to Figma.

