MCP Toolset

MHA Manager exposes its batch queue to Model Context Protocol (MCP) clients, so an agent or external tool can inspect, add, and edit jobs, and start processing — the same operations the panel offers, driven programmatically. It rides Unreal Engine 5.8's native MCP stack; every tool is a thin wrapper over the plugin's queue logic.

Requirements

Requirement Detail
UE 5.8+ The toolset uses the engine's native ModelContextProtocol + ToolsetRegistry stack. On UE 5.5 / 5.7 this stack does not exist, so the toolset is unavailable — the rest of the plugin works normally.
Engine MCP plugins The ModelContextProtocol and ToolsetRegistry engine plugins must be enabled. If they are absent, registration no-ops and the status indicator stays hidden.
Enabled by default The toolset registers automatically at editor startup — there is nothing to turn on. See Status & disabling to opt out.

How it works

At editor startup the plugin registers a toolset with the engine's ToolsetRegistry. Each of the 23 tools delegates to a reflected function on the MHA Manager subsystem — the C++ side owns all state, execution, and quality-gate logic, so the tools add no behavior of their own. Everything the MCP surface does obeys the same rules as the panel:

  • Processing is strictly serial — one solve at a time (Epic's single-performance lock).
  • Execution order is CalibrateStereo -> IdentityCreate -> everything else, so prerequisites exist by the time dependents run.
  • A Stereo take cannot process until both a CameraCalibration and a prepared MetaHuman Identity exist for its actor — the tools surface the blocked status rather than working around it.

Status & disabling

When the toolset registers, an Integrations status indicator in the plugin reports live state — registered or not, and the tool count — with the detailed status line in its tooltip. The indicator is hidden on engines without the MCP stack and when the toolset is off, so its mere presence tells you the surface is live.

Turning it off. There is no toggle in the settings panel — the enable flag is a manifest-only escape hatch. Set "enable_mcp_toolset": false in the batch manifest (.mhajson) and restart the editor; with the flag off the toolset module is never imported, so it provably does not exist in any client.

Connecting a client

The toolset registers into Unreal Engine 5.8's native MCP server rather than hosting its own, so connecting a client is the standard engine MCP flow — point your MCP-capable client at the editor's MCP endpoint and the MHA Manager tools appear alongside any other registered toolsets. Follow Epic's Model Context Protocol documentation for your engine build for the exact endpoint and client configuration; this page documents only the tools the plugin contributes.

Agent skills

The plugin ships three agent skills alongside its source. They turn the toolset from a list of function calls into guided workflows — connect the editor, ask why a job is blocked, or reorganize a shoot's worth of takes before ingest. Each is a folder holding a SKILL.md instruction file (plus a helper script where needed), so any LLM agent that reads skill folders can use them.

Skill Use it when
mha-setup Connecting an agent to the editor for the first time, or the unreal MCP server is not responding. Walks the two Epic MCP plugins, autostart, the ImgMedia cache size, the Capture Manager / Live Link Hub connection, pointing the client at the server, and verification.
mha-help Asking why a job is blocked, what a status means, how the stereo chain fits together, or what a setting does. Reads the live queue to diagnose rather than guessing from documentation.
mha-organize-takes Raw takes need sorting before ingest, take names misclassify, or Capture Data landed in the wrong actor folder. Three modes: organize on disk, verify and fix the /Game layout after ingest, or both as one flow. Its disk-organizing mode needs nothing but a folder; the other two need the toolset connected.

Copy the folders you want from the plugin's Skills/ directory into your agent's skills location — per project, or per user:

# per project - commits with the project, whole team gets them
<YourProject>/.claude/skills/mha-setup/
<YourProject>/.claude/skills/mha-help/
<YourProject>/.claude/skills/mha-organize-takes/

# or per user - available in every project you open
~/.claude/skills/mha-help/

Copy the whole folder, not just the SKILL.md inside it. Skills are picked up on the next session; the plugin does not have to be running for a skill to be listed, only for it to do anything useful.

Reads are free; writes ask first. The skills query the queue, classify takes, and lint a layout without touching anything, then present a plan and stop. Nothing is moved, renamed, queued, or started until you approve it — so "show me what's wrong with this shoot" is a safe thing to ask. The classification rules mha-organize-takes enforces are the same ones documented under Naming Conventions.

Tool reference

23 tools, grouped by purpose. Object paths use the standard UE form (/Game/.../Take.Take); GUIDs are the id values reported by get_queue_state and add_job.

Queue inspection

Read-only tools that report queue and job state as JSON.

Tool Parameters Description
get_queue_state() -> str (none) The whole queue as JSON. Each job carries its persisted fields plus live runtime fields the saved manifest omits: live_status (the real status — Running, MissingCalibration, PoorCalibrationQuality — not the collapsed "pending"), stage, progress, status_message, and estimated_seconds. Log lines are omitted for size — use get_job for a log tail.
get_job(job_id, max_log_lines=25) -> str job_id, max_log_lines One job as JSON, including a log tail and start/complete timestamps. Returns "" if no job has that id.
get_settings() -> str (none) The global plugin settings as JSON (FMHAManagerGlobalSettings) — the same key names update_settings accepts.

Queue editing

Add, remove, and modify jobs and settings. Partial updates route through the same native setters the UI uses, preserving their side effects.

Tool Parameters Description
add_job(capture_data_path) -> str capture_data_path Queue a new job for a Footage Capture Data asset, auto-classifying its type by package-path name (grid/calib -> CalibrateStereo, identity/dna -> IdentityCreate, otherwise Stereo; Mono/Audio come from the asset). A first-frame framing probe runs for mono takes. Returns the new job GUID, or "" on failure.
add_audio_jobs_from_folder(folder_path, recursive=True) -> list[str] folder_path, recursive Queue one audio-driven job per WAV in a folder on disk. The WAV stays where it is — each job keeps only its path and imports it as a sound wave beside the Performance at solve time. WAVs already queued are skipped, so re-running against the same folder adds nothing. Audio jobs need no Capture Data and no identity. Returns the new job GUIDs.
add_wwise_audio_jobs(container_path, waapi_url, platform, language) -> str container_path, waapi_url, platform (default Windows), language (default English(US)) Queue one audio-driven job per Wwise Sound under a container, resolved live over WAAPI — Wwise Authoring (or WwiseConsole waapi-server) must be running with WAAPI enabled. Each sound solves from the media Wwise's own conversion produced, transcoded to a WAV under Saved/MHAManager/WwiseAudio and imported transiently, so nothing Wwise owns is copied into the content tree. Conversions must be PCM — compressed media (Vorbis/Opus/ADPCM) is reported by name instead of queued. Exported Level Sequences carry a Wwise event track rather than a sound wave track. Empty arguments fall back to the WAAPI Endpoint and Default Container settings. Returns JSON {"job_ids": [...], "count": N}.
remove_jobs(job_ids) -> int job_ids (list) Remove jobs from the queue by GUID. Unknown ids are ignored. Returns the number actually removed.
clear_queue() -> bool (none) Remove every job from the queue.
update_job(job_id, fields_json) -> str job_id, fields_json Apply a partial job update — only the JSON keys present are changed. Supported keys include input_type, identity, camera_calibration, start_frame/end_frame, body_tracking, export_output_path, custom_data, and a partial options object. Returns "" on success or an error: ... message (an unknown key lists the supported set).
update_settings(settings_json) -> str settings_json Apply a partial global-settings update, then persist and refresh the ingest watcher. Same key names as get_settings emits; invariants are normalized on apply.

Execution

Start, cancel, and unblock processing. The queue always runs serially (Epic's single-performance lock), parents before dependents.

Tool Parameters Description
start_batch() -> bool (none) Start processing the whole queue. Returns true if the batch is now running.
start_jobs(job_ids) -> bool job_ids (list) Start processing only the given jobs (still serial).
cancel_batch() -> bool (none) Request cooperative cancellation of the running batch (cancels adapters, kills workers). Returns false if nothing was running or the editor is in an unattended session.
retry_jobs(job_ids) -> bool job_ids (list) Requeue completed/failed/skipped jobs for another run, clearing persisted timing.
retry_job_as_mono(job_id) -> bool job_id Convert a blocked Stereo/Depth job to a Mono solve and requeue it — a Mono solve needs neither calibration nor identity, so this unblocks a take stuck on a missing prerequisite. The camera is picked automatically.
skip_job(job_id) -> bool job_id Mark a job Skipped so the serial queue moves past it.
accept_poor_calibration(job_id) -> bool job_id Accept an over-threshold calibration on a PoorCalibrationQuality job: relinks the CameraCalibration to the take, marks the job Done, and wakes dependents paused on it. Only valid while the job's live_status is PoorCalibrationQuality.
validate_queue() -> bool (none) Re-run dependency and asset validation across the whole queue, recomputing blocked statuses (MissingCalibration / MissingIdentity). Run it after renames or bulk edits — anything that changed assets or jobs outside the normal add/update flow.
preview_level_sequence(job_id) -> str job_id Open a job's exported Level Sequence in Sequencer for playback. The sequence carries its own lighting — an audio job's export bakes Epic's Portrait rig into it as spawnables — and opens against Epic's clean MetaHuman backdrop level, which replaces the currently open level: the editor offers unsaved work up for saving first, and declining that prompt cancels the preview. Both the lighting and the backdrop need the MetaHuman Character plugin. The job must have recorded a LevelSequence artifact.

Capture Data

Inspect and reshape Capture Data assets already in the project — list them, fix their layout, and prepare copies for re-solve / isolation runs. Ingest itself is interactive: bring takes in through Live Link Hub, or through the plugin's <strong>Add Jobs...</strong> dialog, then queue them with <code>add_job</code> or the auto-queue watcher.

Tool Parameters Description
list_capture_data(root_path="/Game") -> str root_path List Footage Capture Data assets under a content path. Each entry carries its actor, derived from the Imports/<Actor> path segment — the same rule calibration and identity discovery uses. An empty actor means the asset sits outside an Imports layout and actor-scoped discovery cannot see it.
rename_capture_data(source_object_path, dest_folder, new_name) -> str source_object_path, dest_folder, new_name Rename or move a Footage Capture Data asset, leaving a redirector behind; queued jobs pointing at the old path are updated in place. Folder and asset name tokens drive auto-classification (grid/calib -> Stereo Calibration, identity/dna -> Identity Create), so this is the tool for fixing a misclassified take. Never overwrites an existing asset.
duplicate_capture_data(source_object_path, dest_folder, new_name) -> str source_object_path, dest_folder, new_name Duplicate a Footage Capture Data asset with its depth and calibration links cleared — the copy shares the original RGB sequences but regenerates its own depth and links its own calibration. Never overwrites an existing asset.

Persistence

Write queue state to disk.

Tool Parameters Description
save_manifest(file_path) -> bool file_path Write the queue manifest JSON to disk. Pass "" to write the default autosave manifest.