Skip to main content
Glama

editor_create_object

Create new actors or objects in Unreal Engine with specified class, name, transform, and properties to populate your scene.

Instructions

Create a new object/actor in the world

Example output: {'success': true, 'actor_name': 'StaticMeshActor_1', 'actor_label': 'MyCube', 'class': 'StaticMeshActor', 'location': {'x': 100.0, 'y': 200.0, 'z': 0.0}, 'rotation': {'pitch': 0.0, 'yaw': 45.0, 'roll': 0.0}, 'scale': {'x': 1.0, 'y': 1.0, 'z': 1.0}}

Returns created actor details with final transform values.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
object_classYesUnreal class name (e.g., 'StaticMeshActor', 'DirectionalLight')
object_nameYesName/label for the created object
locationNoWorld position coordinates
rotationNoRotation in degrees
scaleNoScale multipliers
propertiesNoAdditional actor properties. For StaticMeshActor: use 'StaticMesh' for mesh path, 'Material' for single material path, or 'Materials' for array of material paths. Example: {"StaticMesh": "/Game/Meshes/Cube", "Material": "/Game/Materials/M_Basic"}

Implementation Reference

  • MCP tool handler that generates Python code via editorTools.UECreateObject and executes it in the Unreal Editor using tryRunCommand, returning the result as text.
    async ({ object_class, object_name, location, rotation, scale, properties }) => {
    	const result = await tryRunCommand(
    		editorTools.UECreateObject(object_class, object_name, location, rotation, scale, properties),
    	)
    	return {
    		content: [
    			{
    				type: "text",
    				text: result,
    			},
    		],
    	}
    },
  • Zod schema defining the input parameters for the editor_create_object tool, including object class, name, optional transforms and properties.
    {
    	object_class: z.string().describe("Unreal class name (e.g., 'StaticMeshActor', 'DirectionalLight')"),
    	object_name: z.string().describe("Name/label for the created object"),
    	location: z
    		.object({
    			x: z.number().default(0),
    			y: z.number().default(0),
    			z: z.number().default(0),
    		})
    		.optional()
    		.describe("World position coordinates"),
    	rotation: z
    		.object({
    			pitch: z.number().default(0),
    			yaw: z.number().default(0),
    			roll: z.number().default(0),
    		})
    		.optional()
    		.describe("Rotation in degrees"),
    	scale: z
    		.object({
    			x: z.number().default(1),
    			y: z.number().default(1),
    			z: z.number().default(1),
    		})
    		.optional()
    		.describe("Scale multipliers"),
    	properties: z
    		.record(z.any())
    		.optional()
    		.describe(
    			'Additional actor properties. For StaticMeshActor: use \'StaticMesh\' for mesh path, \'Material\' for single material path, or \'Materials\' for array of material paths. Example: {"StaticMesh": "/Game/Meshes/Cube", "Material": "/Game/Materials/M_Basic"}',
    		),
    },
  • Registration of the editor_create_object tool on the McpServer instance, specifying name, description, input schema, and handler.
    server.tool(
    	"editor_create_object",
    	"Create a new object/actor in the world\n\nExample output: {'success': true, 'actor_name': 'StaticMeshActor_1', 'actor_label': 'MyCube', 'class': 'StaticMeshActor', 'location': {'x': 100.0, 'y': 200.0, 'z': 0.0}, 'rotation': {'pitch': 0.0, 'yaw': 45.0, 'roll': 0.0}, 'scale': {'x': 1.0, 'y': 1.0, 'z': 1.0}}\n\nReturns created actor details with final transform values.",
    	{
    		object_class: z.string().describe("Unreal class name (e.g., 'StaticMeshActor', 'DirectionalLight')"),
    		object_name: z.string().describe("Name/label for the created object"),
    		location: z
    			.object({
    				x: z.number().default(0),
    				y: z.number().default(0),
    				z: z.number().default(0),
    			})
    			.optional()
    			.describe("World position coordinates"),
    		rotation: z
    			.object({
    				pitch: z.number().default(0),
    				yaw: z.number().default(0),
    				roll: z.number().default(0),
    			})
    			.optional()
    			.describe("Rotation in degrees"),
    		scale: z
    			.object({
    				x: z.number().default(1),
    				y: z.number().default(1),
    				z: z.number().default(1),
    			})
    			.optional()
    			.describe("Scale multipliers"),
    		properties: z
    			.record(z.any())
    			.optional()
    			.describe(
    				'Additional actor properties. For StaticMeshActor: use \'StaticMesh\' for mesh path, \'Material\' for single material path, or \'Materials\' for array of material paths. Example: {"StaticMesh": "/Game/Meshes/Cube", "Material": "/Game/Materials/M_Basic"}',
    			),
    	},
    	async ({ object_class, object_name, location, rotation, scale, properties }) => {
    		const result = await tryRunCommand(
    			editorTools.UECreateObject(object_class, object_name, location, rotation, scale, properties),
    		)
    		return {
    			content: [
    				{
    					type: "text",
    					text: result,
    				},
    			],
    		}
    	},
    )
  • Helper function that reads the ue_create_object.py template and fills it with JSON-stringified parameters to produce executable Python code.
    export const UECreateObject = (
    	object_class: string,
    	object_name: string,
    	location?: { x: number; y: number; z: number },
    	rotation?: { pitch: number; yaw: number; roll: number },
    	scale?: { x: number; y: number; z: number },
    	properties?: Record<string, any>,
    ) => {
    	return Template(read("./scripts/ue_create_object.py"), {
    		object_class,
    		object_name,
    		location: location ? JSON.stringify(location) : "null",
    		rotation: rotation ? JSON.stringify(rotation) : "null",
    		scale: scale ? JSON.stringify(scale) : "null",
    		properties: properties ? JSON.stringify(properties) : "null",
    	})
    }
  • Core Unreal Python implementation that resolves the actor class, spawns the actor in the editor world, applies location/rotation/scale/properties (including special handling for StaticMeshActor meshes and materials), and returns detailed JSON output.
    def create_object(
        object_class: str,
        object_name: str,
        location: Optional[Dict[str, float]] = None,
        rotation: Optional[Dict[str, float]] = None,
        scale: Optional[Dict[str, float]] = None,
        properties: Optional[Dict[str, Any]] = None,
    ) -> Dict[str, Any]:
        try:
            world = unreal.get_editor_subsystem(
                unreal.UnrealEditorSubsystem
            ).get_editor_world()
            if not world:
                return {"error": "No world loaded"}
    
            actor_class = None
    
            class_mappings = {
                "StaticMeshActor": unreal.StaticMeshActor,
                "SkeletalMeshActor": unreal.SkeletalMeshActor,
                "DirectionalLight": unreal.DirectionalLight,
                "PointLight": unreal.PointLight,
                "SpotLight": unreal.SpotLight,
                "Camera": unreal.CameraActor,
                "CameraActor": unreal.CameraActor,
                "Pawn": unreal.Pawn,
                "Character": unreal.Character,
                "PlayerStart": unreal.PlayerStart,
            }
    
            actor_class = class_mappings.get(object_class)
    
            # If not found, try loading as native class
            if not actor_class:
                try:
                    actor_class = unreal.load_class(None, object_class)
                except Exception:
                    pass
    
            # If still not found, try finding by name
            if not actor_class:
                try:
                    actor_class = unreal.find_class(object_class)
                except Exception:
                    pass
    
            # If still not found, try loading as blueprint class last
            if not actor_class:
                try:
                    actor_class = unreal.EditorAssetLibrary.load_blueprint_class(
                        object_class
                    )
                except Exception:
                    pass
    
            if not actor_class:
                return {"error": f"Could not find class: {object_class}"}
    
            spawn_location = unreal.Vector(
                x=location.get("x", 0.0) if location else 0.0,
                y=location.get("y", 0.0) if location else 0.0,
                z=location.get("z", 0.0) if location else 0.0,
            )
    
            spawn_rotation = unreal.Rotator(
                pitch=rotation.get("pitch", 0.0) if rotation else 0.0,
                yaw=rotation.get("yaw", 0.0) if rotation else 0.0,
                roll=rotation.get("roll", 0.0) if rotation else 0.0,
            )
    
            spawn_scale = unreal.Vector(
                x=scale.get("x", 1.0) if scale else 1.0,
                y=scale.get("y", 1.0) if scale else 1.0,
                z=scale.get("z", 1.0) if scale else 1.0,
            )
    
            actor = unreal.EditorLevelLibrary.spawn_actor_from_class(
                actor_class, spawn_location, spawn_rotation
            )
    
            if not actor:
                return {"error": "Failed to spawn actor"}
    
            if object_name:
                actor.set_actor_label(object_name)
    
            actor.set_actor_scale3d(spawn_scale)
    
            # Apply default mesh and material for StaticMeshActor if no properties provided
            if actor.get_class().get_name() == "StaticMeshActor" and not properties:
                mesh_component = actor.get_component_by_class(unreal.StaticMeshComponent)
                if mesh_component:
                    name_lower = object_name.lower()
                    mesh_path = "/Engine/BasicShapes/Cube"  # Default fallback
    
                    if "sphere" in name_lower or "ball" in name_lower:
                        mesh_path = "/Engine/BasicShapes/Sphere"
                    elif "cylinder" in name_lower:
                        mesh_path = "/Engine/BasicShapes/Cylinder"
                    elif "cone" in name_lower:
                        mesh_path = "/Engine/BasicShapes/Cone"
                    elif "plane" in name_lower:
                        mesh_path = "/Engine/BasicShapes/Plane"
    
                    mesh = unreal.EditorAssetLibrary.load_asset(mesh_path)
                    if mesh:
                        mesh_component.set_static_mesh(mesh)
    
                    # Apply default material
                    default_material = unreal.EditorAssetLibrary.load_asset(
                        "/Engine/BasicShapes/BasicShapeMaterial"
                    )
                    if default_material:
                        mesh_component.set_material(0, default_material)
    
            if properties:
                for prop_name, prop_value in properties.items():
                    try:
                        if (
                            prop_name == "StaticMesh"
                            and actor.get_class().get_name() == "StaticMeshActor"
                        ):
                            static_mesh = unreal.EditorAssetLibrary.load_asset(prop_value)
                            if static_mesh:
                                mesh_component = actor.get_component_by_class(
                                    unreal.StaticMeshComponent
                                )
                                if mesh_component:
                                    mesh_component.set_static_mesh(static_mesh)
                        elif (
                            prop_name == "Material"
                            and actor.get_class().get_name() == "StaticMeshActor"
                        ):
                            material = unreal.EditorAssetLibrary.load_asset(prop_value)
                            if material:
                                mesh_component = actor.get_component_by_class(
                                    unreal.StaticMeshComponent
                                )
                                if mesh_component:
                                    mesh_component.set_material(0, material)
                        elif (
                            prop_name == "Materials"
                            and actor.get_class().get_name() == "StaticMeshActor"
                            and isinstance(prop_value, list)
                        ):
                            mesh_component = actor.get_component_by_class(
                                unreal.StaticMeshComponent
                            )
                            if mesh_component:
                                for i, material_path in enumerate(prop_value):
                                    if material_path:
                                        material = unreal.EditorAssetLibrary.load_asset(
                                            material_path
                                        )
                                        if material:
                                            mesh_component.set_material(i, material)
                        elif hasattr(actor, prop_name):
                            setattr(actor, prop_name, prop_value)
                    except Exception as e:
                        continue
    
            return {
                "success": True,
                "actor_name": actor.get_name(),
                "actor_label": actor.get_actor_label(),
                "class": actor.get_class().get_name(),
                "location": {
                    "x": actor.get_actor_location().x,
                    "y": actor.get_actor_location().y,
                    "z": actor.get_actor_location().z,
                },
                "rotation": {
                    "pitch": actor.get_actor_rotation().pitch,
                    "yaw": actor.get_actor_rotation().yaw,
                    "roll": actor.get_actor_rotation().roll,
                },
                "scale": {
                    "x": actor.get_actor_scale3d().x,
                    "y": actor.get_actor_scale3d().y,
                    "z": actor.get_actor_scale3d().z,
                },
            }
    
        except Exception as e:
            return {"error": f"Failed to create object: {str(e)}"}

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/runreal/unreal-mcp'

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