o3de-mcp
o3de-mcp is an MCP server that lets an AI agent inspect capabilities, automate a running O3DE Editor, and manage O3DE projects, gems, builds, and assets.
Capability detection:
get_capabilitiesreports editor connectivity, AiCompanion AgentServer status, CLI availability, and dynamically discovered tool categories.Editor scripting & sessions: run arbitrary Python in the editor via
run_editor_python(with optional per-call timeout), plus persistent sessions (begin_session/exec_in_session/get_session_vars/end_session).Scene inspection: native gem-served
get_scene_snapshot,get_entity_tree, andvalidate_scene, pluslist_entities.Entity & component editing: list, create, delete, duplicate, and reparent entities; add/remove components; get/set component properties; assign assets by path.
Transforms & prefabs:
get_transform/set_transform; instantiate prefabs, create a prefab from an entity, andsave_prefab(reports the owning prefab rather than writing edits back).Levels:
create_level,load_level,save_level,get_level_info, andlist_levels.Viewport: get/set the viewport camera, focus an entity, and capture screenshots.
Editor control: run console commands, get/set CVARs, enter/exit game mode, and undo/redo.
Engine introspection: discover EBus schemas from
azlmbrstubs or live from the editor, and trigger RenderDoc frame capture (with manual fallback when unavailable).Project & build management (CLI, no editor needed): discover/register/select engines, list projects/gems/templates/project gems, create projects and gems, register/enable/disable gems, edit project properties, build blocking (
build_project) or in background (start_build/get_build_status), and export projects.Asset pipeline & logs: check Asset Processor status, refresh/rescan assets, wait for processing, tail editor/asset logs, and extract error lines.
Safety: strict input validation, JSON serialization of user strings into editor scripts, and path resolution before subprocess use.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@o3de-mcp list registered projects"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
o3de-mcp
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 toolsDynamic 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 (
azlmbrAPI)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 modeList, create, delete, and duplicate entities; reparent with
set_parentAdd and remove components, get/set component properties, assign assets by path
Get and set transforms
create_entity,set_transformanddelete_entitytry 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 transportCreate and instantiate prefabs (saving edits back into an existing prefab is not exposed to editor Python;
save_prefabreports 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 callsFast-fail when editor is unreachable (avoids repeated timeouts)
Engine Introspection (3 tools):
EBus schema discovery, both from generated
azlmbrstubs and live from the editorRenderDoc 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_PATHenv var)Linux/macOS:
~/.o3de/o3de_manifest.jsonWindows:
%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-mcpOr run it without installing, straight from an MCP client config, with uv:
uvx o3de-mcpTo 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-mcpWith Claude Code
Add to your MCP config (or use a project-level .mcp.json):
Linux/macOS:
~/.claude/mcp.jsonWindows:
%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-mcpThis 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-mcpDevelopment
# 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 onlyThe 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.loadswhen 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 |
AI agents | Token-efficient usage guide, decision trees, error handling | |
Developers & agents | System architecture diagram and communication flows | |
Agents & developers | Compact parameter reference for all 96 tools | |
Agents & developers | Composable patterns for scenes, physics, lighting, scripting | |
Agents & developers | O3DE component name catalog with dependency chains | |
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:
New Project: create, configure, and build a project
Build a Scene: sky, lights, ground, camera, static objects
Physics Playground: dynamic bodies, triggers, stacking
Scripted Game: complete mini-game with player, obstacles, goals
Batch Operations: efficient bulk entity creation patterns
CLI-Only Workflow: project management without the editor
Gem Development: create and integrate custom gems
MCP Inspector: interactively test tools via a web UI
Configuration
Environment Variable | Description | Default |
| Override automatic engine discovery | Auto-detected from manifest |
| Select engine by name when multiple are registered | First valid engine |
| Select the project for asset, introspection and | Single registered project |
| Editor AgentServer host |
|
| Editor AgentServer port |
|
| Per-command editor execution timeout (seconds) |
|
| Editor TCP connect timeout (seconds) |
|
| How long to wait for a viewport capture to reach disk (seconds) |
|
| Wrap the editor connection in TLS ( |
|
| Verify the editor's certificate and hostname |
|
| CA bundle used when verification is enabled | System defaults |
| CMake generator for builds | Auto-detected per platform |
| CMake configure timeout (seconds) |
|
| CMake build timeout (seconds) |
|
| Project export timeout (seconds) |
|
Editor timeouts: the editor runs each submitted script synchronously and does not reply until it finishes, so
O3DE_EDITOR_TIMEOUTis 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 separateO3DE_EDITOR_CONNECT_TIMEOUTand the fast-fail window, so a large command timeout costs nothing on the healthy path.run_editor_pythonalso accepts a per-calltimeoutargument.
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 pointO3DE_EDITOR_HOSTat a remote machine, setO3DE_EDITOR_TLS=1andO3DE_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.jsonWindows:
%USERPROFILE%\.o3de\o3de_manifest.json
Related Projects
o3de-ai-companion-gem: O3DE Gem that provides the AgentServer for editor-side communication. Required for editor automation tools. Enable it alongside EditorPythonBindings in your O3DE project.
O3DE (Open 3D Engine): the open-source game engine.
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 toolsadd_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
Scored across 96 tools
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.
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.
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.
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
Related MCP Connectors
Make games with AI: one MCP server that connects your agent to Unity, Unreal and Godot editors.
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to control Unreal E…
Build, run and publish 3D games in the Zero engine from Claude Code, Cursor or Codex, over MCP.
MCP server for building and testing AI agents with multi-model experimentation and insights.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP 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 PyPI216MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for Cocos Creator that enables AI tools to automate scene editing, resource management, and project operations via HTTP and stdio interfaces.27 npm236MIT
- AlicenseNot gradedqualityBmaintenanceAn MCP server that enables AI agents to control the Unity Editor externally, providing tools for scene, GameObject, component, and other editor operations.1MIT
- AlicenseBqualityCmaintenanceAn 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.35MIT