More MCP work

This commit is contained in:
2026-03-08 21:28:47 -04:00
parent 93d4ed2038
commit 695de53b30
19 changed files with 388 additions and 546 deletions

View File

@@ -94,6 +94,10 @@ MCPErrorCallback::MCPErrorCallback(FJsonObject* Result)
: Func([Result](const FString& Msg) { MCPUtils::MakeErrorJson(Result, Msg); })
{}
MCPErrorCallback::MCPErrorCallback(FStringBuilderBase& OutResult)
: Func([&OutResult](const FString& Msg) { OutResult.Reset(); OutResult.Appendf(TEXT("ERROR: %s\n"), *Msg); })
{}
// ============================================================
// JSON helpers
// ============================================================
@@ -1494,3 +1498,64 @@ bool MCPUtils::PopulateFromJson(
return true;
}
// ============================================================
// FormatPropertyType — human-readable type name for a UPROPERTY
// ============================================================
FString MCPUtils::FormatPropertyType(FProperty* Prop)
{
if (CastField<FStrProperty>(Prop)) return TEXT("string");
if (CastField<FIntProperty>(Prop)) return TEXT("integer");
if (CastField<FFloatProperty>(Prop) || CastField<FDoubleProperty>(Prop)) return TEXT("number");
if (CastField<FBoolProperty>(Prop)) return TEXT("boolean");
if (FStructProperty* SP = CastField<FStructProperty>(Prop))
{
FString StructName = SP->Struct->GetName();
StructName.ReplaceInline(TEXT("MCP"), TEXT(""));
return StructName;
}
return TEXT("string");
}
// ============================================================
// FormatCommandHelp — verbose description of one handler command
// ============================================================
void MCPUtils::FormatCommandHelp(UClass* HandlerClass, FStringBuilderBase& Result)
{
const IMCPHandler* Handler = Cast<IMCPHandler>(HandlerClass->GetDefaultObject());
if (!Handler) return;
const FString& ToolName = HandlerClass->GetMetaData(TEXT("ToolName"));
// Command signature line
Result.Append(ToolName);
Result.Append(TEXT("("));
bool bFirst = true;
for (TFieldIterator<FProperty> PropIt(HandlerClass, EFieldIterationFlags::None); PropIt; ++PropIt)
{
if (!bFirst) Result.Append(TEXT(","));
bFirst = false;
if (PropIt->HasMetaData(TEXT("Optional"))) Result.Append(TEXT("?"));
Result.Append(PropertyNameToJsonKey(PropIt->GetName()));
}
Result.Append(TEXT(")\n"));
// Description and parameter details
Result.Appendf(TEXT(" %s\n"), *Handler->GetDescription());
for (TFieldIterator<FProperty> PropIt(HandlerClass, EFieldIterationFlags::None); PropIt; ++PropIt)
{
FProperty* Prop = *PropIt;
FString Name = PropertyNameToJsonKey(Prop->GetName());
FString Type = FormatPropertyType(Prop);
bool bOptional = Prop->HasMetaData(TEXT("Optional"));
const FString& Desc = Prop->GetMetaData(TEXT("Description"));
Result.Appendf(TEXT(" %s %s%s"),
*Type, *Name, bOptional ? TEXT(" (optional)") : TEXT(""));
if (!Desc.IsEmpty())
Result.Appendf(TEXT(" — %s"), *Desc);
Result.Append(TEXT("\n"));
}
}