diff --git a/MCPForUnity/Editor/Helpers/VectorParsing.cs b/MCPForUnity/Editor/Helpers/VectorParsing.cs
index 60bb7e818..adb20657e 100644
--- a/MCPForUnity/Editor/Helpers/VectorParsing.cs
+++ b/MCPForUnity/Editor/Helpers/VectorParsing.cs
@@ -96,6 +96,49 @@ public static Vector3 ParseVector3OrDefault(JToken token, Vector3 defaultValue =
return null;
}
+ ///
+ /// Parses a JToken (array or object) into a Vector4.
+ ///
+ /// The JSON token to parse
+ /// The parsed Vector4 or null if parsing fails
+ public static Vector4? ParseVector4(JToken token)
+ {
+ if (token == null || token.Type == JTokenType.Null)
+ return null;
+
+ try
+ {
+ // Array format: [x, y, z, w]
+ if (token is JArray array && array.Count >= 4)
+ {
+ return new Vector4(
+ array[0].ToObject(),
+ array[1].ToObject(),
+ array[2].ToObject(),
+ array[3].ToObject()
+ );
+ }
+
+ // Object format: {x: 1, y: 2, z: 3, w: 4}
+ if (token is JObject obj && obj.ContainsKey("x") && obj.ContainsKey("y") &&
+ obj.ContainsKey("z") && obj.ContainsKey("w"))
+ {
+ return new Vector4(
+ obj["x"].ToObject(),
+ obj["y"].ToObject(),
+ obj["z"].ToObject(),
+ obj["w"].ToObject()
+ );
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.LogWarning($"[VectorParsing] Failed to parse Vector4 from '{token}': {ex.Message}");
+ }
+
+ return null;
+ }
+
///
/// Parses a JToken (array or object) into a Quaternion.
/// Supports both euler angles [x, y, z] and quaternion components [x, y, z, w].
diff --git a/MCPForUnity/Editor/Tools/ManageScriptableObject.cs b/MCPForUnity/Editor/Tools/ManageScriptableObject.cs
index 0de309cab..771e1aca1 100644
--- a/MCPForUnity/Editor/Tools/ManageScriptableObject.cs
+++ b/MCPForUnity/Editor/Tools/ManageScriptableObject.cs
@@ -1,9 +1,7 @@
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.IO;
using System.Linq;
-using System.Reflection;
using System.Text.RegularExpressions;
using MCPForUnity.Editor.Helpers;
using Newtonsoft.Json.Linq;
@@ -229,6 +227,26 @@ private static object HandleModify(JObject @params)
return new ErrorResponse(CodeInvalidParams, new { message = "'patches' must be an array.", targetPath, targetGuid });
}
+ // Phase 5: Dry-run mode - validate patches without applying
+ bool dryRun = @params["dryRun"]?.ToObject() ?? @params["dry_run"]?.ToObject() ?? false;
+
+ if (dryRun)
+ {
+ var validationResults = ValidatePatches(target, patches);
+ return new SuccessResponse(
+ "Dry-run validation complete.",
+ new
+ {
+ targetGuid,
+ targetPath,
+ targetTypeName = target.GetType().FullName,
+ dryRun = true,
+ valid = validationResults.All(r => (bool)r.GetType().GetProperty("ok")?.GetValue(r)),
+ validationResults
+ }
+ );
+ }
+
var (results, warnings) = ApplyPatches(target, patches);
return new SuccessResponse(
@@ -244,6 +262,148 @@ private static object HandleModify(JObject @params)
);
}
+ ///
+ /// Validates patches without applying them (for dry-run mode).
+ /// Checks that property paths exist and that value types are compatible.
+ ///
+ private static List