Skip to main content
Glama

o3de-mcp

License

Automate Open 3D Engine (O3DE) with AI, an MCP server for editor control, project & build management.

See the architecture documentation for a detailed system diagram and communication flow.

Features

96 tools across seven categories. See docs/tool-reference.md for every parameter.

Capability Detection (1 tool):

  • get_capabilities: check editor connectivity, whether the AiCompanion gem's AgentServer is answering (with its gem, API and protocol versions), and CLI availability before using other tools

  • Dynamic tool discovery: new tools are automatically reported

Editor Automation (41 tools, requires a running O3DE Editor with the AiCompanion + EditorPythonBindings gems):

  • Execute arbitrary Python scripts inside the editor (azlmbr API)

  • Scene snapshot, entity tree, single entity and scene validation served natively by the AiCompanion gem's C++ (get_scene_snapshot / get_entity_tree / get_entity / validate_scene), no editor Python involved, available even in the gem's secure mode

  • List, create, delete, and duplicate entities; reparent with set_parent

  • Add and remove components, get/set component properties, assign assets by path

  • Get and set transforms

  • create_entity, set_transform and delete_entity try the gem's native request types first (gem 0.5.0 or later, validated in C++, available in secure mode) and fall back to editor Python on older gems or the legacy transport

  • Create and instantiate prefabs (saving edits back into an existing prefab is not exposed to editor Python; save_prefab reports that and names the owning prefab)

  • Create, load, save, and query levels

  • Viewport camera control, entity focus, and screenshot capture

  • Run console commands, get/set CVARs

  • Enter/exit game mode, undo/redo

  • Persistent scripting sessions (begin_session / exec_in_session / get_session_vars / end_session) that keep Python state alive across calls

  • Fast-fail when editor is unreachable (avoids repeated timeouts)

Engine Introspection (3 tools):

  • EBus schema discovery, both from generated azlmbr stubs and live from the editor

  • RenderDoc frame capture (on O3DE 26.10.0 the editor does not expose it to Python, so the tool reports the manual steps)

Project & Build Management (17 tools, CLI-based, no editor required):

  • Discover local O3DE engine installations (multi-engine support), register engines, select the active one

  • List registered projects, gems, and available templates

  • Create projects and gems from templates

  • Register, enable, and disable gems

  • Edit project properties

  • Build projects via CMake, either blocking (build_project) or in the background (start_build / get_build_status)

  • Export projects for distribution

Asset Pipeline (9 tools; 5 need no editor):

  • Asset Processor status, asset refresh (AssetProcessorBatch), and waiting for an Asset Processor run to exit

  • Tail editor and Asset Processor logs, filter for errors

  • With the editor running (AiCompanion gem 0.6.0+): one asset's build status, its jobs with failure logs, and wait_for_asset, which waits until a specific asset is built or reports why it failed

Track View (8 tools, requires a running editor):

  • Cinematic sequence authoring: create, list, describe, and delete sequences; set a sequence's time range

  • Add nodes (Director, Event, entity, component) and control playback (play, stop)

  • Editor Python over azlmbr.legacy.trackview, no gem needed. Track and keyframe authoring are not exposed (the reflected API makes them unreliable to drive)

Animation (17 tools, requires a running editor):

  • List the EMotion FX anim graphs the engine holds and describe one in full: nodes, ports and connections, transitions with conditions, parameters

  • Author anim graphs: create, load, save and remove graphs; add, edit and remove nodes (state machines, motion nodes, blend trees); set a state machine's entry state; add and remove parameters

  • Wire them: transitions between states with conditions (parameter, time, play time, motion, state, tag, vector), and blend-tree port connections

  • Native requests through the AiCompanion gem (gem 0.6.0+, plus the EMotionFX gem); they work in the gem's secure mode

Related MCP server: mcp-bridge

Prerequisites

  • Python 3.10+

  • O3DE installed and registered (engine path in the O3DE manifest or O3DE_ENGINE_PATH env var)

    • Linux/macOS: ~/.o3de/o3de_manifest.json

    • Windows: %USERPROFILE%\.o3de\o3de_manifest.json

  • For editor tools (optional): O3DE Editor running with the o3de-ai-companion-gem and EditorPythonBindings gems enabled. The companion gem provides the AgentServer that o3de-mcp connects to for real-time editor automation. Project tools work without the editor; call get_capabilities() to check what's available.

Installation

pip install o3de-mcp

Or run it without installing, straight from an MCP client config, with uv:

uvx o3de-mcp

To work on o3de-mcp itself, install from a checkout instead:

pip install -e .        # or: uv pip install -e .

Usage

As a standalone MCP server

o3de-mcp

With Claude Code

Add to your MCP config (or use a project-level .mcp.json):

  • Linux/macOS: ~/.claude/mcp.json

  • Windows: %USERPROFILE%\.claude\mcp.json

{
  "mcpServers": {
    "o3de": {
      "command": "o3de-mcp"
    }
  }
}

Agent skill: headless verification and editor automation

skills/o3de-headless-and-editor-automation/ is an Agent Skill (a SKILL.md plus reference notes and scripts) that teaches an agent the repeatable workflow around this server on Windows and Linux: AssetProcessor-first launch order and how to tell when it is idle, rendering a level on the real GPU and capturing it with ffmpeg (Xvfb when there is no monitor), in-renderer screenshots from editor Python, driving the editor through o3de-mcp and the AiCompanion gem, wiring asset GUIDs into prefab JSON offline, and proving engine changes with a ScriptContext test. It records the traps that cost hours (the prefab segfault on a missing template, killing your own shell by command-line pattern, the AP idle line living in AP_GUI.log). The Linux path has been run end to end; the Windows path is written from the engine layout and still needs a run on a Windows machine.

Install it by copying or symlinking the directory into your skills folder, then invoke it with /o3de-headless-and-editor-automation:

ln -s "$(pwd)/skills/o3de-headless-and-editor-automation" ~/.claude/skills/

Other clients that read the Agent Skills layout can point at the same directory.

With Claude Desktop

Add to your Claude Desktop config:

{
  "mcpServers": {
    "o3de": {
      "command": "o3de-mcp"
    }
  }
}

Testing with MCP Inspector

MCP Inspector provides a web UI for interactively testing tools without an AI assistant. Useful for verifying tool behavior, inspecting responses, and debugging.

npx @modelcontextprotocol/inspector o3de-mcp

This opens the Inspector UI at http://localhost:6274. From there you can browse all registered tools, invoke them with custom parameters, and see raw responses.

To pass environment variables (e.g., a custom engine path or editor port):

npx @modelcontextprotocol/inspector -e O3DE_ENGINE_PATH=/path/to/engine -e O3DE_EDITOR_PORT=4600 o3de-mcp

Development

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run a single test
pytest tests/test_project.py::TestValidateName::test_valid_simple

# Lint and format
ruff check src/ tests/
ruff format src/ tests/

# Type checking
mypy src/

SBOM (Software Bill of Materials)

A CycloneDX SBOM is generated on every CI run and uploaded as a build artifact. To generate one locally:

python scripts/generate-sbom.py              # JSON + XML
python scripts/generate-sbom.py --format json # JSON only

The script creates an isolated virtual environment with only runtime dependencies, so the SBOM accurately reflects what ships, without the dev and build tooling.

CI

GitHub Actions runs lint, type checking, tests, and SBOM generation on every push and PR to main. See .github/workflows/ci.yml.

Security

  • Editor tool inputs (entity IDs, component types) are validated against strict regex patterns before use.

  • User-supplied strings are serialized via json.dumps / json.loads when passed into editor scripts, never raw string interpolation.

  • Project and gem names are validated against O3DE naming conventions.

  • Filesystem paths are resolved and validated before being passed to subprocesses.

Documentation

Document

Audience

Description

AGENTS.md

AI agents

Token-efficient usage guide, decision trees, error handling

docs/architecture.md

Developers & agents

System architecture diagram and communication flows

docs/tool-reference.md

Agents & developers

Compact parameter reference for all 96 tools

docs/recipes.md

Agents & developers

Composable patterns for scenes, physics, lighting, scripting

docs/components.md

Agents & developers

O3DE component name catalog with dependency chains

skills/o3de-headless-and-editor-automation/

AI agents

Installable skill (Windows and Linux): render capture, editor automation, offline asset GUIDs, ScriptContext proofs, and the traps around each

Examples

Progressive walkthroughs from project creation to a complete game:

  1. New Project: create, configure, and build a project

  2. Build a Scene: sky, lights, ground, camera, static objects

  3. Physics Playground: dynamic bodies, triggers, stacking

  4. Scripted Game: complete mini-game with player, obstacles, goals

  5. Batch Operations: efficient bulk entity creation patterns

  6. CLI-Only Workflow: project management without the editor

  7. Gem Development: create and integrate custom gems

  8. MCP Inspector: interactively test tools via a web UI

Configuration

Environment Variable

Description

Default

O3DE_ENGINE_PATH

Override automatic engine discovery

Auto-detected from manifest

O3DE_ENGINE_NAME

Select engine by name when multiple are registered

First valid engine

O3DE_PROJECT_PATH

Select the project for asset, introspection and list_levels tools

Single registered project

O3DE_EDITOR_HOST

Editor AgentServer host

127.0.0.1

O3DE_EDITOR_PORT

Editor AgentServer port

4600

O3DE_EDITOR_TIMEOUT

Per-command editor execution timeout (seconds)

600

O3DE_EDITOR_CONNECT_TIMEOUT

Editor TCP connect timeout (seconds)

5

O3DE_CAPTURE_WAIT

How long to wait for a viewport capture to reach disk (seconds)

15

O3DE_EDITOR_TLS

Wrap the editor connection in TLS (1 or true to enable)

0 (disabled)

O3DE_EDITOR_TLS_VERIFY

Verify the editor's certificate and hostname

0 (disabled)

O3DE_EDITOR_TLS_CA

CA bundle used when verification is enabled

System defaults

O3DE_CMAKE_GENERATOR

CMake generator for builds

Auto-detected per platform

O3DE_CONFIGURE_TIMEOUT

CMake configure timeout (seconds)

600

O3DE_BUILD_TIMEOUT

CMake build timeout (seconds)

1800

O3DE_EXPORT_TIMEOUT

Project export timeout (seconds)

3600

Editor timeouts: the editor runs each submitted script synchronously and does not reply until it finishes, so O3DE_EDITOR_TIMEOUT is effectively "how long an editor operation may take." It defaults to 600s because real operations (level loads, game-mode entry, on-demand asset compilation) routinely exceed tens of seconds, and a too-short value cuts them off while the editor is still working. An unreachable editor is caught in milliseconds by the separate O3DE_EDITOR_CONNECT_TIMEOUT and the fast-fail window, so a large command timeout costs nothing on the healthy path. run_editor_python also accepts a per-call timeout argument.

Editor TLS: the connection is plaintext by default, which is the right default for the normal case of an editor on 127.0.0.1. If you point O3DE_EDITOR_HOST at a remote machine, set O3DE_EDITOR_TLS=1 and O3DE_EDITOR_TLS_VERIFY=1. Enabling TLS on its own leaves certificate and hostname checking off, which encrypts the channel but does not authenticate the peer.

The server also reads the O3DE manifest for registered engines, projects, and gems:

  • Linux/macOS: ~/.o3de/o3de_manifest.json

  • Windows: %USERPROFILE%\.o3de\o3de_manifest.json

License

This project is dual-licensed under Apache 2.0 or MIT (your choice), matching the O3DE engine license. Free for commercial and non-commercial use.

SPDX-License-Identifier: Apache-2.0 OR MIT

Available Tools

96 tools
add_anim_graph_nodeA

Add a node to an anim graph.

Returns the new node object exactly as get_anim_graph emits it. An unknown node_type is refused with the list of known types.

Args: anim_graph_id: Graph id (number or digit string). node_type: RTTI or palette name, case-insensitive (for example AnimGraphMotionNode, AnimGraphStateMachine, BlendTree, BlendTreeBlend2Node). parent_id: Parent node id (a state machine or blend tree). Defaults to the root state machine. name: Node name. The engine generates one when omitted. position: [x, y] graph-canvas position in integer pixels.

Inputs: node_type (required), anim_graph_id (required), name, position, +1 more. Returns: result

add_anim_graph_parameterA

Add a value parameter to an anim graph.

Returns the parameter object as get_anim_graph emits it. The gem checks each value against the type; min and max are only valid for ranged types (Float, Int, Vector2/3/4, Color, Rotation).

Args: anim_graph_id: Graph id (number or digit string). name: Parameter name. parameter_type: Float (a FloatSlider), FloatSpinner, Int (an IntSlider), IntSpinner, Bool, String, Tag, Vector2, Vector3, Vector3Gizmo, Vector4, Color, Rotation, or the full class name. default: Default value: a number, bool, string, or a list of numbers for vector, color and rotation types. min: Range minimum (ranged types only). max: Range maximum (ranged types only). description: Optional description. group: Group to put the parameter in; created when missing.

Inputs: name (required), anim_graph_id (required), parameter_type (required), max, +4 more. Returns: result

add_anim_graph_transitionA

Add a state-machine transition, optionally with conditions.

Returns the transition object as get_anim_graph emits it. Source and target must share a state-machine parent; an exit node cannot be a source. All conditions are added as one Animation Editor undo step.

Args: anim_graph_id: Graph id (number or digit string). target_node_id: The state to transition to. source_node_id: The state to transition from. Required unless wildcard is true. wildcard: True for a wildcard transition (from any state). Then omit source_node_id. blend_time: Blend time in seconds, 0 or more. priority: Higher wins when several transitions are ready (0 to 2**32-1). disabled: Create the transition disabled. sync_mode: 0 disabled, 1 track based, 2 clip based. interpolation: 0 linear, 1 ease curve. conditions: List of {"condition_type": ..., "attributes": {...}}. Types: ParameterCondition, TimeCondition, PlayTimeCondition, MotionCondition, StateCondition, TagCondition, Vector2Condition (or the RTTI name). For example {"condition_type": "ParameterCondition", "attributes": {"parameterName": "Speed", "function": "GREATER", "testValue": 0.1}}. Enum attributes take the integer or the name; an unsupported attribute is refused with the supported list.

Inputs: anim_graph_id (required), target_node_id (required), disabled, priority, +6 more. Returns: result

add_componentA

Add a component to an entity.

Args: entity_id: The entity ID to add the component to. component_type: Component type name (e.g. 'Mesh', 'PhysX Dynamic Rigid Body').

Inputs: entity_id (required), component_type (required). Returns: result

add_sequence_nodeA

Add a node to a Track View sequence.

Add a Director node first; most other node types need a Director present.

Args: name: Sequence name. node_type: One of Director, Event, AzEntity, Component, CVar, Material, Group, Layer, Comment. node_name: Name for the new node.

Inputs: name (required), node_name (required), node_type (required). Returns: result

assign_assetA

Assign an asset to a component property by resolving the asset path.

asset_path is the product path in the asset catalog (for example objects/thing.fbx.azmodel). The property is read back after setting, and only an assignment that holds is reported as done; an unknown asset, component or property, or a value that does not stick, is returned as an error.

Inputs: entity_id (required), asset_path (required), property_path (required), component_type (required). Returns: result

begin_sessionA

Begin a persistent Python session in the O3DE editor.

Inputs: no named parameters. Returns: result

build_projectB

Build an O3DE project using CMake.

This runs CMake configure followed by CMake build. Timeouts are configurable via O3DE_CONFIGURE_TIMEOUT and O3DE_BUILD_TIMEOUT environment variables.

Args: project_path: Path to the O3DE project. config: Build configuration -- profile, debug, or release (default: profile).

Inputs: project_path (required), config. Returns: result

capture_renderdoc_frameA

Trigger a RenderDoc frame capture in the O3DE editor.

Attempts to trigger a RenderDoc capture via GraphicsProfilerBus. That bus is not exposed to editor Python on O3DE 26.10.0, so there the tool returns manual_required with the manual alternatives (F12 in RenderDoc, or the editor's GPU capture menu).

Returns: JSON with status ok if the capture was triggered, error on failure, or manual_required if the Python API cannot trigger the capture and manual action is needed.

Inputs: no named parameters. Returns: result

capture_viewportA

Capture a screenshot of the editor viewport.

Captures the rendered frame with Atom's FrameCaptureRequestBus.CaptureScreenshot, then waits on the client for a new, fully written file (O3DE_CAPTURE_WAIT, default 15 s). A level must be open: without one the engine accepts the capture and never writes a file, which is reported as capture_not_written. A PySide6 widget grab is tried first, but it cannot run in the editor's embedded interpreter on O3DE 26.10.0 (QApplication.instance() is None).

Args: output_path: File path for the screenshot (.png, .jpg, .jpeg, .bmp, or .tga). width: Scale width for the PySide6 grab only; ignored by the Atom capture, so it has no effect on 26.10.0. height: Scale height for the PySide6 grab only; ignored like width.

Inputs: output_path (required), width, height. Returns: result

connect_anim_graph_portsA

Connect an output port to an input port (blend trees).

Returns the target node's input port object. Refused: a target inside a state machine (use add_anim_graph_transition), incompatible port types, an occupied input, a duplicate, and a cycle. An unknown port name is refused with the node's ports listed as "name" (index).

Args: anim_graph_id: Graph id (number or digit string). source_node_id: Node whose output to connect. source_port: Output port index or name. target_node_id: Node whose input to connect. target_port: Input port index or name.

Inputs: source_port (required), target_port (required), anim_graph_id (required), source_node_id (required), +1 more. Returns: result

create_anim_graphA

Create a new, empty, in-memory EMotion FX anim graph to author.

Returns {"id": <graph id>, "file_name": ""}. The graph starts with only its root state machine. Save it with save_anim_graph; remove it with remove_anim_graph.

Inputs: no named parameters. Returns: result

create_entityA

Create a new entity in the current O3DE level.

Tries the AiCompanion gem's native create_entity request first (gem 0.5.0 or later, works in the gem's secure mode) and returns its JSON verbatim: {"entity_id": ..., "name": ..., "position": [...]}. The name is checked here with the gem's own rule (a letter first, then letters, digits, _ or -, at most 128 characters) before either path, and the gem validates the parent; a refusal is returned as an error. Older gems and the legacy transport fall back to editor Python, which prints Created entity [<id>].

Args: name: Name for the new entity. parent_id: Optional entity ID of the parent. Omit (or pass null) for root-level.

Inputs: name (required), parent_id. Returns: result

create_gemB

Create a new O3DE gem.

Args: name: Gem name (alphanumeric, hyphens, underscores). path: Directory where the gem will be created. template: Gem template to use (default: DefaultGem).

Inputs: name (required), path (required), template. Returns: result

create_levelA

Create a new level in the current O3DE project and open it in the editor.

Args: name: Level name (alphanumeric, hyphens or underscores, starting with a letter). The level is written to <project>/Levels/<name>/. template: Level template prefab, as a path relative to an asset scan folder. Defaults to the editor's own New Level default, Prefabs/Default_Level.prefab (camera, sun, grid). Pass an empty string for a bare level with no entities.

Inputs: name (required), template. Returns: result

create_prefab_from_entityA

Write a prefab file to disk from an existing entity.

The path is relative to the project root. The level is not modified; use instantiate_prefab afterwards to place the saved prefab.

Inputs: entity_id (required), prefab_path (required). Returns: result

create_projectA

Create a new O3DE project.

Args: name: Project name (alphanumeric, hyphens, underscores). path: Directory where the project will be created. template: Project template to use (default: DefaultProject).

Inputs: name (required), path (required), template. Returns: result

create_sequenceA

Create a new Track View cinematic sequence in the current level.

Creates a modern Sequence Component sequence (on its own entity). A new sequence has no nodes; add a Director node with add_sequence_node before adding other nodes. An existing name is reported as an error.

Args: name: Sequence name.

Inputs: name (required). Returns: result

delete_entityA

Delete an entity from the current O3DE level.

Tries the gem's native delete_entity request first (gem 0.5.0 or later, works in secure mode) and returns its JSON verbatim: {"deleted": <id>}. A missing entity or the level's root entity is refused by the gem and returned as an error. Older gems and the legacy transport fall back to editor Python, which prints Deleted entity [<id>].

Args: entity_id: The entity ID to delete.

Inputs: entity_id (required). Returns: result

delete_sequenceC

Delete a Track View cinematic sequence from the current level.

Args: name: Sequence name.

Inputs: name (required). Returns: result

disable_gemB

Disable a gem in an O3DE project.

Args: gem_name: Name of the gem to disable. project_path: Path to the project.

Inputs: gem_name (required), project_path (required). Returns: result

disconnect_anim_graph_portsA

Remove the connection feeding an input port.

Returns {"removed": "<connection id>"}; a free port is not_found.

Args: anim_graph_id: Graph id (number or digit string). target_node_id: Node whose input to free. target_port: Input port index or name.

Inputs: target_port (required), anim_graph_id (required), target_node_id (required). Returns: result

duplicate_entityA

Duplicate an entity (and its children) in the current O3DE level.

Args: entity_id: The entity ID to duplicate.

Inputs: entity_id (required). Returns: result

edit_project_propertiesB

Edit properties of an existing O3DE project.

Args: project_path: Path to the project. project_name: New name for the project (optional). origin: New origin URL or description (optional).

Inputs: project_path (required), origin, project_name. Returns: result

enable_gemC

Enable a gem in an O3DE project.

Args: gem_name: Name of the gem to enable. project_path: Path to the project.

Inputs: gem_name (required), project_path (required). Returns: result

end_sessionB

End a persistent Python session and clean up its namespace.

Inputs: session_id (required). Returns: result

enter_game_modeA

Enter game mode (play-in-editor) in the O3DE Editor.

Inputs: no named parameters. Returns: result

exec_in_sessionB

Execute Python code in a persistent session.

Inputs: script (required), session_id (required). Returns: result

exit_game_modeA

Exit game mode and return to edit mode.

Inputs: no named parameters. Returns: result

export_projectA

Export an O3DE project for distribution.

This is a long-running operation. Timeout is configurable via the O3DE_EXPORT_TIMEOUT environment variable (default: 3600s).

Args: project_path: Path to the O3DE project to export. output_path: Directory where the exported project will be written. config: Build configuration -- profile, debug, or release (default: profile).

Inputs: output_path (required), project_path (required), config. Returns: result

focus_entityB

Focus the viewport camera on an entity.

Inputs: entity_id (required). Returns: result

get_anim_graphA

Describe one EMotion FX anim graph in full.

Returns the gem's JSON: nodes (with type, parent, position, ports and connections; state machines also carry entry_state_id), transitions (with blend time and conditions), parameters, node_groups and the root_state_machine_id. Pass exactly one selector. An unknown graph is returned as an error. Needs the AiCompanion gem's native request (gem 0.6.0+) and the EMotionFX gem.

Args: anim_graph_id: Graph id from list_anim_graphs (number or digit string). file_name: Graph file name, matched exactly first, then by its tail case-insensitively (for example Character.animgraph).

Inputs: file_name, anim_graph_id. Returns: result

get_asset_jobsA

List the Asset Processor jobs for one source file, with failure logs.

Returns {"source_path", "jobs": [{"job_key", "platform", "builder", "status", "error_count", "warning_count", "job_run_key", "source_file", "watch_folder", "log"?, "truncated"?}]} with status one of queued, in_progress, failed, completed or missing. A source the Asset Processor has not registered answers the error code engine_error. Needs the AiCompanion gem 0.6.0+; works in secure mode.

Args: source_path: The source file, relative to the project or a full path. escalate: Move the file's queued jobs to the front of the queue. include_logs: Attach each failed job's log (cut at 64 KB).

Inputs: source_path (required), escalate, include_logs. Returns: result

get_asset_processor_connectionA

Report whether the editor is connected to the Asset Processor.

Returns {"connected", "ping_ms"}. Unlike get_asset_processor_status, which checks for the process on this machine without the editor, this asks the editor itself. Needs the AiCompanion gem 0.6.0+.

Inputs: no named parameters. Returns: result

get_asset_processor_statusB

Check whether the O3DE Asset Processor is running.

Inputs: project_path. Returns: result

get_asset_statusA

Ask the Asset Processor, through the editor, for one asset's build status.

Returns {"path", "status", "connected"} with status one of unknown, missing, queued, compiling, compiled or failed (plus query_path when the gem rewrote the path). The query also escalates the asset in the build queue. A source whose build failed has no products and answers missing; use get_asset_jobs or wait_for_asset to tell that apart from a file not registered yet. Needs the AiCompanion gem 0.6.0+; works in secure mode.

Args: path: A source or product path, relative to the project, or a full path. flush_io: Flush the file monitor first. Use right after writing the file.

Inputs: path (required), flush_io. Returns: result

get_build_statusA

Check the status of a background build.

Args: build_id: Build ID returned by start_build.

Inputs: build_id (required). Returns: result

get_bus_schemaB

Discover the scripting API of any O3DE gem's reflected EBuses.

Inputs: bus, module, project_path. Returns: result

get_bus_schema_liveB

Query the running editor's BehaviorContext for a bus schema.

Tries the AiCompanion gem's native get_bus_schema request first (gem 0.4.0 or later): it reads the live C++ reflection and includes each event's argument names and tooltips, which the Python bindings do not expose, and it works in the gem's secure mode. Older gems, the legacy RemoteConsole transport, or an unknown bus fall through to the editor-Python query, and that in turn falls back to the stub files.

Inputs: bus (required), module (required), project_path. Returns: result

get_capabilitiesA

Check what O3DE MCP capabilities are currently available.

Call this first to determine whether the editor is connected (for editor tools) and whether the O3DE CLI is available (for project tools). This avoids wasting tokens on tools that will fail.

Tool categories are discovered dynamically — any new tools added to the server will automatically appear in the response.

Returns: JSON object with editor, cli, and tool_categories sections describing current availability and configuration.

Inputs: no named parameters. Returns: result

get_component_propertyA

Get a property value from a component on an entity.

Args: entity_id: The entity ID. component_type: Component type name (e.g. 'Transform'). property_path: Property path using '|' separator (e.g. 'Controller|Configuration|Model Asset').

Inputs: entity_id (required), property_path (required), component_type (required). Returns: result

get_cvarB

Get the value of an O3DE console variable (CVAR).

Inputs: name (required). Returns: result

get_engine_infoA

Get information about the local O3DE engine installation.

Returns: JSON object with engine metadata, or an error message if no engine is found.

Inputs: no named parameters. Returns: result

get_entityA

Return one entity's name, transform, parent and component list as JSON.

Served natively by the AiCompanion gem's C++ (get_entity request type, gem 0.4.0 or later) with no editor Python, so it is the cheapest way to look at a single entity and works in the gem's secure mode. On gem 0.6.0 the reply also carries non_uniform_scale and effective_scale, and ids are decimal strings. An unknown id is the error not_found (gem 0.5.0 and earlier answered with the gem's own {"entity_id": ..., "error": ...} object instead).

Inputs: entity_id (required). Returns: result

get_entity_componentsA

List all components attached to an entity.

Args: entity_id: The entity ID to inspect.

Returns: JSON array of objects with 'component_id' and 'type' fields.

Inputs: entity_id (required). Returns: result

get_entity_treeA

Return the entity hierarchy as a nested JSON tree.

Served natively by the AiCompanion gem, without editor Python.

Inputs: no named parameters. Returns: result

get_level_infoA

Get information about the currently loaded level.

Returns: JSON object with 'level_name' and 'level_path' fields.

Inputs: no named parameters. Returns: result

get_log_errorsC

Extract error lines from an O3DE log file.

Inputs: log_name, since_lines, project_path. Returns: result

get_scene_snapshotA

Return the full scene state as JSON, served natively by the AiCompanion gem.

Entities, components, transforms and hierarchy in one call, produced by the gem's C++ SceneSnapshotProvider rather than an editor Python script. Cheaper than list_entities plus per-entity queries, and it still works when the AgentServer runs in secure mode.

Inputs: no named parameters. Returns: result

get_sequenceA

Describe one Track View sequence: its time range and its nodes.

Returns JSON with the time range and the node names at the sequence root. A sequence with no Director node yet reports an empty node list.

Args: name: Sequence name.

Inputs: name (required). Returns: result

get_session_varsA

List the variable names in a persistent Python session.

Inputs: session_id (required). Returns: result

get_transformB

Get the world transform of an entity.

Returns position, rotation (an [x, y, z, w] quaternion) and scale, the effective [x, y, z] scale: the Transform's uniform scale times the entity's Non-uniform Scale component, if it has one. uniform_scale and non_uniform_scale (null without the component) give the two parts.

Inputs: entity_id (required). Returns: result

get_viewport_cameraA

Get the position and rotation of the active editor viewport camera.

Returns JSON with position (3 floats) and rotation (3 Euler angles in degrees). FOV is not available via the Python bindings.

Inputs: no named parameters. Returns: result

instantiate_prefabC

Instantiate a prefab in the current level.

Inputs: prefab_path (required), position, parent_id. Returns: result

list_anim_graphsA

List every EMotion FX anim graph the engine holds.

Returns the gem's JSON: editor_mode and an anim_graphs array with each graph's id, file_name, ownership and dirty flags, node and parameter counts, and the actor instances using it. Needs the AiCompanion gem's native request (gem 0.6.0+) and the EMotionFX gem.

Inputs: no named parameters. Returns: result

list_entitiesA

List all entities in the currently open O3DE level.

Returns a JSON array of objects with 'id' and 'name' fields.

Inputs: no named parameters. Returns: result

list_gemsA

List all external gems registered on this machine.

Returns: JSON array of gem objects, or the error no_gems if none are registered.

Inputs: no named parameters. Returns: result

list_levelsC

List all levels available in an O3DE project.

Inputs: project_path. Returns: result

list_project_gemsA

List gems enabled in a specific O3DE project.

Args: project_path: Path to the O3DE project.

Inputs: project_path (required). Returns: result

list_projectsA

List all O3DE projects registered on this machine.

Returns: JSON array of project objects, or the error no_projects if none are registered.

Inputs: no named parameters. Returns: result

list_sequencesA

List the Track View cinematic sequences in the current level.

Returns {"sequences": [{"name", "start", "end"}, ...], "count": N}, with each sequence's time range in seconds.

Inputs: no named parameters. Returns: result

list_templatesA

List available O3DE project and gem templates.

Scans the engine's Templates directory for template definitions.

Returns: JSON array of template objects with name, summary, and path.

Inputs: no named parameters. Returns: result

load_anim_graphA

Load an .animgraph file into the engine so it can be authored.

Returns {"id", "file_name"}. Loading a file that is already loaded this way returns the existing graph's id.

Args: file_name: Absolute path, an @alias@ path, or a path relative to the project.

Inputs: file_name (required). Returns: result

load_levelB

Open a level in the O3DE Editor.

Args: level_path: Path to the level relative to the project (e.g. 'Levels/MyLevel').

Inputs: level_path (required). Returns: result

play_sequenceC

Start playing a Track View sequence in the editor.

Args: name: Sequence name.

Inputs: name (required). Returns: result

redoA

Redo the last undone editor action.

Inputs: no named parameters. Returns: result

refresh_assetsC

Trigger an Asset Processor rescan for a project.

Inputs: project_path. Returns: result

register_engineA

Register an O3DE engine installation with the O3DE manifest.

Args: engine_path: Path to the engine root directory (must contain engine.json).

Inputs: engine_path (required). Returns: result

register_gemA

Register an external gem with an O3DE project.

Args: gem_path: Path to the gem directory. project_path: Path to the project to add the gem to.

Inputs: gem_path (required), project_path (required). Returns: result

remove_anim_graphB

Remove an anim graph from the engine (not its file on disk).

Returns {"removed": <graph id>}.

Args: anim_graph_id: Graph id (number or digit string).

Inputs: anim_graph_id (required). Returns: result

remove_anim_graph_nodeA

Remove a node (and its children) from an anim graph. The root is refused.

Returns {"removed": "<node id>"}.

Args: anim_graph_id: Graph id (number or digit string). node_id: Node id from get_anim_graph.

Inputs: node_id (required), anim_graph_id (required). Returns: result

remove_anim_graph_parameterB

Remove a value parameter from an anim graph. Groups are refused.

Returns {"removed": "<name>"}.

Args: anim_graph_id: Graph id (number or digit string). name: The parameter's name.

Inputs: name (required), anim_graph_id (required). Returns: result

remove_anim_graph_transitionB

Remove a transition (and its conditions).

Returns {"removed": "<transition id>"}.

Args: anim_graph_id: Graph id (number or digit string). transition_id: Transition id from get_anim_graph.

Inputs: anim_graph_id (required), transition_id (required). Returns: result

remove_componentC

Remove a component from an entity.

Inputs: entity_id (required), component_type (required). Returns: result

run_console_commandC

Execute an O3DE console command in the running editor.

Inputs: command (required). Returns: result

run_editor_pythonA

Execute a Python script inside the running O3DE Editor.

The script runs in the editor's embedded Python interpreter and has access to the full azlmbr (EditorPythonBindings) API. Use this for custom editor automation that isn't covered by other tools.

Args: script: Python code to execute. Has access to azlmbr modules. timeout: Optional per-call execution timeout in seconds. The editor runs the script synchronously and does not reply until it finishes, so raise this for known-heavy operations. Omit to use the O3DE_EDITOR_TIMEOUT default (600s).

Inputs: script (required), timeout. Returns: result

save_anim_graphA

Save an anim graph to disk. Not undoable.

Returns {"id", "file_name"}. The file must land inside the project root; the gem refuses any other path.

Args: anim_graph_id: Graph id (number or digit string). file_name: Where to save. Omit to save to the graph's current file.

Inputs: anim_graph_id (required), file_name. Returns: result

save_levelA

Save the currently open level.

Inputs: no named parameters. Returns: result

save_prefabA

Report where a prefab instance came from.

Propagating live entity edits back to a .prefab file is not reachable from the editor's Python API: PrefabPublicRequestBus reflects no save event, and the only serialiser, SaveTemplateToString, is keyed by template id with nothing exposed to map an entity to one. This returns the owning prefab path and says so, rather than reporting a success that never happened. To get a prefab onto disk, use create_prefab_from_entity.

Inputs: entity_id (required). Returns: result

set_active_engineA

Set the active O3DE engine by name (in-process, not persistent).

Args: name: Name of the registered engine to activate.

Inputs: name (required). Returns: result

set_anim_graph_entry_stateB

Make a node the entry state of the state machine that contains it.

Returns {"entry_state_id": "<node id>"}.

Args: anim_graph_id: Graph id (number or digit string). node_id: The node to enter first; it must be able to act as a state.

Inputs: node_id (required), anim_graph_id (required). Returns: result

set_anim_graph_nodeA

Edit a node: rename, move, enable/disable, or set reflected fields.

Returns the node object as get_anim_graph emits it. Pass at least one change. An unknown attribute is refused with the settable fields listed.

Args: anim_graph_id: Graph id (number or digit string). node_id: Node id from get_anim_graph. name: New node name. position: [x, y] graph-canvas position in integer pixels. enabled: Enable or disable the node. attributes: Reflected fields to set, for example a motion node's {"motionIds": ["<motion id>", ...]} (read back as the node's motion_ids).

Inputs: node_id (required), anim_graph_id (required), name, enabled, +2 more. Returns: result

set_anim_graph_transitionA

Change a transition's settings. Pass at least one setting.

Returns the transition object as get_anim_graph emits it.

Args: anim_graph_id: Graph id (number or digit string). transition_id: Transition id from get_anim_graph. blend_time: Blend time in seconds, 0 or more. priority: Higher wins when several transitions are ready. disabled: Disable or re-enable the transition. sync_mode: 0 disabled, 1 track based, 2 clip based. interpolation: 0 linear, 1 ease curve.

Inputs: anim_graph_id (required), transition_id (required), disabled, priority, +3 more. Returns: result

set_component_propertyB

Set a property value on a component.

Args: entity_id: The entity ID. component_type: Component type name (e.g. 'Transform'). property_path: Property path using '|' separator (e.g. 'Controller|Configuration|Model Asset'). value: The value to set (as a string — booleans as 'true'/'false', numbers as their string representation).

Inputs: value (required), entity_id (required), property_path (required), component_type (required). Returns: result

set_cvarB

Set the value of an O3DE console variable (CVAR).

Inputs: name (required), value (required). Returns: result

set_parentA

Set the parent of an entity (reparent in the hierarchy).

Inputs: entity_id (required), parent_id (required). Returns: result

set_sequence_time_rangeB

Set a Track View sequence's play time range, in seconds.

Args: name: Sequence name. start: Range start in seconds. end: Range end in seconds (must be greater than start).

Inputs: end (required), name (required), start (required). Returns: result

set_transformA

Set the world transform of an entity (only provided components are changed).

rotation is an [x, y, z, w] quaternion and scale an [x, y, z] vector, the effective scale to end up with (each element in (0, 1000]). The call goes to the AiCompanion gem's native set_transform request (works in secure mode) and returns the updated entity's JSON, the same shape as get_entity. The gem refuses an unknown entity or out-of-bounds values, and that is returned as an error.

On gem API 0.5.0 and later (gem 0.6.0) the quaternion and the scale are sent as is. A non-uniform scale is applied through the engine's Non-uniform Scale component (each element at least 0.01); an O3DE Transform itself holds only a uniform scale. A later uniform scale sets that component back to 1. The reply carries scale (uniform), non_uniform_scale and effective_scale.

On older gems the quaternion is converted to XYZ Euler degrees, a rotation at a gimbal pole (pitch within 0.02 degrees of plus or minus 90) goes through editor Python instead, which prints Transform set for entity [<id>], and a non-uniform scale is refused with non_uniform_scale_unsupported. The legacy transport also uses the editor-Python path. An all-zero quaternion is rejected before any path.

Inputs: entity_id (required), scale, position, rotation. Returns: result

set_viewport_cameraC

Set the active editor viewport camera transform.

Inputs: position, rotation. Returns: result

start_buildA

Start a CMake build in the background and return a build ID.

Unlike build_project, this returns immediately with a build ID that can be polled via get_build_status. Output is drained on a background thread to prevent pipe stalls on large builds.

Args: project_path: Path to the O3DE project. config: Build configuration -- profile, debug, or release (default: profile). target: Optional CMake target to build (default: all targets).

Inputs: project_path (required), config, target. Returns: result

stop_sequenceB

Stop the Track View sequence currently playing in the editor.

Inputs: no named parameters. Returns: result

tail_logB

Read the last N lines of an O3DE log file.

Inputs: log_name (required), lines, filter, project_path. Returns: result

undoB

Undo the last editor action.

Inputs: no named parameters. Returns: result

validate_sceneA

Run the AiCompanion gem's scene validation and return the report as JSON.

Flags common problems (missing cameras, entities without transforms, physics bodies without colliders, and similar) without executing any editor Python.

Inputs: no named parameters. Returns: result

wait_for_assetA

Wait until one asset is built, or report why it failed.

Polls get_asset_status. compiled returns {"path", "status": "compiled", "ready": true, "elapsed"}. A failed build returns the error asset_build_failed with the failed jobs and their logs. A source whose build failed answers missing, just like one the Asset Processor has not seen yet, so after a short grace period a missing status is checked against get_asset_jobs. When timeout runs out the result is {"ready": false, "status": <last status>}, not an error. Needs the AiCompanion gem 0.6.0+.

Args: path: The asset to wait for: its source path (best, since the job check needs the source) or a product path. timeout: Seconds to wait (default 120, max 3600). just_written: True right after writing the file, so the first query flushes the file monitor. source_path: The source file to check for failed jobs, when path is a product path. poll_interval: Seconds between polls (0.1 to 10, default 1).

Inputs: path (required), timeout, source_path, just_written, +1 more. Returns: result

wait_for_assetsA

Wait for the Asset Processor process to exit (or until timeout).

This watches for the process to stop, not for it to go idle, so it suits a one-off AssetProcessorBatch run. A GUI Asset Processor running beside the editor stays up while idle, so with one running this waits out the timeout and reports completed: false.

Returns a progress result {"completed": bool, "elapsed": seconds}. completed is True when no Asset Processor process is running, or False when one was still running when timeout elapsed, with a message noting the timeout. A not-yet-finished wait is a result, not a failure, so this tool does not return the error envelope.

Inputs: timeout. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.2/5.0

    Scored across 96 tools

    Disambiguation3/5

    The set contains several tool clusters with overlapping purposes: seven asset-processor status/wait tools, multiple entity-query tools (list_entities, get_entity, get_entity_tree, get_scene_snapshot, get_entity_components), and several Python/session execution tools (run_editor_python, exec_in_session, run_console_command). The descriptions are unusually detailed and do explain the distinctions, but with 96 tools an agent still faces real misselection risk across these clusters.

    Naming Consistency4/5

    Nearly all names use a consistent snake_case verb_noun pattern (create_entity, delete_entity, get_transform, set_transform, add_anim_graph_node, remove_anim_graph_node). Minor deviations like undo/redo and the _live suffix on get_bus_schema_live are readable but not perfect matches for the pattern.

    Tool Count1/5

    96 tools is far beyond what an agent can reliably manage in one MCP surface and qualifies as an extreme mismatch, even for a broad game-engine editor. Many operations (asset status, entity queries, project/gem management) could be consolidated into fewer, more capable tools.

    Completeness4/5

    The surface is very broad, covering entity/component CRUD, transforms, levels, sequences, anim-graph authoring, assets, and project/gem lifecycle. There are some notable gaps and dead ends: no delete_level, delete_project, remove_gem, or deregister_engine, and save_prefab is documented as unable to propagate edits back to disk.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server for controlling Unreal Engine 5 from AI agents, providing 120+ commands for spawning actors, editing Blueprints, managing assets, and more via CLI or MCP.
      27 PyPI
      216
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      MCP server for Cocos Creator that enables AI tools to automate scene editing, resource management, and project operations via HTTP and stdio interfaces.
      27 npm
      236
      MIT
    • A
      license
      B
      quality
      C
      maintenance
      An MCP server that gives AI agents broad control over Unreal Engine 5.7, enabling actor/asset/level management, Blueprint and material creation, screenshots, automation, and arbitrary editor Python execution.
      35
      MIT