VibeUE

MCP Server for Unreal Engine

CREATE CUSTOM TOOLS

Extend VibeUE with custom tools built as Unreal Engine plugins

📚 Example Repository

For a complete working example with all source code, visit the SampleExtension repository:

🔗 View SampleExtension on GitHub

VibeUE can be extended with custom tools in two ways:

Via MCP Servers

Connect external MCP servers with their own tools. See Configure MCP Servers for details.

Via Unreal Plugins

Build custom tools as Unreal Engine plugins using VibeUE's macros. This is the focus of this guide.

Example Repository: See kevinpbuckley/SampleExtension for a complete working example.

⚡ Quick Start

  1. Create Plugin - Use Unreal Editor's plugin wizard: File → New → New Plugin
  2. Add VibeUE Dependency - Configure plugin to depend on VibeUE
  3. Register Tools - Use REGISTER_VIBEUE_TOOL macro to define your tools
  4. Build & Test - Compile and restart Unreal Editor
  5. Use in VibeUE - Your tools appear in AI Chat and can be called directly

📁 Plugin Structure

Recommended Directory Layout

MyCustomTools/
├── MyCustomTools.uplugin          # Plugin descriptor
├── Source/
│   └── MyCustomTools/
│       ├── MyCustomTools.Build.cs # Build configuration
│       ├── Public/
│       │   ├── MyCustomToolsModule.h
│       │   └── Tools/
│       │       └── MyTools.h       # Tool declarations
│       └── Private/
│           ├── MyCustomToolsModule.cpp
│           ├── MyToolRegistration.cpp # Tool registration
│           └── Tools/
│               └── MyTools.cpp     # Tool implementations
└── Binaries/                       # Compiled output
    └── Intermediate/              # Build intermediate files

⚙️ Plugin Configuration

1. Create Plugin Descriptor (MyCustomTools.uplugin)

{
    "FileVersion": 3,
    "Version": 1,
    "VersionName": "1.0",
    "EngineVersion": "5.7",
    "FriendlyName": "My Custom Tools",
    "Description": "Custom tools for VibeUE",
    "Category": "Editor",
    "CreatedBy": "Your Name",
    "CanContainContent": true,
    "IsBetaVersion": false,
    "IsExperimentalVersion": false,
    "Installed": false,
    "Modules": [
        {
            "Name": "MyCustomTools",
            "Type": "Editor",
            "LoadingPhase": "Default"
        }
    ],
    "Plugins": [
        {
            "Name": "VibeUE",
            "Enabled": true
        }
    ]
}

2. Configure Build (Source/MyCustomTools/MyCustomTools.Build.cs)

using UnrealBuildTool;

public class MyCustomTools : ModuleRules
{
    public MyCustomTools(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[]
        {
            "Core",
            "CoreUObject",
            "Engine",
            "VibeUE"  // Required for tool registration
        });

        PrivateDependencyModuleNames.AddRange(new string[]
        {
            "UnrealEd",
            "Slate",
            "SlateCore"
        });
    }
}

🛠️ Creating Tools

Header File (Public/Tools/SampleTools.h)

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "SampleTools.generated.h"

/**
 * Sample tools class demonstrating VibeUE tool registration
 */
UCLASS()
class USampleTools : public UObject
{
	GENERATED_BODY()

public:
	/**
	 * Create a new level with specified parameters
	 * @param LevelPath The path where to create the level
	 * @param LevelName The name of the new level
	 * @param bOpenWorld Whether to create an open world level
	 * @return Success message or error description
	 */
	static FString CreateNewLevel(const FString& LevelPath, const FString& LevelName, bool bOpenWorld);
};

Implementation File (Private/Tools/SampleTools.cpp)

// Copyright Epic Games, Inc. All Rights Reserved.

#include "Tools/SampleTools.h"
#include "Engine/World.h"
#include "Engine/Level.h"
#include "EditorLevelLibrary.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "FileHelpers.h"

FString USampleTools::CreateNewLevel(const FString& LevelPath, const FString& LevelName, bool bOpenWorld)
{
	// Validate inputs
	if (LevelPath.IsEmpty() || LevelName.IsEmpty())
	{
		return TEXT("Error: Level path and name cannot be empty");
	}

	// Construct the full level path
	FString FullLevelPath = FString::Printf(TEXT("%s/%s"), *LevelPath, *LevelName);

	// Create the new level
	UWorld* NewWorld = UEditorLevelLibrary::CreateNewLevel(FullLevelPath, bOpenWorld);
	
	if (!NewWorld)
	{
		return FString::Printf(TEXT("Error: Failed to create level at %s"), *FullLevelPath);
	}

	return FString::Printf(TEXT("Successfully created %s level: %s"),
		bOpenWorld ? TEXT("open world") : TEXT("normal"),
		*FullLevelPath);
}

📝 Register Tools

Registration File (Private/SampleToolRegistration.cpp)

#include "Tools/SampleTools.h"
#include "VibeUE/Public/Core/ToolRegistry.h"

// Register the create_new_level tool with VibeUE
REGISTER_VIBEUE_TOOL(create_new_level,
    "Create a new level in the editor",
    "Levels",
    TOOL_PARAMS(
        TOOL_PARAM("LevelPath", "Path where to save the level (e.g., /Game/Maps/)", "string", true),
        TOOL_PARAM("LevelName", "Name for the new level", "string", true),
        TOOL_PARAM("OpenWorld", "Whether to open the level after creation", "boolean", false)
    ),
    {
        FString LevelPath = Params.FindRef(TEXT("LevelPath"));
        FString LevelName = Params.FindRef(TEXT("LevelName"));
        bool bOpenWorld = Params.FindRef(TEXT("OpenWorld")).Equals(TEXT("true"), ESearchCase::IgnoreCase);

        return USampleTools::CreateNewLevel(LevelPath, LevelName, bOpenWorld);
    }
);

REGISTER_VIBEUE_TOOL Macro Reference

tool_name

String identifier for the tool (snake_case recommended)

description

Human-readable description shown in AI chat

category

Category for tool organization (e.g., "Custom", "Assets", "Actors")

TOOL_PARAMS(...)

Define parameters with TOOL_PARAM("name", "description", "type", required)

implementation

Lambda function receiving TMap<FString, FString> of parameters, returns FString

📦 Parameter Types

Type Description Usage
string Text input Params.FindRef(TEXT("param_name"))
number Numeric input (float/int) FCString::Atof() or FCString::Atoi()
boolean True/false value FString::ToBool()
array Array of values Parse as comma-separated values
object Complex JSON object Parse with FJsonObject

🚀 Installation & Usage

Step 1: Copy Plugin to Your Project

YourProject/
├── Plugins/
│   ├── VibeUE/           # Must be installed
│   └── MyCustomTools/    # Your plugin
└── YourProject.uproject

Step 2: Enable Plugin

  1. Open Unreal Editor
  2. Go to Edit → Plugins
  3. Search for your plugin name
  4. Check Enabled checkbox
  5. Restart the editor

Step 3: Use Your Tools

Open VibeUE AI Chat and use your tools:

# In natural language:
Create a new level called TestLevel in /Game/Maps

# Or using direct tool syntax:
create_new_level(LevelPath="/Game/Maps", LevelName="TestLevel", OpenWorld=false)

✨ Best Practices

Clear Descriptions

Write detailed descriptions for your tools so the AI understands their purpose

Error Handling

Always validate inputs and return clear error messages on failure

Safe Operations

Check for null pointers, valid worlds, and editor availability before performing operations

Logical Organization

Group related tools in categories and use consistent naming conventions

Documentation

Document your tools with clear parameter descriptions and usage examples

📚 References

→ SampleExtension Repository

Complete working example of a VibeUE plugin with custom tools

→ VibeUE Tools Reference

Documentation of all built-in VibeUE tools

→ Configure MCP Servers

Alternative way to extend VibeUE with external MCP servers