ue-mcp 0.4.6 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,13 +20,15 @@ npx ue-mcp init
20
20
 
21
21
  The interactive setup will:
22
22
 
23
- 1. Ask for your `.uproject` path
23
+ 1. Find your `.uproject` (auto-detects in current directory)
24
24
  2. Let you choose which tool categories to enable
25
25
  3. Deploy the C++ bridge plugin to your project
26
26
  4. Enable required UE plugins (Niagara, PCG, GAS, etc.)
27
27
  5. Detect and configure your MCP client (Claude Code, Claude Desktop, Cursor)
28
28
 
29
- Restart the editor once after setup to load the bridge plugin. Then ask your AI:
29
+ Restart the editor once after setup to load the bridge plugin. To update later: `npx ue-mcp update`
30
+
31
+ Then ask your AI:
30
32
 
31
33
  ```
32
34
  project(action="get_status") — verify connection
@@ -36,7 +36,7 @@ export const blueprintTool = categoryTool("blueprint", "Blueprint reading, autho
36
36
  - rename_function: Rename function. Params: assetPath, oldName, newName
37
37
  - add_node: Add graph node (K2, AnimGraph, etc — any UEdGraphNode subclass). Params: assetPath, graphName?, nodeClass, nodeParams?
38
38
  - delete_node: Delete node. Params: assetPath, graphName, nodeName
39
- - set_node_property: Set node property. Params: assetPath, graphName, nodeName, propertyName, value
39
+ - set_node_property: Set node pin default or struct property (supports dot paths like "Node.IKBone.BoneName"). Params: assetPath, graphName, nodeName, propertyName, value
40
40
  - connect_pins: Wire nodes. Params: sourceNode, sourcePin, targetNode, targetPin, assetPath, graphName?
41
41
  - add_component: Add BP component. Params: assetPath, componentClass, componentName?
42
42
  - compile: Compile Blueprint. Params: assetPath
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ue-mcp",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "description": "Unreal Engine MCP server — 19 tools, 300+ actions for AI-driven editor control",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1325,6 +1325,25 @@ TSharedPtr<FJsonValue> FAnimationHandlers::GetBoneTransforms(const TSharedPtr<FJ
1325
1325
  return MakeShared<FJsonValueObject>(Result);
1326
1326
  }
1327
1327
 
1328
+ // ---------------------------------------------------------------------------
1329
+ // Helper: Set the protected SegmentLength property on an FAnimLinkableElement
1330
+ // (e.g. FCompositeSection) via reflection.
1331
+ // ---------------------------------------------------------------------------
1332
+ static void SetSegmentLength(FAnimLinkableElement& Element, float NewLength)
1333
+ {
1334
+ FProperty* Prop = FAnimLinkableElement::StaticStruct()->FindPropertyByName(TEXT("SegmentLength"));
1335
+ if (!Prop) return;
1336
+
1337
+ if (FFloatProperty* FloatProp = CastField<FFloatProperty>(Prop))
1338
+ {
1339
+ FloatProp->SetPropertyValue_InContainer(&Element, NewLength);
1340
+ }
1341
+ else if (FDoubleProperty* DoubleProp = CastField<FDoubleProperty>(Prop))
1342
+ {
1343
+ DoubleProp->SetPropertyValue_InContainer(&Element, static_cast<double>(NewLength));
1344
+ }
1345
+ }
1346
+
1328
1347
  // ---------------------------------------------------------------------------
1329
1348
  // Helper: Set the protected SequenceLength property on a montage via reflection.
1330
1349
  // Handles both float (UE 5.3 and earlier) and double (UE 5.4+) property types.
@@ -1436,7 +1455,7 @@ TSharedPtr<FJsonValue> FAnimationHandlers::SetMontageSequence(const TSharedPtr<F
1436
1455
  // Update composite sections' segment lengths to match new duration
1437
1456
  for (FCompositeSection& Section : Montage->CompositeSections)
1438
1457
  {
1439
- Section.SegmentLength = NewTotalLength;
1458
+ SetSegmentLength(Section, NewTotalLength);
1440
1459
  }
1441
1460
 
1442
1461
  Montage->PostEditChange();
@@ -1491,7 +1510,7 @@ TSharedPtr<FJsonValue> FAnimationHandlers::SetMontageProperties(const TSharedPtr
1491
1510
  // Also update composite sections' segment lengths to match
1492
1511
  for (FCompositeSection& Section : Montage->CompositeSections)
1493
1512
  {
1494
- Section.SegmentLength = NewLength;
1513
+ SetSegmentLength(Section, NewLength);
1495
1514
  }
1496
1515
  Modified.Add(TEXT("sequenceLength"));
1497
1516
  }
@@ -1986,7 +1986,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::SetNodeProperty(const TSharedPtr<FJso
1986
1986
  return MakeShared<FJsonValueObject>(Result);
1987
1987
  }
1988
1988
 
1989
- // Find the pin on the node
1989
+ // First try to find a pin with this name
1990
1990
  UEdGraphPin* TargetPin = nullptr;
1991
1991
  for (UEdGraphPin* Pin : TargetNode->Pins)
1992
1992
  {
@@ -1997,29 +1997,81 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::SetNodeProperty(const TSharedPtr<FJso
1997
1997
  }
1998
1998
  }
1999
1999
 
2000
- if (!TargetPin)
2000
+ bool bSetViaPin = false;
2001
+ bool bSetViaProperty = false;
2002
+
2003
+ if (TargetPin)
2001
2004
  {
2002
- // List available pins for better error message
2003
- TArray<FString> PinNames;
2004
- for (UEdGraphPin* Pin : TargetNode->Pins)
2005
+ // Set pin default value using the graph's own schema
2006
+ const UEdGraphSchema* Schema = TargetGraph->GetSchema();
2007
+ if (Schema)
2005
2008
  {
2006
- if (Pin)
2009
+ Schema->TrySetDefaultValue(*TargetPin, DefaultValue);
2010
+ TargetNode->PinDefaultValueChanged(TargetPin);
2011
+ bSetViaPin = true;
2012
+ }
2013
+ }
2014
+
2015
+ if (!bSetViaPin)
2016
+ {
2017
+ // No pin found — try setting as a node property via reflection.
2018
+ // Supports dotted paths like "Node.IKBone.BoneName" for AnimGraph inner structs.
2019
+ TArray<FString> PathParts;
2020
+ PinName.ParseIntoArray(PathParts, TEXT("."));
2021
+
2022
+ UStruct* CurrentStruct = TargetNode->GetClass();
2023
+ void* CurrentContainer = TargetNode;
2024
+ FProperty* FinalProp = nullptr;
2025
+
2026
+ for (int32 i = 0; i < PathParts.Num(); i++)
2027
+ {
2028
+ FProperty* Prop = CurrentStruct->FindPropertyByName(FName(*PathParts[i]));
2029
+ if (!Prop) break;
2030
+
2031
+ if (i < PathParts.Num() - 1)
2007
2032
  {
2008
- PinNames.Add(Pin->PinName.ToString());
2033
+ // Intermediate path segment — drill into struct
2034
+ FStructProperty* StructProp = CastField<FStructProperty>(Prop);
2035
+ if (!StructProp) break;
2036
+ CurrentContainer = StructProp->ContainerPtrToValuePtr<void>(CurrentContainer);
2037
+ CurrentStruct = StructProp->Struct;
2038
+ }
2039
+ else
2040
+ {
2041
+ FinalProp = Prop;
2009
2042
  }
2010
2043
  }
2011
- FString AvailablePins = FString::Join(PinNames, TEXT(", "));
2012
- Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Pin not found: '%s'. Available pins: [%s]"), *PinName, *AvailablePins));
2013
- Result->SetBoolField(TEXT("success"), false);
2014
- return MakeShared<FJsonValueObject>(Result);
2044
+
2045
+ if (FinalProp)
2046
+ {
2047
+ void* ValuePtr = FinalProp->ContainerPtrToValuePtr<void>(CurrentContainer);
2048
+ FinalProp->ImportText_Direct(*DefaultValue, ValuePtr, nullptr, PPF_None);
2049
+ TargetNode->PostEditChange();
2050
+ bSetViaProperty = true;
2051
+ }
2015
2052
  }
2016
2053
 
2017
- // Set the default value using the schema
2018
- const UEdGraphSchema_K2* Schema = GetDefault<UEdGraphSchema_K2>();
2019
- Schema->TrySetDefaultValue(*TargetPin, DefaultValue);
2054
+ if (!bSetViaPin && !bSetViaProperty)
2055
+ {
2056
+ // Neither pin nor property found — build a helpful error
2057
+ TArray<FString> PinNames;
2058
+ for (UEdGraphPin* Pin : TargetNode->Pins)
2059
+ {
2060
+ if (Pin) PinNames.Add(Pin->PinName.ToString());
2061
+ }
2062
+
2063
+ TArray<FString> PropNames;
2064
+ for (TFieldIterator<FProperty> It(TargetNode->GetClass()); It; ++It)
2065
+ {
2066
+ PropNames.Add(It->GetName());
2067
+ }
2020
2068
 
2021
- // Notify the node that a pin default changed
2022
- TargetNode->PinDefaultValueChanged(TargetPin);
2069
+ Result->SetStringField(TEXT("error"), FString::Printf(
2070
+ TEXT("'%s' not found as pin or property. Pins: [%s]. Properties: [%s]"),
2071
+ *PinName, *FString::Join(PinNames, TEXT(", ")), *FString::Join(PropNames, TEXT(", "))));
2072
+ Result->SetBoolField(TEXT("success"), false);
2073
+ return MakeShared<FJsonValueObject>(Result);
2074
+ }
2023
2075
 
2024
2076
  // Compile and save
2025
2077
  FKismetEditorUtilities::CompileBlueprint(Blueprint);
@@ -2036,8 +2088,9 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::SetNodeProperty(const TSharedPtr<FJso
2036
2088
  Result->SetStringField(TEXT("path"), AssetPath);
2037
2089
  Result->SetStringField(TEXT("graphName"), GraphName);
2038
2090
  Result->SetStringField(TEXT("nodeId"), NodeId);
2039
- Result->SetStringField(TEXT("pinName"), PinName);
2040
- Result->SetStringField(TEXT("defaultValue"), DefaultValue);
2091
+ Result->SetStringField(TEXT("propertyName"), PinName);
2092
+ Result->SetStringField(TEXT("value"), DefaultValue);
2093
+ Result->SetStringField(TEXT("setVia"), bSetViaPin ? TEXT("pin") : TEXT("property"));
2041
2094
  Result->SetBoolField(TEXT("success"), true);
2042
2095
 
2043
2096
  return MakeShared<FJsonValueObject>(Result);