はじめに
第3章では、Figmaのデザインデータを活用してUI分析エージェントを構築し、色のコントラストやフォントサイズの整合性を評価しました。これにより、AIがUIの品質を自動チェックし、改善提案を生成できるようになりました。今回は、Figmaのバージョン管理機能を強化するバージョン管理AIを構築します。このAIは、デザインの変更履歴を追跡し、変更点をリアルタイムで捕捉してコメントとして記録します。
この第4章では、FigmaのWebhook機能とMCPサーバーを統合し、ファイルの更新(例:新しいバージョンやノード変更)をリアルタイムで検知します。AIはこれを利用して、変更の概要をコメントしたり、重要な変更をチームに通知したりできます。コード例とステップごとのガイドで、バージョン管理AIの構築を体験しましょう。さあ、始めましょう!
バージョン管理AIとは?
バージョン管理AIは、Figmaファイルの変更履歴を監視し、デザインの進化を効率的に管理するエージェントです。MCPサーバーとFigmaのWebhookを組み合わせることで、以下のような機能を実現できます:
- 変更検知:新しいバージョンやノードの変更をリアルタイムで捕捉。
- コメント生成:変更内容を要約し、Figmaにコメントとして投稿。
- 通知:重要な変更をチームに通知(例:Slackやメール)。
ユースケース
- デザイン管理:変更履歴を自動記録し、デザインレビューの効率を向上。
- チームコラボレーション:リモートチームに変更点を即座に共有。
- 品質管理:意図しない変更(例:ブランドカラーからの逸脱)を検出。
開発環境の準備
第3章の環境を基に、以下の追加準備を行います:
- Python 3.8以降、mcpライブラリ、requestsライブラリ、Claude Desktop:これまでと同じ。
- webcolorsライブラリ:第3章から再利用。
- ngrok:ローカルサーバーを公開し、Webhookを受信。
- Figmaファイル:バージョン管理用のテストデータ。
インストールコマンド(必要に応じて):
pip install webcolors
Figmaのセットアップ
-
テストファイルの準備:
- 第3章のFigmaファイル(例:
MCP-Design
)を使用。 - 新しいバージョンを作成:Figmaの「Version History」パネルで「Save as new version」をクリックし、名前を付ける(例:
v1.1
)。 - ノードを変更(例:ボタンの色を
#007BFF
から#FF5733
に変更)。
- 第3章のFigmaファイル(例:
-
Webhookの設定:
- Figmaの「Team Settings」でWebhookを作成(有料プランが必要)。
- イベント:
FILE_VERSION_UPDATE
を選択。 - Webhook URL:後でngrokから取得(例:
https://abc123.ngrok.io
)。 - Webhook Secretを記録(セキュリティ用)。
-
ngrokの設定:
- ngrokをインストール(
brew install ngrok
または公式サイト)。 - ローカルサーバーを公開:
ngrok http 8108
- 生成されたURLをFigmaのWebhook設定に登録。
- ngrokをインストール(
-
環境変数:
第3章の.env
ファイルに以下を追加:FIGMA_TOKEN=your_figma_token FIGMA_FILE_ID=your_file_id FIGMA_WEBHOOK_SECRET=your_webhook_secret
コード例:バージョン管理用MCPサーバー
以下のMCPサーバーは、FigmaのWebhookを介してバージョン更新を捕捉し、変更内容を分析してコメントとして投稿します。
from mcp import MCPServer
import os
from dotenv import load_dotenv
import requests
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
import hmac
import hashlib
import threading
class FigmaVersionServer(MCPServer):
def __init__(self, host, port, figma_token, file_id, webhook_secret):
super().__init__(host, port)
self.figma_token = figma_token
self.file_id = file_id
self.webhook_secret = webhook_secret
self.headers = {"X-Figma-Token": figma_token}
self.latest_version = None
self.register_resource("get_latest_version", self.get_latest_version)
self.register_tool("add_comment", self.add_comment)
self.start_webhook_server()
def get_latest_version(self, params):
try:
if self.latest_version:
version_id = self.latest_version["version_id"]
url = f"https://api.figma.com/v1/files/{self.file_id}/versions/{version_id}"
response = requests.get(url, headers=self.headers)
response.raise_for_status()
data = response.json()
version_info = {
"version_id": data["id"],
"description": data.get("description", ""),
"created_at": data["created_at"],
"user": data["user"]["handle"]
}
return {"status": "success", "version_info": version_info}
return {"status": "success", "version_info": None, "message": "バージョン更新なし"}
except Exception as e:
return {"status": "error", "message": str(e)}
def add_comment(self, params):
try:
message = params.get("message", "")
node_id = params.get("node_id", "")
if not message:
return {"status": "error", "message": "コメントが必要です"}
url = f"https://api.figma.com/v1/files/{self.file_id}/comments"
payload = {
"message": message,
"client_meta": {"node_id": node_id} if node_id else None
}
response = requests.post(url, headers=self.headers, json=payload)
response.raise_for_status()
comment = response.json()
return {"status": "success", "comment_id": comment["id"]}
except Exception as e:
return {"status": "error", "message": str(e)}
def start_webhook_server(self):
class WebhookHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers["Content-Length"])
post_data = self.rfile.read(content_length)
signature = self.headers.get("X-Figma-Signature", "")
expected_signature = hmac.new(
self.server.parent.webhook_secret.encode(),
post_data,
hashlib.sha256
).hexdigest()
if hmac.compare_digest(signature, expected_signature):
self.server.parent.latest_version = json.loads(post_data.decode("utf-8"))
self.send_response(200)
self.end_headers()
self.wfile.write(b"Webhook received")
else:
self.send_response(403)
self.end_headers()
self.wfile.write(b"Invalid signature")
server = HTTPServer(("localhost", 8109), WebhookHandler)
server.parent = self
threading.Thread(target=server.serve_forever, daemon=True).start()
print("Webhookサーバーを起動中: http://localhost:8109")
if __name__ == "__main__":
load_dotenv()
server = FigmaVersionServer(
host="localhost",
port=8108,
figma_token=os.getenv("FIGMA_TOKEN"),
file_id=os.getenv("FIGMA_FILE_ID"),
webhook_secret=os.getenv("FIGMA_WEBHOOK_SECRET")
)
print("FigmaバージョンMCPサーバーを起動中: http://localhost:8108")
server.start()
コードの説明
- get_latest_version:Webhookで捕捉した最新のバージョン更新情報を取得し、バージョンID、説明、作成日、ユーザーを返す。
- add_comment:第3章から再利用し、変更内容をコメントとして投稿。
- start_webhook_server:ローカルWebhookサーバーを起動し、Figmaからの更新を受信。
-
WebhookHandler:Webhookリクエストを処理。
X-Figma-Signature
で署名を検証し、正当性を確認。
前提条件
- Figmaファイルにバージョン履歴が存在。
- FigmaのWebhookが設定済みで、ngrok URLが正しく登録。
-
.env
ファイルに正しいFIGMA_TOKEN
、FIGMA_FILE_ID
、FIGMA_WEBHOOK_SECRET
が設定済み。
サーバーのテスト
サーバーが正しく動作するか確認します:
-
ngrok起動:
ngrok http 8109
ngrok URL(例:
https://abc123.ngrok.io
)をFigmaのWebhook設定に登録。 -
サーバー起動:
python figma_version_server.py
コンソールに「FigmaバージョンMCPサーバーを起動中: http://localhost:8108」と「Webhookサーバーを起動中: http://localhost:8109」が表示。
-
Webhookのテスト:
- FigmaのUIで新しいバージョンを保存(例:
v1.2
)。 - サーバーのコンソールにWebhook受信ログが表示。
- FigmaのUIで新しいバージョンを保存(例:
-
最新バージョン取得のテスト:
Pythonでリクエストを送信:import requests import json url = "http://localhost:8108" payload = { "jsonrpc": "2.0", "method": "get_latest_version", "params": {}, "id": 1 } response = requests.post(url, json=payload) print(json.dumps(response.json(), indent=2, ensure_ascii=False))
期待されるレスポンス:
{ "jsonrpc": "2.0", "result": { "status": "success", "version_info": { "version_id": "789", "description": "v1.2: ボタンの色を変更", "created_at": "2025-04-20T10:00:00Z", "user": "DesignerA" } }, "id": 1 }
-
コメント追加のテスト:
payload = { "jsonrpc": "2.0", "method": "add_comment", "params": { "message": "ボタンの色が変更されました(#FF5733)", "node_id": "1:2" }, "id": 2 } response = requests.post(url, json=payload) print(json.dumps(response.json(), indent=2, ensure_ascii=False))
Claude Desktopとの接続
サーバーをClaude Desktopに接続します:
-
設定ファイルの編集:
Claude Desktopの設定ファイル(例:claude_desktop_config.json
)に以下を追加:{ "mcp_servers": [ { "name": "FigmaVersionServer", "url": "http://localhost:8108", "auth": "none" } ] }
-
Claudeでテスト:
Claude Desktopを起動し、プロンプトを入力:最新のバージョン変更を教えてください。
レスポンス例:
最新のバージョン変更: - バージョン:v1.2 - 説明:ボタンの色を変更 - ユーザー:DesignerA - 日時:2025-04-20 10:00
別のプロンプト:
ボタンの色変更をコメントしてください。
レスポンス例:
ボタンに「ボタンの色が変更されました(#FF5733)」をコメントしました。
実装のコツと注意点
- Webhookの安定性:ngrokの無料枠ではセッションが切れる場合がある。本番環境では固定URL(例:AWS Lambda)を使用。
- レートリミティング:Figma APIの制限(通常30リクエスト/分)に注意。
- セキュリティ:Webhook署名を必ず検証し、不正アクセスを防止。
- テスト:テスト用ファイルを作成し、本番データに影響を与えない。
- 拡張性:大量のバージョンを処理する場合、キャッシュやキュー(例:Redis)を検討。
試してみよう:挑戦課題
以下の機能を追加して、エージェントを強化してみてください:
- 変更されたノードの詳細(例:色やサイズ)を分析し、コメントに含める。
- バージョン間の差分を可視化する機能(例:変更されたノードをリスト)。
- Webhookでキャプチャした変更をSlackに通知するツール。
まとめと次のステップ
この第4章では、FigmaのWebhookを活用してバージョン管理AIを構築しました。デザインの変更をリアルタイムで捕捉し、AIが変更内容をコメントや通知として記録できるようになりました。
次の第5章では、MCPサーバーの最適化とコミュニティへの貢献に焦点を当てます。サーバーのパフォーマンス向上、セキュリティ強化、そしてFigma用MCPサーバーをオープンソースとして共有する方法を学びます。コミュニティAIの未来に興味がある方は、ぜひお楽しみに!
役に立ったと思ったら、「いいね」や「ストック」をしていただけると嬉しいです!次の章でまたお会いしましょう!