Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
15 KiB
MCP Migration Implementation Guide
Phase-by-Phase Implementation Plan
Overview
This guide walks through converting DSS from REST-based to MCP-first architecture with persistent state management.
Timeline: 7-8 weeks Current Status: Architecture documented, components audited Next Step: Begin Phase 1 - MCP Tool Suite
Phase 1: Complete MCP Tool Suite (Weeks 1-3)
1.1 Expand MCP Server
File: tools/dss_mcp/server.py
Current Tools: 2 (ingest_figma_file, get_status)
Target Tools: 15+
# Project Management
- dss_create_project(name, root_path, description) → project_id
- dss_list_projects() → [projects]
- dss_get_project(project_id) → project
- dss_update_project(project_id, updates) → project
- dss_delete_project(project_id) → bool
# Figma Integration
- dss_setup_figma_credentials(api_token) → bool
- dss_discover_figma_files(project_id) → [files]
- dss_add_figma_file(project_id, file_key, name) → manifest
- dss_list_figma_files(project_id) → [files]
# Token Management
- dss_sync_tokens(project_id, output_format) → tokens
- dss_extract_tokens(figma_file_key) → tokens
- dss_validate_tokens(tokens) → report
- dss_detect_token_drift(project_id) → drift_report
# Component Analysis
- dss_discover_components(project_id, path) → components
- dss_analyze_components(project_id) → analysis
- dss_get_quick_wins(project_id, path) → [wins]
# Status & Info
- dss_get_project_status(project_id) → status
- dss_get_system_health() → health
1.2 Credential Management
Requirement: Encrypt sensitive data at rest
# In dss_mcp/security.py
class CredentialVault:
"""Manages encrypted credential storage"""
def encrypt_figma_token(token: str) -> str:
"""Encrypt token for storage"""
# Use cryptography library
# Store in database with salt
def decrypt_figma_token(encrypted: str) -> str:
"""Decrypt token for use"""
def rotate_encryption_key() -> bool:
"""Support key rotation"""
1.3 Operation Queuing
Requirement: Handle long-running operations asynchronously
# In dss_mcp/operations.py
class OperationQueue:
"""Manages async operations with status tracking"""
def enqueue(operation_type, args) -> operation_id
def get_status(operation_id) -> status
def get_result(operation_id) -> result
def cancel(operation_id) -> bool
1.4 Audit Logging
Requirement: Track all operations for compliance and debugging
# In dss_mcp/audit.py
class AuditLog:
"""Persistent operation history"""
def log_operation(
operation_type: str,
args: dict,
result: dict,
user_id: str,
timestamp: datetime
) -> log_id
def get_operation_history(project_id, limit=100) -> [logs]
def get_audit_trail(start_date, end_date) -> [logs]
1.5 Testing MCP Tools
# Test each tool independently
python -m pytest tools/dss_mcp/tests/test_project_tools.py
python -m pytest tools/dss_mcp/tests/test_figma_tools.py
python -m pytest tools/dss_mcp/tests/test_token_tools.py
# Integration tests
python -m pytest tools/dss_mcp/tests/test_workflows.py
# End-to-end tests with MCP server
python -m pytest tools/dss_mcp/tests/test_e2e.py
Phase 2: Persistence Layer (Week 4)
2.1 State Machine for Projects
Requirement: Track project state through workflow
# In tools/storage/state_machine.py
from enum import Enum
class ProjectState(Enum):
CREATED = "created"
FIGMA_CONFIGURED = "figma_configured"
TOKENS_EXTRACTED = "tokens_extracted"
COMPONENTS_ANALYZED = "components_analyzed"
READY = "ready"
class ProjectStateMachine:
"""Manages valid state transitions"""
def __init__(self, project_id):
self.project_id = project_id
self.state = self.load_state()
def transition(self, action: str) -> bool:
"""Validate and apply state transition"""
# Only allow valid transitions
# Log transition
# Update database
def can_transition(self, action: str) -> bool:
"""Check if action is valid for current state"""
2.2 Operation History
Requirement: Support undo/rollback
# In tools/storage/operation_history.py
class OperationHistory:
"""Tracks all state-changing operations"""
def record_operation(
project_id,
operation: Operation,
before_state: dict,
after_state: dict
) -> history_id
def get_operation(operation_id) -> Operation
def rollback(operation_id) -> bool
def get_timeline(project_id) -> [operations]
2.3 Concurrent Operation Handling
Requirement: Handle multiple operations safely
# In dss_mcp/concurrency.py
import asyncio
from threading import Lock
class OperationLock:
"""Prevents concurrent modifications to same resource"""
def acquire(project_id, resource_type) -> lock
def release(lock) -> bool
class OperationScheduler:
"""Queues operations and executes sequentially per resource"""
async def queue_operation(operation) -> operation_id
async def process_queue(project_id, resource_type)
Phase 3: JS UI Migration (Weeks 5-6)
3.1 Remove REST Calls
Before:
// In admin-ui/js/core/ai.js
async sendMessage(message) {
const response = await fetch('/api/claude/chat', {
method: 'POST',
body: JSON.stringify({ message })
});
const data = await response.json();
return data.response;
}
After:
// Delegate to Claude via MCP
async sendMessage(message) {
return {
action: 'mcp_tool_call',
tool: 'chat',
args: { message }
};
// Claude handles the REST call or MCP tool call
}
3.2 MCP Tool Invocation Layer
File: admin-ui/js/core/mcp-client.js
class MCPClient {
/**
* Calls an MCP tool and waits for result
*/
async callTool(toolName, args) {
const response = await fetch('/api/mcp/call', {
method: 'POST',
body: JSON.stringify({
tool: toolName,
args: args
})
});
if (!response.ok) {
throw new Error(`Tool ${toolName} failed`);
}
return await response.json();
}
async listTools() {
const response = await fetch('/api/mcp/tools');
return await response.json();
}
}
// Usage in components
const mcp = new MCPClient();
const project = await mcp.callTool('dss_create_project', {
name: 'web-ui',
root_path: './packages/design'
});
3.3 Update AI Chat Component
File: admin-ui/js/core/ai.js
// Replace REST calls with MCP
async handleSendCommand(command) {
const parsed = this.ai.parseCommand(command);
if (parsed) {
// Delegate to Claude with MCP tools
const result = await this.ai.sendMessage(command, {
enableTools: true // Use MCP tools
});
// Claude will call appropriate MCP tools
// and return formatted response
this.addMessage('assistant', result);
return;
}
// Regular chat
const response = await this.ai.sendMessage(command);
this.addMessage('assistant', response);
}
3.4 Update Component Data Binding
File: admin-ui/js/components/ds-project-card.js
class DsProjectCard extends HTMLElement {
async connectedCallback() {
const projectId = this.getAttribute('data-project-id');
// Fetch project data via MCP
const mcp = new MCPClient();
const project = await mcp.callTool(
'dss_get_project',
{ project_id: projectId }
);
this.render(project);
}
render(project) {
this.shadowRoot.innerHTML = `
<div class="project-card">
<h3>${project.name}</h3>
<p>${project.description}</p>
<span class="status ${project.state}">
${project.state}
</span>
</div>
`;
}
}
Phase 4: Testing & Documentation (Week 7)
4.1 Integration Tests
# tests/integration/test_mcp_workflows.py
import pytest
from dss_mcp.server import mcp_server
class TestProjectWorkflow:
"""End-to-end project creation workflow"""
async def test_create_project_full_workflow(self):
"""Test: Create → Configure Figma → Extract Tokens"""
# Step 1: Create project
project = await mcp_server.call_tool('dss_create_project', {
name: 'test-project',
root_path: '/tmp/test'
})
assert project['id']
# Step 2: Setup Figma
result = await mcp_server.call_tool('dss_setup_figma_credentials', {
api_token: TEST_FIGMA_TOKEN
})
assert result['configured']
# Step 3: Discover files
files = await mcp_server.call_tool('dss_discover_figma_files', {
project_id: project['id']
})
assert len(files) > 0
# Step 4: Sync tokens
tokens = await mcp_server.call_tool('dss_sync_tokens', {
project_id: project['id']
})
assert tokens['count'] > 0
4.2 API Documentation
File: docs/MCP_API_REFERENCE.md
# MCP Tools Reference
## dss_create_project
Creates a new design system project.
**Parameters:**
- `name` (string, required): Project name
- `root_path` (string, required): Root directory path
- `description` (string, optional): Project description
**Returns:**
```json
{
"id": "proj_12345",
"name": "web-ui",
"root_path": "/projects/web-ui",
"created_at": "2025-12-06T00:00:00Z",
"state": "created"
}
Errors:
ProjectAlreadyExists: Project with this name existsInvalidPath: Root path is invalidPermissionDenied: No permission to create project
---
## Architecture Workflows
### Workflow 1: Create Project with Figma
┌─────────────────┐ │ User Input: │ │ "Create web-ui │ │ project with │ │ Figma" │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ JavaScript │ │ Parse command │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Send to Claude │ │ with MCP tools │ └────────┬────────┘ │ ▼ ┌─────────────────────────────────────┐ │ Claude orchestrates: │ │ 1. Check Figma token configured │ │ 2. Create project (MCP tool) │ │ 3. Setup Figma (MCP tool) │ │ 4. Discover files (MCP tool) │ │ 5. Return summary │ └────────┬────────────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ Each MCP Tool: │ │ - Validates input │ │ - Updates database │ │ - Updates project state │ │ - Logs operation │ │ - Returns result │ └────────┬────────────────────────────┘ │ ▼ ┌─────────────────┐ │ Update UI │ │ with results │ └─────────────────┘
### Workflow 2: Sync Tokens from Figma
User: "Sync tokens from Figma" │ ▼ JavaScript → Claude │ ▼ Claude calls MCP tools sequentially:
-
dss_get_project(current_project_id) → Get current project
-
dss_list_figma_files(project_id) → Get linked Figma files
-
For each file: dss_sync_tokens(project_id, file_id) → Extract and sync tokens
-
dss_get_token_drift(project_id) → Check for inconsistencies │ ▼ Return results → Update UI → Show to user
---
## Key Configuration Files
### MCP Server Config
**File:** `tools/dss_mcp/config.py`
```python
MCP_CONFIG = {
'server_name': 'dss',
'version': '1.0.0',
'tools': [
'dss_create_project',
'dss_list_projects',
# ... all 15+ tools
],
'database': {
'type': 'sqlite',
'path': '.dss/dss.db'
},
'credentials': {
'encryption_key': os.environ.get('DSS_ENCRYPTION_KEY'),
'salt': os.environ.get('DSS_ENCRYPTION_SALT')
},
'logging': {
'level': 'INFO',
'file': '.dss/logs/dss.log'
}
}
REST Bridge (Temporary)
File: tools/api/mcp_bridge.py
from fastapi import APIRouter, HTTPException
from dss_mcp.server import mcp_server
router = APIRouter(prefix="/api/mcp")
@router.post("/call")
async def call_mcp_tool(request: ToolCallRequest):
"""
Bridge REST calls to MCP tools.
Temporary during migration.
Will be removed once all clients use MCP directly.
"""
try:
result = await mcp_server.call_tool(
request.tool,
request.args
)
return {'success': True, 'result': result}
except Exception as e:
logger.error(f"MCP tool error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/tools")
async def list_mcp_tools():
"""List all available MCP tools"""
return {'tools': mcp_server.get_tools()}
Rollout Strategy
Week 1-3: Backend Only
- Implement MCP tools
- Test tools thoroughly
- Deploy MCP server
- REST still primary
Week 4-5: Parallel Operation
- Update JavaScript to use MCP tools
- REST bridge for compatibility
- All new features use MCP only
- Gradual migration of old features
Week 6+: MCP Primary
- Most operations via MCP
- REST endpoints deprecated
- Documentation updated
- Monitoring in place
Monitoring & Metrics
Key Metrics to Track
# In dss_mcp/metrics.py
metrics = {
'tool_calls_total': Counter('MCP tool calls'),
'tool_call_duration': Histogram('Tool execution time'),
'tool_errors': Counter('Tool errors by type'),
'operation_queue_depth': Gauge('Operations waiting'),
'database_queries': Counter('Database operations'),
'credential_rotations': Counter('Encryption key rotations')
}
Troubleshooting Guide
Problem: "Tool not found"
Solution: Verify tool is registered in MCP server
Problem: "Credential encryption failed"
Solution: Check encryption key environment variable
Problem: "State transition invalid"
Solution: Project state doesn't allow this operation
Problem: "Operation timeout"
Solution: Long-running operation in queue, check logs