Skip to main content
Glama

editor_update_object

Modify existing objects or actors in Unreal Engine by updating their position, rotation, scale, materials, or name to adjust scene composition.

Instructions

Update an existing object/actor in the world

Example output: {'success': true, 'actor_name': 'StaticMeshActor_1', 'actor_label': 'UpdatedCube', 'class': 'StaticMeshActor', 'location': {'x': 150.0, 'y': 200.0, 'z': 50.0}, 'rotation': {'pitch': 0.0, 'yaw': 90.0, 'roll': 0.0}, 'scale': {'x': 2.0, 'y': 2.0, 'z': 2.0}}

Returns updated actor details with new transform values.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actor_nameYesName or label of the actor to update
locationNoNew world position coordinates
rotationNoNew rotation in degrees
scaleNoNew scale multipliers
propertiesNoAdditional actor properties to update. 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"}
new_nameNoNew name/label for the actor

Implementation Reference

  • Core handler function that finds the target actor in the editor world by name or label, then updates its location, rotation, scale, properties, and optionally renames it. Returns success status and updated actor details.
    def update_object(
        actor_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,
        new_name: Optional[str] = None,
    ) -> Dict[str, Any]:
        try:
            world = unreal.get_editor_subsystem(
                unreal.UnrealEditorSubsystem
            ).get_editor_world()
            if not world:
                return {"error": "No world loaded"}
    
            all_actors = unreal.get_editor_subsystem(
                unreal.EditorActorSubsystem
            ).get_all_level_actors()
            target_actor = None
    
            for actor in all_actors:
                if actor.get_name() == actor_name or actor.get_actor_label() == actor_name:
                    target_actor = actor
                    break
    
            if not target_actor:
                return {"error": f"Actor not found: {actor_name}"}
    
            if location:
                new_location = unreal.Vector(
                    x=location.get("x", target_actor.get_actor_location().x),
                    y=location.get("y", target_actor.get_actor_location().y),
                    z=location.get("z", target_actor.get_actor_location().z),
                )
                target_actor.set_actor_location(new_location, False, False)
    
            if rotation:
                new_rotation = unreal.Rotator(
                    pitch=rotation.get("pitch", target_actor.get_actor_rotation().pitch),
                    yaw=rotation.get("yaw", target_actor.get_actor_rotation().yaw),
                    roll=rotation.get("roll", target_actor.get_actor_rotation().roll),
                )
                target_actor.set_actor_rotation(new_rotation, False)
    
            if scale:
                new_scale = unreal.Vector(
                    x=scale.get("x", target_actor.get_actor_scale3d().x),
                    y=scale.get("y", target_actor.get_actor_scale3d().y),
                    z=scale.get("z", target_actor.get_actor_scale3d().z),
                )
                target_actor.set_actor_scale3d(new_scale)
    
            if new_name:
                target_actor.set_actor_label(new_name)
    
            if properties:
                for prop_name, prop_value in properties.items():
                    try:
                        if hasattr(target_actor, prop_name):
                            setattr(target_actor, prop_name, prop_value)
                    except Exception as e:
                        continue
    
            return {
                "success": True,
                "actor_name": target_actor.get_name(),
                "actor_label": target_actor.get_actor_label(),
                "class": target_actor.get_class().get_name(),
                "location": {
                    "x": target_actor.get_actor_location().x,
                    "y": target_actor.get_actor_location().y,
                    "z": target_actor.get_actor_location().z,
                },
                "rotation": {
                    "pitch": target_actor.get_actor_rotation().pitch,
                    "yaw": target_actor.get_actor_rotation().yaw,
                    "roll": target_actor.get_actor_rotation().roll,
                },
                "scale": {
                    "x": target_actor.get_actor_scale3d().x,
                    "y": target_actor.get_actor_scale3d().y,
                    "z": target_actor.get_actor_scale3d().z,
                },
            }
    
        except Exception as e:
            return {"error": f"Failed to update object: {str(e)}"}
  • Helper function that loads the ue_update_object.py script as a template and substitutes the input parameters (JSON stringified where needed) to generate the executable Python code.
    export const UEUpdateObject = (
    	actor_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>,
    	new_name?: string,
    ) => {
    	return Template(read("./scripts/ue_update_object.py"), {
    		actor_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",
    		new_name: new_name || "null",
    	})
    }
  • Registers the 'editor_update_object' tool with the MCP server, including description and the thin async handler that invokes tryRunCommand on the UEUpdateObject helper.
    server.tool(
    	"editor_update_object",
    	"Update an existing object/actor in the world\n\nExample output: {'success': true, 'actor_name': 'StaticMeshActor_1', 'actor_label': 'UpdatedCube', 'class': 'StaticMeshActor', 'location': {'x': 150.0, 'y': 200.0, 'z': 50.0}, 'rotation': {'pitch': 0.0, 'yaw': 90.0, 'roll': 0.0}, 'scale': {'x': 2.0, 'y': 2.0, 'z': 2.0}}\n\nReturns updated actor details with new transform values.",
    	{
    		actor_name: z.string().describe("Name or label of the actor to update"),
    		location: z
    			.object({
    				x: z.number(),
    				y: z.number(),
    				z: z.number(),
    			})
    			.optional()
    			.describe("New world position coordinates"),
    		rotation: z
    			.object({
    				pitch: z.number(),
    				yaw: z.number(),
    				roll: z.number(),
    			})
    			.optional()
    			.describe("New rotation in degrees"),
    		scale: z
    			.object({
    				x: z.number(),
    				y: z.number(),
    				z: z.number(),
    			})
    			.optional()
    			.describe("New scale multipliers"),
    		properties: z
    			.record(z.any())
    			.optional()
    			.describe(
    				'Additional actor properties to update. 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"}',
    			),
    		new_name: z.string().optional().describe("New name/label for the actor"),
    	},
    	async ({ actor_name, location, rotation, scale, properties, new_name }) => {
    		const result = await tryRunCommand(
    			editorTools.UEUpdateObject(actor_name, location, rotation, scale, properties, new_name),
    		)
    		return {
    			content: [
    				{
    					type: "text",
    					text: result,
    				},
    			],
    		}
    	},
    )
  • Zod schema for input validation: requires actor_name; optional location, rotation, scale as objects with x/y/z, properties as record, new_name string.
    {
    	actor_name: z.string().describe("Name or label of the actor to update"),
    	location: z
    		.object({
    			x: z.number(),
    			y: z.number(),
    			z: z.number(),
    		})
    		.optional()
    		.describe("New world position coordinates"),
    	rotation: z
    		.object({
    			pitch: z.number(),
    			yaw: z.number(),
    			roll: z.number(),
    		})
    		.optional()
    		.describe("New rotation in degrees"),
    	scale: z
    		.object({
    			x: z.number(),
    			y: z.number(),
    			z: z.number(),
    		})
    		.optional()
    		.describe("New scale multipliers"),
    	properties: z
    		.record(z.any())
    		.optional()
    		.describe(
    			'Additional actor properties to update. 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"}',
    		),
    	new_name: z.string().optional().describe("New name/label for the actor"),
    },
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. While it mentions the tool updates objects/actors and shows example output, it doesn't disclose important behavioral traits: whether this requires specific permissions, if updates are reversible, what happens to properties not mentioned, error conditions, or side effects. The description is minimal beyond stating the basic operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is reasonably concise but poorly structured. It front-loads the purpose but then immediately jumps to an example output before explaining what the tool returns. The two sentences could be better organized - first stating purpose, then explaining return values. The example output takes significant space but doesn't add proportional value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with 6 parameters (including nested objects), no annotations, and no output schema, the description is inadequate. It should explain more about the update behavior: what fields are optional vs required beyond actor_name, whether partial updates are allowed, what the success/failure responses look like beyond the example, and how this interacts with the world state. The example output helps but doesn't compensate for missing behavioral context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 6 parameters thoroughly. The description adds no parameter semantics beyond what's in the schema - it doesn't explain parameter relationships, constraints, or usage patterns. The baseline of 3 is appropriate when the schema does all the parameter documentation work.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('Update') and resource ('an existing object/actor in the world'), making the purpose immediately understandable. It distinguishes from siblings like 'editor_create_object' and 'editor_delete_object' by focusing on modification rather than creation or deletion. However, it doesn't explicitly differentiate from other potential update operations that might exist.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. While siblings include 'editor_create_object' and 'editor_delete_object', there's no mention of when to choose update over create/delete, nor any prerequisites (like needing an existing actor). The example output shows what happens but doesn't provide usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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