Documentation Index
Fetch the complete documentation index at: https://mintlify.com/davidbuenov/dbv-mcp-server/llms.txt
Use this file to discover all available pages before exploring further.
A custom toolset is a C++ class derived from UToolsetDefinition, placed inside your project’s Source/ directory. Every static method annotated with UFUNCTION(meta = (AICallable)) is automatically exposed to the MCP server as a callable tool. AI agents connected to the server can discover these tools via list_toolsets and invoke them via call_tool.
Key rules for AICallable methods:
- Methods must be
static.
- Methods must have
UFUNCTION(meta = (AICallable)).
- Parameter names are serialized to camelCase in the JSON schema automatically by Unreal’s reflection system — incoming argument mapping is tolerant and transparent.
- The class itself must have
UCLASS(BlueprintType) to participate in Unreal’s UObject reflection.
The template files docs/templates/MyCustomSceneToolset.h and MyCustomSceneToolset.cpp are ready to copy directly into your Source/<YourProjectName>/ folder. Rename the class if needed. The code below is identical to those templates.
Create MyCustomSceneToolset.h in Source/<YourProjectName>/:
// =============================================================================
// MyCustomSceneToolset.h — Custom toolset template for the MCP server
// Part of the guide: Unreal MCP Web Client — docs/UNREAL_MCP_INTEGRATION_GUIDE.md
// Copyright (c) 2026 David Bueno Vallejo · https://github.com/davidbuenov
// Licensed under the MIT License. See LICENSE for details.
// Built with dbv-specs-ops · https://github.com/davidbuenov/dbv-specs-ops
// =============================================================================
//
// Copy this file to Source/<ProjectName>/ of your Unreal Engine 5.8 project
// (alongside its .cpp) and rename the class/file if needed. See Step 3 of
// docs/UNREAL_MCP_INTEGRATION_GUIDE.md for full details.
#pragma once
#include "CoreMinimal.h"
#include "ToolsetRegistry/ToolsetDefinition.h"
#include "MyCustomSceneToolset.generated.h"
UCLASS(BlueprintType)
class UMyCustomSceneToolset : public UToolsetDefinition
{
GENERATED_BODY()
public:
/**
* Counts how many actors match a static mesh name in the active level.
*/
UFUNCTION(meta = (AICallable), Category = "Scene Tools")
static int32 CountActorsWithMesh(const FString& MeshName);
/**
* Executes a multi-line Python command or script in the Editor.
*/
UFUNCTION(meta = (AICallable), Category = "Scene Tools")
static FString RunPython(const FString& Code);
};
Implementation file
Create MyCustomSceneToolset.cpp in the same directory:
// =============================================================================
// MyCustomSceneToolset.cpp — Custom toolset template for the MCP server
// Part of the guide: Unreal MCP Web Client — docs/UNREAL_MCP_INTEGRATION_GUIDE.md
// Copyright (c) 2026 David Bueno Vallejo · https://github.com/davidbuenov
// Licensed under the MIT License. See LICENSE for details.
// Built with dbv-specs-ops · https://github.com/davidbuenov/dbv-specs-ops
// =============================================================================
//
// Copy this file to Source/<ProjectName>/ of your Unreal Engine 5.8 project
// (alongside its .h) and rename the class/file if needed. See Step 3 of
// docs/UNREAL_MCP_INTEGRATION_GUIDE.md for full details.
#include "MyCustomSceneToolset.h"
#include "EngineUtils.h"
#include "Engine/World.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/StaticMesh.h"
#include "IPythonScriptPlugin.h" // Python Plugin header
int32 UMyCustomSceneToolset::CountActorsWithMesh(const FString& MeshName)
{
int32 Count = 0;
UWorld* World = GWorld;
if (World)
{
for (TActorIterator<AActor> It(World); It; ++It)
{
AActor* Actor = *It;
if (Actor && Actor->GetName().Contains(MeshName))
{
Count++;
}
}
}
return Count;
}
FString UMyCustomSceneToolset::RunPython(const FString& Code)
{
// 1. Verify the Python plugin is available in the Editor
if (IPythonScriptPlugin::Get() && IPythonScriptPlugin::Get()->IsPythonAvailable())
{
FPythonCommandEx PythonCommand;
PythonCommand.Command = Code;
// CRITICAL: Use ExecuteFile instead of ExecuteStatement to support
// multi-line scripts and import statements.
PythonCommand.ExecutionMode = EPythonCommandExecutionMode::ExecuteFile;
PythonCommand.FileExecutionScope = EPythonFileExecutionScope::Public;
bool bSuccess = IPythonScriptPlugin::Get()->ExecPythonCommandEx(PythonCommand);
return bSuccess ? TEXT("Python command executed successfully. Check Output Log for details.")
: TEXT("Failed to execute Python command. Check Output Log for errors.");
}
return TEXT("Python Script Plugin is not available.");
}
RunPython — multi-line script execution
RunPython uses EPythonCommandExecutionMode::ExecuteFile instead of ExecuteStatement. This is the critical distinction:
ExecuteStatement runs a single Python expression. It rejects multi-line code blocks and import statements — common pitfall when agents try to run complex scripts.
ExecuteFile treats the input string as a complete Python file, supporting import, loops, conditionals, function definitions, and any multi-statement logic an agent might generate.
The return value is intentionally minimal ("Python command executed successfully" or an error string). Detailed output, print() calls, and tracebacks are written to the Output Log under LogPython traces captured by FPythonCommandEx. Always check the Output Log when debugging agent-generated scripts.
CountActorsWithMesh — actor enumeration
CountActorsWithMesh demonstrates the basic pattern for iterating the active scene: obtain GWorld, walk it with TActorIterator<AActor>, and filter by name. Extend this pattern to return richer data (positions, component counts, asset paths) or operate on specific actor subclasses by templating the iterator (e.g., TActorIterator<AStaticMeshActor>).
File placement
Both files belong in Source/<YourProjectName>/ alongside your existing project C++ files:
Source/
└── MyProject/
├── MyProject.h
├── MyProject.cpp ← module entry point (registration goes here)
├── MyCustomSceneToolset.h ← copy here
└── MyCustomSceneToolset.cpp ← copy here
After adding the files, regenerate Visual Studio project files and perform a full build. The class will compile, but it will not appear in list_toolsets until you complete the registration step — see Toolset Registration.