unreal-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| unreal_get_statusA | Check whether a running Unreal Editor is reachable, and describe it. Call this first when any other tool fails, to distinguish "the editor is not listening" from "the script had a bug". Discovery is UDP multicast, so an editor that is open but has remote execution disabled will NOT appear. Args: params (StatusInput): Validated input containing: - wait_seconds (float): Discovery listen window, 0.5-15.0 (default 2.0) Returns: str: JSON with the following schema: { "connected": bool, # True if at least one editor answered "node_count": int, # Number of editor instances discovered "nodes": [ # One entry per editor instance { "node_id": str, # Internal session id "user": str, # OS user running the editor "machine": str, # Host name "engine_version": str, # e.g. "5.6.0-..." "engine_root": str, # Engine install path "project_name": str, # Loaded project "project_root": str # Project directory on disk } ], "live_check": { # Present only when connected "engine_version": str, "project_file": str, "current_level": str, "actor_count": int } } On failure: "Error: " Examples: - Use when: another tool returned a connection error and you need the cause - Use when: confirming which project the editor currently has open - Don't use when: you already know the editor is connected and want to run code (use unreal_execute_python instead) |
| unreal_execute_pythonA | Run arbitrary Python inside the running Unreal Editor. This is the general-purpose escape hatch for anything the dedicated tools do not cover. Prefer a specific tool when one exists, because those return structured data while this returns raw console output. The code runs in the editor's own interpreter with full access to the
Args: params (ExecuteInput): Validated input containing: - code (str): Python source to run - evaluate (bool): True for single-expression evaluation (default False) Returns: str: JSON with the following schema: { "success": bool, # False if Unreal reported the command as failed "result": str, # Value for evaluate=True, else Unreal's status string "output": str # Everything the script printed / logged } On failure: "Error: " Examples: - Use when: "how many static meshes are in /Game/Props?" -> code that counts them and prints the number - Use when: calling an unreal API no other tool exposes - Don't use when: listing actors or assets (use unreal_list_actors / unreal_list_assets, which paginate and return structured fields) |
| unreal_list_assetsA | List assets in the project's content browser, with filtering and pagination. Use this to find the object path of an asset before spawning it into a level.
Returns paths in Unreal's Args: params (ListAssetsInput): Validated input containing: - directory (str): Content path to list (default '/Game') - recursive (bool): Recurse into subfolders (default True) - name_filter (Optional[str]): Case-insensitive substring match - limit (int): Max results, 1-500 (default 50) - offset (int): Results to skip (default 0) Returns: str: JSON with the following schema: { "total": int, # Assets matching the filter "count": int, # Assets in this page "offset": int, "has_more": bool, "next_offset": int | None, "items": [ { "name": str, # Asset name (e.g. "SM_Chair") "path": str, # Object path for loading (e.g. "/Game/Props/SM_Chair") "class": str # Asset class (e.g. "StaticMesh", "Material") } ] } On failure: "Error: " Examples: - Use when: "what meshes did my FBX import create?" -> directory of the import - Use when: you need an asset path to pass to unreal_spawn_actor - Don't use when: you want actors placed in the level (use unreal_list_actors) |
| unreal_import_assetA | Import a file from disk (FBX, OBJ, texture) into the project's content browser. Runs Unreal's automated import pipeline, so no import dialog appears. With
Args: params (ImportAssetInput): Validated input containing: - source_file (str): Absolute path to the file on disk - destination_path (str): Content folder, must start with /Game - replace_existing (bool): Overwrite same-named assets (default True) - save (bool): Save to disk right away (default True) Returns: str: JSON with the following schema: { "imported_count": int, # Number of assets created "imported": [str], # Object paths of the new assets "destination": str # Folder they landed in } On failure: "Error: " — including a clear message when the source file does not exist on the machine running the editor. Examples: - Use when: "bring this FBX into Unreal" -> source_file set to the .fbx - Use when: staging a model before placing it with unreal_spawn_actor - Don't use when: the asset is already in the project (use unreal_list_assets) |
| unreal_list_actorsA | List actors placed in the currently open level, with their transforms. The Args: params (ListActorsInput): Validated input containing: - name_filter (Optional[str]): Substring match on the actor label - class_filter (Optional[str]): Substring match on the actor class - limit (int): Max results, 1-500 (default 50) - offset (int): Results to skip (default 0) Returns: str: JSON with the following schema: { "total": int, "count": int, "offset": int, "has_more": bool, "next_offset": int | None, "items": [ { "label": str, # Outliner name, use this as an identifier "path": str, # Unique full path "class": str, # e.g. "StaticMeshActor" "location": [float, float, float], # X, Y, Z in cm "rotation": [float, float, float], # pitch, yaw, roll in degrees "scale": [float, float, float] } ] } On failure: "Error: " Examples: - Use when: "what's in this level?" -> no filters - Use when: finding the exact label to pass to unreal_set_actor_transform - Don't use when: looking for unplaced content (use unreal_list_assets) |
| unreal_spawn_actorA | Place an existing content asset into the current level as a new actor. Each call creates a new actor, so calling it twice spawns two copies. Get
valid Args: params (SpawnActorInput): Validated input containing: - asset_path (str): Content path of the asset to place - location (list[float]): [X, Y, Z] in centimetres (default origin) - rotation (list[float]): [pitch, yaw, roll] in degrees - scale (list[float]): [X, Y, Z] multipliers - label (Optional[str]): Outliner name for the actor Returns: str: JSON describing the created actor: { "label": str, "path": str, "class": str, "location": [float, float, float], "rotation": [float, float, float], "scale": [float, float, float] } On failure: "Error: " — including a clear message when asset_path does not exist. Examples: - Use when: "put the imported chair at the origin" after unreal_import_asset - Don't use when: moving something already in the level (use unreal_set_actor_transform) |
| unreal_set_actor_transformA | Change the location, rotation and/or scale of an actor already in the level. Any field left as None keeps its current value, so this can nudge one axis of a transform without disturbing the rest. Setting the same values twice has no additional effect. Args: params (SetTransformInput): Validated input containing: - actor (str): Label or path identifying the actor - location (Optional[list[float]]): New [X, Y, Z] in cm - rotation (Optional[list[float]]): New [pitch, yaw, roll] in degrees - scale (Optional[list[float]]): New [X, Y, Z] multipliers Returns: str: JSON describing the actor after the change, same schema as unreal_spawn_actor. On failure: "Error: " — including the hint to list actors when the label does not resolve. Examples: - Use when: "raise the camera rig 200 units" -> location with new Z - Don't use when: creating a new copy (use unreal_spawn_actor) |
| unreal_delete_actorA | Permanently remove an actor from the current level. This is destructive. The actor is destroyed in the editor world; recovering
it requires an undo inside Unreal, which this server cannot trigger. Confirm
the intended target with Args: params (DeleteActorInput): Validated input containing: - actor (str): Label or path identifying the actor to destroy Returns: str: JSON confirming the removal: { "deleted": bool, "label": str, # Label of the actor that was destroyed "path": str # Its former path } On failure: "Error: " Examples: - Use when: the user explicitly asks to remove a placed object - Don't use when: you only want to hide it, or when unsure which actor the label refers to (list them first) |
| unreal_set_viewport_cameraA | Move the editor's perspective viewport camera to a specific pose. Affects only the editor view, not any CameraActor in the level and no saved
project data. Pair with Args: params (ViewportCameraInput): Validated input containing: - location (list[float]): Camera position [X, Y, Z] in cm - rotation (list[float]): Camera orientation [pitch, yaw, roll] degrees Returns: str: JSON with the camera pose actually applied: { "location": [float, float, float], "rotation": [float, float, float] } On failure: "Error: " Examples: - Use when: framing a shot before unreal_take_screenshot - Don't use when: you want a camera the level keeps (spawn a CameraActor) |
| unreal_take_screenshotA | Capture a high-resolution screenshot of the editor viewport to a PNG file. Unreal writes the file asynchronously, so the path is returned before the
image is guaranteed to be on disk; allow a moment before reading it. Frame
the shot first with Args: params (ScreenshotInput): Validated input containing: - filename (str): Absolute output path for the PNG - width (int): Width in pixels, 64-7680 (default 1920) - height (int): Height in pixels, 64-4320 (default 1080) Returns: str: JSON confirming the request: { "requested": bool, "filename": str, # Where Unreal was told to write "resolution": [int, int], "note": str # Reminder that the write is asynchronous } On failure: "Error: " Examples: - Use when: producing a visual check of the level after placing actors - Don't use when: you need a final production render (use Movie Render Queue via unreal_execute_python) |
| unreal_save_allA | Save every modified asset, and optionally the open level, to disk. Writes to the project on disk. Running it twice with nothing changed in between is harmless. Args: params (SaveInput): Validated input containing: - save_level (bool): Also save the open level (default True) Returns: str: JSON with the outcome: { "saved": bool, # False if the user cancelled a save prompt "save_level": bool # What was requested } On failure: "Error: " Examples: - Use when: finishing a batch of spawns or imports the user wants kept - Don't use when: the user is still experimenting and may want to discard |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Christancho-co/unreal-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server