Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| π¨ Figma MCP Server - Hosted on Hugging Face Spaces | |
| MCP Server to control Figma via Claude/Cursor with real REST API | |
| """ | |
| import gradio as gr | |
| import asyncio | |
| import json | |
| import logging | |
| from PIL import Image | |
| import base64 | |
| import io | |
| # Configuration du logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # Import all MCP tools from the tools folder | |
| # Gradio will automatically detect all functions with docstrings/type hints | |
| try: | |
| from tools import * | |
| logger.info( "β All MCP tools successfully imported" ) | |
| except Exception as e: | |
| logger.error( f"β Error importing MCP tools: {e} " ) | |
| raise | |
| # === GRADIO APPLICATION CONFIGURATION === | |
| def setup_demo(): | |
| "Configure the Gradio interface for the MCP server" | |
| with gr.Blocks( | |
| title="π¨ Figma MCP Server", | |
| theme=gr.themes.Soft(), | |
| ) as demo: | |
| gr.Markdown(""" | |
| # π¨ Figma MCP Server | |
| **MCP Server to control Figma via Claude/Cursor with REST API** | |
| ## π **Instructions de configuration :** | |
| ### 1. **Get a Figma token:** | |
| - Aller sur [Figma Settings > Personal Access Tokens](https://www.figma.com/settings) | |
| - Create a new token | |
| - Copy the token (starts with `figd_` or `figc_`) | |
| ### 2. **Getting the ID of a file:** | |
| - Open your Figma file | |
| - Copy the ID from the URL: `https://www.figma.com/file/FILE_ID/file-name` | |
| ### 3. **Configure:** | |
| ```json | |
| { | |
| "mcpServers": { | |
| "figure": { | |
| "command": "sse", | |
| "args": ["https://underground-digital-middle-fig.hf.space/gradio_api/mcp/sse"] | |
| } | |
| } | |
| } | |
| ``` | |
| """) | |
| # Test interface (optional) | |
| with gr.Tab("π§ͺ Test"): | |
| with gr.Row(): | |
| token_input = gr.Textbox( | |
| placeholder="figd_...", | |
| label="Token Figma", | |
| type="password" | |
| ) | |
| token_btn = gr.Button("Configurer Token") | |
| with gr.Row(): | |
| file_input = gr.Textbox( | |
| placeholder= "file ID" , | |
| label= "Figma file ID" | |
| ) | |
| file_btn = gr.Button( "Configure File" ) | |
| status_output = gr.Textbox(label="Status", lines=3) | |
| # Test actions | |
| with gr.Row(): | |
| test_info_btn = gr.Button("π Info Fichier") | |
| test_comments_btn = gr.Button( "π Comments" ) | |
| test_user_btn = gr.Button( "π€ User Info" ) | |
| # New buttons for detailed user info | |
| with gr.Row(): | |
| test_user_detailed_btn = gr.Button( "π€ Detailed Profile" ) | |
| test_teams_btn = gr.Button( "π’ My Teams" ) | |
| test_permissions_btn = gr.Button("π Permissions") | |
| with gr.Row(): | |
| test_stats_btn = gr.Button("π Stats Workspace") | |
| with gr.Row(): | |
| test_limitations_btn = gr.Button("π Limitations API") | |
| # Event Connections | |
| token_btn.click( | |
| configure_figma_token, | |
| inputs=[token_input], | |
| outputs=[status_output] | |
| ) | |
| file_btn.click( | |
| configure_figma_file_id, | |
| inputs=[file_input], | |
| outputs=[status_output] | |
| ) | |
| test_info_btn.click( | |
| get_figma_file_info, | |
| outputs=[status_output] | |
| ) | |
| test_comments_btn.click( | |
| get_figma_comments, | |
| outputs=[status_output] | |
| ) | |
| test_user_btn.click( | |
| get_figma_user_info, | |
| outputs=[status_output] | |
| ) | |
| test_user_detailed_btn.click( | |
| get_figma_user_detailed_info, | |
| outputs=[status_output] | |
| ) | |
| test_teams_btn.click( | |
| list_figma_user_teams, | |
| outputs=[status_output] | |
| ) | |
| test_permissions_btn.click( | |
| get_figma_current_user_permissions, | |
| outputs=[status_output] | |
| ) | |
| test_stats_btn.click( | |
| get_figma_workspace_usage_stats, | |
| outputs=[status_output] | |
| ) | |
| test_limitations_btn.click( | |
| get_figma_api_limitations_info, | |
| outputs=[status_output] | |
| ) | |
| gr.Markdown(""" | |
| --- | |
| ### π οΈ **Available MCP tools (auto-detection):** | |
| **π Configuration :** | |
| - `configure_figma_token(token)` - Configure le token d'accès | |
| - `configure_figma_file_id(file_id)` - Configure l'ID du fichier | |
| **π Navigation :** | |
| - `get_figma_file_info()` - Gets file info | |
| - `get_figma_comments()` - Retrieves comments | |
| - `get_figma_user_info()` - Logged in user info | |
| **π€ User account and team:** | |
| - `get_figma_user_detailed_info()` - Detailed user information (full profile) | |
| - `list_figma_user_teams()` - Lists all user's teams with roles and plans | |
| - `get_figma_team_info(team_id)` - Detailed team info (plan, limits, storage) | |
| - `get_figma_current_user_permissions()` - Permissions in the current file (via Plugin API) | |
| - `get_figma_workspace_usage_stats()` - Workspace usage statistics | |
| - `list_figma_team_projects(team_id)` - Projects of a team | |
| - `get_figma_api_limitations_info()` - Explique les limitations API Plugin vs REST | |
| **π¨ Creation of basic elements (Figma Design):** | |
| - `create_figma_rectangle(x, y, width, height, name, color)` - CrΓ©e un rectangle | |
| - `create_figma_frame(x, y, width, height, name)` - CrΓ©e un frame | |
| - `create_figma_text(x, y, text, name, font_size)` - Creates a text | |
| **π‘ FigJam - Basic Elements:** | |
| - `create_figjam_sticky_note(x, y, text, width, height)` - Post-it (dΓ©faut: 240Γ240px) | |
| - `create_figjam_connector_between_elements(element1_name, element2_name, style)` - Connector between elements | |
| - `create_figjam_shape_with_text(x, y, shape_type, text, width, height)` - Shape with text (default: 208Γ208px) | |
| - `create_figjam_table(rows, columns, x, y)` - Tableau interactif | |
| - `create_figjam_code_block(x, y, code, language)` - Code block with syntax highlighting | |
| **π FigJam - Zones and organization:** | |
| - `create_figjam_background_shape(x, y, width, height, color, title, corner_radius)` - Zone de fond rectangulaire | |
| - `create_figjam_organized_zone(title, x, y, width, height, max_stickies)` - Zone avec grille de post-its | |
| - `create_figjam_workshop_template(template_type, x, y)` - Templates d'atelier complets | |
| **π FigJam - Stickers and reactions:** | |
| - `create_figjam_sticker(x, y, sticker_type, size)` - Stickers/emoji for reactions | |
| **π― Available types:** | |
| - **Formes:** rectangle, circle, triangle, diamond, star, hexagon | |
| - **Stickers:** thumbs_up, thumbs_down, heart, star, fire, rocket, bulb, warning, check, cross, question, idea, clock, money, target, celebrate, thinking, confused | |
| - **Templates:** retrospective, brainstorm, user_journey | |
| **π‘ Recommended workflow:** | |
| 1. Create a background area with `create_figjam_background_shape()` | |
| 2. Add sticky notes with `create_figjam_sticky_note()` | |
| 3. Connect the elements with `create_figjam_connector_between_elements()` | |
| 4. Add stickers for reactions with `create_figjam_sticker()` | |
| **β¨ All functions generate JavaScript code ready to use in a Figma plugin!** | |
| --- | |
| ## π **Documentation Gradio MCP** | |
| Selon la [documentation officielle](https://www.gradio.app/guides/building-mcp-server-with-gradio) : | |
| - Gradio **automatically** detects all functions with docstrings and type hints | |
| - Just set `mcp_server=True` in `.launch()` | |
| - No need for manual exposure of tools | |
| """) | |
| return demo | |
| # === LAUNCHING THE APPLICATION === | |
| if __name__ == "__main__": | |
| try: | |
| demo = setup_demo() | |
| logger.info( "π Starting MCP Figma server..." ) | |
| # Configuration for Hugging Face Spaces with MCP | |
| # Gradio will automatically detect all imported functions | |
| demo.launch( | |
| mcp_server= True , # π Enables MCP server with auto-detection! | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| show_error=True | |
| ) | |
| except Exception as e: | |
| logger.error( f"β Error launching: {e} " ) | |
| raise | |