Audit¶
9 tools. Back to the index.
audit_asset_references¶
Destructive.
Project-wide reference audit under folder_path: assets with zero referencers ("orphans") and dependencies pointing at a package no longer on disk ("broken"). Metadata-only through the AssetRegistry -- it never LOADS the assets, so it scales to a large project without spiking memory. It returns only a summary plus a report path; read the detail back with read_mcp_audit_file. For one asset rather than a sweep, use get_asset_referencers / get_asset_dependencies; for unused assets only, find_unused_assets.
| Parameter | Type | Required | Description |
|---|---|---|---|
folder_path |
string | no | Content-relative folder to scan. Defaults to "/Game". |
recursive |
boolean | no | Recurse into subfolders. Defaults to true. |
max_results |
number | no | Cap on assets processed (1-100000). Defaults to 5000. |
dependency_type |
string | no | "hard"|"soft"|"all" (case-insensitive), default "all". Scopes BOTH the referencer check (orphan detection) and the dependency check (broken-reference detection) to that dependency kind. Use "hard" to find only the broken references that actually break loading -- a broken SOFT reference (TSoftObjectPtr/FSoftObjectPath) does not. "all" applies no Hard/Soft requirement at all. |
Returns: { path: string, summary: { asset_count: int, orphan_count: int, broken_reference_count: int, dependency_type: string } }
audit_blueprint_health¶
Destructive.
Project-wide compile-sweep: RECOMPILES every Blueprint under folder_path and records error/warning counts. By far the heaviest audit here (it compiles, it does not just read metadata) and it runs synchronously in the editor -- ALWAYS scope it with folder_path on a large project, and lean on max_results, which is a hard cap. It returns only a summary plus a report path; read the detail back with read_mcp_audit_file. To find already-broken Blueprints WITHOUT recompiling anything, use find_erroring_blueprints instead.
| Parameter | Type | Required | Description |
|---|---|---|---|
folder_path |
string | no | Content-relative folder to scan. Defaults to "/Game". |
recursive |
boolean | no | Recurse into subfolders. Defaults to true. |
max_results |
number | no | Cap on Blueprints compiled (1-100000). Defaults to 200 (lighter than the other audits -- compiling is expensive). |
Returns: { path: string, summary: { blueprint_count: int, clean_count: int, error_count: int, warning_count: int } }
audit_collision_profiles¶
Destructive.
Aggregate report of every project collision profile AND every collision channel (built-in + custom), including which custom ECC_GameTraceChannelN slots are already taken -- the question to ask before add_collision_channel. Cheap: it reads the collision settings in memory, with no AssetRegistry scan and no asset loading, so unlike the other audit_* sweeps it takes no folder_path and no max_results. Returns a summary + a report path (read the detail with read_mcp_audit_file).
No parameters.
Returns: { path: string, summary: { profile_count: int, channel_count: int, custom_channels_in_use: int } }
audit_replication¶
Destructive.
Project-wide replication audit: for every Blueprint under folder_path, which variables are Replicated (CPF_Net), whether the class itself replicates (AActor::GetIsReplicated on the GeneratedClass CDO), and which UFUNCTIONs are RPCs (FUNC_NetFuncFlags). It returns only a SUMMARY plus a report path -- the full per-Blueprint detail is written to Saved/MCPAudits/ and must be read back with read_mcp_audit_file. For one actor rather than a sweep, use get_replication_info / get_actor_replication_info.
| Parameter | Type | Required | Description |
|---|---|---|---|
folder_path |
string | no | Content-relative folder to scan. Defaults to "/Game". |
recursive |
boolean | no | Recurse into subfolders. Defaults to true. |
max_results |
number | no | Cap on Blueprints processed (1-100000). Defaults to 1000. |
Returns: { path: string, summary: { blueprint_count: int, replicated_class_count: int, replicated_variable_count: int, rpc_count: int } }
audit_widget_accessibility¶
Read-only.
Sweep Widget Blueprints for the accessibility problems that are measurable from what was AUTHORED: text/background contrast against the WCAG 2.x threshold, text smaller than a legible minimum, interactive widgets with no accessible label for a screen reader, and buttons below a minimum touch/focus size. On console this is a CERTIFICATION requirement, not a nicety. READ THE LIMITS BEFORE TRUSTING A PASS: contrast is computed against the FIRST ancestor holding a solid colour -- a UBorder's brush, a UButton's WidgetStyle.Normal, or a flat UImage -- so a background painted by a texture, a material, a video or a sibling drawn underneath is INVISIBLE to this, and those cases come back as background_source:"none" rather than quietly passing, because "could not judge" and "fine" are different answers. A brush only counts when it has no ResourceObject, its TintColor is UseColor_Specified, and its DrawAs actually FILLS the middle: Box, Image or RoundedBox. DrawAs=Border is excluded on purpose (it tiles the sides and leaves the centre empty, which is exactly where the text sits). Colours coming from a CommonUI style asset or a property binding are equally invisible: only authored values are read. What IS exact is the maths -- relative luminance 0.2126R+0.7152G+0.0722B over LINEAR values (which is what an FLinearColor already is) and ratio (Llight+0.05)/(Ldark+0.05), straight from WCAG.
| Parameter | Type | Required | Description |
|---|---|---|---|
folder_path |
string | no | Content folder to sweep (default /Game). |
recursive |
boolean | no | Recurse into subfolders (default true). |
min_contrast_ratio |
number | no | Contrast floor for normal-size text (default 4.5, the WCAG AA rule). Text at or above large_text_size only needs 3.0, applied automatically. |
large_text_size |
number | no | Font size from which text counts as "large" for the contrast rule (default 18.0, per WCAG). |
min_font_size |
number | no | Smallest legible font size; anything under it is reported (default 12.0). |
min_touch_size |
number | no | Minimum width/height in pixels for an interactive widget's authored slot size (default 44.0, the common touch-target guideline). Only checkable when the slot actually carries a size -- an auto-sized slot reports size_known:false instead of a false pass. |
max_results |
number | no | Max Widget Blueprints to load (default 500). |
Returns: { folder_path, widget_blueprints_scanned, widgets_examined, issue_count, issues_by_kind: {low_contrast, contrast_unknown, small_text, missing_accessible_text, small_touch_target}, entries: [{ widget_bp_path, widget_name, widget_class, kind, detail, contrast_ratio?, required_ratio?, text_color?, background_color?, background_source?, font_size?, width?, height? }], truncated }
audit_widget_style¶
Read-only.
Sweep Widget Blueprints and report every widget whose style DEVIATES from a reference widget -- the "who is off-theme" question, which is the one that scales badly by hand once there are more than a couple of screens. You designate one widget as the truth (reference_bp_path + reference_widget_name), list the property paths that define the style (dotted paths work: "WidgetStyle.Normal.TintColor"), and this reports, per matching widget, which of those paths differ and what each side holds. Comparison is on the property's exported text, so it is type-agnostic and reports a real difference rather than a formatting one. Pair it with apply_widget_style_preset, which can copy those same paths off that same reference widget to FIX what this finds.
| Parameter | Type | Required | Description |
|---|---|---|---|
reference_bp_path |
string | yes | /Game path of the Widget Blueprint holding the reference widget (the style source of truth). |
reference_widget_name |
string | yes | Name of the reference widget inside that Widget Blueprint. |
property_paths |
array | yes | The paths that define the style, e.g. ["WidgetStyle.Normal.TintColor","WidgetStyle.NormalPadding"]. A path that does not resolve on the REFERENCE is an error (the reference must define the style); one that does not resolve on a target is reported as unresolved, not as a deviation. |
folder_path |
string | no | Content folder to sweep for targets (default /Game). |
recursive |
boolean | no | Recurse into subfolders (default true). |
target_class |
string | no | Only compare widgets of this class, matched with IsA (defaults to the reference widget's own class, which is almost always what you want). |
include_matching |
boolean | no | Also report the widgets that already match (default false). |
max_results |
number | no | Max Widget Blueprints to load (default 500). |
Returns: { reference, property_paths, widget_blueprints_scanned, widgets_compared, deviating_count, matching_count, entries: [{ widget_bp_path, widget_name, widget_class, deviations: [{path, actual, expected}], unresolved_paths: [string], matches: bool }], truncated }
audit_widget_text¶
Read-only.
Sweep Widget Blueprints and report which player-visible texts are typed INLINE rather than coming from a String Table -- the localization-maintainability question. NOTE: this corrects the intuition most people start with: a text written as a bare string is NOT lost to localization. Unreal assigns it a stable key when the package is saved, and FTextInspector::ShouldGatherForLocalization returns true, so it DOES get collected and translated. What it lacks is a MEANINGFUL identity: the namespace comes out empty and the key is an opaque GUID like 971E3B3B436AEE91028BA1ADB97B3046. That still costs -- translators see no context, and re-authoring the text churns the key, orphaning the translation. So this reports identity_kind per text: string_table (best), explicit (an author-given namespace/key), auto_key (typed inline, key generated on save) and none (never saved, no identity yet). Default output is everything that is NOT string_table or explicit.
| Parameter | Type | Required | Description |
|---|---|---|---|
folder_path |
string | no | Content folder to sweep (default /Game). Every UWidgetBlueprint under it is loaded and walked. |
recursive |
boolean | no | Recurse into subfolders (default true). |
include_all |
boolean | no | Also report the texts that already have a good identity, string_table and explicit ones included (default false). |
include_data_assets |
boolean | no | Also sweep DataTables and DataAssets under the same folder (default false). This is where an AAA game actually keeps its text -- item names, quest descriptions, tooltips -- and it is text the widget walk cannot reach, because there the FTexts sit in nested struct fields rather than on a widget class. Nested structs and arrays of structs are walked too. |
max_results |
number | no | Max Widget Blueprints to load (default 500). Loading a WBP is not free; a whole-project sweep is a heavy call. |
Returns: { folder_path, widget_blueprints_scanned, texts_examined, counts_by_identity: {string_table, explicit, auto_key, none}, not_gathered_count, entries: [{ widget_bp_path, widget_name, widget_class, property_name, text, identity_kind, will_be_gathered, namespace, key, string_table }], truncated } -- not_gathered_count is the engine's own ShouldGatherForLocalization saying a text will NOT be collected at all; in a saved asset that is normally 0, and anything above it is a real alarm.
capture_pie_state¶
Destructive.
Snapshot of every actor in the ACTIVE PIE world, with every property flagged Replicated or SaveGame (generic -- no judgment call about what is "relevant"). It requires a live PIE session: with none running for pie_client_index it errors cleanly instead of silently snapshotting the EDITOR world, which is what makes it usable as co-op evidence -- point it at a client index to prove a value really replicated. On a large world ALWAYS pass class_filter and/or max_actors. Returns a summary plus a report path; read the detail with read_mcp_audit_file.
| Parameter | Type | Required | Description |
|---|---|---|---|
pie_client_index |
number | no | Which PIE client's world to snapshot (0 = first/server/standalone). Defaults to 0. |
class_filter |
any | no | Optional actor-class guardrail. Accepts a single class name OR an array of them (the hint is deliberately absent: the type-hint grammar has no union, and [string\|array] would make this whole @param unparseable, leaving it an EMPTY description in the catalog). Detail: one class name or an array of them, each resolved to a UClass (object/script path, short name, or the Blueprint asset name -- "<Name>_C" is tried too) and matched with IsA, so subclasses match. An entry that does not resolve, or that resolves to a non-AActor class, is a hard ERROR rather than being dropped: dropping it would silently snapshot the whole World Partition world, keeping it would silently return an empty snapshot. Defaults to no filter (every actor). |
max_actors |
number | no | Optional cap on how many actors get their properties reflected into the report; 0 (the default) means UNLIMITED, and negative values are clamped to 0. Actors past the cap are still COUNTED (cheap) but not reflected (the expensive part), so total_matching_actors and truncated are exact, not estimated. |
Returns: { path: string, truncated: bool, summary: { actor_count: int, actors_seen: int, total_matching_actors: int, max_actors: int, truncated: bool, class_filter: [string], replicated_property_count: int, savegame_property_count: int, savegame_filter_status: "active"|"dead_in_this_run" }, report_size_bytes: int, verification: {...}, verification_checks: [...] } -- class_filter lists the resolved class paths; success is false when the report is missing or empty on disk.
read_mcp_audit_file¶
Read-only.
Read back the FULL report that an audit_* or capture_pie_state command wrote to disk. Those commands return only a summary plus a path, so this is the second half of every one of them -- without it you never see the per-Blueprint / per-asset / per-actor detail. Restricted to Saved/MCPAudits/: it is not a general file reader.
| Parameter | Type | Required | Description |
|---|---|---|---|
path |
string | yes | Path returned by a prior audit command |
Returns: the full parsed JSON report object