# Herramientas personalizadas — Unreal Engine · AI Game Developer Wiki

Añade herramientas de IA, módulos RQL, prompts y recursos a Unreal MCP desde cualquier plugin de C++ y expón herramientas de gameplay en el juego.

Esta página se tradujo automáticamente del inglés. [Lee el original en inglés](https://ai-game.dev/docs/wiki/unreal/custom-tools).

Unreal MCP permite que cualquier plugin de Unreal, incluidos los del propio proyecto de tu juego, añada capacidades para agentes de IA. No bifurcas Unreal MCP: implementas una pequeña interfaz pública, la registras como **modular feature** de Unreal y el plugin la detecta cuando se carga tu módulo.

Esta página es para desarrolladores de C++. Si solo quieres más cobertura del motor, consulta primero las [extensiones](https://ai-game.dev/es/docs/wiki/unreal/extensions) ya listas.

## Elige el tipo de contribución adecuado

| Quieres que el agente… | Contribuye con | Interfaz |
| --- | --- | --- |
| Leer o cambiar datos del editor para una característica del motor o tus propios tipos | Un **módulo RQL** (recomendado para trabajo en el editor) | `IUnrealMcpRqlModule` |
| Ejecutar una acción que no sea acceso a datos, o actuar dentro de un juego en ejecución | **Herramientas** | `IUnrealMcpToolProvider` |
| Obtener una plantilla de prompt reutilizable | **Prompts** | `IUnrealMcpPromptProvider` |
| Leer contenido fijo por URI | **Recursos** | `IUnrealMcpResourceProvider` |

Todas las extensiones propias son módulos RQL, así que el agente accede a ellas mediante las mismas herramientas `rql-query` y `rql-mutate` que al resto del editor.

## Opción 1: un módulo RQL

Depende del módulo `UnrealMcpRql` en el `Build.cs` de tu módulo de editor y declara el plugin `UnrealMCP` en el array `Plugins` de tu `.uplugin`. Después, implementa el módulo:

```cpp
#include "IUnrealMcpRqlModule.h"

class FMyRqlModule : public IUnrealMcpRqlModule
{
public:
    virtual FString GetRqlModuleName() const override { return TEXT("Niagara"); }
    virtual FString GetExtensionId() const override { return TEXT("com.example.niagara-ai"); }
    virtual FString GetExtensionVersion() const override { return UnrealMcpRql::PluginVersion(TEXT("MyNiagaraAI")); }
    virtual void ConfigureRql(FUnrealMcpRqlModuleContext& Context) override
    {
        Context.AddAssetSource(TEXT("niagaraSystems"), TEXT("Niagara system assets"), UNiagaraSystem::StaticClass());
        Context.AddApiSource(TEXT("niagara"), TEXT("Niagara operations"), UMyNiagaraOperations::StaticClass(),
            TEXT("NiagaraOperations"));
        Context.AddGuide(TEXT("Niagara"), TEXT("... markdown with example queries ..."));
    }
};

IMPLEMENT_MODULE(TUnrealMcpRqlEditorModule<FMyRqlModule>, MyNiagaraAI)
```

Lo que el contexto puede añadir:

- **Fuentes** (donde comienza una consulta): `AddObjectSource`, `AddObjectListSource`, `AddAssetSource`, `AddClassDefaultsSource`.
- **Operaciones** (se invocan con `call`): `AddApiClass` o `AddApiSource` hacen que cualquier `UFUNCTION` de una clase se pueda invocar. Decláralas `UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))`; el comentario de documentación que hay encima de cada una se convierte en la descripción que lee el agente.
- **Miembros**: `ExposeProperties` para propiedades que la reflexión oculta, y miembros calculados de solo lectura con `AddJsonMember`, `AddObjectMember`, `AddObjectListMember`.
- **Guías**: `AddGuide` añade una sección a la skill `unreal-rql`.

Una mutación se ejecuta en una única transacción del editor, así que crea los objetos con `RF_Transactional` y llama a `Modify()` en lo que modifiques. La sección Extensions del editor lista tu módulo y permite deshabilitarlo. La referencia compilable es el plugin `samples/UnrealAITemplate` del [repositorio Unreal-MCP](https://github.com/IvanMurzak/Unreal-MCP).

## Opción 2: herramientas personalizadas

### Paso 1: añade la dependencia

En el `Build.cs` de tu módulo:

```csharp
PublicDependencyModuleNames.AddRange(new string[] { "Core" });

PrivateDependencyModuleNames.AddRange(new string[]
{
    "CoreUObject", "Engine", "Projects",
    "Json",            // the registry header includes Dom/JsonObject.h
    "UnrealMcpEditor", // the extension contract and tool registry
});
```

En tu `.uplugin`, añade la dependencia del plugin para que se resuelva el orden de carga:

```json
{
  "Plugins": [ { "Name": "UnrealMCP", "Enabled": true } ]
}
```

### Paso 2: implementa el proveedor

```cpp
#include "IUnrealMcpToolProvider.h"
#include "UnrealMcpToolRegistry.h"

class FMyExtensionProvider : public IUnrealMcpToolProvider
{
public:
    virtual FString GetExtensionId() const override      { return TEXT("com.foo.my-extension"); }
    virtual FText   GetDisplayName() const override      { return NSLOCTEXT("Foo", "Name", "My Extension"); }
    virtual FString GetExtensionVersion() const override { return TEXT("1.0.0"); }

    virtual void RegisterTools(FUnrealMcpToolRegistry& Registry) override
    {
        Registry.Tool(TEXT("hello-extension"))
            .Title(TEXT("Hello Extension"))
            .Description(TEXT("Returns a friendly greeting."))
            .ParamString(TEXT("name"), TEXT("Who to greet. Defaults to 'world'."))
            .ReadOnlyHint(true).DestructiveHint(false).IdempotentHint(true).OpenWorldHint(false)
            .Handle([](const FUnrealMcpToolCall& Call) -> FUnrealMcpToolResult
            {
                const FString Name = Call.Has(TEXT("name")) ? Call.GetString(TEXT("name")) : TEXT("world");
                return FUnrealMcpToolResult::Success(FString::Printf(TEXT("Hello, %s!"), *Name));
            });
    }
};
```

El builder ofrece `.Title`, `.Description`, los helpers de parámetros `.ParamString`, `.ParamInt`, `.ParamNumber`, `.ParamBool` y `.ParamVector` (pasa `EUnrealMcpParamRequirement::Required` para uno obligatorio), los cuatro hints de MCP y `.Handle`. El handler se ejecuta en el hilo del juego, así que puedes llamar directamente a las API del editor y de `UObject`.

Reglas importantes:

- Los ids de las herramientas usan kebab-case: letras minúsculas y dígitos separados por un único guion.
- Asigna un título a cada herramienta y los cuatro hints. Marca como destructiva cualquier herramienta que elimine o sobrescriba.
- No llames tú a `.ExtensionId(...)`; tu `GetExtensionId()` se aplica automáticamente.

### Paso 3: regístralo como una modular feature

```cpp
virtual void StartupModule() override
{
    Provider = MakeUnique<FMyExtensionProvider>();
    IModularFeatures::Get().RegisterModularFeature(
        IUnrealMcpToolProvider::GetModularFeatureName(), Provider.Get());
}

virtual void ShutdownModule() override
{
    if (Provider.IsValid())
    {
        IModularFeatures::Get().UnregisterModularFeature(
            IUnrealMcpToolProvider::GetModularFeatureName(), Provider.Get());
        Provider.Reset();
    }
}
```

Mantén el proveedor vivo mientras esté registrado y anula siempre su registro al apagar.

## Cómo funciona el registro

- **Descubrimiento y recarga en caliente.** Los proveedores se detectan al iniciar el editor. Cargar o descargar tu módulo después reconstruye el registro y los clientes de IA ven el cambio automáticamente.
- **Orden determinista.** Los proveedores se fusionan en orden ascendente de id de extensión; las herramientas dentro de un mismo proveedor conservan su orden de declaración.
- **Aislamiento.** Una herramienta no válida (id incorrecto, esquema roto, sin handler) o un nombre de herramienta duplicado se descarta y se registra en la entrada de tu extensión. Tus demás herramientas y las demás extensiones no se ven afectadas. Un fallo dentro de un handler sigue siendo un fallo del editor, así que valida las entradas y devuelve `FUnrealMcpToolResult::Error(...)`.
- **Visibilidad y conmutadores.** Tus herramientas tienen la misma casilla **Visible** en la ventana MCP Tools que las integradas. Una extensión deshabilitada no aporta nada.

## Prompts y recursos

Los prompts y los recursos usan el mismo patrón con `IUnrealMcpPromptProvider` más `FUnrealMcpPromptRegistry`, y `IUnrealMcpResourceProvider` más `FUnrealMcpResourceRegistry`. Un prompt declara parámetros con los mismos helpers `Param*` y devuelve mensajes etiquetados por rol. Un recurso se identifica por su URI y devuelve texto o un blob en base64 con un tipo MIME. Hoy solo se admiten URIs fijas, no con plantillas. El prompt integrado `level-design-brief` y el recurso `unreal://project/levels` son referencias que funcionan.

## Genera una herramienta con el agente

Con una instalación del plugin desde el código fuente, la herramienta de sistema `unreal-skill-create` escribe un nuevo archivo de herramienta en C++ en el módulo de editor del plugin. La herramienta solo existe después de recompilar el editor (Live Coding o una recompilación del proyecto).

## Herramientas en el juego (tiempo de ejecución)

Unreal MCP también puede conectar un juego en ejecución (Play In Editor, Standalone o una compilación Development empaquetada) para que un agente de IA pueda controlarlo. Una conexión en tiempo de ejecución no ofrece herramientas del motor: solo las herramientas que registre tu juego.

1. Haz que tu módulo de juego dependa de `UnrealMcpRuntime` (no de `UnrealMcpEditor`) y crea las herramientas exactamente como se ha descrito arriba.
2. Activa **Project Settings, Plugins, Unreal MCP (Runtime)**. El interruptor está desactivado por defecto y se guarda en `DefaultGame.ini`.
3. Conéctate explícitamente. El juego nunca se conecta por sí solo.

Desde C++:

```cpp
#include "UnrealMcpRuntimeSubsystem.h"

if (UUnrealMcpRuntimeSubsystem* Mcp = UUnrealMcpRuntimeSubsystem::Get(this))
{
    Mcp->RegisterToolProvider(MyToolProvider);
    Mcp->Connect(TEXT("http://localhost:8080"), TEXT("my-token"));
}
```

Desde Blueprint, usa **Get Unreal MCP Runtime Subsystem** y luego **Connect**, **Disconnect** e **Is Connected**. Desde la consola:

```text
UnrealMcp.Connect <host> [token]
UnrealMcp.Disconnect
```

Reglas de seguridad integradas en `Connect()`:

- Las compilaciones Shipping se niegan a conectarse a menos que compiles con el flag `bUnrealMcpAllowShipping`.
- Solo se permiten hosts de loopback a menos que pases `bAllowRemoteHost = true`.
- El modo de tiempo de ejecución solo funciona en plataformas de escritorio (Windows, macOS, Linux).

El plugin `samples/UnrealAIRuntimeSample` del repositorio añade una herramienta `game-time-dilation` que lee y establece la dilatación temporal del mundo en un juego en ejecución. Si no necesitas herramientas en tiempo de ejecución, excluye el plugin de las compilaciones empaquetadas como se describe en [Instalación](https://ai-game.dev/es/docs/wiki/unreal/installation#editor-only).

---

Source (HTML): https://ai-game.dev/es/docs/wiki/unreal/custom-tools

Machine-translated (es) from the English page: https://ai-game.dev/docs/wiki/unreal/custom-tools
