Receber por email
← Voltar para o catálogo

ue5-mcp

Um manual prático para operar o Unreal Engine 5.7/5.8 via MCP, detalhando problemas de motor, padrões de falha e sequências de chamada eficazes. É aplicável a qualquer servidor MCP e é ativado automaticamente ao detectar ferramentas MCP do Unreal Engine ou mencionar 'Unreal'.

32estrelas
Atualizado há 2 meses

Ver no GitHub ↗

Como adicionar

/plugin marketplace add ibrews/ue5-mcp

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/ue5-mcp/svg)](https://www.skillteca.com.br/skills/ue5-mcp)

Skills relacionadas

Ver todas de DevOps e Infra →

Alerta por categoria

Receba novas skills de DevOps e Infra toda segunda

1 email curto, só com as skills novas de DevOps e Infra. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

ue5-mcp — Field manual for driving Unreal Engine 5 via MCP

Engine-level wisdom an LLM needs to drive UE5 through an MCP server without faceplanting on UE's silent-fail edges. This skill is server-agnostic: the gotchas, patterns, and identifiers documented here apply whether you're connected to Epic's official ModelContextProtocol plugin (UE 5.8+) or any other MCP server that exposes UE5 functionality.

What this skill isn't: a list of commands for any particular MCP server. Each server publishes its own tool catalogue — ask the server with tools/list for what it actually exposes. This skill covers what bites you after you know the tool names.

1. Session checklist — read before you write

UE5 is a structured-asset editor. The agent that wins is the one that reads state before mutating it.

  1. Always dump the asset before editing it. Blueprint, material, Niagara

system, widget, level — every MCP server worth its salt exposes a dump_* / inspect_* / read_* family. Use it. Editing a graph without first knowing what's there creates broken connections, duplicate nodes, and unrecoverable corruption faster than anything else.

  1. Discover before assuming. Call tools/list once on connect, cache it,

and use it to figure out which tools your server actually exposes. Different servers wrap UE5 differently; recipes from this manual that reference a generic capability (e.g., "dump the Blueprint graph") will map to different concrete tool names on different servers.

  1. Verify after mutating. UE5 has too many silent-fail edges to trust a

successful response. Read the property back. Compare to what you asked for. If they differ, re-examine.

  1. Save explicitly. Most introspection tools serialize from disk. If

your last mutation is in-memory only, the dump returns the pre-mutation state. Save the asset (or SaveDirtyAssets) before re-reading.

2. UE5 reflection gotchas

These bite agents regardless of which MCP server sits in front of them. Every one has cost real debugging time.

2.1 PascalCase, not snake_case, for UPROPERTY writes

Setting a UPROPERTY via the Python binding's set_editor_property("auto_possess_ai", ...) silently no-ops on many builds. UPROPERTY names are PascalCase at the reflection layer: AutoPossessAI. Python's unreal module accepts snake_case at the call site, but the underlying lookup is case-sensitive against the PascalCase name. There is no error returned — the property simply doesn't change.

Detection pattern: round-trip verify. After any UPROPERTY write, read the property back and compare. Naive string compare misses normalization (EFoo::Bar vs Foo::Bar, (X=1,Y=2) vs (X=1.000000,Y=2.000000)). The robust pattern in native C++:

  1. Allocate a scratch buffer aligned to Property->GetMinAlignment() and

call Property->InitializeValue(Scratch).

  1. Property->ImportText_Direct(RequestedValue, Scratch, Owner, PPF_None)

to canonicalize what was requested.

  1. Property->ExportTextItem_Direct(ExpectedText, Scratch, ...) for the

canonical form of "what we asked for."

  1. Apply the write, then Property->ExportTextItem_Direct(ActualText, ...)

for "what we got."

  1. Compare ExpectedText to ActualText.

If they differ, the write didn't take — usually due to snake_case mismatch, an enum-class qualifier issue, or a struct-text format the property doesn't recognize.

2.2 Blueprint class path needs the _C suffix

LoadObject<UClass>(nullptr, "/Game/Path/BP_Foo") returns nullptr. The Blueprint's generated class lives under a different name: /Game/Path/BP_Foo.BP_Foo_C. StaticLoadClass expands this internally; LoadObject<UClass> does not.

If an MCP tool returns "Class not found: /Game/Path/BP_Foo," that's almost always the missing suffix. Retry with <path>.<asset>_C.

2.3 Async asset operations don't block

MetaHuman texture downloads, asset compilation, shader compilation, derived-data builds, Niagara compile, package save — all async. An agent that requests "download MetaHuman textures" and immediately reads the character sees the previous texture state, not the new one.

Patterns:

  • Poll the relevant Is*Complete predicate before continuing.
  • Subscribe to the completion delegate if the subsystem exposes one

(FAssetCompilingManager::Get().GetPostCompilationDelegate(), etc.).

  • For MetaHuman: poll IsTextureSourceRequestComplete(Character) after

RequestTextureSources.

  • For asset save: don't immediately re-read the package file; let

UPackage::SavePackage complete first.

2.4 Save before reading from disk

Many "dump" / "serialize" operations read the asset from its .uasset package on disk. If the most recent edits are in-memory only, the dump returns the pre-edit state. Save explicitly between mutate and read, or use an in-memory-aware introspection path if the server provides one.

2.5 PostEditChangeProperty is required after direct property writes

Property->CopyCompleteValue(Dest, Src) writes the value but doesn't fire PostEditChangeProperty. Any derived state set up by the object's PostEditChangeProperty handler — preview meshes, generated thumbnails, recompiles, dependent properties — won't update. Notify it manually:

FPropertyChangedEvent ChangeEvent(Property, EPropertyChangeType::ValueSet);
Object->PostEditChangeProperty(ChangeEvent);

The Details panel will show the new value either way, but the object's behaviour won't reflect it until the event fires.

2.6 Blueprint graph mutations need three steps, not one

To safely add a node to a UEdGraph:

  1. Construct the node (NewObject<UEdGraphNode>(Graph)).
  2. Graph->Nodes.Add(NewNode).
  3. Graph->NotifyGraphChanged().

Single-call helpers in some bindings do step 1 only and leave the graph in an inconsistent state — the node exists but the editor's pin-resolution + compile pipeline doesn't see it. Symptoms: phantom "missing node" errors at compile, broken connect operations, or nodes that vanish after editor reload.

2.7 Enum-string resolution has three accepted forms

UENUM-defined enums store their entries as fully-qualified FName forms like EAutoExposureMethod::AEM_Manual. UEnum::GetValueByNameString matches the fully-qualified form, but bare short names (AEM_Manual) and the Python-binding casing the unreal module exposes (AEM_MANUAL from unreal.EAutoExposureMethod.AEM_MANUAL) silently miss — those are the forms agents most naturally reach for, especially when copying values out of dump_post_process_settings output or Python docs.

A 3-step resolver covers the common cases:

int64 ResolveEnumValue(UEnum* Enum, const FString& Name)
{
    if (!Enum) return INDEX_NONE;
    int64 Val = Enum->GetValueByNameString(Name);            // EEnumType::ShortName
    if (Val != INDEX_NONE) return Val;
    Val = Enum->GetValueByName(FName(*Name));                // FName lookup
    if (Val != INDEX_NONE) return Val;
    const int32 N = Enum->NumEnums();                        // case-insensitive
    for (int32 i = 0; i < N; ++i)                            // suffix-after-::
    {
        FString EntryName = Enum->GetNameStringByIndex(i);
        int32 ColonPos = INDEX_NONE;
        if (EntryName.FindLastChar(TEXT(':'), ColonPos))
            EntryName = EntryName.RightChop(ColonPos + 1);
        if (EntryName.Equals(Name, ESearchCase::IgnoreCase))
            return Enum->GetValueByIndex(i);
    }
    return INDEX_NONE;
}

Affects every reflection-driven property setter that accepts enum-typed JSON strings (FEnumProperty, FByteProperty whose Enum field is populated, properties resolved via StaticEnum<...>()). The 1-step form Enum->GetValueByNameString(Name, EGetByNameFlags::CaseSensitive) is the most fragile — it rejects everything except the fully-qualified form. The fallback chain trades a tiny scan cost (enums rarely have more than a few dozen entries) for actually

Compartilhar X LinkedIn