Game Simulation
6 tools — 0 typed MCP · 6 via cu CLI.
- Play In Editor (PIE) — 6 tools
Play In Editor (PIE)
Section titled “Play In Editor (PIE)”start_play_in_editor CLI
Section titled “start_play_in_editor ”Launch a Play In Editor session to test gameplay, then capture screenshots and logs at runtime.
@mcp.tool()@showcase( "Launch a Play In Editor session to test gameplay, then capture screenshots and logs at runtime.", featured=True,)def start_play_in_editor(ctx: Context, mode: str = None) -> ToolResult: """[Sim] Start a Play In Editor (PIE) session.
Forces single-process PIE regardless of saved Standalone-Game preferences so ``get_runtime_log`` can see log output (cross-process capture is broken).
Modes: - "floating" (default): new editor window (was the only option pre-mode). - "viewport": run in the active editor viewport — same camera, no window flip. - "simulate": physics only, no PlayerController/PlayerStart. Editor camera stays in control. Use this when you want physics to tick without possessing a player (great for cinematic/demo captures).
Polls until PIE is confirmed running (up to 15 s).
Args: ctx: The MCP context mode: "floating" | "viewport" | "simulate". Default "floating".
Examples: start_play_in_editor() start_play_in_editor(mode="simulate") """ from claude_unreal_server import get_unreal_connection
if mode is None: mode = "floating"
try: unreal = get_unreal_connection() if not unreal: logger.error("Failed to connect to Unreal Engine") return err("Failed to start PIE: no response from Unreal Engine")
response = unreal.send_command("start_pie", {"mode": mode}) if not response: return err("Failed to start PIE: no response from Unreal Engine")
# If already running or error, return immediately result = response.get("result", response) status = result.get("status", "") if status == "already_running": return ok("PIE already running") if status == "error": error_message = result.get("error") or response.get("error") or "unknown error" return err(f"Failed to start PIE: {error_message}", error=error_message)
# Poll get_pie_state until PIE is confirmed running for _ in range(30): # 30 * 0.5s = 15s max time.sleep(0.5) try: poll = unreal.send_command("get_pie_state", {}) if poll: poll_result = poll.get("result", poll) if poll_result.get("running", False): return ok("Started PIE session") except Exception: pass # Connection hiccup during PIE startup, keep polling
return err("Failed to start PIE: did not start within 15s", error="timeout")
except Exception as e: logger.error(f"Error in start_play_in_editor: {e}") return err("Failed to start PIE", error=str(e))stop_play_in_editor CLI
Section titled “stop_play_in_editor ”get_pie_state CLI
Section titled “get_pie_state ”take_screenshot_pie CLI
Section titled “take_screenshot_pie ”get_runtime_log CLI
Section titled “get_runtime_log ”inject_enhanced_input_action CLI
Section titled “inject_enhanced_input_action ”Inject an Enhanced Input action into a running PIE session for autonomous UI/input testing.
@mcp.tool()@showcase( "Inject an Enhanced Input action into a running PIE session for autonomous UI/input testing.",)def inject_enhanced_input_action( ctx: Context, action_name: str, value: bool = None, player_index: int = 0,) -> ToolResult: """[Sim] Inject an Enhanced Input action into the running PIE session.
Routes through UEnhancedPlayerInput::InjectInputForAction. PIE must be running. value=True presses, False releases. Always pair both — omitting release leaves trigger "held". Non-Boolean actions unsupported.
Anti-patterns: no PIE → error; "Key" console bypasses Enhanced Input; value=None → validation error.
Example: inject_enhanced_input_action("IA_ToggleInventory", value=True) inject_enhanced_input_action("IA_ToggleInventory", value=False) """ from claude_unreal_server import get_unreal_connection
if value is None: return err( "'value' is required (Boolean — True=press, False=release)", error="missing_value", )
try: unreal = get_unreal_connection() if not unreal: logger.error("Failed to connect to Unreal Engine") return err("Failed to inject input: no response from Unreal Engine")
response = unreal.send_command( "inject_enhanced_input_action", { "action_name": action_name, "value": value, "player_index": player_index, }, ) if not response: return err("Failed to inject input: no response from Unreal Engine") if response.get("status") == "error": return err( "Failed to inject input", error=response.get("error", "Unknown error"), ) result = response.get("result", response) return ok(result.get("message", "Injected input action"), **result)
except Exception as e: logger.error(f"Error in inject_enhanced_input_action: {e}") return err("Failed to inject input", error=str(e))