Skip to main content
Glama
mikeysrecipes

BlenderMCP

execute_blender_code

Execute Python code directly in Blender to automate 3D modeling tasks, create scenes, and manipulate objects through code-driven commands.

Instructions

Execute arbitrary Python code in Blender. Make sure to do it step-by-step by breaking it into smaller chunks.

Parameters:

  • code: The Python code to execute

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
codeYes

Implementation Reference

  • The handler function for the 'execute_blender_code' tool. It sends the provided Python code to the Blender addon via socket connection for execution and returns the result or error message.
    @mcp.tool()
    def execute_blender_code(ctx: Context, code: str) -> str:
        """
        Execute arbitrary Python code in Blender. Make sure to do it step-by-step by breaking it into smaller chunks.
        
        Parameters:
        - code: The Python code to execute
        """
        try:
            # Get the global connection
            blender = get_blender_connection()
            result = blender.send_command("execute_code", {"code": code})
            return f"Code executed successfully: {result.get('result', '')}"
        except Exception as e:
            logger.error(f"Error executing code: {str(e)}")
            return f"Error executing code: {str(e)}"
  • The @mcp.tool() decorator registers the execute_blender_code function as an MCP tool.
    @mcp.tool()
  • The send_command method of BlenderConnection class, used by the handler to communicate the code to Blender.
    def send_command(self, command_type: str, params: Dict[str, Any] = None) -> Dict[str, Any]:
        """Send a command to Blender and return the response"""
        if not self.sock and not self.connect():
            raise ConnectionError("Not connected to Blender")
        
        command = {
            "type": command_type,
            "params": params or {}
        }
        
        try:
            # Log the command being sent
            logger.info(f"Sending command: {command_type} with params: {params}")
            
            # Send the command
            self.sock.sendall(json.dumps(command).encode('utf-8'))
            logger.info(f"Command sent, waiting for response...")
            
            # Set a timeout for receiving - use the same timeout as in receive_full_response
            self.sock.settimeout(15.0)  # Match the addon's timeout
            
            # Receive the response using the improved receive_full_response method
            response_data = self.receive_full_response(self.sock)
            logger.info(f"Received {len(response_data)} bytes of data")
            
            response = json.loads(response_data.decode('utf-8'))
            logger.info(f"Response parsed, status: {response.get('status', 'unknown')}")
            
            if response.get("status") == "error":
                logger.error(f"Blender error: {response.get('message')}")
                raise Exception(response.get("message", "Unknown error from Blender"))
            
            return response.get("result", {})
        except socket.timeout:
            logger.error("Socket timeout while waiting for response from Blender")
            # Don't try to reconnect here - let the get_blender_connection handle reconnection
            # Just invalidate the current socket so it will be recreated next time
            self.sock = None
            raise Exception("Timeout waiting for Blender response - try simplifying your request")
        except (ConnectionError, BrokenPipeError, ConnectionResetError) as e:
            logger.error(f"Socket connection error: {str(e)}")
            self.sock = None
            raise Exception(f"Connection to Blender lost: {str(e)}")
        except json.JSONDecodeError as e:
            logger.error(f"Invalid JSON response from Blender: {str(e)}")
            # Try to log what was received
            if 'response_data' in locals() and response_data:
                logger.error(f"Raw response (first 200 bytes): {response_data[:200]}")
            raise Exception(f"Invalid response from Blender: {str(e)}")
        except Exception as e:
            logger.error(f"Error communicating with Blender: {str(e)}")
            # Don't try to reconnect here - let the get_blender_connection handle reconnection
            self.sock = None
            raise Exception(f"Communication error with Blender: {str(e)}")
  • Helper function to get or create the persistent socket connection to Blender, called by the handler.
    def get_blender_connection():
        """Get or create a persistent Blender connection"""
        global _blender_connection, _polyhaven_enabled  # Add _polyhaven_enabled to globals
        
        # If we have an existing connection, check if it's still valid
        if _blender_connection is not None:
            try:
                # First check if PolyHaven is enabled by sending a ping command
                result = _blender_connection.send_command("get_polyhaven_status")
                # Store the PolyHaven status globally
                _polyhaven_enabled = result.get("enabled", False)
                return _blender_connection
            except Exception as e:
                # Connection is dead, close it and create a new one
                logger.warning(f"Existing connection is no longer valid: {str(e)}")
                try:
                    _blender_connection.disconnect()
                except:
                    pass
                _blender_connection = None
        
        # Create a new connection if needed
        if _blender_connection is None:
            _blender_connection = BlenderConnection(host="localhost", port=9876)
            if not _blender_connection.connect():
                logger.error("Failed to connect to Blender")
                _blender_connection = None
                raise Exception("Could not connect to Blender. Make sure the Blender addon is running.")
            logger.info("Created new persistent connection to Blender")
        
        return _blender_connection

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/mikeysrecipes/blender-mcp'

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