Skip to main content
Glama
theme_tools.py15.3 kB
""" Theme Tools for Remotion MCP Server Provides async MCP tools for managing and applying themes to video compositions. Consolidates all theme-related functionality in one place. """ import asyncio import json from typing import TYPE_CHECKING if TYPE_CHECKING: from chuk_virtual_fs import AsyncVirtualFileSystem from ..themes.theme_manager import ThemeManager def register_theme_tools(mcp, project_manager, vfs: "AsyncVirtualFileSystem"): """ Register all theme-related tools with the MCP server. Args: mcp: ChukMCPServer instance project_manager: ProjectManager instance for applying themes vfs: Virtual filesystem instance for file operations """ # Create a single theme manager instance with virtual filesystem theme_manager = ThemeManager(vfs) @mcp.tool async def remotion_list_themes() -> str: """ List all available video themes with descriptions. Returns a list of built-in YouTube-optimized themes including their characteristics, primary colors, and recommended use cases. Returns: JSON array of themes with metadata Example: themes = await remotion_list_themes() # Returns: tech, finance, education, lifestyle, gaming, minimal, business """ def _list(): theme_keys = theme_manager.list_themes() theme_list = [] for key in theme_keys: theme = theme_manager.get_theme(key) if theme: theme_list.append( { "key": key, "name": theme.name, "description": theme.description, "primary_color": theme.colors.primary[0] if theme.colors.primary else "N/A", "accent_color": theme.colors.accent[0] if theme.colors.accent else "N/A", "use_cases": theme.use_cases[:3], # First 3 use cases } ) return json.dumps({"themes": theme_list}, indent=2) return await asyncio.get_event_loop().run_in_executor(None, _list) @mcp.tool async def remotion_get_theme_info(theme_name: str) -> str: """ Get detailed information about a specific theme. Returns complete theme configuration including colors, typography, motion design, and usage recommendations. Args: theme_name: Theme identifier (e.g., "tech", "finance", "education") Returns: JSON object with complete theme information Example: info = await remotion_get_theme_info(theme_name="tech") # Returns tech theme with all design tokens """ def _get_info(): info = theme_manager.get_theme_info(theme_name) if not info: return json.dumps( { "error": f"Theme '{theme_name}' not found", "available_themes": theme_manager.list_themes(), } ) return json.dumps(info, indent=2) return await asyncio.get_event_loop().run_in_executor(None, _get_info) @mcp.tool async def remotion_search_themes(query: str) -> str: """ Search themes by name, description, or use case. Performs a case-insensitive search across theme metadata to help find suitable themes for specific content types. Args: query: Search term (e.g., "gaming", "professional", "education") Returns: JSON array of matching theme keys Example: results = await remotion_search_themes(query="professional") # Returns: ["business", "minimal", "finance"] """ def _search(): matches = theme_manager.search_themes(query) theme_details = [] for key in matches: theme = theme_manager.get_theme(key) if theme: theme_details.append( { "key": key, "name": theme.name, "description": theme.description, "use_cases": theme.use_cases, } ) return json.dumps({"query": query, "matches": theme_details}, indent=2) return await asyncio.get_event_loop().run_in_executor(None, _search) @mcp.tool async def remotion_compare_themes(theme1: str, theme2: str) -> str: """ Compare two themes side by side. Returns a comparison of colors, motion feel, and use cases to help choose between themes or understand their differences. Args: theme1: First theme identifier theme2: Second theme identifier Returns: JSON object with side-by-side comparison Example: comparison = await remotion_compare_themes(theme1="tech", theme2="gaming") # Shows differences in colors, motion, and use cases """ def _compare(): comparison = theme_manager.compare_themes(theme1, theme2) return json.dumps(comparison, indent=2) return await asyncio.get_event_loop().run_in_executor(None, _compare) @mcp.tool async def remotion_set_current_theme(theme_name: str) -> str: """ Set the active theme for the current session. Sets the default theme that will be used for new components and compositions. This doesn't affect existing compositions. Args: theme_name: Theme identifier to set as active Returns: JSON with success status Example: result = await remotion_set_current_theme(theme_name="gaming") # Sets gaming theme as default """ def _set(): success = theme_manager.set_current_theme(theme_name) if success: return json.dumps( { "status": "success", "current_theme": theme_name, "message": f"Current theme set to '{theme_name}'", } ) else: return json.dumps( { "status": "error", "message": f"Theme '{theme_name}' not found", "available_themes": theme_manager.list_themes(), } ) return await asyncio.get_event_loop().run_in_executor(None, _set) @mcp.tool async def remotion_get_current_theme() -> str: """ Get the currently active theme. Returns the theme key that's currently set as default for new compositions and components. Returns: JSON with current theme information Example: current = await remotion_get_current_theme() # Returns current theme key or null if none set """ def _get(): current = theme_manager.get_current_theme() if current: theme_info = theme_manager.get_theme_info(current) return json.dumps({"current_theme": current, "info": theme_info}, indent=2) else: return json.dumps({"current_theme": None, "message": "No theme currently set"}) return await asyncio.get_event_loop().run_in_executor(None, _get) @mcp.tool async def remotion_validate_theme(theme_data: str) -> str: """ Validate a theme data structure. Checks if a theme JSON has all required fields and proper structure. Useful before importing or creating custom themes. Args: theme_data: JSON string with theme data to validate Returns: JSON with validation results and any errors Example: result = await remotion_validate_theme(theme_data='{"name": "Custom", ...}') # Returns validation status and error list if invalid """ def _validate(): try: theme_dict = json.loads(theme_data) validation = theme_manager.validate_theme(theme_dict) return json.dumps(validation, indent=2) except json.JSONDecodeError as e: return json.dumps({"valid": False, "errors": [f"Invalid JSON: {str(e)}"]}) return await asyncio.get_event_loop().run_in_executor(None, _validate) @mcp.tool async def remotion_create_custom_theme( name: str, description: str, base_theme: str | None = None, primary_colors: str | None = None, accent_colors: str | None = None, ) -> str: """ Create a custom theme based on an existing theme. Creates a new theme by starting with an existing theme and applying custom color overrides. More advanced customization can be done by exporting, editing, and importing the theme JSON. Args: name: Custom theme name description: Theme description base_theme: Base theme to start from (default: "tech") primary_colors: JSON array of primary colors (optional) accent_colors: JSON array of accent colors (optional) Returns: JSON with created theme key and details Example: theme = await remotion_create_custom_theme( name="My Brand", description="Custom brand colors", base_theme="tech", primary_colors='["#FF0000", "#CC0000", "#990000"]', accent_colors='["#00FF00", "#00CC00", "#009900"]' ) """ def _create(): try: # Parse color overrides if provided color_overrides = {} if primary_colors: color_overrides["primary"] = json.loads(primary_colors) if accent_colors: color_overrides["accent"] = json.loads(accent_colors) result = theme_manager.create_custom_theme( name=name, description=description, base_theme=base_theme or "tech", color_overrides=color_overrides if color_overrides else None, ) # Check if result is an error message if result.startswith("Error"): return json.dumps({"error": result}) # Success - return theme info theme_info = theme_manager.get_theme_info(result) return json.dumps( {"status": "success", "theme_key": result, "theme": theme_info}, indent=2 ) except json.JSONDecodeError as e: return json.dumps({"error": f"Invalid color JSON: {str(e)}"}) except Exception as e: return json.dumps({"error": str(e)}) return await asyncio.get_event_loop().run_in_executor(None, _create) @mcp.tool async def remotion_export_theme(theme_name: str, file_path: str | None = None) -> str: """ Export a theme to a JSON file. Saves a theme to a JSON file that can be shared, version controlled, or edited externally. The file can later be imported. Args: theme_name: Theme identifier to export file_path: Output file path (default: theme_name_theme.json) Returns: JSON with export status and file path Example: result = await remotion_export_theme( theme_name="tech", file_path="my_tech_theme.json" ) """ result = await theme_manager.export_theme(theme_name, file_path) if result.startswith("Error"): return json.dumps({"error": result}) return json.dumps( { "status": "success", "file_path": result, "message": f"Theme '{theme_name}' exported successfully", }, indent=2, ) @mcp.tool async def remotion_import_theme(file_path: str, theme_key: str | None = None) -> str: """ Import a theme from a JSON file. Loads a theme from a JSON file and registers it for use. The theme will be available immediately for new compositions. Args: file_path: Path to theme JSON file theme_key: Optional key to register under (default: from file) Returns: JSON with import status and theme key Example: result = await remotion_import_theme( file_path="custom_theme.json", theme_key="my_custom" ) """ result = await theme_manager.import_theme(file_path, theme_key) if result.startswith("Error"): return json.dumps({"error": result}) return json.dumps({"status": "success", "message": result}, indent=2) @mcp.tool async def remotion_get_theme_for_content(content_type: str) -> str: """ Get recommended themes for a content type. Suggests suitable themes based on the type of content you're creating. Searches theme use cases and descriptions for matches. Args: content_type: Type of content (e.g., "tutorial", "vlog", "review") Returns: JSON with recommended themes Example: recommendations = await remotion_get_theme_for_content( content_type="gaming" ) # Returns gaming theme and possibly tech theme """ def _get(): matches = theme_manager.search_themes(content_type) if not matches: # If no direct matches, suggest popular themes return json.dumps( { "content_type": content_type, "recommendations": [], "message": "No specific matches found", "popular_themes": ["tech", "minimal", "business"], }, indent=2, ) recommendations = [] for key in matches: theme = theme_manager.get_theme(key) if theme: recommendations.append( { "key": key, "name": theme.name, "description": theme.description, "use_cases": theme.use_cases, } ) return json.dumps( {"content_type": content_type, "recommendations": recommendations}, indent=2 ) return await asyncio.get_event_loop().run_in_executor(None, _get)

Implementation Reference

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/chrishayuk/chuk-mcp-remotion'

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