Skip to content

Editor

126 tools. Back to the index.

add_component_to_actor

Additive, idempotent.

Attach a new component of a given class to an actor ALREADY PLACED in the level (an instance-level component, not a change to its Blueprint -- for that use add_component_to_blueprint, which affects every instance). Returns object_path, the full reflection path to feed straight into set_property_value / call_function to configure it, so no dedicated add_* wrapper is needed. Pass idempotent=true to make re-running safe. Editor world only; the change dirties the actor's package, so save_level to keep it.

Parameter Type Required Description
actor_name string yes Name of the placed actor to add the component to (editor world).
component_type string yes Component class name (e.g., 'StaticMeshComponent', 'BoxComponent', 'UStaticMeshComponent')
component_name string yes Name to assign to the new component
location array no Optional [x, y, z] relative location (for scene components)
rotation array no Optional [pitch, yaw, roll] relative rotation (for scene components)
scale array no Optional [x, y, z] relative scale (for scene components)
idempotent boolean no Optional bool (default false). When true, if the actor already has a component of this class, return it instead of adding a duplicate (already_existed:true). Use for single-instance components.

Returns: { actor_name: string, component_name: string, object_path: string, requested_component_name: string, component_type: string, already_existed: bool, success: bool }

add_enum_entry

Additive, idempotent.

Append one enumerator to a Blueprint Enum (UUserDefinedEnum) and give it a display name. Idempotent (an entry whose display/internal name already exists reports already_existed with added=false, leaving the enum unchanged -- the engine itself does NOT dedup). The new entry lands at the end, before the hidden _MAX sentinel.

Parameter Type Required Description
enum_path string yes Full asset path of the UUserDefinedEnum (e.g. /Game/Blueprints/MyEnum).
entry_name string yes Display name for the new enumerator.

Returns: { enum_path: string, entry_name: string, added: bool, already_existed: bool, entry_count: int, entries: [string] }

add_message_log_entry

Additive.

Add one message to a named editor Message Log listing (for example "PIE", "MapCheck" or a new name, created on demand) at Info, Warning or Error severity; an unrecognised severity becomes Info, and a missing log_name or message is an error. Entries stay in memory for the editor session and are never saved. Use it for diagnostics meant for Window > Message Log; print_to_output_log writes to the Output Log instead. message_count is the listing's message count after the add. Read entries back with get_message_log_entries, show the window with open_message_log, empty the listing with clear_message_log.

Parameter Type Required Description
log_name string yes The message log listing name (e.g. "PIE", "MapCheck", or a custom name).
message string yes The message text to add.
severity string no EMessageSeverity token: "Info" (default), "Warning", "Error".

Returns: { added: bool, log_name: string, message: string, severity: string, message_count: int }

add_struct_member

Additive.

Add a field to a Blueprint (user-defined) struct: the way to grow a data shape -- a DataTable row struct, a save record, a component's payload -- without opening the struct editor. Honest on collisions: if the new name is invalid or already used it ROLLS BACK the auto-named member it had to create first and returns an error, instead of reporting success under the engine's MemberVar_N name and leaving orphans behind. Adding a field to a struct a DataTable already uses changes every row (new field at its default), so re-read the table afterwards. get_struct_members lists what is there; rename_struct_member and remove_struct_member are the edits.

Parameter Type Required Description
struct_path string yes Full asset path of the struct (e.g. /Game/Blueprints/MyStruct).
member_name string yes New member name.
member_type string yes Type string resolved through the Blueprint pin-type resolver: scalars (bool, int, int64, float, string, name, text, byte), plus struct/enum/class/object types addressed by name or asset path. An unresolvable string is an error, not a silent default.

Returns: { struct_path, member_name, member_type, member_count }

align_actors

Destructive.

Snap two or more editor-world actors onto a shared location, rotation and/or scale taken from a reference (the first, the last, their average, or a named actor). Use it to straighten a hand-placed row or make a set of props share an orientation, in one undoable step; batch_set_actor_transform is the tool when each actor needs a DIFFERENT transform. WARNING: aligning "location" collapses them onto the same point -- for a row, align only rotation/scale and set positions yourself.

Parameter Type Required Description
actor_names array yes Array of at least 2 INTERNAL actor names (GetName) in the editor world; fewer is an error, and editor labels do not resolve.
align_type string no "location" (default), "rotation", "scale" or "all" -- which transform components get copied from the reference.
reference string no Where the target values come from: "first" (default), "last", "average" (the componentwise mean of all of them), or the internal name of one of the listed actors.

Returns: { aligned_count: int, align_type: string, reference: string, aligned_actors: [actor JSON] }

backup_asset

Destructive.

Duplicate an asset into a timestamped /Game/MCP_Backups/ folder. Call this before destructive operations (delete, reparent, overwrite). Accepts a package path or a full object path.

Parameter Type Required Description
path string yes Source asset path (package path like /Game/Foo/Foo or full object path .Foo)

Returns: { source: string, backup_path: string }

batch_delete_actors

Destructive.

Delete several editor-world actors at once through the editor's own delete path, in ONE undoable transaction (a single undo brings them all back), returning the count and the JSON of each actor captured before deletion. WARNING: matches INTERNAL names only -- editor labels do not resolve -- names it cannot find are skipped silently, so compare deleted_count against how many you asked for; and if NONE resolve it errors with "No actors found to delete". Editor world only, and the removal is in memory until save_level writes the .umap.

Parameter Type Required Description
actor_names array yes Array of internal actor names (GetName), case-insensitive whole-string. Unmatched entries are dropped without an error; resolve labels first with find_actors_by_name.

Returns: { deleted_count: int (compare against your input length), deleted_actors: [actor JSON captured before the delete] }

batch_place_actors_on_terrain

Additive.

Ground many actors on the landscape in one call by sampling the heightmap at each actor's XY (no line trace; scatter without per-point python). Same grounding math as place_actor_on_terrain, applied per actor.

Parameter Type Required Description
actors array yes Array of
align string no Optional default align for entries without their own; 'mesh_bbox_bottom' (default; drops the lowest mesh point) or 'actor_origin'
z_offset number no Optional default extra world-Z above the sampled ground for entries without their own; defaults to 0

Returns: { placed: [ { name, label, previous_z, new_z, landed_z, in_bounds, align, align_used, z_offset } ], failed: [ { name?, label?, error } ], placed_count: int, failed_count: int, requested_count: int, landscape_actor_name: string, world_name: string }

batch_set_actor_transform

Destructive, idempotent.

Move/rotate/scale MANY actors in a single undoable transaction, each with its own optional location/rotation/scale, reporting success_count, failure_count and the names that did not resolve. Cheaper and atomically undoable versus N set_actor_transform calls. Calls Modify() per actor so their OFPA packages dirty and save_level actually writes them. Takes the same world selector as set_actor_transform, so it reaches a live PIE world too. WARNING: resolves the INTERNAL name only (no editor labels, unlike set_actor_transform); a name it cannot find is counted in failure_count, not raised as an error -- read that number.

Parameter Type Required Description
actor_transforms array yes Array of objects {actor_name: internal GetName; location?: [x,y,z] array only; rotation?: [pitch,yaw,roll] or the safer {pitch,yaw,roll}; scale?: [x,y,z] array only}. Omitted components keep their current value; an entry with no actor_name just increments failure_count, and a malformed vector silently reads as zero.
world string no Optional: "editor" (default) | "pie" | "server" | "client" | "pie:N". The response stamps which world answered.

Returns: { success_count: int, failure_count: int (unresolved or malformed entries -- check it), updated_actors: [actor JSON re-read after the write], failed_actors?: [string], world_name, world_package, ... }

begin_transaction

Destructive.

Open one undoable transaction so a whole batch of edits collapses into a SINGLE undo entry: every Modify() between this and end_transaction joins it, and cancel_transaction rolls the lot back without leaving anything on the stack. Use it to make a multi-step edit atomically reversible; the returned transaction_index is what end_transaction / cancel_transaction need. already_open:true means one was already running -- transactions do not nest here.

Parameter Type Required Description
description string no Label shown in the editor's undo history (e.g. 'MCP: retag turrets'). Make it recognisable; it is what get_transaction_history and next_undo report.
primary_object_path string no Optional object path recorded as the transaction's PrimaryObject, so the undo entry is attributable to one asset/actor.

Returns: { description: string, transaction_index: int, already_open: bool, undo_count: int }

bulk_delete_assets

Destructive.

GUARDED batch asset deletion. dry_run DEFAULTS TO TRUE (deliberate: it is the most destructive command in the plugin, bulk_delete_assets(["/Game/VendorPack"], recursive=true) would be a valid unconfirmed call, and agent allowlists may run mutating tools with no prompt). Four independent gates REFUSE per item instead of skipping silently: readonly_roots (default: the project's Read Only Content Roots), protect_paths (wildcards -- the only gate that saves a zero-referencer asset), the currently-open editor world, and the OPT-IN require_zero_referencers gate whose referencer count EXCLUDES referencers that are themselves in this batch (so a self-contained dead subgraph can still be deleted whole). Deletion is a single ObjectTools::ForceDeleteObjects over the whole eligible batch -- resolving each object here via StaticFindObject/StaticLoadObject rather than through UEditorAssetSubsystem::DeleteAsset, whose UE::EditorAssetUtils::LoadAssetFromPath/EnsureAssetsLoaded preamble is a known crash site ("Array index out of bounds", deterministic on corrupted leftovers). deleted_count counts ONLY items that passed BOTH post-delete probes -- the package file is gone (FPackageName::DoesPackageExist) AND the object no longer resolves at its original path (StaticFindObject) -- never the API's own return value. Both are required because for a never-saved, registry-visible asset the disk probe is vacuously true (it was never on disk), so residency is the only real evidence; each failure names which probe still sees the item.

Parameter Type Required Description
asset_paths array yes List of asset paths (or folder paths when recursive is true). Required, non-empty.
recursive boolean no If true, expand folder paths to all contained assets. Default false.
dry_run boolean no Default TRUE. Nothing is deleted; would_delete reports what WOULD go, with each item's gate verdict. Pass false to actually delete.
readonly_roots array no Content roots that may never be deleted from. Default: the project's Read Only Content Roots; pass [] to disable the gate entirely. Matches are REFUSED (refused_readonly_root), never silently skipped. (Read via mcp_common::ParseReadonlyRoots, so the type is declared here.)
protect_paths array no Wildcard patterns (FString::MatchesWildcard, case-insensitive, * spans '/') matched against both the package name and the object path. Default [] (gate off). Matches are REFUSED (refused_protected).
require_zero_referencers boolean no Default FALSE. When true, an asset with at least one referencer OUTSIDE this batch is refused. The per-item external_referencer_count is reported either way.
dependency_type string no Referencer filter for the count above: "hard"|"soft"|"all" (case-insensitive), default "all".

Returns: { requested_count, expanded_count, recursive, dry_run, readonly_roots: [string], protect_paths: [string], require_zero_referencers: bool, dependency_type: string, expanded_folders: [{folder, asset_count}], eligible_count, would_delete: [{path, package_name, external_referencer_count, external_referencers: [string], on_disk}], deleted: [{path, package_name, deleted, still_loaded, error?}], deleted_count, failed_count, force_delete_reported_count, refused_readonly_root: [{path, matched_root}], refused_protected: [{path, matched_pattern}], refused_referenced: [{path, external_referencer_count, external_referencers: [string]}], refused_open_world: [{path, reason}], refused_count, results: [{path, success, error}], note, verification: {...} }

can_redo

Read-only.

Cheap yes/no on whether anything can be re-applied, plus the LABEL of the entry redo would restore. can_redo:false right after an undo normally means a new edit has since wiped the redo stack. Prefer get_undo_state for the whole picture in one call.

No parameters.

Returns: { can_redo: bool, label: string (title of the transaction redo would restore), reason?: string (why not, when can_redo is false) }

can_undo

Read-only.

Cheap yes/no on whether anything is undoable right now, plus the LABEL of the entry undo would revert -- read that label before undoing so you do not roll back someone else's edit. Prefer get_undo_state when you also want counts and the redo side in the same call.

No parameters.

Returns: { can_undo: bool, label: string (title of the transaction undo would revert), reason?: string (why not, when can_undo is false) }

cancel_transaction

Destructive.

Abort the transaction opened by begin_transaction: the edits made inside it are rolled back and NO entry is written to the undo stack (undo_count is unchanged). The escape hatch when a multi-step edit goes wrong halfway -- cleaner than committing with end_transaction and then calling undo, which leaves history behind.

No parameters.

Returns: { success: bool, transaction_index: int (the one that was cancelled), undo_count: int (unchanged -- nothing was recorded) }

capture_viewport

Destructive.

Screenshot the active editor viewport to a PNG (forcing a fresh draw first), optionally resized and optionally returned inline as base64. Use it to SHOW a result -- proof that something looks right, an image to hand to a human. Do NOT use it to diagnose: an image costs far more context than a command and is read far less reliably than one, so for "is the actor there / did the value change / did it move" prefer get_actor_bounds, get_component_properties, raycast_scene or a property read, which answer exactly and cheaply. Captures the EDITOR viewport, not a PIE window; high_res_screenshot is the higher-resolution sibling.

Parameter Type Required Description
width number no Optional target width to downscale/upscale to (omit to keep native viewport size).
height number no Optional target height (only used when width is also supplied).
filename string no Optional output filename (default MCP_Capture_<timestamp>.png); ".png" extension is added if missing.
return_base64 boolean no bool, also include image_base64 + image_format in the response (default false).

Returns: { file_path: string, width: int, height: int, byte_size: int, image_base64: string, image_format: string }

clear_message_log

Destructive, idempotent.

Clear all messages from a named engine Message Log listing.

Parameter Type Required Description
log_name string yes The message log listing name (e.g. "PIE", "MapCheck", or a custom name).

Returns: { cleared: bool, log_name: string, cleared_count: int, messages_after: int }

clear_undo_barriers

Destructive, idempotent.

Remove ALL undo barriers at once so undo can traverse the whole buffer again -- including barriers another session or the human placed to protect their work, so prefer remove_undo_barrier for just your own. Nothing is undone by this; it only lifts the floor. WARNING: success is hardcoded true: had_barrier is the oracle, false meaning there was nothing to clear.

No parameters.

Returns: { success: bool (hardcoded), had_barrier: bool (THE oracle -- false = honest no-op), undo_count: int, queue_length: int }

consolidate_assets

Destructive.

Redirect every reference to the source assets onto the target with UEditorAssetSubsystem::ConsolidateAssets, which DELETES the sources (leaving redirectors) and saves what it changed. Only class-compatible sources are used; others are listed in skipped_incompatible and unloadable ones are dropped silently. dry_run=true only reports.

Parameter Type Required Description
target_asset_path string yes The asset to keep, all references point here
source_asset_paths array yes Assets to consolidate into the target
dry_run boolean no If true, skip ConsolidateAssets entirely and only report what would happen, default false

Returns: dry_run=true: { target_asset_path, target_class, dry_run: true, would_consolidate: [string], skipped_incompatible: [{path,class}], compatible_count: int, incompatible_count: int }; dry_run=false (default): { target_asset_path, target_class, dry_run: false, consolidated_count: int, source_count: int, success: bool, skipped_incompatible: [{path,class}], incompatible_count: int }

copy_actors

Destructive.

Put editor-world actors on the editor CLIPBOARD (edactCopySelected), either by name or whatever is currently selected, so paste_actors can drop them back -- the way to clone a group while keeping their relative layout, which duplicate_actor (one actor, in place) does not do. WARNING: naming them REPLACES the current selection as a side effect, and matching is by INTERNAL name only. One of actor_names or copy_selected=true is required.

Parameter Type Required Description
actor_names array no Optional array of internal actor names (GetName) to copy; supplying it re-selects exactly those actors first.
copy_selected boolean no Optional bool. True (with actor_names omitted) copies whatever is selected right now, leaving the selection alone.

Returns: { copied_count: int, success: bool (hardcoded; verify with paste_actors' pasted_count) }

create_blueprint_interface

Destructive.

Create a Blueprint Interface asset: a contract of function signatures that unrelated classes can implement, so callers talk to the contract instead of a concrete class. The right tool when several different kinds of actor must answer the same request (interactable, damageable, workable) and you do not want a shared base class -- one interface replaces N-by-M hard-wired cases. Created empty: add functions with add_blueprint_function, then implement_interface on each class and implement_interface_function per class.

Parameter Type Required Description
name string yes Asset name (no path)
path string no Target content path for the new asset (default /Game/Blueprints)

Returns: { name, path, type }

create_directory

Additive, idempotent.

Make a content-browser folder at a UE long path (e.g. /Game/MyGame/Systems/Foo). Idempotent: an existing folder is not an error, it comes back already_existed:true. Use it to lay out a system's folders before creating assets there; a path that does not start with '/' is rejected.

Parameter Type Required Description
path string yes UE long path of the folder to create, e.g. /Game/MyGame/Systems/Foo. Must start with '/', not a disk path.

Returns: { path: string, already_existed: bool (true = nothing was created, and that is a success) }

create_enum

Additive.

Create a Blueprint enum asset from an ordered list of enumerator DISPLAY names -- states, categories and types that Blueprints and DataTable columns switch on. Errors if the asset already exists (not idempotent). Beware the display/internal split that follows: the engine stores enumerators internally as NewEnumerator0, NewEnumerator1, ... and writers into DataTables must use those internal names, because a display name containing spaces is cut at the first space by the text importer and silently lands on index 0. So keep single-word display names, or expect to write NewEnumeratorN. add_enum_entry / rename_enum_entry / reorder_enum_entry edit it afterwards.

Parameter Type Required Description
name string yes Enum asset name.
entries array yes Ordered list of enumerator display-name strings.
path string no Target content path for the new asset (default /Game/Blueprints)

Returns: { name, path, entry_count }

create_file_media_source

Additive.

Create a UFileMediaSource asset at package_path/name that points at a movie file path, register it and save it; the file does not need to exist. An existing asset is returned unchanged (file_path is not applied). Returns asset_path, the stored file_path, created and saved.

Parameter Type Required Description
name string yes Name of the file media source asset to create.
file_path string yes Movie file on disk, absolute or "./"-relative to the project Content folder, e.g. "./Movies/Intro.mp4"; a path inside Content is stored in that relative form.
package_path string no Target content package path where the asset is created (default /Game/Media)

Returns: { media_source_name, asset_path, created, already_exists, file_path, saved, save_error }

create_functional_test

Additive.

Create a Blueprint subclass of AFunctionalTest (the canonical UE pattern for a multiplayer-friendly, Blueprint-scriptable test actor) and save it.

Parameter Type Required Description
asset_name string yes Name for the new Functional Test BP asset.
package_path string no Target content folder; defaults to /Game/MCP.
parent_class string no Optional AFunctionalTest-derivative parent (default "FunctionalTest").

Returns: { asset_name, asset_path, package_class, parent_class, already_existed, saved }

create_media_player

Additive.

Create a UMediaPlayer asset at package_path/name with PlayOnOpen and looping set, optionally with a linked UMediaTexture named "<name>_T" beside it, and save both. An existing player is returned unchanged (flags not applied). Returns asset_path, play_on_open, loop, media_texture_path, saved and texture_saved.

Parameter Type Required Description
name string yes Name of the media player asset to create.
package_path string no Target content package path where the asset is created (default /Game/Media)
create_output_texture boolean no Also create a UMediaTexture "<name>_T" next to the player and link it (default true).
play_on_open boolean no Set the player's PlayOnOpen flag (default true)
loop boolean no Set the player to loop via SetLooping (default false)

Returns: { media_player_name, asset_path, created, already_exists, play_on_open, loop, texture_created, media_texture_path, saved, texture_saved, save_error, texture_save_error }

create_media_texture

Additive.

Create a UMediaTexture asset at package_path/name (AutoClear on, no player linked) and save it; an existing texture is returned unchanged, with its linked player if any. Link a player with link_media_texture_to_player. Returns asset_path, created, has_media_player and saved.

Parameter Type Required Description
name string yes Name of the media texture asset to create.
package_path string no Target content package path where the asset is created (default /Game/Media)

Returns: { media_texture_name, asset_path, created, already_exists, has_media_player, media_player_path, saved, save_error }

create_struct

Destructive, idempotent.

Create a Blueprint Struct (UUserDefinedStruct). Idempotent by reset+rebuild: a stale struct already at the path is deleted and recreated fresh (reset_stale:true); a same-path asset of a different type is an honest error.

Parameter Type Required Description
name string yes Asset name (no path)
path string no Target content path for the new asset (default /Game/Blueprints)

Returns: { name, path, reset_stale }

delete_actor

Destructive.

Remove one actor from the EDITOR level through the editor's own delete path (select + edactDeleteSelected), so it is transacted and undoable, and echo back the deleted actor's JSON. WARNING: two edges that bite: it matches the INTERNAL name only -- unlike set_actor_transform, an editor LABEL will not resolve -- and it clears the current selection as a side effect. It cannot touch PIE actors (editor world only), and the deletion lives in memory until save_level writes the .umap. Use batch_delete_actors for several at once.

Parameter Type Required Description
name string yes Actor's internal name (GetName), case-insensitive but WHOLE-string. Editor labels are NOT accepted here; resolve one first with find_actors_by_name.

Returns: { deleted_actor: actor JSON captured before the delete }

delete_directory

Destructive, idempotent.

DESTRUCTIVE: removes a content-browser folder AND every asset inside it, recursively, with no dry-run and no referencer check (unlike bulk_delete_assets, which defaults to dry_run and refuses vendored roots). Driven through UEditorAssetSubsystem, which is the pair that works headless. Idempotent: an already-absent folder answers already_absent:true. Verify afterwards with git status on the corresponding Content/ path -- never with the deleted flag alone.

Parameter Type Required Description
path string yes UE long path of the folder to delete, e.g. /Game/Scratch. Must start with '/'. Everything under it goes.

Returns: { path: string, already_absent: bool, deleted: bool }

deselect_actors

Destructive.

Drop specific actors from the editor selection, or clear it entirely with deselect_all. The counterpart of select_actors; use the clear-all form to leave the editor in a known state before a tool that acts on the selection (copy_actors, move_actors_to_level) so it does not pick up leftovers. Editor world only; matches INTERNAL names.

Parameter Type Required Description
actor_names array no Optional array of internal actor names (GetName) to remove from the selection. One of actor_names or deselect_all=true is required.
deselect_all boolean no Optional bool. True clears the whole selection; it wins over actor_names when both are sent.

Returns: { deselected_all: bool, deselected_count: int }

disable_plugin

Destructive, idempotent.

Turn a plugin off in the .uproject and save the project file to disk. WARNING: enabled:false is hardcoded on the write succeeding and the modules stay LOADED for this session -- the plugin's classes keep working until the editor restarts, so a still-functioning feature is not evidence the call failed. WARNING: disabling a plugin whose assets are referenced leaves those references broken on the next start; check get_plugin_status and the referencers first.

Parameter Type Required Description
plugin_name string yes Plugin name exactly as in its .uplugin file, not a path.

Returns: { plugin_name: string, enabled: bool (hardcoded false when the .uproject write succeeded), project_saved: bool, note: string about the required restart }

duplicate_actor

Additive.

Copy one editor-world actor in place through the editor's duplicate path, keeping its component overrides, and return both the new actor's JSON and the original's. Undoable; it changes the editor SELECTION as a side effect. Matches the INTERNAL name only (no editor labels). The clone exists in memory until save_level writes the .umap -- and a save that answers success while git status stays clean means the .umap is read-only (e.g. a Git LFS lockable file you have not locked), not that the duplicate failed.

Parameter Type Required Description
actor_name string yes Actor's internal name (GetName), case-insensitive whole-string. Editor labels are NOT accepted; resolve one with find_actors_by_name first.

Returns: { duplicated_actor: actor JSON (its auto-assigned name lives here), original_actor: actor JSON }

enable_plugin

Destructive, idempotent.

Turn a plugin on in the .uproject and save the project file to disk. WARNING: enabled:true is hardcoded on the write succeeding, and the plugin's MODULES are not loaded by this call -- the editor has to be restarted before its classes, assets or MCP tools actually exist. So do not treat a following "class not found" as a failure of this command; check project_saved and then restart. Use get_plugin_status to read the current state and disable_plugin for the inverse.

Parameter Type Required Description
plugin_name string yes Plugin name exactly as in its .uplugin file (e.g. 'PythonScriptPlugin'), not a path.

Returns: { plugin_name: string, enabled: bool (hardcoded true when the .uproject write succeeded), project_saved: bool, note: string about the required restart }

end_transaction

Destructive.

Close the transaction opened by begin_transaction and COMMIT it, so everything done inside becomes one entry on the editor's undo stack (undo_count grows by one). Pair it with every begin_transaction -- leaving one open makes later edits silently join it. Use cancel_transaction instead when you want the batch thrown away rather than kept.

No parameters.

Returns: { success: bool, transaction_index: int (the one that was closed), undo_count: int after the commit }

execute_console_command

Destructive.

Run a console command through the EDITOR (GEditor->Exec against the editor world): cvars, stat overlays, r.* toggles, engine commands. WARNING: it does NOT reach a running PIE session's PlayerController, so player cheats like BugItGo come back handled:false -- to move or cheat a PIE pawn use execute_python against the anchored PIE world. handled is the engine's own "some Exec claimed this string", not proof of an effect: verify with the state (get_cvar, a property read), never with this bool.

Parameter Type Required Description
command string yes Console command line, e.g. 'stat fps', 'r.ScreenPercentage 50', 'ShowFlag.Grid 0'. Editor-side only.

Returns: { command: string, handled: bool (an Exec handler claimed the string -- not evidence the effect happened) }

execute_python

Destructive, open world.

Execute Python code inside the running Unreal Editor. DO NOT GUESS A FIELD NAME: most of this tool's errors are "object has no attribute" -- and the field usually EXISTS, just not where you reached for it: HitResult().impact_point raises, get_editor_property cannot find it, and only to_dict() returns it (Transform.translation is the reverse). The engine's own stub and Epic's web docs list it either way, so neither settles it -- ask the object (dir(x), x.to_dict(), x.get_editor_property(...)). PIE TRAP -- this tool is the ONE HOLE in the plugin's PIE guard: the commands that compile a Blueprint or write to disk are REFUSED while Play-in-Editor is live (McpPieSafety.gen.h), but arbitrary Python cannot be classified statically, so a script that reaches compile/save through unreal.* (BlueprintEditorLibrary.compile_blueprint, EditorAssetLibrary.save_asset, save_loaded_asset, anything that dirties a Blueprint) RUNS ANYWAY. With PIE live that ends either in a DEAD EDITOR -- the compiler's UREINST_* trampoline retains a world and CheckForWorldGCLeaks is Fatal, taking every unsaved edit with it -- or in a save that reports success without writing a byte (Editor.AllowSavingAssetsDuringPIE=0). So: call is_play_in_editor_active FIRST whenever your script compiles, saves, or mutates a Blueprint, and stop PIE before running it. READING the live world during PIE is safe and is exactly what this tool is for -- do not avoid it for that. BEFORE writing a loop, check what already answers it in ONE call: scripts that re-implement something a tool already does fail far more often than scripts doing something genuinely new -- hand-rolled scaffolding is where the errors are, and a bug in the scaffold reads exactly like a finding about the game. enumerate actors of a class -> get_actors_by_class. enumerate them AND read their properties, filtered by class or editor label, drilling into one component, with the answering world STAMPED on the result (this tool cannot tell you which world answered) -> get_actor_properties_by_class. read properties off ONE known object -> get_properties / get_property_value. list an actor's components -> get_actor_components. one line trace -> raycast_scene. sample a property across a whole PIE session ARMED BEFORE BeginPlay -- a window a post-tick callback cannot reach at all -> watch_pie_property. But do NOT read this as "always prefer the specific tool": only a minority of scripts are replaceable end-to-end. Python remains the right answer when the script does what those cannot: several classes in one round trip, walking components AND calling a method, filtering by name substring, correlating two values in the same tick, or anything that mutates. Do not trade one call for twelve. WARNING: log_output IS NOT THE LOG OF THE CALL -- it is Python's own prints only (UE fills it from a delegate broadcast solely by unreal.log/log_warning/log_error), so every UE_LOG the ENGINE emits during your script is absent from it. Read engine_log instead: it is the GLog slice bracketed to this call, Warning+Error by default. Example: build_meta_human can run, return None, write zero assets and report a clean log_output while "LogMetaHumanCoreTechLib: Error: Texture Synthesis has not been initialized" sits in GLog. When a call reports success and NOTHING HAPPENED, engine_log is the first place to look; widen with engine_log_level=Log, or pass log_cursor_before to get_output_log_lines(since_sequence_id=...) for the unfiltered rest.

Parameter Type Required Description
command string yes Python code to run (single or multi-line).
capture_output boolean no Run as a file and collect captured log (default true)
mode string no Execution mode: ExecuteFile, ExecuteStatement, or EvaluateStatement (default ExecuteFile)
engine_log_level string no Minimum severity of ENGINE log to return in engine_log: Error, Warning (default), Display, Log/All.
engine_log_max string no Max lines in engine_log (default 50, 0 disables, hard cap 4096).

Returns: { command, python_success, execution_mode, command_result, output, log_output, log_line_count, engine_log, engine_log_count, engine_log_truncated, log_cursor_before }

execute_python_file

Destructive, open world.

Execute a Python (.py) file inside the running Unreal Editor. PIE TRAP: same hole as execute_python -- arbitrary Python is NOT covered by the plugin's PIE guard, so a script that compiles a Blueprint or saves an asset runs even with Play-in-Editor live, where compiling can KILL the editor (UREINST_* retains a world, CheckForWorldGCLeaks is Fatal) and saving reports success without writing (Editor.AllowSavingAssetsDuringPIE=0). Check is_play_in_editor_active first when the file compiles, saves or mutates a Blueprint; reading the live world during PIE is safe. WARNING: log_output IS NOT THE LOG OF THE CALL -- it is Python's own prints only (UE fills it from a delegate broadcast solely by unreal.log/log_warning/log_error), so every UE_LOG the ENGINE emits during your script is absent from it. Read engine_log instead: it is the GLog slice bracketed to this call, Warning+Error by default. Example: build_meta_human can run, return None, write zero assets and report a clean log_output while "LogMetaHumanCoreTechLib: Error: Texture Synthesis has not been initialized" sits in GLog. When a call reports success and NOTHING HAPPENED, engine_log is the first place to look; widen with engine_log_level=Log, or pass log_cursor_before to get_output_log_lines(since_sequence_id=...) for the unfiltered rest.

Parameter Type Required Description
file_path string yes Absolute path to a .py file accessible from the editor host.
engine_log_level string no Minimum severity of ENGINE log to return in engine_log: Error, Warning (default), Display, Log/All.
engine_log_max string no Max lines in engine_log (default 50, 0 disables, hard cap 4096).

Returns: { file_path, python_success, command_result, output, log_output, log_line_count, engine_log, engine_log_count, engine_log_truncated, log_cursor_before }

export_assets

Destructive.

Export assets to files via IAssetTools::ExportAssets (preferred format, FBX/PNG/EXR first), each written to export_path/<package path without its leading slash>.<extension>, e.g. D:/Exports/Game/Meshes/SM_Rock.FBX. What was written is measured per asset on disk: exported lists each asset with its file, and not_exported the ones that did not load, have no exporter or failed to write. Succeeds only when every requested asset was written.

Parameter Type Required Description
asset_paths array yes Asset object or package paths to export (e.g. ["/Game/Meshes/SM_Rock"]); empty strings are ignored.
export_path string yes Destination directory on disk (e.g. "D:/Exports"), created if missing; each file lands in subfolders named after its package path.

Returns: { exported_count: int, failed_count: int, requested_count: int, export_path: string, exported: [{ asset_path: string, file: string }], not_exported: [string] }

find_actors_by_name

Read-only.

Locate actors by a SUBSTRING of their internal name and/or their editor label, returning name, label, class and transform for each hit. This is the one to use when you know what a thing is CALLED but not its class -- get_actors_by_class needs an exact class name, and this one alone can search labels (match='label'), which is where hand-assigned names live. Plain case-INSENSITIVE substring, no wildcards and no regex: 'turret' matches BP_Turret_C_2, and '*' matches literally nothing. Its world selector is the canonical one: 'editor' (default), 'pie'/'game', 'server', 'client' and 'pie:N' all resolve for real, an unrecognised value FAILS instead of falling through to the editor world, and the reply stamps world_package/world_type/net_mode/pie_instance so you can tell which world answered.

Parameter Type Required Description
pattern string yes Substring to look for, case-insensitive, no wildcards or regex. Cannot be empty.
match string no Optional 'name' | 'label' | 'both' (default 'both'). 'name' = internal object name only; 'label' = the editor label from the outliner; 'both' = a hit on either. An unknown value is a clean error.
max_results number no Optional cap on hits (default 1000); results_truncated says whether the scan stopped early.
world string no Optional world selector: absent/'editor' (default) | 'pie' (ambiguous: PlayWorld, else the first PIE context) | 'game' (alias of 'pie') | 'server' (the PIE world with authority, GetNetMode() != NM_Client) | 'client' | 'pie:N' (the PIE context whose PIEInstance is N). Case-insensitive; an unrecognised value is a clean error listing the worlds present, never a silent fallback to the editor world.

Returns: { matching_actors: [ { name, actor_name, label, class, location, rotation, scale, is_loaded } ], matching_actors_count: int, search_pattern: string, match: string, results_truncated: bool, max_results: int, world: string (the normalized selector that resolved), world_name: string, world_package: string (in World Partition the UEDPIE_N prefix lives HERE, not in world_name), world_type: string, net_mode: string, pie_instance: int }

find_duplicate_assets

Read-only.

Find groups of assets sharing the same base name under a folder tree (e.g. same name existing under both a vendored library tree and a first-party fork)

Parameter Type Required Description
folder_path string no Content folder to scan, default /Game
recursive boolean no If true, scan subfolders, default true
min_group_size number no Minimum number of same-named assets to report as a duplicate group, default 2
class_filter array no Optional list of class short names (e.g. "StaticMesh","Material"); only assets whose AssetClassPath short name case-insensitively matches one of these are considered
max_results number no Cap on the number of duplicate GROUPS returned (not raw assets), clamped 1..20000, default 2000

Returns: { folder_path, recursive, class_filter, min_group_size, group_count, total_duplicate_assets, assets_scanned, max_results, results_truncated, groups: [{ name, count, classes: [string], assets: [{path, package, class}] }] } (groups sorted by count descending)

find_unused_assets

Read-only.

Find assets in a folder with zero referencers, and annotate each survivor with the reasons it should be KEPT anyway. "Zero referencers" is not the same as "safe to delete": there are three common ways an asset stays alive with an empty referencer set -- it is explicitly protected, a Config/Default*.ini names it, or it is a fork descending from a vendored base library. Each becomes a keep_reason string on the entry; deletion_candidates lists only the entries with NO keep_reason. Nothing is ever removed from unused_assets by these flags (hiding a genuinely unreferenced asset would be the same lie in the other direction). NOTE: there is deliberately no is_world -- it is already visible in class_name ("World").

Parameter Type Required Description
folder_path string yes Content folder to scan, e.g. /Game/Unused
recursive boolean no If true, scan subfolders, default true
exclude_classes array no Optional list of class name fragments to skip
dependency_type string no Referencer filter: "hard"|"soft"|"all" (case-insensitive), default "all" (identical behavior to omitting it)
protect_paths array no Wildcard patterns (FString::MatchesWildcard, case-insensitive, * spans '/') matched against the package name and the object path. Default [] . A match adds keep_reason "protected_path".
include_lineage_reasons boolean no Default FALSE because it LOADS every candidate Blueprint. When true, a Blueprint whose super chain reaches a class owned by one of base_libraries gets keep_reason "descends_from_base_library" -- the only signal that saves a fork carrying no fork-origin tag (project setting Fork Origin Tag).
base_libraries array no Vendored-library content roots for the lineage check. Default: the project's Read Only Content Roots (same default as audit_class_purity).

Returns: { folder_path, folder_exists, recursive, dependency_type, protect_paths: [string], include_lineage_reasons, base_libraries: [string], unused_assets: [{path, class_name, size_kb, keep_reasons: [string], keep_reason_detail: {...}}], unused_count, total_scanned, deletion_candidates: [string], deletion_candidate_count, assets_with_keep_reason, keep_reason_counts: {protected_path, referenced_by_config, descends_from_base_library}, config_scan: {files_scanned: int, files: [string]}, lineage_scan: {attempted, blueprints_loaded, skipped_non_blueprint, load_failures} }

fixup_redirectors

Destructive.

Clean up the redirectors a rename/move left behind, under a folder: load each referencing package (which repoints it) and re-save it, optionally force-deleting redirectors whose referencers all saved. Hand-rolled on purpose -- IAssetTools::FixupReferencers HARD-CRASHES on World-Partition/OFPA projects -- and heavily railed: it REFUSES while PIE is active, never writes under readonly_roots (default: the project's Read Only Content Roots), never outside /Game, and never loads or saves map or OFPA packages, handing the resident ones back in skipped_current_world for you to save_level instead. Deletions are DISK-verified (a redirector whose .uasset survives lands in redirectors_delete_failed, not in the count). WARNING: redirectors_found/deleted count OBJECTS: one renamed Blueprint leaves THREE in a single package -- read redirector_packages_found for files.

Parameter Type Required Description
path string no Long path to scan, defaults to /Game
delete_redirectors boolean no Optional bool (default false). After a successful repoint, force-delete the redirectors whose every non-redirector referencer was saved. Left in place by default (a redirector is ~2 KB and harmless).
readonly_roots array no Optional array of long-path prefixes that must NEVER be written (default: the project's Read Only Content Roots, i.e. the vendored library roots). Referencers under them are reported in skipped_readonly instead of being saved.

Returns: { path: string, redirectors_found: int, redirector_packages_found: int, referencers_repointed: int, packages_saved: int, packages_failed: [{ package: string, error: string }], skipped_readonly: [string], skipped_current_world: [string], redirectors_deleted: int, redirector_packages_deleted: int, redirectors_delete_failed: [{ package: string, reason: string }], redirectors_fixed: int, message: string }

get_actors_in_level

Read-only.

Dump EVERY actor of a world (name, class, transform), capped by max_results at 5000, with total_actors_in_level and results_truncated so you know if you saw all of it. The unfiltered census: reach for get_actors_by_class when you know the class, find_actors_by_name for a name/label substring, get_actors_in_radius for a place. Its world selector is the canonical one: 'editor' (default), 'pie'/'game', 'server', 'client' and 'pie:N' all resolve for real, an unrecognised value FAILS naming the worlds that exist instead of quietly answering from the editor world, and every reply carries world_package/world_type/net_mode/pie_instance so you can see WHICH world answered rather than assuming.

Parameter Type Required Description
max_results number no Optional cap on returned actors (default 5000). Must be > 0. Truncation is reported, never silent.
world string no Optional world selector: absent/'editor' (default) | 'pie' (ambiguous: PlayWorld, else the first PIE context) | 'game' (alias of 'pie') | 'server' (the PIE world with authority, GetNetMode() != NM_Client) | 'client' | 'pie:N' (the PIE context whose PIEInstance is N). Case-insensitive; an unrecognised value is a clean error listing the worlds present, never a silent fallback to the editor world.

Returns: { actors: [actor JSON], actors_count: int, total_actors_in_level: int, results_truncated: bool, max_results: int, world: string (the normalized selector that resolved), world_name: string, world_package: string (in World Partition the UEDPIE_N prefix lives HERE, not in world_name), world_type: string, net_mode: string, pie_instance: int }

get_allow_cinematic_control

Read-only.

Read whether the active editor viewport allows cinematic control (Sequencer possession)

No parameters.

Returns: { allows_cinematic_control: bool }

get_automation_test_results

Read-only.

Returns the cached result of the last synchronous test completed through run_automation_test or start_gauntlet_run, without running anything: test_name, passed, verdict, duration_s, errors, warnings and entries. Skipped or multi-tick tests leave the cache unchanged; fails when no test has completed this editor session.

No parameters.

Returns: { test_name, started, completed, passed, verdict, duration_s, errors, warnings, entries:[{type,message,context,filename,line}], entry_count }

get_compile_errors

Destructive.

WARNING: despite the get_ prefix this COMPILES the Blueprint (silently) and then returns its error/warning count and every message with severity -- it is a mutation, not a read: compiling dirties the package, can cascade into other packages, and can knock a Blueprint's placed OFPA instances out of the world in memory (get_actors_by_class then returns 0 in editor AND PIE; load_level of the same map brings them back). Use it as the honest oracle for "does this BP build" -- num_errors and the message list are real, read off the compiler results log -- and reach for check_blueprint_errors / find_erroring_blueprints when a compile is not what you want.

Parameter Type Required Description
blueprint_name string yes Blueprint name or full asset path (e.g. BP_MyActor or /Game/MyGame/Core/BP_MyActor).

Returns: { name: string, num_errors: int, num_warnings: int, succeeded: bool (num_errors == 0), messages: [{ severity: 'error'|'warning'|'info', message: string }] }

get_current_level

Read-only.

Which map a world is sitting on: level_name, its package_name (/Game/... or /Engine/...), the resolved disk filename, whether the package is dirty, and a live actor count. package_name is the discriminator that catches the classic mistake -- if it starts with /Engine/ you are on an engine template (what new_level leaves behind) and a save_level without filename would overwrite the ENGINE's own map. Defaults to the EDITOR world; it also takes the standard world selector, so during PIE you can ask the play world ('pie'/'server'/'client'/'pie:N') instead of being told about the authoring map and having no way to know it.

Parameter Type Required Description
world string no Optional world selector: absent/'editor' (default -- the authoring map even while PIE runs) | 'pie' (ambiguous: PlayWorld, else the first PIE context) | 'game' (alias of 'pie') | 'server' (the PIE world with authority) | 'client' | 'pie:N'. Case-insensitive; an unrecognised value is a clean error listing the worlds present, never a silent fallback to the editor world.

Returns: { level_name: string, package_name: string (the /Game or /Engine path -- read this one), filename: string, is_dirty: bool, actor_count: int, world: string (the normalized selector that resolved), world_name: string, world_package: string (the UEDPIE_N prefix lives HERE, not in world_name), world_type: string ("Editor" | "PIE" | ...), net_mode: string, pie_instance: int }

get_cvar

Read-only.

Reads a console variable's live value, help text, and flags.

Parameter Type Required Description
name string yes Console variable name, e.g. "r.ScreenPercentage".

Returns: { name: string, value: string, string_value: string, int_value: int, float_value: float, bool_value: bool, help: string, flags: int, set_by: string }

get_engine_ini_value

Read-only.

Read one key from the merged in-memory config (GConfig) of an INI such as Engine or Game. Read-only; returns value and found (false, with an empty value, when the section or key is missing). Pass config_file without .ini. Writer: set_engine_ini_value.

Parameter Type Required Description
section string yes Section name (e.g. "/Script/Engine.RendererSettings")
key string yes Key inside the section, e.g. "r.DefaultFeature.AntiAliasing".
config_file string no Config base name without extension, e.g. "Engine" (default), "Game", "Input", "Editor", "Scalability"; "Engine.ini" is not resolved.

Returns: { section, key, value, found }

get_level_blueprint

Additive.

Get (or, with create=true, bring into being) the current level's Level Blueprint and return the blueprint_path that the graph tools need -- its event graph is always called "EventGraph", so add_graph_node / connect_pins can target it directly with graph_name="EventGraph". This is the entry point for level-specific scripting that does not belong in any actor. Read-only by default: with create=false and no blueprint present it answers exists:false + success:true rather than failing.

Parameter Type Required Description
create boolean no Optional bool (default false). True creates the Level Blueprint if the level has none -- a mutation that dirties the map, so save_level afterwards.

Returns: { exists: true, created: bool, blueprint_path: string, blueprint_name: string, event_graph: "EventGraph", level_name: string, success: true }, or, when no blueprint exists and create=false: { exists: false, success: true, level_name: string, note: string }

get_media_info

Read-only.

Read a media asset by path: class and media_type ("MediaPlayer", "MediaTexture", "FileMediaSource" or "Other"), plus play_on_open and loop for a player, the linked player and auto_clear for a texture, or file_path for a file source. Read-only.

Parameter Type Required Description
asset_path string yes Path of a UMediaPlayer, UMediaTexture or UFileMediaSource asset, e.g. "/Game/Media/MP_Intro"; any other asset reports only its name and class.

Returns: { asset_path, asset_name, class, media_type, play_on_open, loop, has_media_player, media_player_path, auto_clear, file_path }

get_message_log_entries

Read-only.

Read back the messages currently in a named engine Message Log listing (IMessageLogListing::GetFilteredMessages), each resolved back to the actor/component the engine attached to it. The reader that pairs with add_message_log_entry/clear_message_log.

Parameter Type Required Description
log_name string yes The message log listing name (e.g. "PIE", "MapCheck", or a custom name). Required.
severity string no Optional severity filter: "Error"|"PerformanceWarning"|"Warning"|"Info" (case-insensitive). Omit for all.
base_libraries array no Package roots to classify each entry's class against (optional, default: the project's Read Only Content Roots). An explicit [] disables the classification. Reported as data in class_root/class_root_is_base_library; the tool never judges which root is "upstream".

Returns: { log_name: string, severity_filter: string|null, base_libraries: [string], entries: [{message: string, severity: string, token_source: string, object_path: string, object_resolved: bool, actor_name: string, actor_label: string, actor_path: string, actor_class: string, actor_guid: string, component_name: string, class_asset_path: string, class_root: string, class_root_is_base_library: bool}], count: int }

get_near_clip_plane

Read-only.

Read the near clip plane (and far clip override) of the active editor viewport

No parameters.

Returns: { near_clip_plane: number, far_clip_plane_override: number }

get_output_log_lines

Read-only.

Read the single per-editor-session log buffer UEAgent attaches to GLog (general editor output, not PIE-only -- Serialize() captures every category/verbosity that passes through GLog, regardless of PIE state; usable for PIE Functional Test / wait_for_pie_completion orchestration too). NON-DESTRUCTIVE cursor read (since_sequence_id, same idiom as poll_gameplay_messages), structured entries. Supports all three filters (message text, verbosity level, category).

Parameter Type Required Description
count number no Optional int32 cap on the number of entries returned (default 200, max 4096).
filter string no Optional case-insensitive substring on the message text.
level_filter string no Optional exact verbosity name filter (Fatal|Error|Warning|Display|Log|Verbose|VeryVerbose), case-insensitive.
category_filter string no Optional case-insensitive substring on the log category name.
since_sequence_id number no Optional int64 cursor; only entries with a higher sequence_id are returned (default 0 = everything currently retained).

Returns: { lines: [{sequence_id, ts, level, category, message}], count, held_total, last_sequence_id }

get_python_status

Read-only.

Reports whether the editor Python plugin is loaded, available, configured and initialized, with the interpreter path and engine version; when Python is initialized it also evaluates sys.version for python_version (empty otherwise). Changes nothing; check it before execute_python or execute_python_file.

No parameters.

Returns: { engine_version, module_loaded, python_available, python_configured, python_initialized, interpreter_path, python_version }

get_scalability_levels

Read-only.

Reads the current engine scalability quality levels. Calls Scalability::GetQualityLevels().

No parameters.

Returns: { ResolutionQuality: int, ViewDistanceQuality: int, AntiAliasingQuality: int, ShadowQuality: int, GlobalIlluminationQuality: int, ReflectionQuality: int, PostProcessQuality: int, TextureQuality: int, EffectsQuality: int, FoliageQuality: int, ShadingQuality: int, LandscapeQuality: int, single_quality_level: int }

get_selected_actors

Read-only.

Read what is selected in the editor viewport/outliner right now: each actor's JSON plus the count and the world it belongs to. Use it to act on "what the user just clicked" without asking for names, and as the read-back for select_actors / deselect_actors. Editor world only, and remember that delete_actor, duplicate_actor, copy_actors and move_actors_to_level all MUTATE the selection as a side effect -- read it before those, not after.

No parameters.

Returns: { selected_actors: [actor JSON], selected_count: int, world_name: string }

get_struct_members

Read-only.

List the members of a user-defined struct (UUserDefinedStruct) with their type, default value, and flags. The reader that pairs with add_struct_member.

Parameter Type Required Description
struct_path string yes Full asset path of the UUserDefinedStruct (e.g. /Game/Blueprints/MyStruct).

Returns: { struct_path: string, member_count: int, members: [ { name: string, var_name: string, guid: string, category: string, sub_category?: string, sub_category_object?: string, container_type: string, default_value: string, current_default_value: string, tooltip?: string, edit_on_instance: bool, save_game: bool } ] }

get_transaction_history

Read-only.

Read the editor's undo buffer as a list, most-recent-first: each entry's title, context, primary object and whether it has already been undone. Use it to answer "what changed the editor recently, and was it me" -- including edits made by the human in the UI -- before you undo anything or blame a tool for a state you did not expect. Pure read; get_undo_state gives the counts-only summary.

Parameter Type Required Description
max_entries number no Max entries to return, newest first (default 50, clamped to 1..500).

Returns: { count: int, entries: [{ queue_index: int, title: string, context: string, is_transient: bool, primary_object: string, is_undone: bool }] }

get_undo_state

Read-only.

One call that answers everything you need before touching undo/redo: both counts, both next-entry LABELS, and whether a transaction is still OPEN (transaction_open -- the thing that silently swallows later edits into someone else's batch). Read this instead of chaining can_undo + can_redo, and read it BEFORE undo/undo_multiple so you know what you are about to revert.

No parameters.

Returns: { can_undo, can_redo, undo_count (entries undo can still revert), redo_count (undone entries redo can restore), next_undo, next_redo, transaction_open, transaction_index }

get_view_type

Read-only.

Read the current view type of the active level editor viewport

No parameters.

Returns: { view_type: string, view_type_index: int }

get_viewport_exposure

Read-only.

Read the current exposure settings of the active editor viewport

No parameters.

Returns: { fixed: bool, ev100: number }

get_viewport_fov

Read-only.

Read the current perspective FOV (in degrees) of the active editor viewport

No parameters.

Returns: { fov: number }

get_viewport_state

Read-only.

Read the active level editor viewport (the focused one, else the first) without changing it: realtime, view mode name and index, camera speed, camera location [x, y, z] and rotation [pitch, yaw, roll], and the Grid, Bounds, Collision, Wireframe and Lighting show flags.

No parameters.

Returns: { realtime: bool, view_mode_index: int, view_mode: string, camera_speed: number, location: [number], rotation: [number], show_flags: object }

high_res_screenshot

Destructive.

Capture a high-resolution (supersampled) screenshot and write it to a PNG SYNCHRONOUSLY. Prefers the Play-In-Editor game view when PIE is active (captured_pie=true); otherwise the active editor viewport. Drives FViewport::TakeHighResScreenShot() + FViewport::Draw(), which renders at resolution_multiplier x the viewport size and blocks (via ProcessScreenShots) until the file is on disk. The "HighResShot" exec path defers the write to the next render frame, which never runs headless, so it writes nothing. Requires a real RHI (errors honestly under -nullrhi) and a live viewport. Note: the supersampled path re-renders the scene, so the UMG/Slate HUD is NOT included; use capture_pie_screenshot for a HUD-inclusive PIE shot.

Parameter Type Required Description
resolution_multiplier number no Resolution multiplier (clamped 1..16, default 2).
filename string no Optional output path; a bare name lands under <ProjectSaved>/Screenshots/, an absolute path is respected verbatim. ".png" is appended if missing. Defaults to a timestamped name.

Returns: { written: bool, file_path: string, resolution_multiplier: int, width: int, height: int, captured_pie: bool }

import_asset

Destructive.

Import an IMAGE file from disk into a content folder as a Texture2D, driving the texture factory inline (it deliberately avoids IAssetTools::ImportAssets, which asserts when re-entered from the engine tick) and returning the created object path. It always overwrites an asset of the same name -- replace_existing is accepted and ignored. Images ONLY -- png/jpg/jpeg/bmp/tga/dds/exr/hdr/tif/tiff/psd/pcx: any other extension is a clean error naming the dedicated handler to use instead (import_texture_file for images, import_sound_file for .wav, import_landscape_heightmap for terrain, interchange_import_asset for FBX/glTF meshes). A missing source file or a destination that is not a /Game long path also errors before anything is touched.

Parameter Type Required Description
source_file_path string yes Absolute path to the image on disk; its existence is checked before any work starts.
destination_path string yes UE long path of the target content folder, e.g. /Game/Imported. Must start with '/'.
replace_existing boolean no ACCEPTED AND IGNORED: the tool reads this flag and never uses it. The underlying import suppresses the overwrite dialog and re-imports over an existing asset of the same name regardless of what you pass, so neither value changes anything.

Returns: { source_file_path: string, destination_path: string, imported_object_paths: [string] }

import_font_file

Destructive.

Import a .ttf/.otf/.ttc/.otc font from disk as a UFontFace, and optionally the companion UFont that a FSlateFontInfo needs to actually render text. This is the only way to get a typeface into the project headlessly: import_asset is images-only on purpose, and nothing else in the toolset touches fonts. Drives UFontFileImportFactory inline (never IAssetTools::ImportAssets, which asserts when re-entered from the engine tick, same reason import_asset avoids it) and ALWAYS sets BatchCreateFontAsset explicitly -- left at its default the factory pops a MODAL DIALOG asking whether to create the UFont, which would hang the editor on a click that is never coming. Once imported, point a widget at it with set_widget_property on the dotted path "Font.FontObject" (a UFont) plus "Font.TypefaceFontName", or "Font.Size" for the size.

Parameter Type Required Description
source_file_path string yes Absolute path on disk to the .ttf/.otf/.ttc/.otc file. A missing file, or any other extension, is a clean error before anything is touched.
destination_path string yes UE long path of the destination content folder, e.g. /Game/MyGame/UI/Fonts.
name string no Optional asset name; defaults to the source file's base name.
create_font_asset boolean no Also create the companion UFont asset (default true). A UFontFace alone is a raw typeface: a FSlateFontInfo's FontObject wants a UFont. Pass false to import only the face, e.g. to add it as another typeface entry of an existing font.

Returns: { source_file_path, destination_path, imported_object_path, font_face_created, create_font_asset, message }

Destructive.

Links a media texture to a media player via SetMediaPlayer

Parameter Type Required Description
media_texture_path string yes Asset path of the UMediaTexture (e.g.
media_player_path string yes Asset path of the UMediaPlayer to bind.

Returns: { media_texture_path, media_player_path, linked, saved, bound_player_path, save_error }

list_automation_tests

Read-only.

List registered automation tests in the editor (read-only; does not run them)

Parameter Type Required Description
filter string no Optional case-insensitive substring matched against the full test path
max_results number no Cap on returned entries (default 500)

Returns: { display_name, full_test_path, test_name, test_tags, test_parameter, source_file, source_file_line, num_participants_required, tests, total_count, matched_count, returned_count, max_results, truncated, filter }

list_cvars

Read-only.

Lists registered console variables whose name contains a substring. Iterates IConsoleManager::Get().ForEachConsoleObjectThatContains(filter), collecting only console variables (commands are skipped), capped at max_results.

Parameter Type Required Description
filter string no Substring filter for cvar names (empty matches all).
max_results number no Cap on results (default 200, min 1).

Returns: { filter: string, cvars: [{name, value, help}], count: int, total_matches: int, max_results: int, truncated: bool }

list_cvars_with_prefix

Read-only.

List console variables and commands whose name starts with prefix (case-insensitive); each entry has its name and, for a variable, its current value. Read-only. Stops at max, so count is what was returned, not the total. For a substring search use search_cvars.

Parameter Type Required Description
prefix string yes Name prefix to match, case-insensitive, e.g. "r.Shadow." or "t.".
max number no Maximum number of entries to return (default 100, minimum 1).

Returns: { count, cvars: [...] }

list_dirty_packages

Read-only.

What is UNSAVED in the editor right now: every dirty package with its disk path, split into map / OFPA-external / asset, and -- the reason to run it -- readonly_dirty_count, the single go/no-go number telling you a vendored root like /Game/VendorPack would be REWRITTEN by the next bulk save. Run it before closing the editor, before compiling, and before any save; it also resolves OFPA hashes to actor labels so /ExternalActors/AB/CD/EF12 becomes a name. Strictly read-only: never marks dirty, never saves. WARNING: it reports IN-MEMORY state only -- a package clean here can still differ from HEAD on disk, so git status stays the disk authority. And do NOT use its pie_active field as the PIE gate: it can answer false with PIE running; the oracle is is_play_in_editor_active.

Parameter Type Required Description
readonly_roots array no Optional array of long-path prefixes treated as vendored/upstream (default: the project's Read Only Content Roots). Only used to CLASSIFY (under_readonly_root / readonly_dirty_count); nothing is ever written. Pass [] to switch the classification off.
path_prefix string no Optional long-path prefix filter, e.g. /Game/VendorPack, to ask "is anything of THEIRS dirty". Empty (default) lists everything; what it excluded is counted in filtered_out.
include_objects boolean no Optional bool (default false). Also list every object carried by each dirty package. One object-hash walk per package -- a dirty map can hold thousands, so leave it off unless you need the contents.

Returns: { dirty_count: int, readonly_dirty_count: int, map_dirty_count: int, external_dirty_count: int, asset_dirty_count: int, filtered_out: int, pie_active: bool, current_world_package: string, path_prefix: string, readonly_roots: [string], readonly_roots_defaulted: bool, packages: [{ package_name: string, file_path: string, exists_on_disk: bool, kind: string, contains_map: bool, newly_created: bool, actor_label: string, actor_name: string, asset_name: string, asset_class: string, under_readonly_root: bool, objects?: [string] }], message: string, note: string }

list_engine_ini_sections

Read-only.

List the section names of one INI in the merged in-memory config (GConfig), like get_engine_ini_value reads it: count, sections, found (false when GConfig does not know that INI) and file_path. Read-only.

Parameter Type Required Description
config_file string no INI base name, e.g. "Engine" (default), "Game", "Input", "Editor", "Scalability"; a trailing ".ini" is dropped.
include_base boolean no Ignored: the code reads it but never uses it, so Base.ini sections are neither added nor removed.

Returns: { count, sections: [string], found: bool, config_file, file_path }

load_level

Destructive.

Open a map in the editor (by /Game path or disk .umap), replacing the current world. Also the repair for actors that VANISHED from a world in memory after compile_blueprint: reloading the same map brings the placed OFPA instances back with their per-instance config -- never re-place them. REFUSES up front when any other UWorld is still resident in memory, because the engine's world-leak check turns that into a Fatal error that kills the editor process and every unsaved edit with it; the refusal lists the resident worlds and the remedy. Run list_dirty_packages first: a reload discards unsaved work.

Parameter Type Required Description
filename string yes Disk path to a .umap, OR a /Game asset path (e.g. /Game/Maps/Foo) resolved to the on-disk map file
load_as_template boolean no When true, loads the level as a template; defaults to false
force boolean no Skip the resident-world preflight and call LoadMap anyway. With resident worlds alive this PROBABLY KILLS THE EDITOR: the engine raises a Fatal error ("World Memory Leaks"), the process dies and every unsaved in-memory edit is lost. Defaults to false.

Returns: { success: bool, error?: string, refused?: bool, load_attempted?: bool, resident_world_count?: int, resident_worlds?: [{ package: string, world_name: string, world_type: string, has_world_context: bool, is_load_target: bool }], remedy?: string, data?: { loaded_filename: string, target_package: string, level_name?: string, world_name?: string, resident_world_count: int, forced_past_resident_worlds: bool, resident_worlds?: [...] } }

migrate_assets

Destructive.

Copy assets, and their dependencies unless ignore_dependencies, into another project's Content folder with IAssetTools::MigratePackages, with no prompt and skipping files that already exist there. The engine first saves every dirty package of this editor, and migrates nothing if one of them fails to save. What was copied is measured from the migration's own package list against the disk: migrated lists each package written (dependencies included), skipped_existing the requested ones the destination already had, failed the requested ones neither written nor skipped. Succeeds when nothing requested failed. destination_path must be a Content folder with a .uproject (or one .uplugin) next to it, or the engine migrates nothing and the call fails.

Parameter Type Required Description
asset_paths array yes Asset object or package paths to migrate (e.g. ["/Game/Props/SM_Crate"]); each is reduced to its package name.
destination_path string yes Target content folder, e.g. D:/OtherProject/Content
ignore_dependencies boolean no When true only the listed packages are copied, without their dependencies (default false).

Returns: { migrated_count: int, failed_count: int, requested_count: int, destination_path: string, ignore_dependencies: bool, migrated: [{ package: string, file: string }], skipped_existing: [string], failed: [string], note: string? }

move_actors_to_level

Destructive, idempotent.

Relocate existing editor-world actors into another sub-level (persistent or a loaded streaming level) -- it rescues actors that got spawned into the wrong level, which set_current_level only prevents going forward. Idempotent: actors already there come back in already_in_level instead of being touched. WARNING: it is clipboard-backed, so the editor SELECTION is mutated as a side effect, and the destination must be loaded AND unlocked. Both levels' packages get dirty: save_level after.

Parameter Type Required Description
actor_names array yes Array of actor names OR editor labels in the editor world (this one does accept labels, unlike delete_actor/batch_delete_actors).
target_level string yes "persistent" or the short name of a loaded streaming sub-level
move_all_or_fail boolean no When true, fail the whole move if any actor cannot be moved; defaults to false

Returns: { requested: int, moved_count: int, already_in_level: [string], target_level: string, success: bool, note: string }

new_level

Destructive.

Loads the ENGINE default template map into the editor. It does NOT create a level and the level is NOT empty (~45 actors: Floor, PlayerStart, DirectionalLight, SkyLight, SkyAtmosphere, fog); level_name is accepted but IGNORED. After this the editor sits on an /Engine map, so a save_level without filename would write over the engine's own .umap. Like load_level it REFUSES to run while other UWorlds are resident in memory, because this is a LoadMap and the engine's world-leak check turns that into a Fatal error that kills the editor process (see force).

Parameter Type Required Description
level_name string no IGNORED. Accepted for wire compatibility only; the loaded map is always /Engine/Maps/Templates/Template_Default. When you pass one, the response echoes it in requested_level_name and sets level_name_ignored=true.
force boolean no Skip the resident-world preflight and call LoadMap anyway. With resident worlds alive this PROBABLY KILLS THE EDITOR: the engine raises a Fatal error ("World Memory Leaks"), the process dies and every unsaved in-memory edit is lost. Defaults to false.

Returns: { success: bool, error?: string, refused?: bool, load_attempted?: bool, requested_filename?: string, target_package?: string, resident_world_count?: int, resident_worlds?: [{ package: string, world_name: string, world_type: string, has_world_context: bool, is_load_target: bool }], resident_world_is_load_target?: bool, remedy?: string, data?: { template_package: string, level_name_ignored: bool, requested_level_name?: string, resident_world_count: int, forced_past_resident_worlds: bool, resident_worlds?: [...], level_name?: string, world_name?: string, loaded_package?: string, is_engine_template?: bool, warning?: string, message?: string } }

open_message_log

Additive, idempotent.

Open or focus the editor Message Log window on one listing (PIE by default), creating the listing empty when it does not exist yet and enabling message log display; no message is changed. opened only says the request was made: without an editor UI nothing shows. module_available says whether the MessageLog module loaded. To read the messages use get_message_log_entries rather than the window; add or empty them with add_message_log_entry and clear_message_log.

Parameter Type Required Description
log_name string no Listing to surface (default "PIE").

Returns: { opened: bool, log_name: string, module_available: bool }

paste_actors

Destructive.

Drop whatever copy_actors left on the editor clipboard into the current level (edactPasteSelected), optionally re-centring the whole group on a world location while KEEPING each actor's relative offset -- that is the point of the copy/paste pair versus duplicate_actor. The pasted actors end up selected and are returned with their new names and transforms. Editor world only; they live in memory until save_level writes the .umap.

Parameter Type Required Description
location array no Optional world point to centre the pasted group on, ARRAY form only [x, y, z] (the group's average is moved there, each actor's offset preserved). Omit to paste where the originals were; a malformed array silently means the origin.

Returns: { pasted_actors: [actor JSON with the new auto-assigned names], pasted_count: int, success: bool }

place_actor_on_terrain

Additive.

Ground an actor on the landscape by sampling the heightmap at its XY (no line trace; traces miss the landscape headless). Sets the actor's Z so either its mesh bbox bottom or its origin sits at the sampled height + z_offset.

Parameter Type Required Description
actor_name string yes Internal name of the actor to place (Actor->GetName())
align string no Optional 'mesh_bbox_bottom' (default; drops the lowest mesh-geometry point onto the ground) or 'actor_origin' (puts the actor origin at the ground)
z_offset number no Optional extra world-Z added above the sampled ground height; defaults to 0

Returns: { actor: actor JSON, landed_z: number (sampled ground world-Z), previous_z: number, new_z: number, sampled_from: 'heightmap', in_bounds: bool, align: string, align_used: string, z_offset: number, landscape_actor_name: string }

Destructive.

Print a message to the Unreal Output Log via UE_LOG(LogTemp, ...).

Parameter Type Required Description
message string yes The text to log.
verbosity string no UE_LOG verbosity: "Log" (default), "Warning", "Error".

Returns: { logged: bool, message: string, verbosity: string }

redo

Destructive.

Re-apply the transaction that undo just reverted and report what remains, including next_redo. WARNING: success is ALWAYS true even with an empty redo stack -- read applied instead. Note the redo stack is discarded as soon as any NEW edit is made after an undo, so a redo that answers applied:false usually means something was changed in between, not that the command failed.

No parameters.

Returns: { applied: bool (THE oracle), undo_count: int, can_redo: bool, next_redo: string (label of the next redoable entry) }

redo_multiple

Destructive.

Re-apply N undone transactions in one call, stopping early when the redo stack runs out rather than erroring. WARNING: compare actually_redone against requested -- that gap is the only honest signal. Remember any new edit made after an undo wipes the redo stack, so this can legitimately redo nothing.

Parameter Type Required Description
count number no How many transactions to redo (>= 1). Silently capped at what the redo stack holds.

Returns: { requested: int (your input), actually_redone: int (compare against it), undo_count: int }

reload_asset_package

Destructive.

Re-read already-loaded packages FROM DISK, non-interactively (it never opens the modal that would freeze a headless editor), either preserving or permanently discarding their in-memory edits. This is the repair for the situation list_dirty_packages flags: a vendored package left dirty by a compile cascade is cleaned with on_dirty="discard" (was_dirty:[...] -> still_dirty:[]), so the next bulk save cannot write it. Also the way to throw away a bad in-memory edit without touching disk. It reports before/after evidence per package, and skips what it cannot safely reload (not loaded, OFPA, worlds) instead of pretending. WARNING: on_dirty="discard" is irreversible for unsaved work -- check what is dirty first.

Parameter Type Required Description
package_names array no Array of long package names (or object paths) to reload, e.g. ["/Game/VendorPack/.../DT_ItemRows"].
package_name string no Convenience single-name alias for package_names.
on_dirty string no Optional "abort" (default) or "discard". "abort" -> EReloadPackagesInteractionMode::AssumeNegative: a package with unsaved in-memory edits is NOT reloaded and its edits are kept. "discard" -> AssumePositive: UPackageTools clears the dirty flag and reloads, PERMANENTLY THROWING AWAY those in-memory edits.

Returns: { requested: [string], on_dirty: string, interaction_mode: string, attempted: [string], reloaded: [string], was_dirty: [string], still_dirty: [string], failed: [string], skipped_not_loaded: [string], skipped_ofpa: [string], skipped_world: [object], skipped_invalid: [object], api_returned: bool, api_error: string, verify: { before: [object], after: [object] }, message: string }

remove_component_from_actor

Destructive.

Detach and destroy one component from an actor PLACED in the level, by component name -- the inverse of add_component_to_actor and, like it, an instance-level edit that does not touch the actor's Blueprint (use remove_component_from_blueprint for the class). Discover the exact component_name with get_actor_components first. Editor world only; dirties the actor's package, so save_level to keep it.

Parameter Type Required Description
actor_name string yes Name of the placed actor (editor world).
component_name string yes Exact component name as reported by get_actor_components.

Returns: { actor_name: string, removed_component: string, component_type: string, success: bool }

remove_enum_entry

Destructive, idempotent.

Remove one enumerator from a Blueprint Enum by display name (or internal name). Idempotent (a missing entry reports already_absent without error); refuses to remove the last remaining entry. The hidden _MAX sentinel is never counted or removable.

Parameter Type Required Description
enum_path string yes Full asset path of the UUserDefinedEnum.
entry_name string yes Enumerator to remove, by display name (or internal name).

Returns: { enum_path: string, entry_name: string, removed: bool, already_absent: bool, entry_count: int }

remove_struct_member

Destructive, idempotent.

Remove a member from a user-defined struct. Idempotent (a missing member reports already_absent without error); the engine refuses to remove the last remaining member (a struct cannot be empty) -- reported as an honest error.

Parameter Type Required Description
struct_path string yes Full asset path of the UUserDefinedStruct.
member_name string yes Member to remove, by its display name (or internal var name).

Returns: { struct_path: string, member_name: string, removed: bool, already_absent: bool, member_count: int }

remove_undo_barrier

Destructive.

Lift the most recent undo barrier so undo can step past it again -- the counterpart of set_undo_barrier, for when the protected batch is finished. WARNING: success is hardcoded true: removed is the oracle and comes back false as an honest no-op when there was no barrier. Use clear_undo_barriers to drop every barrier at once.

No parameters.

Returns: { success: bool (hardcoded), removed: bool (THE oracle -- false = there was nothing to pop), undo_barrier: int now in force, undo_count: int }

rename_enum_entry

Destructive, idempotent.

Rename one enumerator of a Blueprint Enum (UUserDefinedEnum): resolve the entry by its current display name (or internal name) to its index, then set a new display name via FEnumEditorUtils::SetEnumeratorDisplayName. Idempotent: renaming an entry to the name it already has is a no-op success (already_named). An unknown current entry is an honest error; so is a new name that is empty/invalid or duplicates another entry's display name (the engine's IsEnumeratorDisplayNameValid rejects it). The hidden _MAX sentinel is never addressable.

Parameter Type Required Description
enum_path string yes Full asset path of the UUserDefinedEnum (e.g. /Game/Blueprints/MyEnum).
entry_name string yes Enumerator to rename, by its current display name (or internal name).
new_name string yes New display name for the enumerator.

Returns: { enum_path: string, entry_name: string, new_name: string, renamed: bool, already_named: bool, index: int, entries: [string] }

rename_struct_member

Destructive, idempotent.

Rename a member of a user-defined struct by resolving its current display name to its stable VarGuid, then applying the new display name (the same FStructureEditorUtils::RenameVariable path add_struct_member uses to set the initial name). Idempotent: renaming a member to the name it already has is a no-op success (already_named). An unknown current member, or a new name that collides with another member's name, is an honest error.

Parameter Type Required Description
struct_path string yes Full asset path of the UUserDefinedStruct.
member_name string yes Member to rename, by its current display name (or internal var name).
new_name string yes New display name for the member.

Returns: { struct_path: string, member_name: string, new_name: string, renamed: bool, already_named: bool, member: object }

reorder_enum_entry

Destructive.

Move one enumerator to a new position in a Blueprint Enum, shifting the others (e.g. [A,B,C,D] move B->index 2 = [A,C,B,D]). to_index is clamped to the user-entry range (the trailing _MAX sentinel is excluded). An unknown entry is an honest error.

Parameter Type Required Description
enum_path string yes Full asset path of the UUserDefinedEnum.
entry_name string yes Enumerator to move, by display name (or internal name).
to_index number yes Target zero-based position among the user entries.

Returns: { enum_path: string, entry_name: string, from_index: int, to_index: int, moved: bool, entries: [string] }

reset_transaction_buffer

Destructive, idempotent.

IRREVERSIBLE: wipes the editor's ENTIRE undo AND redo history (the human's entries too, not just yours) and drops any open transaction. It does not revert anything -- edits already made stay made, they just stop being undoable. Use only to reclaim memory after a huge batch, or when a corrupt buffer is causing trouble; to undo work use undo/undo_multiple. undo_count_before vs after is the evidence.

Parameter Type Required Description
reason string no Human-readable reason, logged by the engine so the wipe is traceable. Defaults to 'MCP reset_transaction_buffer'.

Returns: { success: bool (hardcoded), undo_count_before: int, undo_count_after: int (0) }

run_automation_test

Destructive.

Run a single automation test by name and return its result (synchronous tests only)

Parameter Type Required Description
test_name string yes The exact registered test name (the "test_name" field from list_automation_tests)

Returns: { test_name, started, completed, passed, verdict, duration_s, errors, warnings, entries:[{type,message,context,filename,line}], entry_count, note }

run_functional_test_in_pie

Destructive.

Start a Play-in-Editor session that runs the named AFunctionalTest BP and return the test verdict. Requires the named BP to exist; it will be auto-added to the current editor world's "PrepareForPIE" list so PIE picks it up. Honest-gated: returns success=false (not an error) if PIE fails to start -- the harness detects a transport drop separately.

Parameter Type Required Description
test_asset_path string yes Path to the AFunctionalTest BP asset (e.g. "/Game/Tests/BP_FT_PlayerHealth").
auto_stop_pie boolean no Optional bool (default true). After the test completes (pass/fail), stop PIE and return the verdict.

Returns: { test_asset_path, pie_started, verdict: "pass"|"fail"|"not_run", pie_stopped, already_in_pie }

run_smoke_tests

Destructive.

Runs every registered automation test with the smoke filter, synchronously in the editor, and returns only the aggregate: ran, all_passed and a note. Under a commandlet the engine skips them, so ran and all_passed come back false. For one test with its log entries use run_automation_test.

No parameters.

Returns: { ran, all_passed, note }

save_asset

Destructive.

Write ONE .uasset to disk by package path (a Blueprint, DataTable, material...) and VERIFY the effect: still_dirty_after_save:false plus file_on_disk:true is the oracle, not saved. Use save_level for the .umap and reload_asset_package to undo an in-memory edit instead. PIE: this is REFUSED while Play-in-Editor runs (it never stops or touches your session) -- the engine guard Editor.AllowSavingAssetsDuringPIE=0 rejects the write before attempting anything, so a save during play would report success without writing a byte. Stop PIE and retry, or pass force=true. WARNING: when it answers success:false with PIE down, a common cause is the file being READ-ONLY on disk (e.g. a Git LFS lockable file that has not been git lfs locked). You do not have to check that by hand: file_read_only is measured on every call and the error message states whether a read-only file IS or is NOT the explanation. WARNING: it writes exactly one package, so it cannot stop a compile cascade from dirtying a vendored asset that a LATER bulk save then rewrites -- list_dirty_packages before, git status after.

Parameter Type Required Description
path string yes Full asset path to save, e.g. /Game/MyGame/Core/BP_MyActor (an .Object suffix is tolerated). Must already exist or the call errors.
readonly_roots array no Optional array of long-path prefixes treated as vendored/upstream (default: the project's Read Only Content Roots). A save under one of them is REFUSED by default; see refuse_readonly. Pass [] to disable the classification entirely.
refuse_readonly boolean no Optional bool. When true, a save whose package falls under one of readonly_roots is REFUSED (success:false, saved:false, refused_readonly:true) instead of performed. Default = the process-wide switch (mcp_common::IsReadOnlyRootSaveEnforcementEnabled(), true unless mcp.ReadOnlyRootEnforcement 0); when false the write happens and is only reported + ledgered.

Returns: { path: string, package_name: string, saved: bool, success: bool, under_readonly_root: bool, readonly_root_matched: string, refused_readonly: bool, readonly_roots: [string], readonly_roots_defaulted: bool, still_dirty_after_save: bool, file_on_disk: bool, file_read_only: bool (measured on disk -- true means the file is read-only, e.g. an unlocked Git LFS `lockable` file), verification: object, verification_checks: [object], error?: string }

save_level

Destructive.

Write the editor's current level (.umap) to disk; it REFUSES while PIE is running (the engine guard rejects the write anyway) and derives success from the file being on disk afterwards, never from the save call's own bool. WARNING: it also REFUSES when the target .umap is READ-ONLY on disk, which in an LFS repo means a lockable path you have not git lfs locked: that write cannot succeed, and answering over HEAD's still-untouched bytes would report success:true having written nothing. The refusal names the file and the fix (git lfs lock <file>) -- take the lock, do not retry. WARNING: on a file that ALREADY existed, file_exists_on_disk alone still cannot tell "I wrote it" from "it was already there": the field that proves the write is file_mtime_changed. It is deliberately NOT gating success, because a save with nothing dirty to write also leaves the mtime alone and that is not a failure. WARNING: with filename this is a SaveAs that DUPLICATES: the editor stays on the old map, the new one becomes a resident world (which then makes load_level refuse), and a SECOND save to the same filename opens a modal that freezes the editor -- treat filename as one-shot per name per session.

Parameter Type Required Description
filename string no Optional. A /Game asset path (e.g. /Game/Maps/Foo) or a disk .umap path; both accepted and resolved. Omit it to save the level in place -- that is the branch that just works. Passing one is a SaveAs: duplicate + resident world + the one-shot rule above.
save_as string no Accepted for wire compatibility and IGNORED: the branch is chosen by whether filename was given. It comes back inside requested to mark it as your input, not a measurement.

Returns: { success: bool, error?: string, data?: { saved_filename?: string, saved_package?: string, saved_disk_path?: string, level_name?: string, file_exists_on_disk: bool, file_size_bytes: int, file_existed_before: bool, file_mtime_changed: bool (the write itself -- see the read-only note above), save_call_returned: bool, rescued_with_save_packages: bool, pie_was_stopped: bool, orphan_world_risk?: bool, requested?: { filename?: string, save_as?: bool } } }

search_cvars

Read-only.

Search console variables and commands whose name contains term (case-insensitive); each hit has its name and, for a variable, its current value. Read-only. Stops at max, so count is what was returned, not the total. For a prefix listing use list_cvars_with_prefix; for one cvar in full, get_cvar.

Parameter Type Required Description
term string yes Substring to search (case-insensitive)
max number no Maximum number of entries to return (default 50, minimum 1).

Returns: { count, cvars: [{name, value?}] }

select_actors

Destructive.

Select actors by name in the editor viewport/outliner, appending to or replacing the current selection, and report which ones were not found. Use it to stage the input for the selection-driven tools (copy_actors with copy_selected, move_actors_to_level) or to show the user what you mean before they look. WARNING: matches INTERNAL names only (no editor labels) and misses are reported in not_found_names instead of failing, so check not_found_count. Editor world only.

Parameter Type Required Description
actor_names array yes Array of internal actor names (GetName), case-insensitive whole-string. Editor labels do NOT resolve here; convert them with find_actors_by_name.
add_to_selection boolean no Optional bool (default TRUE = append to whatever is already selected). Pass false to clear the selection first and end up with exactly these actors.

Returns: { selected_actors: [actor JSON], selected_count: int, not_found_count: int, not_found_names?: [string], add_to_selection: bool }

set_actor_transform

Destructive, idempotent.

Move, rotate and/or scale ONE actor (omitted components are left as they are) and return the actor's re-read transform plus the identity of the world that was written. Undoable, and it calls Modify() first -- which matters, because moving an actor from Python does NOT dirty its OFPA package and then save_level reports success while writing nothing. Takes a world selector, so it also reaches a LIVE PIE pawn (an editor-only lookup would answer "Actor not found" for an actor that exists in another world). Use batch_set_actor_transform for many actors, place_actor_on_terrain to drop one onto the landscape.

Parameter Type Required Description
name string yes Actor's internal name (GetName) or editor label (GetActorLabel), case-insensitive whole-string match.
world string no Optional: "editor" (default) | "pie" | "server" | "client" | "pie:N". In co-op the authoritative pawn lives on the server, and a move written to the client world will be corrected by replication.
location array no Optional new WORLD location, ARRAY form only: [x, y, z]. Absolute, not a delta; an object or a shorter array is silently read as the origin, which teleports the actor to 0,0,0.
rotation array no Optional new WORLD rotation as the array [pitch, yaw, roll] -- note index 2 is ROLL, not yaw -- or, unambiguously, the object {"pitch":..,"yaw":..,"roll":..}, which is the recommended form.
scale array no Optional new WORLD scale, ARRAY form only: [x, y, z]. A malformed value silently becomes 0,0,0 and the actor disappears.

Returns: { actor JSON via DescribeActorObject, transform RE-READ off the actor after the write }

set_allow_cinematic_control

Destructive, idempotent.

Set whether the active level editor viewport (the focused one, else the first) may be possessed by cinematic tools such as Sequencer to preview sequences (FEditorViewportClient::SetAllowCinematicControl). It sets the given value rather than toggling; it lasts for this editor session, nothing is saved or undoable, and no viewport is an error. allows_cinematic_control is read back from the viewport. Read the flag without changing it with get_allow_cinematic_control.

Parameter Type Required Description
allow boolean yes True to allow cinematic control, false to block it

Returns: { applied: bool, requested: bool, allows_cinematic_control: bool }

set_camera_speed

Destructive, idempotent.

Set the camera movement speed of the active level editor viewport (the focused one, else the first). Affects this editor session only and saves nothing. Returns requested and camera_speed, the value read back from the viewport afterwards.

Parameter Type Required Description
speed number yes Camera speed as a positive float; 0 or less is an error. Compare camera_speed in the reply to see what the viewport kept.

Returns: { applied: bool, requested: number, camera_speed: number }

set_current_level

Destructive, idempotent.

Choose which sub-level of the editor world is CURRENT, i.e. where newly spawned or pasted actors will land. Set it before spawn_actor / paste_actors when a map is split into streaming sub-levels, otherwise everything piles into whichever level happens to be active. Errors honestly if the named streaming level is not loaded/visible; already_current:true when it was already the one. Use move_actors_to_level to relocate actors that ended up in the wrong one.

Parameter Type Required Description
level_name string yes "persistent" for the persistent level, or the SHORT name of a loaded, visible streaming sub-level (not a /Game path).

Returns: { current_level: string, changed: bool, already_current: bool, success: true } -- current_level is the level current after the call; a level that is not found, or not loaded and visible, is an error instead.

set_cvar

Destructive, idempotent.

Sets a console variable via IConsoleManager and reads the value back. Uses IConsoleManager::Get().FindConsoleVariable(name)->Set(value, ECVF_SetByConsole). Honest error if the named cvar does not exist (unlike a raw console Exec which silently no-ops).

Parameter Type Required Description
name string yes Console variable name, e.g. "r.ScreenPercentage", "r.Shadow.MaxResolution".
value any yes New value (string, number, or bool; coerced to the cvar's type).

Returns: { set: bool, requested_value: string, name: string, value: string, string_value: string, int_value: int, float_value: float, bool_value: bool, help: string, flags: int, set_by: string }

set_cvars_from_json

Destructive, idempotent.

Apply many cvars in one call. JSON shape: {"name":"value", ...}

Parameter Type Required Description
cvars string yes JSON object string

Returns: { applied, requested, errors: [{name, error}] }

set_engine_ini_value

Destructive, idempotent.

Write one key into the GConfig copy of an INI (Engine by default), flush it to the saved config under Saved/Config/<Platform>/, and verify by reading it back (applied). It does not edit Config/Default*.ini, and objects that already loaded their config are not reloaded.

Parameter Type Required Description
section string yes INI section, e.g. "/Script/Engine.RendererSettings"; created when missing.
key string yes Key inside the section, e.g. "r.DefaultFeature.AntiAliasing"; its current value is replaced.
value string yes Value as text, written verbatim; an empty string is allowed.
config_file string no Config base name without extension, e.g. "Engine" (default), "Game", "Input"; "Engine.ini" is not resolved.

Returns: { applied, section, key, value, readback_value }

set_enum_bitflags

Destructive, idempotent.

Toggle the "bitflags" meta on a Blueprint Enum (UUserDefinedEnum) so its enumerators can be combined as bit flags. Idempotent: re-setting the same state reports already_set with applied=false.

Parameter Type Required Description
enum_path string yes Full asset path of the UUserDefinedEnum (e.g. /Game/Blueprints/MyEnum).
bitflags boolean yes Desired state: true to mark as bitflags, false to clear.

Returns: { enum_path: string, bitflags: bool, already_set: bool, applied: bool }

set_far_clip_plane

Destructive, idempotent.

Override the far clip plane distance on the active editor viewport

Parameter Type Required Description
distance number yes Far clip distance (in cm). Pass 0 to clear the override (use GFarClippingPlane).

Returns: { applied: bool, requested: number, far_clip_plane: number, override_active: bool }

set_game_view

Destructive, idempotent.

Toggle "Game View" mode on the active editor viewport (hides editor-only chrome)

Parameter Type Required Description
enabled boolean yes True to enable game view, false to revert to editor view

Returns: { applied: bool, requested: bool, in_game_view: bool }

set_near_clip_plane

Destructive, idempotent.

Override the near clip plane distance on the active editor viewport

Parameter Type Required Description
distance number yes Near clip distance (in cm). Pass -1 to clear the override (use GNearClippingPlane).

Returns: { applied: bool, requested: number, near_clip_plane: number, override_active: bool }

set_scalability_quality

Destructive, idempotent.

Sets engine scalability quality via the Scalability API and reads it back. Modifies a Scalability::FQualityLevels (starting from the current live state), then applies it with Scalability::SetQualityLevels + ApplyCachedQualityLevels.

Parameter Type Required Description
quality any no Level 0-3(/4) or one of "Low"/"Medium"/"High"/"Epic"/"Cinematic".
category string no Optional category name: "ViewDistance", "AntiAliasing", "Shadows", "GlobalIllumination", "Reflection", "PostProcess", "Texture", "Effects", "Foliage", "Shading", "Landscape", or "all" (default all).

Returns: { set: bool, requested_level: int, category: string, ResolutionQuality: int, ViewDistanceQuality: int, AntiAliasingQuality: int, ShadowQuality: int, GlobalIlluminationQuality: int, ReflectionQuality: int, PostProcessQuality: int, TextureQuality: int, EffectsQuality: int, FoliageQuality: int, ShadingQuality: int, LandscapeQuality: int }

set_show_flag

Destructive, idempotent.

Toggle a single engine show flag on the active editor viewport

Parameter Type Required Description
flag_name string yes Engine show flag name, e.g. Grid, Bounds, Collision, Wireframe, Lighting
enabled boolean yes True to set the flag, false to clear it

Returns: { applied: bool, flag_name: string, flag_index: int, requested: bool, value: bool }

set_struct_member_default

Destructive, idempotent.

Set the default value of a user-defined struct member (read-modify-write; the value is validated against the member's type by the engine, so an incompatible value is an honest error). Idempotent: re-setting the same value is a no-op success.

Parameter Type Required Description
struct_path string yes Full asset path of the UUserDefinedStruct.
member_name string yes Member to edit, by its display name (or internal var name).
default_value string yes New default as a string appropriate to the member's type (e.g. "7", "true", "1.5", "Hello"); pass "" to clear.

Returns: { struct_path: string, member_name: string, default_value: string, applied_default_value: string, already_set: bool, applied: bool, member: object }

set_undo_barrier

Destructive, idempotent.

Drop a floor in the undo stack at the current position so no later undo can cross it -- the way to protect everything done SO FAR (yours or the human's) before starting a risky batch that you may want to unwind. Idempotent: a barrier already sitting at the cursor is not pushed twice (already_existed:true). Lift it with remove_undo_barrier, or clear_undo_barriers for all of them.

No parameters.

Returns: { success: bool (hardcoded), already_existed: bool (true = nothing new was pushed), undo_barrier: int (cursor it sits at), undo_count: int, queue_length: int }

set_view_type

Destructive, idempotent.

Set the active editor viewport type (perspective / top / bottom / left / right / front / back)

Parameter Type Required Description
type string yes View type name. One of: Perspective, Top, Bottom, Left, Right, Front, Back.

Returns: { applied: bool, requested: string, view_type: string, view_type_index: int }

set_viewport_camera

Destructive, idempotent.

Place the camera of the active level editor viewport (the focused one, else the first) at an absolute world location and/or rotation; at least one is required and no viewport is an error. Editor view only, not undoable or saved: a PIE player camera (set_view_target) or a camera actor (set_camera_transform) does not move. location must be an [x, y, z] array of three numbers in cm and rotation three numbers or a roll/pitch/yaw object; anything else is refused before the camera moves. The reply reads location and rotation back, rotation as [pitch, yaw, roll]. Frame an actor with focus_viewport.

Parameter Type Required Description
location array no Optional [x, y, z] world location
rotation array no Optional [pitch, yaw, roll] world rotation

Returns: { applied: bool, location_set: bool, rotation_set: bool, location: [number], rotation: [number] }

set_viewport_exposure

Destructive, idempotent.

Set the exposure of the active level editor viewport: fixed at ev100 when fixed is true, automatic eye adaptation when false. Affects the viewport only and saves nothing. Returns applied, fixed and ev100 as read back; get_viewport_exposure reads them.

Parameter Type Required Description
fixed boolean yes True for fixed exposure (use FixedEV100), false for automatic eye-adaptation
ev100 number yes EV100 value to use when fixed=true (any float; typical range -3..20)

Returns: { applied: bool, fixed: bool, ev100: number }

set_viewport_fov

Destructive, idempotent.

Set the perspective FOV (in degrees) of the active editor viewport

Parameter Type Required Description
fov number yes Field of view in degrees (positive; clamped to 5..170 by editor)

Returns: { applied: bool, requested: number, fov: number }

set_viewport_realtime

Destructive, idempotent.

Enable or disable realtime rendering on the active editor viewport

Parameter Type Required Description
enabled boolean yes True to turn on realtime updates, false to turn them off

Returns: { applied: bool, requested: bool, realtime: bool, effective_realtime: bool, override_active: bool, override_source: string }

set_viewport_view_mode

Destructive, idempotent.

Set the rendering view mode of the active editor viewport

Parameter Type Required Description
view_mode string yes One of Lit, Unlit, Wireframe, DetailLighting, LightingOnly, BrushWireframe, ShaderComplexity, LightComplexity, LightmapDensity, Reflections

Returns: { applied: bool, requested: string, view_mode_index: int, view_mode: string }

show_notification

Destructive.

Show a fire-and-forget toast in the editor (Slate notification manager) with a message, an optional completion state and a lifetime in seconds. Returns shown and echoes message, completion_state and duration; an unrecognized completion_state silently falls back to None. Changes nothing else.

Parameter Type Required Description
message string yes The text to display in the notification.
completion_state string no Completion state, case-insensitive: "None" (default), "Pending", "Success" or "Fail"; any other value counts as "None".
duration number no Notification lifetime in seconds (default 4.0).

Returns: { shown: bool, message: string, completion_state: string, duration: float }

snap_actor_to_ground

Destructive.

Drop ONE editor-world actor straight down until its bounds bottom rests on whatever is below -- meshes, BSP or the landscape. It line-traces first and, because headless traces routinely MISS the landscape, falls back to sampling the heightmap so the actor still lands; sampled_from tells you which path answered. Use place_actor_on_terrain when the ground is definitely the landscape and you want no trace at all, batch_place_actors_on_terrain for many actors.

Parameter Type Required Description
actor_name string yes Name of the actor to snap (editor world).
trace_distance number no Optional downward trace distance in cm; defaults to 10000
align_to_surface boolean no When true, rotate actor to match the surface normal (trace hits only; the heightmap fallback has no normal); defaults to false
fallback_heightmap boolean no When true (default) and the downward line trace misses (headless traces routinely miss the landscape), fall back to sampling the landscape heightmap at the actor's XY (same sampler as place_actor_on_terrain) so the actor still lands. Set false to require a real trace hit.

Returns: { actor: actor JSON, hit: bool, landed: bool, sampled_from: 'trace'|'heightmap', hit_actor?: string, hit_distance?: number }

spawn_actor

Additive.

Place a BUILT-IN engine actor (StaticMeshActor, PointLight, SpotLight, DirectionalLight, CameraActor) into the editor level or a live PIE world, at an optional location/rotation/scale, and return the created actor's JSON. Only these types: for a Blueprint class use spawn_blueprint_actor. Refuses when an actor of that name already exists, and the spawn is undoable. It creates the actor in MEMORY only -- save_level (with the .umap writable) is what puts it on disk. WARNING: with 2+ PIE clients world='pie' can land in the CLIENT world, producing an actor the authority never sees -- ask for world='server' instead, and check the reply's world_package/net_mode to see where the actor actually went.

Parameter Type Required Description
type string yes One of StaticMeshActor, PointLight, SpotLight, DirectionalLight, CameraActor. Anything else is a clean error; Blueprints go through spawn_blueprint_actor.
name string yes Internal name for the new actor; must be unused in the target world or the call is refused.
location array no Optional world location, ARRAY form only: [x, y, z]. An object or a shorter array is silently read as the origin.
rotation array no Optional world rotation as the array [pitch, yaw, roll] -- note index 2 is ROLL, not yaw -- or, unambiguously, the object {"pitch":..,"yaw":..,"roll":..}, which is the recommended form. Defaults to zero.
scale array no Optional world scale, ARRAY form only: [x, y, z]. Defaults to 1,1,1; a malformed value silently becomes 0,0,0 (an invisible actor).
static_mesh string no Optional UStaticMesh asset path, only honoured for type=StaticMeshActor (e.g. /Engine/BasicShapes/Cube).
world string no Optional world selector for WHERE the actor is spawned: absent/'editor' (default) | 'pie' (ambiguous: PlayWorld, else the first PIE context) | 'game' (alias of 'pie') | 'server' (the PIE world with authority -- what you want for anything replicated) | 'client' | 'pie:N'. Case-insensitive; an unrecognised value is a clean error listing the worlds present, never a silent spawn into the editor world.

Returns: { actor JSON via DescribeActorObject: name, class, location, rotation, scale, plus world: string (the normalized selector that resolved), world_name: string, world_package: string (the UEDPIE_N prefix lives HERE), world_type: string, net_mode: string, pie_instance: int }

start_gauntlet_run

Destructive.

Drive the in-process FAutomationTestFramework as the in-editor equivalent of a Gauntlet test run. Gauntlet proper still requires a dedicated subprocess (UnrealEditor-Cmd.exe -Gauntlet=...) that the MCP headless harness cannot spawn, but for the common case of "run a test and report pass/fail" the Automation Framework gives the same verdict from inside the editor. We run synchronously (single game-thread callback) and report the execution info (errors / warnings / duration). Multi-tick tests (PIE / load-map / latent waits) are abandoned honestly with completed=false (StopTest asserts on a non-empty latent queue).

Parameter Type Required Description
test_name string yes Name of the test to run (e.g. "Project.NetworkStress" or any registered automation test).

Returns: { test_name, gauntlet_started: true, gauntlet_subprocess: false, automation_equivalent: true, started, completed, errors, warnings, duration_s, verdict: "pass"|"fail"|"skipped", note }

undo

Destructive.

Step the editor's undo stack back by one transaction and report what is left, including next_undo (the label of the entry now on top). WARNING: success is ALWAYS true, including when there was nothing to undo -- the real oracle is applied, and the honest verification is re-reading whatever you changed. Use undo_multiple for N steps and get_undo_state to look before you leap; an undo barrier will stop it.

No parameters.

Returns: { applied: bool (THE oracle -- false means nothing was undone), undo_count: int, can_undo: bool, next_undo: string (label of the next entry) }

undo_multiple

Destructive.

Walk the undo stack back N transactions in one call, stopping early at the real stack depth (or at an undo barrier) instead of erroring. Use it to unwind a whole failed batch. WARNING: compare actually_undone against requested: a smaller number is the honest signal that the stack ran out, and it is the only oracle here.

Parameter Type Required Description
count number no How many transactions to undo (>= 1). Silently capped at what the stack actually holds.

Returns: { requested: int (your input), actually_undone: int (compare against it), undo_count: int remaining }