2025-09-03 10:27:40 +08:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2025-12-29 12:57:57 +08:00
|
|
|
using System.Linq;
|
2025-09-03 10:27:40 +08:00
|
|
|
using NUnit.Framework;
|
|
|
|
|
using UnityEngine;
|
2025-09-04 00:57:12 +08:00
|
|
|
using UnityEngine.TestTools;
|
2025-09-03 10:27:40 +08:00
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
|
using MCPForUnity.Editor.Tools;
|
|
|
|
|
|
|
|
|
|
namespace MCPForUnityTests.Editor.Tools
|
|
|
|
|
{
|
|
|
|
|
public class ManageGameObjectTests
|
|
|
|
|
{
|
|
|
|
|
private GameObject testGameObject;
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
[SetUp]
|
|
|
|
|
public void SetUp()
|
|
|
|
|
{
|
|
|
|
|
// Create a test GameObject for each test
|
|
|
|
|
testGameObject = new GameObject("TestObject");
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-01 04:25:33 +08:00
|
|
|
[TearDown]
|
2025-09-03 10:27:40 +08:00
|
|
|
public void TearDown()
|
|
|
|
|
{
|
|
|
|
|
// Clean up test GameObject
|
|
|
|
|
if (testGameObject != null)
|
|
|
|
|
{
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(testGameObject);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void HandleCommand_ReturnsError_ForNullParams()
|
|
|
|
|
{
|
|
|
|
|
var result = ManageGameObject.HandleCommand(null);
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
Assert.IsNotNull(result, "Should return a result object");
|
|
|
|
|
// Note: Actual error checking would need access to Response structure
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-01 04:25:33 +08:00
|
|
|
[Test]
|
2025-09-03 10:27:40 +08:00
|
|
|
public void HandleCommand_ReturnsError_ForEmptyParams()
|
|
|
|
|
{
|
|
|
|
|
var emptyParams = new JObject();
|
|
|
|
|
var result = ManageGameObject.HandleCommand(emptyParams);
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
Assert.IsNotNull(result, "Should return a result object for empty params");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void HandleCommand_ProcessesValidCreateAction()
|
|
|
|
|
{
|
|
|
|
|
var createParams = new JObject
|
|
|
|
|
{
|
|
|
|
|
["action"] = "create",
|
|
|
|
|
["name"] = "TestCreateObject"
|
|
|
|
|
};
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
var result = ManageGameObject.HandleCommand(createParams);
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
Assert.IsNotNull(result, "Should return a result for valid create action");
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
// Clean up - find and destroy the created object
|
|
|
|
|
var createdObject = GameObject.Find("TestCreateObject");
|
|
|
|
|
if (createdObject != null)
|
|
|
|
|
{
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(createdObject);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void ComponentResolver_Integration_WorksWithRealComponents()
|
|
|
|
|
{
|
|
|
|
|
// Test that our ComponentResolver works with actual Unity components
|
|
|
|
|
var transformResult = ComponentResolver.TryResolve("Transform", out Type transformType, out string error);
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
Assert.IsTrue(transformResult, "Should resolve Transform component");
|
|
|
|
|
Assert.AreEqual(typeof(Transform), transformType, "Should return correct Transform type");
|
|
|
|
|
Assert.IsEmpty(error, "Should have no error for valid component");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void ComponentResolver_Integration_WorksWithBuiltInComponents()
|
|
|
|
|
{
|
|
|
|
|
var components = new[]
|
|
|
|
|
{
|
|
|
|
|
("Rigidbody", typeof(Rigidbody)),
|
2025-10-01 04:25:33 +08:00
|
|
|
("Collider", typeof(Collider)),
|
2025-09-03 10:27:40 +08:00
|
|
|
("Renderer", typeof(Renderer)),
|
|
|
|
|
("Camera", typeof(Camera)),
|
|
|
|
|
("Light", typeof(Light))
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
foreach (var (componentName, expectedType) in components)
|
|
|
|
|
{
|
|
|
|
|
var result = ComponentResolver.TryResolve(componentName, out Type actualType, out string error);
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
// Some components might not resolve (abstract classes), but the method should handle gracefully
|
|
|
|
|
if (result)
|
|
|
|
|
{
|
2025-10-01 04:25:33 +08:00
|
|
|
Assert.IsTrue(expectedType.IsAssignableFrom(actualType),
|
2025-09-03 10:27:40 +08:00
|
|
|
$"{componentName} should resolve to assignable type");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Assert.IsNotEmpty(error, $"Should have error message for {componentName}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void PropertyMatching_Integration_WorksWithRealGameObject()
|
|
|
|
|
{
|
|
|
|
|
// Add a Rigidbody to test real property matching
|
|
|
|
|
var rigidbody = testGameObject.AddComponent<Rigidbody>();
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
var properties = ComponentResolver.GetAllComponentProperties(typeof(Rigidbody));
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
Assert.IsNotEmpty(properties, "Rigidbody should have properties");
|
|
|
|
|
Assert.Contains("mass", properties, "Rigidbody should have mass property");
|
|
|
|
|
Assert.Contains("useGravity", properties, "Rigidbody should have useGravity property");
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
// Test AI suggestions
|
🔧 Clean up & Consolidate Shared Services Across MCP Tools (#519)
* feat: Redesign GameObject API for better LLM ergonomics
- find_gameobjects: Search GameObjects, returns paginated instance IDs only
- manage_components: Component lifecycle (add, remove, set_property)
- unity://scene/gameobject/{id}: Single GameObject data (no component serialization)
- unity://scene/gameobject/{id}/components: All components (paginated)
- unity://scene/gameobject/{id}/component/{name}: Single component by type
- manage_scene get_hierarchy: Now includes componentTypes array
- manage_gameobject: Slimmed to lifecycle only (create, modify, delete)
- Legacy actions (find, get_components, etc.) log deprecation warnings
- ParamCoercion: Centralized int/bool/float/string coercion
- VectorParsing: Vector3/Vector2/Quaternion/Color parsing
- GameObjectLookup: Centralized GameObject search logic
- 76 new Unity EditMode tests for ManageGameObject actions
- 21 new pytest tests for Python tools/resources
- New NL/T CI suite for GameObject API (GO-0 to GO-5)
Addresses LLM confusion with parameter overload by splitting into
focused tools and read-only resources.
* feat: Add GameObject API stress tests and NL/T suite updates
Stress Tests (12 new tests):
- BulkCreate small/medium batches
- FindGameObjects pagination with by_component search
- AddComponents to single object
- GetComponents with full serialization
- SetComponentProperties (complex Rigidbody)
- Deep hierarchy creation and path lookup
- GetHierarchy with large scenes
- Resource read performance tests
- RapidFire create-modify-delete cycles
NL/T Suite Updates:
- Added GO-0..GO-10 tests in nl-gameobject-suite.md
- Fixed tool naming: mcp__unity__ → mcp__UnityMCP__
Other:
- Fixed LongUnityScriptClaudeTest.cs compilation errors
- Added reports/, .claude/local/, scripts/local-test/ to .gitignore
All 254 EditMode tests pass (250 run, 4 explicit skips)
* fix: Address code review feedback
- ParamCoercion: Use CultureInfo.InvariantCulture for float parsing
- ManageComponents: Move Transform removal check before GetComponent
- ManageGameObjectFindTests: Use try-finally for LogAssert.ignoreFailingMessages
- VectorParsing: Document that quaternions are not auto-normalized
- gameobject.py: Prefix unused ctx parameter with underscore
* fix: Address more code review feedback
NL/T Prompt Fixes:
- nl-gameobject-suite.md: Remove non-existent list_resources/read_resource from AllowedTools
- nl-gameobject-suite.md: Fix parameter names (component_type, properties)
- nl-unity-suite-nl.md: Remove unused manage_editor from AllowedTools
Test Fixes:
- GameObjectAPIStressTests: Add null check to ToJObject helper
- GameObjectAPIStressTests: Clarify AudioSource usage comment
- ManageGameObjectFindTests: Use built-in 'UI' layer instead of 'Water'
- LongUnityScriptClaudeTest: Clean up NL/T test artifacts (Counte42 typo, HasTarget)
* docs: update README tools and resources lists
- Add missing tools: manage_components, batch_execute, find_gameobjects, refresh_unity
- Add missing resources: gameobject_api, editor_state_v2
- Make descriptions more concise across all tools and resources
- Ensure documentation matches current MCP server functionality
* chore: Remove accidentally committed test artifacts
- Remove Materials folder (40 .mat files from interactive testing)
- Remove Shaders folder (5 noise shaders from testing)
- Remove test scripts (Bounce*, CylinderBounce* from testing)
- Remove Temp.meta and commit.sh
* refactor: remove deprecated manage_gameobject actions
- Remove deprecated switch cases: find, get_components, get_component, add_component, remove_component, set_component_property
- Remove deprecated wrapper methods (423 lines deleted from ManageGameObject.cs)
- Delete ManageGameObjectFindTests.cs (tests deprecated 'find' action)
- Remove deprecated test methods from ManageGameObjectTests.cs
- Add GameObject resource URIs to README documentation
- Add batch_execute performance tips to README, tool description, and gameobject_api resource
- Enhance batch_execute description to emphasize 10-100x performance gains
Total: ~1200 lines removed. New API (find_gameobjects, manage_components, resources) is the recommended path forward.
* refactor: consolidate shared services across MCP tools
Major architectural improvements:
- Create UnityJsonSerializer for shared JSON/Unity type conversion
- Create ObjectResolver for unified object resolution (GameObjects, Components, Assets)
- Create UnityTypeResolver for consolidated type resolution with caching
- Create PropertyConversion for unified JSON→Unity property conversion
- Create ComponentOps for low-level component operations
- Create Pagination helpers for standardized pagination across tools
Tool simplifications:
- ManageGameObject: Remove 68-line prefab redirect anti-pattern, delegate to helpers
- ManageAsset: Remove ~80 lines duplicate ConvertJTokenToType
- ManageScriptableObject: Remove ~40 lines duplicate ResolveType
- ManageComponents: Use ComponentOps, UnityTypeResolver (~90 lines saved)
- ManageMaterial: Standardize to SuccessResponse/ErrorResponse patterns
- FindGameObjects: Use PaginationRequest/PaginationResponse
- GameObjectLookup: FindComponentType delegates to UnityTypeResolver
Tests: 242/246 passed, 4 skipped (expected)
* Apply code review feedback: consolidate utilities and improve compatibility
Python Server:
- Extract normalize_properties() to shared utils.py (removes duplication)
- Move search_term validation before preflight() for fail-fast
- Fix manage_script.py documentation (remove incorrect 'update' reference)
- Remove stale comments in execute_menu_item.py, manage_editor.py
- Remove misleading destructiveHint from manage_shader.py
C# Unity:
- Add Vector4Converter (commonly used, was missing)
- Fix Unity 2021 compatibility: replace FindObjectsByType with FindObjectsOfType
- Add path normalization in ObjectResolver before StartsWith check
- Improve ComponentOps.SetProperty conversion error detection
- Add Undo.RecordObject in ManageComponents before property modifications
- Improve error message clarity in ManageMaterial.cs
- Add defensive error handling to stress test ToJObject helper
- Increase CI timeout thresholds for test stability
GitHub Workflows:
- Fix GO test sorting in markdown output (GO-10 now sorts after GO-9)
- Add warning logging for fragment parsing errors
* Fix animator hash names in test fixture to match parameter names
BlendXHash/BlendYHash now use 'reachX'/'reachY' to match the
actual animator parameter names.
* fix(windows): improve HTTP server detection and auto-start reliability
- Fix netstat detection on Windows by running netstat.exe directly instead
of piping through findstr (findstr returns exit code 1 when no matches,
causing false detection failures)
- Increase auto-start retry attempts (20→30) and delays (2s→3s) to handle
slow server starts during first install, version upgrades, and dev mode
- Only attempt blind connection after 20 failed detection attempts to reduce
connection error spam during server startup
- Remove verbose debug logs that were spamming the console every frame
* fix: auto-create tags and remove deprecated manage_gameobject actions
- ManageGameObject.cs: Check tag existence before setting; auto-create
undefined tags using InternalEditorUtility.AddTag() instead of relying
on exception handling (Unity logs warning, doesn't throw)
- manage_gameobject.py: Remove deprecated actions (find, get_components,
add_component, remove_component, set_component_property, get_component)
from Literal type - these are now handled by find_gameobjects and
manage_components tools
- Update test suite and unit tests to reflect new auto-create behavior
* fix: address code review feedback
Bug fixes:
- Fix searchInactive flag ignored in FindObjectsOfType (use includeInactive overload)
- Fix property lookup to try both original and normalized names for backwards compat
- Remove dead code for deprecated 'find' action validation
- Update error message to list only valid actions
Improvements:
- Add destructiveHint=True to manage_shader tool
- Limit fallback connection attempts (every 3rd attempt) to avoid spamming errors
- Consolidate PropertyConversion exception handlers to single catch block
- Add tag existence assertion and cleanup in tag auto-creation tests
Test fixes:
- Update SetComponentProperties_ContinuesAfterException log regex for new error format
- Update test_manage_gameobject_param_coercion to test valid actions only
2026-01-07 04:58:17 +08:00
|
|
|
var suggestions = ComponentResolver.GetFuzzyPropertySuggestions("Use Gravity", properties);
|
2025-09-03 10:27:40 +08:00
|
|
|
Assert.Contains("useGravity", suggestions, "Should suggest useGravity for 'Use Gravity'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void PropertyMatching_HandlesMonoBehaviourProperties()
|
|
|
|
|
{
|
|
|
|
|
var properties = ComponentResolver.GetAllComponentProperties(typeof(MonoBehaviour));
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
Assert.IsNotEmpty(properties, "MonoBehaviour should have properties");
|
|
|
|
|
Assert.Contains("enabled", properties, "MonoBehaviour should have enabled property");
|
|
|
|
|
Assert.Contains("name", properties, "MonoBehaviour should have name property");
|
|
|
|
|
Assert.Contains("tag", properties, "MonoBehaviour should have tag property");
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-01 04:25:33 +08:00
|
|
|
[Test]
|
2025-09-03 10:27:40 +08:00
|
|
|
public void PropertyMatching_HandlesCaseVariations()
|
|
|
|
|
{
|
|
|
|
|
var testProperties = new List<string> { "maxReachDistance", "playerHealth", "movementSpeed" };
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
var testCases = new[]
|
|
|
|
|
{
|
|
|
|
|
("max reach distance", "maxReachDistance"),
|
|
|
|
|
("Max Reach Distance", "maxReachDistance"),
|
|
|
|
|
("MAX_REACH_DISTANCE", "maxReachDistance"),
|
|
|
|
|
("player health", "playerHealth"),
|
|
|
|
|
("movement speed", "movementSpeed")
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
foreach (var (input, expected) in testCases)
|
|
|
|
|
{
|
🔧 Clean up & Consolidate Shared Services Across MCP Tools (#519)
* feat: Redesign GameObject API for better LLM ergonomics
- find_gameobjects: Search GameObjects, returns paginated instance IDs only
- manage_components: Component lifecycle (add, remove, set_property)
- unity://scene/gameobject/{id}: Single GameObject data (no component serialization)
- unity://scene/gameobject/{id}/components: All components (paginated)
- unity://scene/gameobject/{id}/component/{name}: Single component by type
- manage_scene get_hierarchy: Now includes componentTypes array
- manage_gameobject: Slimmed to lifecycle only (create, modify, delete)
- Legacy actions (find, get_components, etc.) log deprecation warnings
- ParamCoercion: Centralized int/bool/float/string coercion
- VectorParsing: Vector3/Vector2/Quaternion/Color parsing
- GameObjectLookup: Centralized GameObject search logic
- 76 new Unity EditMode tests for ManageGameObject actions
- 21 new pytest tests for Python tools/resources
- New NL/T CI suite for GameObject API (GO-0 to GO-5)
Addresses LLM confusion with parameter overload by splitting into
focused tools and read-only resources.
* feat: Add GameObject API stress tests and NL/T suite updates
Stress Tests (12 new tests):
- BulkCreate small/medium batches
- FindGameObjects pagination with by_component search
- AddComponents to single object
- GetComponents with full serialization
- SetComponentProperties (complex Rigidbody)
- Deep hierarchy creation and path lookup
- GetHierarchy with large scenes
- Resource read performance tests
- RapidFire create-modify-delete cycles
NL/T Suite Updates:
- Added GO-0..GO-10 tests in nl-gameobject-suite.md
- Fixed tool naming: mcp__unity__ → mcp__UnityMCP__
Other:
- Fixed LongUnityScriptClaudeTest.cs compilation errors
- Added reports/, .claude/local/, scripts/local-test/ to .gitignore
All 254 EditMode tests pass (250 run, 4 explicit skips)
* fix: Address code review feedback
- ParamCoercion: Use CultureInfo.InvariantCulture for float parsing
- ManageComponents: Move Transform removal check before GetComponent
- ManageGameObjectFindTests: Use try-finally for LogAssert.ignoreFailingMessages
- VectorParsing: Document that quaternions are not auto-normalized
- gameobject.py: Prefix unused ctx parameter with underscore
* fix: Address more code review feedback
NL/T Prompt Fixes:
- nl-gameobject-suite.md: Remove non-existent list_resources/read_resource from AllowedTools
- nl-gameobject-suite.md: Fix parameter names (component_type, properties)
- nl-unity-suite-nl.md: Remove unused manage_editor from AllowedTools
Test Fixes:
- GameObjectAPIStressTests: Add null check to ToJObject helper
- GameObjectAPIStressTests: Clarify AudioSource usage comment
- ManageGameObjectFindTests: Use built-in 'UI' layer instead of 'Water'
- LongUnityScriptClaudeTest: Clean up NL/T test artifacts (Counte42 typo, HasTarget)
* docs: update README tools and resources lists
- Add missing tools: manage_components, batch_execute, find_gameobjects, refresh_unity
- Add missing resources: gameobject_api, editor_state_v2
- Make descriptions more concise across all tools and resources
- Ensure documentation matches current MCP server functionality
* chore: Remove accidentally committed test artifacts
- Remove Materials folder (40 .mat files from interactive testing)
- Remove Shaders folder (5 noise shaders from testing)
- Remove test scripts (Bounce*, CylinderBounce* from testing)
- Remove Temp.meta and commit.sh
* refactor: remove deprecated manage_gameobject actions
- Remove deprecated switch cases: find, get_components, get_component, add_component, remove_component, set_component_property
- Remove deprecated wrapper methods (423 lines deleted from ManageGameObject.cs)
- Delete ManageGameObjectFindTests.cs (tests deprecated 'find' action)
- Remove deprecated test methods from ManageGameObjectTests.cs
- Add GameObject resource URIs to README documentation
- Add batch_execute performance tips to README, tool description, and gameobject_api resource
- Enhance batch_execute description to emphasize 10-100x performance gains
Total: ~1200 lines removed. New API (find_gameobjects, manage_components, resources) is the recommended path forward.
* refactor: consolidate shared services across MCP tools
Major architectural improvements:
- Create UnityJsonSerializer for shared JSON/Unity type conversion
- Create ObjectResolver for unified object resolution (GameObjects, Components, Assets)
- Create UnityTypeResolver for consolidated type resolution with caching
- Create PropertyConversion for unified JSON→Unity property conversion
- Create ComponentOps for low-level component operations
- Create Pagination helpers for standardized pagination across tools
Tool simplifications:
- ManageGameObject: Remove 68-line prefab redirect anti-pattern, delegate to helpers
- ManageAsset: Remove ~80 lines duplicate ConvertJTokenToType
- ManageScriptableObject: Remove ~40 lines duplicate ResolveType
- ManageComponents: Use ComponentOps, UnityTypeResolver (~90 lines saved)
- ManageMaterial: Standardize to SuccessResponse/ErrorResponse patterns
- FindGameObjects: Use PaginationRequest/PaginationResponse
- GameObjectLookup: FindComponentType delegates to UnityTypeResolver
Tests: 242/246 passed, 4 skipped (expected)
* Apply code review feedback: consolidate utilities and improve compatibility
Python Server:
- Extract normalize_properties() to shared utils.py (removes duplication)
- Move search_term validation before preflight() for fail-fast
- Fix manage_script.py documentation (remove incorrect 'update' reference)
- Remove stale comments in execute_menu_item.py, manage_editor.py
- Remove misleading destructiveHint from manage_shader.py
C# Unity:
- Add Vector4Converter (commonly used, was missing)
- Fix Unity 2021 compatibility: replace FindObjectsByType with FindObjectsOfType
- Add path normalization in ObjectResolver before StartsWith check
- Improve ComponentOps.SetProperty conversion error detection
- Add Undo.RecordObject in ManageComponents before property modifications
- Improve error message clarity in ManageMaterial.cs
- Add defensive error handling to stress test ToJObject helper
- Increase CI timeout thresholds for test stability
GitHub Workflows:
- Fix GO test sorting in markdown output (GO-10 now sorts after GO-9)
- Add warning logging for fragment parsing errors
* Fix animator hash names in test fixture to match parameter names
BlendXHash/BlendYHash now use 'reachX'/'reachY' to match the
actual animator parameter names.
* fix(windows): improve HTTP server detection and auto-start reliability
- Fix netstat detection on Windows by running netstat.exe directly instead
of piping through findstr (findstr returns exit code 1 when no matches,
causing false detection failures)
- Increase auto-start retry attempts (20→30) and delays (2s→3s) to handle
slow server starts during first install, version upgrades, and dev mode
- Only attempt blind connection after 20 failed detection attempts to reduce
connection error spam during server startup
- Remove verbose debug logs that were spamming the console every frame
* fix: auto-create tags and remove deprecated manage_gameobject actions
- ManageGameObject.cs: Check tag existence before setting; auto-create
undefined tags using InternalEditorUtility.AddTag() instead of relying
on exception handling (Unity logs warning, doesn't throw)
- manage_gameobject.py: Remove deprecated actions (find, get_components,
add_component, remove_component, set_component_property, get_component)
from Literal type - these are now handled by find_gameobjects and
manage_components tools
- Update test suite and unit tests to reflect new auto-create behavior
* fix: address code review feedback
Bug fixes:
- Fix searchInactive flag ignored in FindObjectsOfType (use includeInactive overload)
- Fix property lookup to try both original and normalized names for backwards compat
- Remove dead code for deprecated 'find' action validation
- Update error message to list only valid actions
Improvements:
- Add destructiveHint=True to manage_shader tool
- Limit fallback connection attempts (every 3rd attempt) to avoid spamming errors
- Consolidate PropertyConversion exception handlers to single catch block
- Add tag existence assertion and cleanup in tag auto-creation tests
Test fixes:
- Update SetComponentProperties_ContinuesAfterException log regex for new error format
- Update test_manage_gameobject_param_coercion to test valid actions only
2026-01-07 04:58:17 +08:00
|
|
|
var suggestions = ComponentResolver.GetFuzzyPropertySuggestions(input, testProperties);
|
2025-09-03 10:27:40 +08:00
|
|
|
Assert.Contains(expected, suggestions, $"Should suggest {expected} for input '{input}'");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void ErrorHandling_ReturnsHelpfulMessages()
|
|
|
|
|
{
|
|
|
|
|
// This test verifies that error messages are helpful and contain suggestions
|
|
|
|
|
var testProperties = new List<string> { "mass", "velocity", "drag", "useGravity" };
|
🔧 Clean up & Consolidate Shared Services Across MCP Tools (#519)
* feat: Redesign GameObject API for better LLM ergonomics
- find_gameobjects: Search GameObjects, returns paginated instance IDs only
- manage_components: Component lifecycle (add, remove, set_property)
- unity://scene/gameobject/{id}: Single GameObject data (no component serialization)
- unity://scene/gameobject/{id}/components: All components (paginated)
- unity://scene/gameobject/{id}/component/{name}: Single component by type
- manage_scene get_hierarchy: Now includes componentTypes array
- manage_gameobject: Slimmed to lifecycle only (create, modify, delete)
- Legacy actions (find, get_components, etc.) log deprecation warnings
- ParamCoercion: Centralized int/bool/float/string coercion
- VectorParsing: Vector3/Vector2/Quaternion/Color parsing
- GameObjectLookup: Centralized GameObject search logic
- 76 new Unity EditMode tests for ManageGameObject actions
- 21 new pytest tests for Python tools/resources
- New NL/T CI suite for GameObject API (GO-0 to GO-5)
Addresses LLM confusion with parameter overload by splitting into
focused tools and read-only resources.
* feat: Add GameObject API stress tests and NL/T suite updates
Stress Tests (12 new tests):
- BulkCreate small/medium batches
- FindGameObjects pagination with by_component search
- AddComponents to single object
- GetComponents with full serialization
- SetComponentProperties (complex Rigidbody)
- Deep hierarchy creation and path lookup
- GetHierarchy with large scenes
- Resource read performance tests
- RapidFire create-modify-delete cycles
NL/T Suite Updates:
- Added GO-0..GO-10 tests in nl-gameobject-suite.md
- Fixed tool naming: mcp__unity__ → mcp__UnityMCP__
Other:
- Fixed LongUnityScriptClaudeTest.cs compilation errors
- Added reports/, .claude/local/, scripts/local-test/ to .gitignore
All 254 EditMode tests pass (250 run, 4 explicit skips)
* fix: Address code review feedback
- ParamCoercion: Use CultureInfo.InvariantCulture for float parsing
- ManageComponents: Move Transform removal check before GetComponent
- ManageGameObjectFindTests: Use try-finally for LogAssert.ignoreFailingMessages
- VectorParsing: Document that quaternions are not auto-normalized
- gameobject.py: Prefix unused ctx parameter with underscore
* fix: Address more code review feedback
NL/T Prompt Fixes:
- nl-gameobject-suite.md: Remove non-existent list_resources/read_resource from AllowedTools
- nl-gameobject-suite.md: Fix parameter names (component_type, properties)
- nl-unity-suite-nl.md: Remove unused manage_editor from AllowedTools
Test Fixes:
- GameObjectAPIStressTests: Add null check to ToJObject helper
- GameObjectAPIStressTests: Clarify AudioSource usage comment
- ManageGameObjectFindTests: Use built-in 'UI' layer instead of 'Water'
- LongUnityScriptClaudeTest: Clean up NL/T test artifacts (Counte42 typo, HasTarget)
* docs: update README tools and resources lists
- Add missing tools: manage_components, batch_execute, find_gameobjects, refresh_unity
- Add missing resources: gameobject_api, editor_state_v2
- Make descriptions more concise across all tools and resources
- Ensure documentation matches current MCP server functionality
* chore: Remove accidentally committed test artifacts
- Remove Materials folder (40 .mat files from interactive testing)
- Remove Shaders folder (5 noise shaders from testing)
- Remove test scripts (Bounce*, CylinderBounce* from testing)
- Remove Temp.meta and commit.sh
* refactor: remove deprecated manage_gameobject actions
- Remove deprecated switch cases: find, get_components, get_component, add_component, remove_component, set_component_property
- Remove deprecated wrapper methods (423 lines deleted from ManageGameObject.cs)
- Delete ManageGameObjectFindTests.cs (tests deprecated 'find' action)
- Remove deprecated test methods from ManageGameObjectTests.cs
- Add GameObject resource URIs to README documentation
- Add batch_execute performance tips to README, tool description, and gameobject_api resource
- Enhance batch_execute description to emphasize 10-100x performance gains
Total: ~1200 lines removed. New API (find_gameobjects, manage_components, resources) is the recommended path forward.
* refactor: consolidate shared services across MCP tools
Major architectural improvements:
- Create UnityJsonSerializer for shared JSON/Unity type conversion
- Create ObjectResolver for unified object resolution (GameObjects, Components, Assets)
- Create UnityTypeResolver for consolidated type resolution with caching
- Create PropertyConversion for unified JSON→Unity property conversion
- Create ComponentOps for low-level component operations
- Create Pagination helpers for standardized pagination across tools
Tool simplifications:
- ManageGameObject: Remove 68-line prefab redirect anti-pattern, delegate to helpers
- ManageAsset: Remove ~80 lines duplicate ConvertJTokenToType
- ManageScriptableObject: Remove ~40 lines duplicate ResolveType
- ManageComponents: Use ComponentOps, UnityTypeResolver (~90 lines saved)
- ManageMaterial: Standardize to SuccessResponse/ErrorResponse patterns
- FindGameObjects: Use PaginationRequest/PaginationResponse
- GameObjectLookup: FindComponentType delegates to UnityTypeResolver
Tests: 242/246 passed, 4 skipped (expected)
* Apply code review feedback: consolidate utilities and improve compatibility
Python Server:
- Extract normalize_properties() to shared utils.py (removes duplication)
- Move search_term validation before preflight() for fail-fast
- Fix manage_script.py documentation (remove incorrect 'update' reference)
- Remove stale comments in execute_menu_item.py, manage_editor.py
- Remove misleading destructiveHint from manage_shader.py
C# Unity:
- Add Vector4Converter (commonly used, was missing)
- Fix Unity 2021 compatibility: replace FindObjectsByType with FindObjectsOfType
- Add path normalization in ObjectResolver before StartsWith check
- Improve ComponentOps.SetProperty conversion error detection
- Add Undo.RecordObject in ManageComponents before property modifications
- Improve error message clarity in ManageMaterial.cs
- Add defensive error handling to stress test ToJObject helper
- Increase CI timeout thresholds for test stability
GitHub Workflows:
- Fix GO test sorting in markdown output (GO-10 now sorts after GO-9)
- Add warning logging for fragment parsing errors
* Fix animator hash names in test fixture to match parameter names
BlendXHash/BlendYHash now use 'reachX'/'reachY' to match the
actual animator parameter names.
* fix(windows): improve HTTP server detection and auto-start reliability
- Fix netstat detection on Windows by running netstat.exe directly instead
of piping through findstr (findstr returns exit code 1 when no matches,
causing false detection failures)
- Increase auto-start retry attempts (20→30) and delays (2s→3s) to handle
slow server starts during first install, version upgrades, and dev mode
- Only attempt blind connection after 20 failed detection attempts to reduce
connection error spam during server startup
- Remove verbose debug logs that were spamming the console every frame
* fix: auto-create tags and remove deprecated manage_gameobject actions
- ManageGameObject.cs: Check tag existence before setting; auto-create
undefined tags using InternalEditorUtility.AddTag() instead of relying
on exception handling (Unity logs warning, doesn't throw)
- manage_gameobject.py: Remove deprecated actions (find, get_components,
add_component, remove_component, set_component_property, get_component)
from Literal type - these are now handled by find_gameobjects and
manage_components tools
- Update test suite and unit tests to reflect new auto-create behavior
* fix: address code review feedback
Bug fixes:
- Fix searchInactive flag ignored in FindObjectsOfType (use includeInactive overload)
- Fix property lookup to try both original and normalized names for backwards compat
- Remove dead code for deprecated 'find' action validation
- Update error message to list only valid actions
Improvements:
- Add destructiveHint=True to manage_shader tool
- Limit fallback connection attempts (every 3rd attempt) to avoid spamming errors
- Consolidate PropertyConversion exception handlers to single catch block
- Add tag existence assertion and cleanup in tag auto-creation tests
Test fixes:
- Update SetComponentProperties_ContinuesAfterException log regex for new error format
- Update test_manage_gameobject_param_coercion to test valid actions only
2026-01-07 04:58:17 +08:00
|
|
|
var suggestions = ComponentResolver.GetFuzzyPropertySuggestions("weight", testProperties);
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
// Even if no perfect match, should return valid list
|
|
|
|
|
Assert.IsNotNull(suggestions, "Should return valid suggestions list");
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
// Test with completely invalid input
|
🔧 Clean up & Consolidate Shared Services Across MCP Tools (#519)
* feat: Redesign GameObject API for better LLM ergonomics
- find_gameobjects: Search GameObjects, returns paginated instance IDs only
- manage_components: Component lifecycle (add, remove, set_property)
- unity://scene/gameobject/{id}: Single GameObject data (no component serialization)
- unity://scene/gameobject/{id}/components: All components (paginated)
- unity://scene/gameobject/{id}/component/{name}: Single component by type
- manage_scene get_hierarchy: Now includes componentTypes array
- manage_gameobject: Slimmed to lifecycle only (create, modify, delete)
- Legacy actions (find, get_components, etc.) log deprecation warnings
- ParamCoercion: Centralized int/bool/float/string coercion
- VectorParsing: Vector3/Vector2/Quaternion/Color parsing
- GameObjectLookup: Centralized GameObject search logic
- 76 new Unity EditMode tests for ManageGameObject actions
- 21 new pytest tests for Python tools/resources
- New NL/T CI suite for GameObject API (GO-0 to GO-5)
Addresses LLM confusion with parameter overload by splitting into
focused tools and read-only resources.
* feat: Add GameObject API stress tests and NL/T suite updates
Stress Tests (12 new tests):
- BulkCreate small/medium batches
- FindGameObjects pagination with by_component search
- AddComponents to single object
- GetComponents with full serialization
- SetComponentProperties (complex Rigidbody)
- Deep hierarchy creation and path lookup
- GetHierarchy with large scenes
- Resource read performance tests
- RapidFire create-modify-delete cycles
NL/T Suite Updates:
- Added GO-0..GO-10 tests in nl-gameobject-suite.md
- Fixed tool naming: mcp__unity__ → mcp__UnityMCP__
Other:
- Fixed LongUnityScriptClaudeTest.cs compilation errors
- Added reports/, .claude/local/, scripts/local-test/ to .gitignore
All 254 EditMode tests pass (250 run, 4 explicit skips)
* fix: Address code review feedback
- ParamCoercion: Use CultureInfo.InvariantCulture for float parsing
- ManageComponents: Move Transform removal check before GetComponent
- ManageGameObjectFindTests: Use try-finally for LogAssert.ignoreFailingMessages
- VectorParsing: Document that quaternions are not auto-normalized
- gameobject.py: Prefix unused ctx parameter with underscore
* fix: Address more code review feedback
NL/T Prompt Fixes:
- nl-gameobject-suite.md: Remove non-existent list_resources/read_resource from AllowedTools
- nl-gameobject-suite.md: Fix parameter names (component_type, properties)
- nl-unity-suite-nl.md: Remove unused manage_editor from AllowedTools
Test Fixes:
- GameObjectAPIStressTests: Add null check to ToJObject helper
- GameObjectAPIStressTests: Clarify AudioSource usage comment
- ManageGameObjectFindTests: Use built-in 'UI' layer instead of 'Water'
- LongUnityScriptClaudeTest: Clean up NL/T test artifacts (Counte42 typo, HasTarget)
* docs: update README tools and resources lists
- Add missing tools: manage_components, batch_execute, find_gameobjects, refresh_unity
- Add missing resources: gameobject_api, editor_state_v2
- Make descriptions more concise across all tools and resources
- Ensure documentation matches current MCP server functionality
* chore: Remove accidentally committed test artifacts
- Remove Materials folder (40 .mat files from interactive testing)
- Remove Shaders folder (5 noise shaders from testing)
- Remove test scripts (Bounce*, CylinderBounce* from testing)
- Remove Temp.meta and commit.sh
* refactor: remove deprecated manage_gameobject actions
- Remove deprecated switch cases: find, get_components, get_component, add_component, remove_component, set_component_property
- Remove deprecated wrapper methods (423 lines deleted from ManageGameObject.cs)
- Delete ManageGameObjectFindTests.cs (tests deprecated 'find' action)
- Remove deprecated test methods from ManageGameObjectTests.cs
- Add GameObject resource URIs to README documentation
- Add batch_execute performance tips to README, tool description, and gameobject_api resource
- Enhance batch_execute description to emphasize 10-100x performance gains
Total: ~1200 lines removed. New API (find_gameobjects, manage_components, resources) is the recommended path forward.
* refactor: consolidate shared services across MCP tools
Major architectural improvements:
- Create UnityJsonSerializer for shared JSON/Unity type conversion
- Create ObjectResolver for unified object resolution (GameObjects, Components, Assets)
- Create UnityTypeResolver for consolidated type resolution with caching
- Create PropertyConversion for unified JSON→Unity property conversion
- Create ComponentOps for low-level component operations
- Create Pagination helpers for standardized pagination across tools
Tool simplifications:
- ManageGameObject: Remove 68-line prefab redirect anti-pattern, delegate to helpers
- ManageAsset: Remove ~80 lines duplicate ConvertJTokenToType
- ManageScriptableObject: Remove ~40 lines duplicate ResolveType
- ManageComponents: Use ComponentOps, UnityTypeResolver (~90 lines saved)
- ManageMaterial: Standardize to SuccessResponse/ErrorResponse patterns
- FindGameObjects: Use PaginationRequest/PaginationResponse
- GameObjectLookup: FindComponentType delegates to UnityTypeResolver
Tests: 242/246 passed, 4 skipped (expected)
* Apply code review feedback: consolidate utilities and improve compatibility
Python Server:
- Extract normalize_properties() to shared utils.py (removes duplication)
- Move search_term validation before preflight() for fail-fast
- Fix manage_script.py documentation (remove incorrect 'update' reference)
- Remove stale comments in execute_menu_item.py, manage_editor.py
- Remove misleading destructiveHint from manage_shader.py
C# Unity:
- Add Vector4Converter (commonly used, was missing)
- Fix Unity 2021 compatibility: replace FindObjectsByType with FindObjectsOfType
- Add path normalization in ObjectResolver before StartsWith check
- Improve ComponentOps.SetProperty conversion error detection
- Add Undo.RecordObject in ManageComponents before property modifications
- Improve error message clarity in ManageMaterial.cs
- Add defensive error handling to stress test ToJObject helper
- Increase CI timeout thresholds for test stability
GitHub Workflows:
- Fix GO test sorting in markdown output (GO-10 now sorts after GO-9)
- Add warning logging for fragment parsing errors
* Fix animator hash names in test fixture to match parameter names
BlendXHash/BlendYHash now use 'reachX'/'reachY' to match the
actual animator parameter names.
* fix(windows): improve HTTP server detection and auto-start reliability
- Fix netstat detection on Windows by running netstat.exe directly instead
of piping through findstr (findstr returns exit code 1 when no matches,
causing false detection failures)
- Increase auto-start retry attempts (20→30) and delays (2s→3s) to handle
slow server starts during first install, version upgrades, and dev mode
- Only attempt blind connection after 20 failed detection attempts to reduce
connection error spam during server startup
- Remove verbose debug logs that were spamming the console every frame
* fix: auto-create tags and remove deprecated manage_gameobject actions
- ManageGameObject.cs: Check tag existence before setting; auto-create
undefined tags using InternalEditorUtility.AddTag() instead of relying
on exception handling (Unity logs warning, doesn't throw)
- manage_gameobject.py: Remove deprecated actions (find, get_components,
add_component, remove_component, set_component_property, get_component)
from Literal type - these are now handled by find_gameobjects and
manage_components tools
- Update test suite and unit tests to reflect new auto-create behavior
* fix: address code review feedback
Bug fixes:
- Fix searchInactive flag ignored in FindObjectsOfType (use includeInactive overload)
- Fix property lookup to try both original and normalized names for backwards compat
- Remove dead code for deprecated 'find' action validation
- Update error message to list only valid actions
Improvements:
- Add destructiveHint=True to manage_shader tool
- Limit fallback connection attempts (every 3rd attempt) to avoid spamming errors
- Consolidate PropertyConversion exception handlers to single catch block
- Add tag existence assertion and cleanup in tag auto-creation tests
Test fixes:
- Update SetComponentProperties_ContinuesAfterException log regex for new error format
- Update test_manage_gameobject_param_coercion to test valid actions only
2026-01-07 04:58:17 +08:00
|
|
|
var badSuggestions = ComponentResolver.GetFuzzyPropertySuggestions("xyz123invalid", testProperties);
|
2025-09-03 10:27:40 +08:00
|
|
|
Assert.IsNotNull(badSuggestions, "Should handle invalid input gracefully");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void PerformanceTest_CachingWorks()
|
|
|
|
|
{
|
|
|
|
|
var properties = ComponentResolver.GetAllComponentProperties(typeof(Transform));
|
|
|
|
|
var input = "Test Property Name";
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
// First call - populate cache
|
|
|
|
|
var startTime = System.DateTime.UtcNow;
|
🔧 Clean up & Consolidate Shared Services Across MCP Tools (#519)
* feat: Redesign GameObject API for better LLM ergonomics
- find_gameobjects: Search GameObjects, returns paginated instance IDs only
- manage_components: Component lifecycle (add, remove, set_property)
- unity://scene/gameobject/{id}: Single GameObject data (no component serialization)
- unity://scene/gameobject/{id}/components: All components (paginated)
- unity://scene/gameobject/{id}/component/{name}: Single component by type
- manage_scene get_hierarchy: Now includes componentTypes array
- manage_gameobject: Slimmed to lifecycle only (create, modify, delete)
- Legacy actions (find, get_components, etc.) log deprecation warnings
- ParamCoercion: Centralized int/bool/float/string coercion
- VectorParsing: Vector3/Vector2/Quaternion/Color parsing
- GameObjectLookup: Centralized GameObject search logic
- 76 new Unity EditMode tests for ManageGameObject actions
- 21 new pytest tests for Python tools/resources
- New NL/T CI suite for GameObject API (GO-0 to GO-5)
Addresses LLM confusion with parameter overload by splitting into
focused tools and read-only resources.
* feat: Add GameObject API stress tests and NL/T suite updates
Stress Tests (12 new tests):
- BulkCreate small/medium batches
- FindGameObjects pagination with by_component search
- AddComponents to single object
- GetComponents with full serialization
- SetComponentProperties (complex Rigidbody)
- Deep hierarchy creation and path lookup
- GetHierarchy with large scenes
- Resource read performance tests
- RapidFire create-modify-delete cycles
NL/T Suite Updates:
- Added GO-0..GO-10 tests in nl-gameobject-suite.md
- Fixed tool naming: mcp__unity__ → mcp__UnityMCP__
Other:
- Fixed LongUnityScriptClaudeTest.cs compilation errors
- Added reports/, .claude/local/, scripts/local-test/ to .gitignore
All 254 EditMode tests pass (250 run, 4 explicit skips)
* fix: Address code review feedback
- ParamCoercion: Use CultureInfo.InvariantCulture for float parsing
- ManageComponents: Move Transform removal check before GetComponent
- ManageGameObjectFindTests: Use try-finally for LogAssert.ignoreFailingMessages
- VectorParsing: Document that quaternions are not auto-normalized
- gameobject.py: Prefix unused ctx parameter with underscore
* fix: Address more code review feedback
NL/T Prompt Fixes:
- nl-gameobject-suite.md: Remove non-existent list_resources/read_resource from AllowedTools
- nl-gameobject-suite.md: Fix parameter names (component_type, properties)
- nl-unity-suite-nl.md: Remove unused manage_editor from AllowedTools
Test Fixes:
- GameObjectAPIStressTests: Add null check to ToJObject helper
- GameObjectAPIStressTests: Clarify AudioSource usage comment
- ManageGameObjectFindTests: Use built-in 'UI' layer instead of 'Water'
- LongUnityScriptClaudeTest: Clean up NL/T test artifacts (Counte42 typo, HasTarget)
* docs: update README tools and resources lists
- Add missing tools: manage_components, batch_execute, find_gameobjects, refresh_unity
- Add missing resources: gameobject_api, editor_state_v2
- Make descriptions more concise across all tools and resources
- Ensure documentation matches current MCP server functionality
* chore: Remove accidentally committed test artifacts
- Remove Materials folder (40 .mat files from interactive testing)
- Remove Shaders folder (5 noise shaders from testing)
- Remove test scripts (Bounce*, CylinderBounce* from testing)
- Remove Temp.meta and commit.sh
* refactor: remove deprecated manage_gameobject actions
- Remove deprecated switch cases: find, get_components, get_component, add_component, remove_component, set_component_property
- Remove deprecated wrapper methods (423 lines deleted from ManageGameObject.cs)
- Delete ManageGameObjectFindTests.cs (tests deprecated 'find' action)
- Remove deprecated test methods from ManageGameObjectTests.cs
- Add GameObject resource URIs to README documentation
- Add batch_execute performance tips to README, tool description, and gameobject_api resource
- Enhance batch_execute description to emphasize 10-100x performance gains
Total: ~1200 lines removed. New API (find_gameobjects, manage_components, resources) is the recommended path forward.
* refactor: consolidate shared services across MCP tools
Major architectural improvements:
- Create UnityJsonSerializer for shared JSON/Unity type conversion
- Create ObjectResolver for unified object resolution (GameObjects, Components, Assets)
- Create UnityTypeResolver for consolidated type resolution with caching
- Create PropertyConversion for unified JSON→Unity property conversion
- Create ComponentOps for low-level component operations
- Create Pagination helpers for standardized pagination across tools
Tool simplifications:
- ManageGameObject: Remove 68-line prefab redirect anti-pattern, delegate to helpers
- ManageAsset: Remove ~80 lines duplicate ConvertJTokenToType
- ManageScriptableObject: Remove ~40 lines duplicate ResolveType
- ManageComponents: Use ComponentOps, UnityTypeResolver (~90 lines saved)
- ManageMaterial: Standardize to SuccessResponse/ErrorResponse patterns
- FindGameObjects: Use PaginationRequest/PaginationResponse
- GameObjectLookup: FindComponentType delegates to UnityTypeResolver
Tests: 242/246 passed, 4 skipped (expected)
* Apply code review feedback: consolidate utilities and improve compatibility
Python Server:
- Extract normalize_properties() to shared utils.py (removes duplication)
- Move search_term validation before preflight() for fail-fast
- Fix manage_script.py documentation (remove incorrect 'update' reference)
- Remove stale comments in execute_menu_item.py, manage_editor.py
- Remove misleading destructiveHint from manage_shader.py
C# Unity:
- Add Vector4Converter (commonly used, was missing)
- Fix Unity 2021 compatibility: replace FindObjectsByType with FindObjectsOfType
- Add path normalization in ObjectResolver before StartsWith check
- Improve ComponentOps.SetProperty conversion error detection
- Add Undo.RecordObject in ManageComponents before property modifications
- Improve error message clarity in ManageMaterial.cs
- Add defensive error handling to stress test ToJObject helper
- Increase CI timeout thresholds for test stability
GitHub Workflows:
- Fix GO test sorting in markdown output (GO-10 now sorts after GO-9)
- Add warning logging for fragment parsing errors
* Fix animator hash names in test fixture to match parameter names
BlendXHash/BlendYHash now use 'reachX'/'reachY' to match the
actual animator parameter names.
* fix(windows): improve HTTP server detection and auto-start reliability
- Fix netstat detection on Windows by running netstat.exe directly instead
of piping through findstr (findstr returns exit code 1 when no matches,
causing false detection failures)
- Increase auto-start retry attempts (20→30) and delays (2s→3s) to handle
slow server starts during first install, version upgrades, and dev mode
- Only attempt blind connection after 20 failed detection attempts to reduce
connection error spam during server startup
- Remove verbose debug logs that were spamming the console every frame
* fix: auto-create tags and remove deprecated manage_gameobject actions
- ManageGameObject.cs: Check tag existence before setting; auto-create
undefined tags using InternalEditorUtility.AddTag() instead of relying
on exception handling (Unity logs warning, doesn't throw)
- manage_gameobject.py: Remove deprecated actions (find, get_components,
add_component, remove_component, set_component_property, get_component)
from Literal type - these are now handled by find_gameobjects and
manage_components tools
- Update test suite and unit tests to reflect new auto-create behavior
* fix: address code review feedback
Bug fixes:
- Fix searchInactive flag ignored in FindObjectsOfType (use includeInactive overload)
- Fix property lookup to try both original and normalized names for backwards compat
- Remove dead code for deprecated 'find' action validation
- Update error message to list only valid actions
Improvements:
- Add destructiveHint=True to manage_shader tool
- Limit fallback connection attempts (every 3rd attempt) to avoid spamming errors
- Consolidate PropertyConversion exception handlers to single catch block
- Add tag existence assertion and cleanup in tag auto-creation tests
Test fixes:
- Update SetComponentProperties_ContinuesAfterException log regex for new error format
- Update test_manage_gameobject_param_coercion to test valid actions only
2026-01-07 04:58:17 +08:00
|
|
|
var suggestions1 = ComponentResolver.GetFuzzyPropertySuggestions(input, properties);
|
2025-09-03 10:27:40 +08:00
|
|
|
var firstCallTime = (System.DateTime.UtcNow - startTime).TotalMilliseconds;
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
// Second call - should use cache
|
|
|
|
|
startTime = System.DateTime.UtcNow;
|
🔧 Clean up & Consolidate Shared Services Across MCP Tools (#519)
* feat: Redesign GameObject API for better LLM ergonomics
- find_gameobjects: Search GameObjects, returns paginated instance IDs only
- manage_components: Component lifecycle (add, remove, set_property)
- unity://scene/gameobject/{id}: Single GameObject data (no component serialization)
- unity://scene/gameobject/{id}/components: All components (paginated)
- unity://scene/gameobject/{id}/component/{name}: Single component by type
- manage_scene get_hierarchy: Now includes componentTypes array
- manage_gameobject: Slimmed to lifecycle only (create, modify, delete)
- Legacy actions (find, get_components, etc.) log deprecation warnings
- ParamCoercion: Centralized int/bool/float/string coercion
- VectorParsing: Vector3/Vector2/Quaternion/Color parsing
- GameObjectLookup: Centralized GameObject search logic
- 76 new Unity EditMode tests for ManageGameObject actions
- 21 new pytest tests for Python tools/resources
- New NL/T CI suite for GameObject API (GO-0 to GO-5)
Addresses LLM confusion with parameter overload by splitting into
focused tools and read-only resources.
* feat: Add GameObject API stress tests and NL/T suite updates
Stress Tests (12 new tests):
- BulkCreate small/medium batches
- FindGameObjects pagination with by_component search
- AddComponents to single object
- GetComponents with full serialization
- SetComponentProperties (complex Rigidbody)
- Deep hierarchy creation and path lookup
- GetHierarchy with large scenes
- Resource read performance tests
- RapidFire create-modify-delete cycles
NL/T Suite Updates:
- Added GO-0..GO-10 tests in nl-gameobject-suite.md
- Fixed tool naming: mcp__unity__ → mcp__UnityMCP__
Other:
- Fixed LongUnityScriptClaudeTest.cs compilation errors
- Added reports/, .claude/local/, scripts/local-test/ to .gitignore
All 254 EditMode tests pass (250 run, 4 explicit skips)
* fix: Address code review feedback
- ParamCoercion: Use CultureInfo.InvariantCulture for float parsing
- ManageComponents: Move Transform removal check before GetComponent
- ManageGameObjectFindTests: Use try-finally for LogAssert.ignoreFailingMessages
- VectorParsing: Document that quaternions are not auto-normalized
- gameobject.py: Prefix unused ctx parameter with underscore
* fix: Address more code review feedback
NL/T Prompt Fixes:
- nl-gameobject-suite.md: Remove non-existent list_resources/read_resource from AllowedTools
- nl-gameobject-suite.md: Fix parameter names (component_type, properties)
- nl-unity-suite-nl.md: Remove unused manage_editor from AllowedTools
Test Fixes:
- GameObjectAPIStressTests: Add null check to ToJObject helper
- GameObjectAPIStressTests: Clarify AudioSource usage comment
- ManageGameObjectFindTests: Use built-in 'UI' layer instead of 'Water'
- LongUnityScriptClaudeTest: Clean up NL/T test artifacts (Counte42 typo, HasTarget)
* docs: update README tools and resources lists
- Add missing tools: manage_components, batch_execute, find_gameobjects, refresh_unity
- Add missing resources: gameobject_api, editor_state_v2
- Make descriptions more concise across all tools and resources
- Ensure documentation matches current MCP server functionality
* chore: Remove accidentally committed test artifacts
- Remove Materials folder (40 .mat files from interactive testing)
- Remove Shaders folder (5 noise shaders from testing)
- Remove test scripts (Bounce*, CylinderBounce* from testing)
- Remove Temp.meta and commit.sh
* refactor: remove deprecated manage_gameobject actions
- Remove deprecated switch cases: find, get_components, get_component, add_component, remove_component, set_component_property
- Remove deprecated wrapper methods (423 lines deleted from ManageGameObject.cs)
- Delete ManageGameObjectFindTests.cs (tests deprecated 'find' action)
- Remove deprecated test methods from ManageGameObjectTests.cs
- Add GameObject resource URIs to README documentation
- Add batch_execute performance tips to README, tool description, and gameobject_api resource
- Enhance batch_execute description to emphasize 10-100x performance gains
Total: ~1200 lines removed. New API (find_gameobjects, manage_components, resources) is the recommended path forward.
* refactor: consolidate shared services across MCP tools
Major architectural improvements:
- Create UnityJsonSerializer for shared JSON/Unity type conversion
- Create ObjectResolver for unified object resolution (GameObjects, Components, Assets)
- Create UnityTypeResolver for consolidated type resolution with caching
- Create PropertyConversion for unified JSON→Unity property conversion
- Create ComponentOps for low-level component operations
- Create Pagination helpers for standardized pagination across tools
Tool simplifications:
- ManageGameObject: Remove 68-line prefab redirect anti-pattern, delegate to helpers
- ManageAsset: Remove ~80 lines duplicate ConvertJTokenToType
- ManageScriptableObject: Remove ~40 lines duplicate ResolveType
- ManageComponents: Use ComponentOps, UnityTypeResolver (~90 lines saved)
- ManageMaterial: Standardize to SuccessResponse/ErrorResponse patterns
- FindGameObjects: Use PaginationRequest/PaginationResponse
- GameObjectLookup: FindComponentType delegates to UnityTypeResolver
Tests: 242/246 passed, 4 skipped (expected)
* Apply code review feedback: consolidate utilities and improve compatibility
Python Server:
- Extract normalize_properties() to shared utils.py (removes duplication)
- Move search_term validation before preflight() for fail-fast
- Fix manage_script.py documentation (remove incorrect 'update' reference)
- Remove stale comments in execute_menu_item.py, manage_editor.py
- Remove misleading destructiveHint from manage_shader.py
C# Unity:
- Add Vector4Converter (commonly used, was missing)
- Fix Unity 2021 compatibility: replace FindObjectsByType with FindObjectsOfType
- Add path normalization in ObjectResolver before StartsWith check
- Improve ComponentOps.SetProperty conversion error detection
- Add Undo.RecordObject in ManageComponents before property modifications
- Improve error message clarity in ManageMaterial.cs
- Add defensive error handling to stress test ToJObject helper
- Increase CI timeout thresholds for test stability
GitHub Workflows:
- Fix GO test sorting in markdown output (GO-10 now sorts after GO-9)
- Add warning logging for fragment parsing errors
* Fix animator hash names in test fixture to match parameter names
BlendXHash/BlendYHash now use 'reachX'/'reachY' to match the
actual animator parameter names.
* fix(windows): improve HTTP server detection and auto-start reliability
- Fix netstat detection on Windows by running netstat.exe directly instead
of piping through findstr (findstr returns exit code 1 when no matches,
causing false detection failures)
- Increase auto-start retry attempts (20→30) and delays (2s→3s) to handle
slow server starts during first install, version upgrades, and dev mode
- Only attempt blind connection after 20 failed detection attempts to reduce
connection error spam during server startup
- Remove verbose debug logs that were spamming the console every frame
* fix: auto-create tags and remove deprecated manage_gameobject actions
- ManageGameObject.cs: Check tag existence before setting; auto-create
undefined tags using InternalEditorUtility.AddTag() instead of relying
on exception handling (Unity logs warning, doesn't throw)
- manage_gameobject.py: Remove deprecated actions (find, get_components,
add_component, remove_component, set_component_property, get_component)
from Literal type - these are now handled by find_gameobjects and
manage_components tools
- Update test suite and unit tests to reflect new auto-create behavior
* fix: address code review feedback
Bug fixes:
- Fix searchInactive flag ignored in FindObjectsOfType (use includeInactive overload)
- Fix property lookup to try both original and normalized names for backwards compat
- Remove dead code for deprecated 'find' action validation
- Update error message to list only valid actions
Improvements:
- Add destructiveHint=True to manage_shader tool
- Limit fallback connection attempts (every 3rd attempt) to avoid spamming errors
- Consolidate PropertyConversion exception handlers to single catch block
- Add tag existence assertion and cleanup in tag auto-creation tests
Test fixes:
- Update SetComponentProperties_ContinuesAfterException log regex for new error format
- Update test_manage_gameobject_param_coercion to test valid actions only
2026-01-07 04:58:17 +08:00
|
|
|
var suggestions2 = ComponentResolver.GetFuzzyPropertySuggestions(input, properties);
|
2025-09-03 10:27:40 +08:00
|
|
|
var secondCallTime = (System.DateTime.UtcNow - startTime).TotalMilliseconds;
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
Assert.AreEqual(suggestions1.Count, suggestions2.Count, "Cached results should be identical");
|
|
|
|
|
CollectionAssert.AreEqual(suggestions1, suggestions2, "Cached results should match exactly");
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-03 10:27:40 +08:00
|
|
|
// Second call should be faster (though this test might be flaky)
|
|
|
|
|
Assert.LessOrEqual(secondCallTime, firstCallTime * 2, "Cached call should not be significantly slower");
|
|
|
|
|
}
|
2025-09-04 00:57:12 +08:00
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void SetComponentProperties_CollectsAllFailuresAndAppliesValidOnes()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - add Transform and Rigidbody components to test with
|
|
|
|
|
var transform = testGameObject.transform;
|
|
|
|
|
var rigidbody = testGameObject.AddComponent<Rigidbody>();
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-04 00:57:12 +08:00
|
|
|
// Create a params object with mixed valid and invalid properties
|
|
|
|
|
var setPropertiesParams = new JObject
|
|
|
|
|
{
|
|
|
|
|
["action"] = "modify",
|
|
|
|
|
["target"] = testGameObject.name,
|
2025-10-01 04:25:33 +08:00
|
|
|
["search_method"] = "by_name",
|
2025-09-04 00:57:12 +08:00
|
|
|
["componentProperties"] = new JObject
|
|
|
|
|
{
|
|
|
|
|
["Transform"] = new JObject
|
|
|
|
|
{
|
|
|
|
|
["localPosition"] = new JObject { ["x"] = 1.0f, ["y"] = 2.0f, ["z"] = 3.0f }, // Valid
|
|
|
|
|
["rotatoin"] = new JObject { ["x"] = 0.0f, ["y"] = 90.0f, ["z"] = 0.0f }, // Invalid (typo - should be rotation)
|
|
|
|
|
["localScale"] = new JObject { ["x"] = 2.0f, ["y"] = 2.0f, ["z"] = 2.0f } // Valid
|
|
|
|
|
},
|
2025-10-01 04:25:33 +08:00
|
|
|
["Rigidbody"] = new JObject
|
2025-09-04 00:57:12 +08:00
|
|
|
{
|
|
|
|
|
["mass"] = 5.0f, // Valid
|
|
|
|
|
["invalidProp"] = "test", // Invalid - doesn't exist
|
|
|
|
|
["useGravity"] = true // Valid
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Store original values to verify changes
|
|
|
|
|
var originalLocalPosition = transform.localPosition;
|
|
|
|
|
var originalLocalScale = transform.localScale;
|
|
|
|
|
var originalMass = rigidbody.mass;
|
|
|
|
|
var originalUseGravity = rigidbody.useGravity;
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-04 00:57:12 +08:00
|
|
|
Debug.Log($"BEFORE TEST - Mass: {rigidbody.mass}, UseGravity: {rigidbody.useGravity}");
|
|
|
|
|
|
|
|
|
|
// Expect the warning logs from the invalid properties
|
|
|
|
|
LogAssert.Expect(LogType.Warning, new System.Text.RegularExpressions.Regex("Property 'rotatoin' not found"));
|
|
|
|
|
LogAssert.Expect(LogType.Warning, new System.Text.RegularExpressions.Regex("Property 'invalidProp' not found"));
|
|
|
|
|
|
|
|
|
|
// Act
|
|
|
|
|
var result = ManageGameObject.HandleCommand(setPropertiesParams);
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-04 00:57:12 +08:00
|
|
|
Debug.Log($"AFTER TEST - Mass: {rigidbody.mass}, UseGravity: {rigidbody.useGravity}");
|
|
|
|
|
Debug.Log($"AFTER TEST - LocalPosition: {transform.localPosition}");
|
|
|
|
|
Debug.Log($"AFTER TEST - LocalScale: {transform.localScale}");
|
|
|
|
|
|
|
|
|
|
// Assert - verify that valid properties were set despite invalid ones
|
2025-10-01 04:25:33 +08:00
|
|
|
Assert.AreEqual(new Vector3(1.0f, 2.0f, 3.0f), transform.localPosition,
|
2025-09-04 00:57:12 +08:00
|
|
|
"Valid localPosition should be set even with other invalid properties");
|
|
|
|
|
Assert.AreEqual(new Vector3(2.0f, 2.0f, 2.0f), transform.localScale,
|
|
|
|
|
"Valid localScale should be set even with other invalid properties");
|
|
|
|
|
Assert.AreEqual(5.0f, rigidbody.mass, 0.001f,
|
|
|
|
|
"Valid mass should be set even with other invalid properties");
|
|
|
|
|
Assert.AreEqual(true, rigidbody.useGravity,
|
|
|
|
|
"Valid useGravity should be set even with other invalid properties");
|
|
|
|
|
|
|
|
|
|
// Verify the result indicates errors (since we had invalid properties)
|
|
|
|
|
Assert.IsNotNull(result, "Should return a result object");
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-04 00:57:12 +08:00
|
|
|
// The collect-and-continue behavior means we should get an error response
|
|
|
|
|
// that contains info about the failed properties, but valid ones were still applied
|
|
|
|
|
// This proves the collect-and-continue behavior is working
|
2025-09-07 01:58:11 +08:00
|
|
|
|
|
|
|
|
// Harden: verify structured error response with failures list contains both invalid fields
|
|
|
|
|
var successProp = result.GetType().GetProperty("success");
|
|
|
|
|
Assert.IsNotNull(successProp, "Result should expose 'success' property");
|
|
|
|
|
Assert.IsFalse((bool)successProp.GetValue(result), "Result.success should be false for partial failure");
|
|
|
|
|
|
|
|
|
|
var dataProp = result.GetType().GetProperty("data");
|
|
|
|
|
Assert.IsNotNull(dataProp, "Result should include 'data' with errors");
|
|
|
|
|
var dataVal = dataProp.GetValue(result);
|
|
|
|
|
Assert.IsNotNull(dataVal, "Result.data should not be null");
|
|
|
|
|
var errorsProp = dataVal.GetType().GetProperty("errors");
|
|
|
|
|
Assert.IsNotNull(errorsProp, "Result.data should include 'errors' list");
|
|
|
|
|
var errorsEnum = errorsProp.GetValue(dataVal) as System.Collections.IEnumerable;
|
|
|
|
|
Assert.IsNotNull(errorsEnum, "errors should be enumerable");
|
|
|
|
|
|
|
|
|
|
bool foundRotatoin = false;
|
|
|
|
|
bool foundInvalidProp = false;
|
|
|
|
|
foreach (var err in errorsEnum)
|
|
|
|
|
{
|
|
|
|
|
string s = err?.ToString() ?? string.Empty;
|
|
|
|
|
if (s.Contains("rotatoin")) foundRotatoin = true;
|
|
|
|
|
if (s.Contains("invalidProp")) foundInvalidProp = true;
|
|
|
|
|
}
|
|
|
|
|
Assert.IsTrue(foundRotatoin, "errors should mention the misspelled 'rotatoin' property");
|
|
|
|
|
Assert.IsTrue(foundInvalidProp, "errors should mention the 'invalidProp' property");
|
2025-09-04 00:57:12 +08:00
|
|
|
}
|
|
|
|
|
|
2025-10-01 04:25:33 +08:00
|
|
|
[Test]
|
2025-09-04 00:57:12 +08:00
|
|
|
public void SetComponentProperties_ContinuesAfterException()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - create scenario that might cause exceptions
|
|
|
|
|
var rigidbody = testGameObject.AddComponent<Rigidbody>();
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-04 00:57:12 +08:00
|
|
|
// Set initial values that we'll change
|
|
|
|
|
rigidbody.mass = 1.0f;
|
|
|
|
|
rigidbody.useGravity = true;
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-04 00:57:12 +08:00
|
|
|
var setPropertiesParams = new JObject
|
|
|
|
|
{
|
|
|
|
|
["action"] = "modify",
|
|
|
|
|
["target"] = testGameObject.name,
|
|
|
|
|
["search_method"] = "by_name",
|
|
|
|
|
["componentProperties"] = new JObject
|
|
|
|
|
{
|
|
|
|
|
["Rigidbody"] = new JObject
|
|
|
|
|
{
|
|
|
|
|
["mass"] = 2.5f, // Valid - should be set
|
|
|
|
|
["velocity"] = "invalid_type", // Invalid type - will cause exception
|
|
|
|
|
["useGravity"] = false // Valid - should still be set after exception
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Expect the error logs from the invalid property
|
🔧 Clean up & Consolidate Shared Services Across MCP Tools (#519)
* feat: Redesign GameObject API for better LLM ergonomics
- find_gameobjects: Search GameObjects, returns paginated instance IDs only
- manage_components: Component lifecycle (add, remove, set_property)
- unity://scene/gameobject/{id}: Single GameObject data (no component serialization)
- unity://scene/gameobject/{id}/components: All components (paginated)
- unity://scene/gameobject/{id}/component/{name}: Single component by type
- manage_scene get_hierarchy: Now includes componentTypes array
- manage_gameobject: Slimmed to lifecycle only (create, modify, delete)
- Legacy actions (find, get_components, etc.) log deprecation warnings
- ParamCoercion: Centralized int/bool/float/string coercion
- VectorParsing: Vector3/Vector2/Quaternion/Color parsing
- GameObjectLookup: Centralized GameObject search logic
- 76 new Unity EditMode tests for ManageGameObject actions
- 21 new pytest tests for Python tools/resources
- New NL/T CI suite for GameObject API (GO-0 to GO-5)
Addresses LLM confusion with parameter overload by splitting into
focused tools and read-only resources.
* feat: Add GameObject API stress tests and NL/T suite updates
Stress Tests (12 new tests):
- BulkCreate small/medium batches
- FindGameObjects pagination with by_component search
- AddComponents to single object
- GetComponents with full serialization
- SetComponentProperties (complex Rigidbody)
- Deep hierarchy creation and path lookup
- GetHierarchy with large scenes
- Resource read performance tests
- RapidFire create-modify-delete cycles
NL/T Suite Updates:
- Added GO-0..GO-10 tests in nl-gameobject-suite.md
- Fixed tool naming: mcp__unity__ → mcp__UnityMCP__
Other:
- Fixed LongUnityScriptClaudeTest.cs compilation errors
- Added reports/, .claude/local/, scripts/local-test/ to .gitignore
All 254 EditMode tests pass (250 run, 4 explicit skips)
* fix: Address code review feedback
- ParamCoercion: Use CultureInfo.InvariantCulture for float parsing
- ManageComponents: Move Transform removal check before GetComponent
- ManageGameObjectFindTests: Use try-finally for LogAssert.ignoreFailingMessages
- VectorParsing: Document that quaternions are not auto-normalized
- gameobject.py: Prefix unused ctx parameter with underscore
* fix: Address more code review feedback
NL/T Prompt Fixes:
- nl-gameobject-suite.md: Remove non-existent list_resources/read_resource from AllowedTools
- nl-gameobject-suite.md: Fix parameter names (component_type, properties)
- nl-unity-suite-nl.md: Remove unused manage_editor from AllowedTools
Test Fixes:
- GameObjectAPIStressTests: Add null check to ToJObject helper
- GameObjectAPIStressTests: Clarify AudioSource usage comment
- ManageGameObjectFindTests: Use built-in 'UI' layer instead of 'Water'
- LongUnityScriptClaudeTest: Clean up NL/T test artifacts (Counte42 typo, HasTarget)
* docs: update README tools and resources lists
- Add missing tools: manage_components, batch_execute, find_gameobjects, refresh_unity
- Add missing resources: gameobject_api, editor_state_v2
- Make descriptions more concise across all tools and resources
- Ensure documentation matches current MCP server functionality
* chore: Remove accidentally committed test artifacts
- Remove Materials folder (40 .mat files from interactive testing)
- Remove Shaders folder (5 noise shaders from testing)
- Remove test scripts (Bounce*, CylinderBounce* from testing)
- Remove Temp.meta and commit.sh
* refactor: remove deprecated manage_gameobject actions
- Remove deprecated switch cases: find, get_components, get_component, add_component, remove_component, set_component_property
- Remove deprecated wrapper methods (423 lines deleted from ManageGameObject.cs)
- Delete ManageGameObjectFindTests.cs (tests deprecated 'find' action)
- Remove deprecated test methods from ManageGameObjectTests.cs
- Add GameObject resource URIs to README documentation
- Add batch_execute performance tips to README, tool description, and gameobject_api resource
- Enhance batch_execute description to emphasize 10-100x performance gains
Total: ~1200 lines removed. New API (find_gameobjects, manage_components, resources) is the recommended path forward.
* refactor: consolidate shared services across MCP tools
Major architectural improvements:
- Create UnityJsonSerializer for shared JSON/Unity type conversion
- Create ObjectResolver for unified object resolution (GameObjects, Components, Assets)
- Create UnityTypeResolver for consolidated type resolution with caching
- Create PropertyConversion for unified JSON→Unity property conversion
- Create ComponentOps for low-level component operations
- Create Pagination helpers for standardized pagination across tools
Tool simplifications:
- ManageGameObject: Remove 68-line prefab redirect anti-pattern, delegate to helpers
- ManageAsset: Remove ~80 lines duplicate ConvertJTokenToType
- ManageScriptableObject: Remove ~40 lines duplicate ResolveType
- ManageComponents: Use ComponentOps, UnityTypeResolver (~90 lines saved)
- ManageMaterial: Standardize to SuccessResponse/ErrorResponse patterns
- FindGameObjects: Use PaginationRequest/PaginationResponse
- GameObjectLookup: FindComponentType delegates to UnityTypeResolver
Tests: 242/246 passed, 4 skipped (expected)
* Apply code review feedback: consolidate utilities and improve compatibility
Python Server:
- Extract normalize_properties() to shared utils.py (removes duplication)
- Move search_term validation before preflight() for fail-fast
- Fix manage_script.py documentation (remove incorrect 'update' reference)
- Remove stale comments in execute_menu_item.py, manage_editor.py
- Remove misleading destructiveHint from manage_shader.py
C# Unity:
- Add Vector4Converter (commonly used, was missing)
- Fix Unity 2021 compatibility: replace FindObjectsByType with FindObjectsOfType
- Add path normalization in ObjectResolver before StartsWith check
- Improve ComponentOps.SetProperty conversion error detection
- Add Undo.RecordObject in ManageComponents before property modifications
- Improve error message clarity in ManageMaterial.cs
- Add defensive error handling to stress test ToJObject helper
- Increase CI timeout thresholds for test stability
GitHub Workflows:
- Fix GO test sorting in markdown output (GO-10 now sorts after GO-9)
- Add warning logging for fragment parsing errors
* Fix animator hash names in test fixture to match parameter names
BlendXHash/BlendYHash now use 'reachX'/'reachY' to match the
actual animator parameter names.
* fix(windows): improve HTTP server detection and auto-start reliability
- Fix netstat detection on Windows by running netstat.exe directly instead
of piping through findstr (findstr returns exit code 1 when no matches,
causing false detection failures)
- Increase auto-start retry attempts (20→30) and delays (2s→3s) to handle
slow server starts during first install, version upgrades, and dev mode
- Only attempt blind connection after 20 failed detection attempts to reduce
connection error spam during server startup
- Remove verbose debug logs that were spamming the console every frame
* fix: auto-create tags and remove deprecated manage_gameobject actions
- ManageGameObject.cs: Check tag existence before setting; auto-create
undefined tags using InternalEditorUtility.AddTag() instead of relying
on exception handling (Unity logs warning, doesn't throw)
- manage_gameobject.py: Remove deprecated actions (find, get_components,
add_component, remove_component, set_component_property, get_component)
from Literal type - these are now handled by find_gameobjects and
manage_components tools
- Update test suite and unit tests to reflect new auto-create behavior
* fix: address code review feedback
Bug fixes:
- Fix searchInactive flag ignored in FindObjectsOfType (use includeInactive overload)
- Fix property lookup to try both original and normalized names for backwards compat
- Remove dead code for deprecated 'find' action validation
- Update error message to list only valid actions
Improvements:
- Add destructiveHint=True to manage_shader tool
- Limit fallback connection attempts (every 3rd attempt) to avoid spamming errors
- Consolidate PropertyConversion exception handlers to single catch block
- Add tag existence assertion and cleanup in tag auto-creation tests
Test fixes:
- Update SetComponentProperties_ContinuesAfterException log regex for new error format
- Update test_manage_gameobject_param_coercion to test valid actions only
2026-01-07 04:58:17 +08:00
|
|
|
// Note: PropertyConversion logs "Error converting token to..." when conversion fails
|
|
|
|
|
LogAssert.Expect(LogType.Error, new System.Text.RegularExpressions.Regex("Error converting token to UnityEngine.Vector3"));
|
|
|
|
|
LogAssert.Expect(LogType.Error, new System.Text.RegularExpressions.Regex(@"\[SetProperty\].*Failed to set 'velocity'"));
|
2025-09-04 00:57:12 +08:00
|
|
|
LogAssert.Expect(LogType.Warning, new System.Text.RegularExpressions.Regex("Property 'velocity' not found"));
|
|
|
|
|
|
|
|
|
|
// Act
|
|
|
|
|
var result = ManageGameObject.HandleCommand(setPropertiesParams);
|
|
|
|
|
|
|
|
|
|
// Assert - verify that valid properties before AND after the exception were still set
|
|
|
|
|
Assert.AreEqual(2.5f, rigidbody.mass, 0.001f,
|
|
|
|
|
"Mass should be set even if later property causes exception");
|
|
|
|
|
Assert.AreEqual(false, rigidbody.useGravity,
|
|
|
|
|
"UseGravity should be set even if previous property caused exception");
|
|
|
|
|
|
|
|
|
|
Assert.IsNotNull(result, "Should return a result even with exceptions");
|
2025-10-01 04:25:33 +08:00
|
|
|
|
2025-09-04 00:57:12 +08:00
|
|
|
// The key test: processing continued after the exception and set useGravity
|
|
|
|
|
// This proves the collect-and-continue behavior works even with exceptions
|
2025-09-07 01:58:11 +08:00
|
|
|
|
|
|
|
|
// Harden: verify structured error response contains velocity failure
|
|
|
|
|
var successProp2 = result.GetType().GetProperty("success");
|
|
|
|
|
Assert.IsNotNull(successProp2, "Result should expose 'success' property");
|
|
|
|
|
Assert.IsFalse((bool)successProp2.GetValue(result), "Result.success should be false when an exception occurs for a property");
|
|
|
|
|
|
|
|
|
|
var dataProp2 = result.GetType().GetProperty("data");
|
|
|
|
|
Assert.IsNotNull(dataProp2, "Result should include 'data' with errors");
|
|
|
|
|
var dataVal2 = dataProp2.GetValue(result);
|
|
|
|
|
Assert.IsNotNull(dataVal2, "Result.data should not be null");
|
|
|
|
|
var errorsProp2 = dataVal2.GetType().GetProperty("errors");
|
|
|
|
|
Assert.IsNotNull(errorsProp2, "Result.data should include 'errors' list");
|
|
|
|
|
var errorsEnum2 = errorsProp2.GetValue(dataVal2) as System.Collections.IEnumerable;
|
|
|
|
|
Assert.IsNotNull(errorsEnum2, "errors should be enumerable");
|
|
|
|
|
|
|
|
|
|
bool foundVelocityError = false;
|
|
|
|
|
foreach (var err in errorsEnum2)
|
|
|
|
|
{
|
|
|
|
|
string s = err?.ToString() ?? string.Empty;
|
|
|
|
|
if (s.Contains("velocity")) { foundVelocityError = true; break; }
|
|
|
|
|
}
|
|
|
|
|
Assert.IsTrue(foundVelocityError, "errors should include a message referencing 'velocity'");
|
2025-09-04 00:57:12 +08:00
|
|
|
}
|
2025-10-21 09:34:33 +08:00
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void GetComponentData_DoesNotInstantiateMaterialsInEditMode()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - Create a GameObject with MeshRenderer and MeshFilter components
|
|
|
|
|
var testObject = new GameObject("MaterialMeshTestObject");
|
|
|
|
|
var meshRenderer = testObject.AddComponent<MeshRenderer>();
|
|
|
|
|
var meshFilter = testObject.AddComponent<MeshFilter>();
|
|
|
|
|
|
|
|
|
|
// Create a simple material and mesh for testing
|
|
|
|
|
var testMaterial = new Material(Shader.Find("Standard"));
|
|
|
|
|
var tempCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
|
|
|
var testMesh = tempCube.GetComponent<MeshFilter>().sharedMesh;
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(tempCube);
|
|
|
|
|
|
|
|
|
|
// Set the shared material and mesh (these should be used in edit mode)
|
|
|
|
|
meshRenderer.sharedMaterial = testMaterial;
|
|
|
|
|
meshFilter.sharedMesh = testMesh;
|
|
|
|
|
|
|
|
|
|
// Act - Get component data which should trigger material/mesh property access
|
|
|
|
|
var prevIgnore = LogAssert.ignoreFailingMessages;
|
|
|
|
|
LogAssert.ignoreFailingMessages = true; // Avoid failing due to incidental editor logs during reflection
|
|
|
|
|
object result;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
LogAssert.ignoreFailingMessages = prevIgnore;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assert - Basic success and shape tolerance
|
|
|
|
|
Assert.IsNotNull(result, "GetComponentData should return a result");
|
|
|
|
|
if (result is Dictionary<string, object> dict &&
|
|
|
|
|
dict.TryGetValue("properties", out var propsObj) &&
|
|
|
|
|
propsObj is Dictionary<string, object> properties)
|
|
|
|
|
{
|
|
|
|
|
Assert.IsTrue(properties.ContainsKey("material") || properties.ContainsKey("sharedMaterial") || properties.ContainsKey("materials") || properties.ContainsKey("sharedMaterials"),
|
|
|
|
|
"Serialized data should include a material-related key when present.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clean up
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(testMaterial);
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(testObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void GetComponentData_DoesNotInstantiateMeshesInEditMode()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - Create a GameObject with MeshFilter component
|
|
|
|
|
var testObject = new GameObject("MeshTestObject");
|
|
|
|
|
var meshFilter = testObject.AddComponent<MeshFilter>();
|
|
|
|
|
|
|
|
|
|
// Create a simple mesh for testing
|
|
|
|
|
var tempSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
|
|
|
|
var testMesh = tempSphere.GetComponent<MeshFilter>().sharedMesh;
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(tempSphere);
|
|
|
|
|
meshFilter.sharedMesh = testMesh;
|
|
|
|
|
|
|
|
|
|
// Act - Get component data which should trigger mesh property access
|
|
|
|
|
var prevIgnore2 = LogAssert.ignoreFailingMessages;
|
|
|
|
|
LogAssert.ignoreFailingMessages = true;
|
|
|
|
|
object result;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshFilter);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
LogAssert.ignoreFailingMessages = prevIgnore2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assert - Basic success and shape tolerance
|
|
|
|
|
Assert.IsNotNull(result, "GetComponentData should return a result");
|
|
|
|
|
if (result is Dictionary<string, object> dict2 &&
|
|
|
|
|
dict2.TryGetValue("properties", out var propsObj2) &&
|
|
|
|
|
propsObj2 is Dictionary<string, object> properties2)
|
|
|
|
|
{
|
|
|
|
|
Assert.IsTrue(properties2.ContainsKey("mesh") || properties2.ContainsKey("sharedMesh"),
|
|
|
|
|
"Serialized data should include a mesh-related key when present.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clean up
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(testObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void GetComponentData_UsesSharedMaterialInEditMode()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - Create a GameObject with MeshRenderer
|
|
|
|
|
var testObject = new GameObject("SharedMaterialTestObject");
|
|
|
|
|
var meshRenderer = testObject.AddComponent<MeshRenderer>();
|
|
|
|
|
|
|
|
|
|
// Create a test material
|
|
|
|
|
var testMaterial = new Material(Shader.Find("Standard"));
|
|
|
|
|
testMaterial.name = "TestMaterial";
|
|
|
|
|
meshRenderer.sharedMaterial = testMaterial;
|
|
|
|
|
|
|
|
|
|
// Act - Get component data in edit mode
|
|
|
|
|
var result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
|
|
|
|
|
|
|
|
|
|
// Assert - Verify that the material property was accessed without instantiation
|
|
|
|
|
Assert.IsNotNull(result, "GetComponentData should return a result");
|
|
|
|
|
|
|
|
|
|
// Check that result is a dictionary with properties key
|
|
|
|
|
if (result is Dictionary<string, object> resultDict &&
|
|
|
|
|
resultDict.TryGetValue("properties", out var propertiesObj) &&
|
|
|
|
|
propertiesObj is Dictionary<string, object> properties)
|
|
|
|
|
{
|
|
|
|
|
Assert.IsTrue(properties.ContainsKey("material") || properties.ContainsKey("sharedMaterial"),
|
|
|
|
|
"Serialized data should include 'material' or 'sharedMaterial' when present.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clean up
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(testMaterial);
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(testObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void GetComponentData_UsesSharedMeshInEditMode()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - Create a GameObject with MeshFilter
|
|
|
|
|
var testObject = new GameObject("SharedMeshTestObject");
|
|
|
|
|
var meshFilter = testObject.AddComponent<MeshFilter>();
|
|
|
|
|
|
|
|
|
|
// Create a test mesh
|
|
|
|
|
var tempCylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
|
|
|
var testMesh = tempCylinder.GetComponent<MeshFilter>().sharedMesh;
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(tempCylinder);
|
|
|
|
|
testMesh.name = "TestMesh";
|
|
|
|
|
meshFilter.sharedMesh = testMesh;
|
|
|
|
|
|
|
|
|
|
// Act - Get component data in edit mode
|
|
|
|
|
var result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshFilter);
|
|
|
|
|
|
|
|
|
|
// Assert - Verify that the mesh property was accessed without instantiation
|
|
|
|
|
Assert.IsNotNull(result, "GetComponentData should return a result");
|
|
|
|
|
|
|
|
|
|
// Check that result is a dictionary with properties key
|
|
|
|
|
if (result is Dictionary<string, object> resultDict &&
|
|
|
|
|
resultDict.TryGetValue("properties", out var propertiesObj) &&
|
|
|
|
|
propertiesObj is Dictionary<string, object> properties)
|
|
|
|
|
{
|
|
|
|
|
Assert.IsTrue(properties.ContainsKey("mesh") || properties.ContainsKey("sharedMesh"),
|
|
|
|
|
"Serialized data should include 'mesh' or 'sharedMesh' when present.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clean up
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(testObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void GetComponentData_HandlesNullMaterialsAndMeshes()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - Create a GameObject with MeshRenderer and MeshFilter but no materials/meshes
|
|
|
|
|
var testObject = new GameObject("NullMaterialMeshTestObject");
|
|
|
|
|
var meshRenderer = testObject.AddComponent<MeshRenderer>();
|
|
|
|
|
var meshFilter = testObject.AddComponent<MeshFilter>();
|
|
|
|
|
|
|
|
|
|
// Don't set any materials or meshes - they should be null
|
|
|
|
|
|
|
|
|
|
// Act - Get component data
|
|
|
|
|
var rendererResult = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
|
|
|
|
|
var meshFilterResult = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshFilter);
|
|
|
|
|
|
|
|
|
|
// Assert - Verify that the operations succeeded even with null materials/meshes
|
|
|
|
|
Assert.IsNotNull(rendererResult, "GetComponentData should handle null materials");
|
|
|
|
|
Assert.IsNotNull(meshFilterResult, "GetComponentData should handle null meshes");
|
|
|
|
|
|
|
|
|
|
// Clean up
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(testObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void GetComponentData_WorksWithMultipleMaterials()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - Create a GameObject with MeshRenderer that has multiple materials
|
|
|
|
|
var testObject = new GameObject("MultiMaterialTestObject");
|
|
|
|
|
var meshRenderer = testObject.AddComponent<MeshRenderer>();
|
|
|
|
|
|
|
|
|
|
// Create multiple test materials
|
|
|
|
|
var material1 = new Material(Shader.Find("Standard"));
|
|
|
|
|
material1.name = "TestMaterial1";
|
|
|
|
|
var material2 = new Material(Shader.Find("Standard"));
|
|
|
|
|
material2.name = "TestMaterial2";
|
|
|
|
|
|
|
|
|
|
meshRenderer.sharedMaterials = new Material[] { material1, material2 };
|
|
|
|
|
|
|
|
|
|
// Act - Get component data
|
|
|
|
|
var result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
|
|
|
|
|
|
|
|
|
|
// Assert - Verify that the operation succeeded with multiple materials
|
|
|
|
|
Assert.IsNotNull(result, "GetComponentData should handle multiple materials");
|
|
|
|
|
|
|
|
|
|
// Clean up
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(material1);
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(material2);
|
|
|
|
|
UnityEngine.Object.DestroyImmediate(testObject);
|
|
|
|
|
}
|
🔧 Clean up & Consolidate Shared Services Across MCP Tools (#519)
* feat: Redesign GameObject API for better LLM ergonomics
- find_gameobjects: Search GameObjects, returns paginated instance IDs only
- manage_components: Component lifecycle (add, remove, set_property)
- unity://scene/gameobject/{id}: Single GameObject data (no component serialization)
- unity://scene/gameobject/{id}/components: All components (paginated)
- unity://scene/gameobject/{id}/component/{name}: Single component by type
- manage_scene get_hierarchy: Now includes componentTypes array
- manage_gameobject: Slimmed to lifecycle only (create, modify, delete)
- Legacy actions (find, get_components, etc.) log deprecation warnings
- ParamCoercion: Centralized int/bool/float/string coercion
- VectorParsing: Vector3/Vector2/Quaternion/Color parsing
- GameObjectLookup: Centralized GameObject search logic
- 76 new Unity EditMode tests for ManageGameObject actions
- 21 new pytest tests for Python tools/resources
- New NL/T CI suite for GameObject API (GO-0 to GO-5)
Addresses LLM confusion with parameter overload by splitting into
focused tools and read-only resources.
* feat: Add GameObject API stress tests and NL/T suite updates
Stress Tests (12 new tests):
- BulkCreate small/medium batches
- FindGameObjects pagination with by_component search
- AddComponents to single object
- GetComponents with full serialization
- SetComponentProperties (complex Rigidbody)
- Deep hierarchy creation and path lookup
- GetHierarchy with large scenes
- Resource read performance tests
- RapidFire create-modify-delete cycles
NL/T Suite Updates:
- Added GO-0..GO-10 tests in nl-gameobject-suite.md
- Fixed tool naming: mcp__unity__ → mcp__UnityMCP__
Other:
- Fixed LongUnityScriptClaudeTest.cs compilation errors
- Added reports/, .claude/local/, scripts/local-test/ to .gitignore
All 254 EditMode tests pass (250 run, 4 explicit skips)
* fix: Address code review feedback
- ParamCoercion: Use CultureInfo.InvariantCulture for float parsing
- ManageComponents: Move Transform removal check before GetComponent
- ManageGameObjectFindTests: Use try-finally for LogAssert.ignoreFailingMessages
- VectorParsing: Document that quaternions are not auto-normalized
- gameobject.py: Prefix unused ctx parameter with underscore
* fix: Address more code review feedback
NL/T Prompt Fixes:
- nl-gameobject-suite.md: Remove non-existent list_resources/read_resource from AllowedTools
- nl-gameobject-suite.md: Fix parameter names (component_type, properties)
- nl-unity-suite-nl.md: Remove unused manage_editor from AllowedTools
Test Fixes:
- GameObjectAPIStressTests: Add null check to ToJObject helper
- GameObjectAPIStressTests: Clarify AudioSource usage comment
- ManageGameObjectFindTests: Use built-in 'UI' layer instead of 'Water'
- LongUnityScriptClaudeTest: Clean up NL/T test artifacts (Counte42 typo, HasTarget)
* docs: update README tools and resources lists
- Add missing tools: manage_components, batch_execute, find_gameobjects, refresh_unity
- Add missing resources: gameobject_api, editor_state_v2
- Make descriptions more concise across all tools and resources
- Ensure documentation matches current MCP server functionality
* chore: Remove accidentally committed test artifacts
- Remove Materials folder (40 .mat files from interactive testing)
- Remove Shaders folder (5 noise shaders from testing)
- Remove test scripts (Bounce*, CylinderBounce* from testing)
- Remove Temp.meta and commit.sh
* refactor: remove deprecated manage_gameobject actions
- Remove deprecated switch cases: find, get_components, get_component, add_component, remove_component, set_component_property
- Remove deprecated wrapper methods (423 lines deleted from ManageGameObject.cs)
- Delete ManageGameObjectFindTests.cs (tests deprecated 'find' action)
- Remove deprecated test methods from ManageGameObjectTests.cs
- Add GameObject resource URIs to README documentation
- Add batch_execute performance tips to README, tool description, and gameobject_api resource
- Enhance batch_execute description to emphasize 10-100x performance gains
Total: ~1200 lines removed. New API (find_gameobjects, manage_components, resources) is the recommended path forward.
* refactor: consolidate shared services across MCP tools
Major architectural improvements:
- Create UnityJsonSerializer for shared JSON/Unity type conversion
- Create ObjectResolver for unified object resolution (GameObjects, Components, Assets)
- Create UnityTypeResolver for consolidated type resolution with caching
- Create PropertyConversion for unified JSON→Unity property conversion
- Create ComponentOps for low-level component operations
- Create Pagination helpers for standardized pagination across tools
Tool simplifications:
- ManageGameObject: Remove 68-line prefab redirect anti-pattern, delegate to helpers
- ManageAsset: Remove ~80 lines duplicate ConvertJTokenToType
- ManageScriptableObject: Remove ~40 lines duplicate ResolveType
- ManageComponents: Use ComponentOps, UnityTypeResolver (~90 lines saved)
- ManageMaterial: Standardize to SuccessResponse/ErrorResponse patterns
- FindGameObjects: Use PaginationRequest/PaginationResponse
- GameObjectLookup: FindComponentType delegates to UnityTypeResolver
Tests: 242/246 passed, 4 skipped (expected)
* Apply code review feedback: consolidate utilities and improve compatibility
Python Server:
- Extract normalize_properties() to shared utils.py (removes duplication)
- Move search_term validation before preflight() for fail-fast
- Fix manage_script.py documentation (remove incorrect 'update' reference)
- Remove stale comments in execute_menu_item.py, manage_editor.py
- Remove misleading destructiveHint from manage_shader.py
C# Unity:
- Add Vector4Converter (commonly used, was missing)
- Fix Unity 2021 compatibility: replace FindObjectsByType with FindObjectsOfType
- Add path normalization in ObjectResolver before StartsWith check
- Improve ComponentOps.SetProperty conversion error detection
- Add Undo.RecordObject in ManageComponents before property modifications
- Improve error message clarity in ManageMaterial.cs
- Add defensive error handling to stress test ToJObject helper
- Increase CI timeout thresholds for test stability
GitHub Workflows:
- Fix GO test sorting in markdown output (GO-10 now sorts after GO-9)
- Add warning logging for fragment parsing errors
* Fix animator hash names in test fixture to match parameter names
BlendXHash/BlendYHash now use 'reachX'/'reachY' to match the
actual animator parameter names.
* fix(windows): improve HTTP server detection and auto-start reliability
- Fix netstat detection on Windows by running netstat.exe directly instead
of piping through findstr (findstr returns exit code 1 when no matches,
causing false detection failures)
- Increase auto-start retry attempts (20→30) and delays (2s→3s) to handle
slow server starts during first install, version upgrades, and dev mode
- Only attempt blind connection after 20 failed detection attempts to reduce
connection error spam during server startup
- Remove verbose debug logs that were spamming the console every frame
* fix: auto-create tags and remove deprecated manage_gameobject actions
- ManageGameObject.cs: Check tag existence before setting; auto-create
undefined tags using InternalEditorUtility.AddTag() instead of relying
on exception handling (Unity logs warning, doesn't throw)
- manage_gameobject.py: Remove deprecated actions (find, get_components,
add_component, remove_component, set_component_property, get_component)
from Literal type - these are now handled by find_gameobjects and
manage_components tools
- Update test suite and unit tests to reflect new auto-create behavior
* fix: address code review feedback
Bug fixes:
- Fix searchInactive flag ignored in FindObjectsOfType (use includeInactive overload)
- Fix property lookup to try both original and normalized names for backwards compat
- Remove dead code for deprecated 'find' action validation
- Update error message to list only valid actions
Improvements:
- Add destructiveHint=True to manage_shader tool
- Limit fallback connection attempts (every 3rd attempt) to avoid spamming errors
- Consolidate PropertyConversion exception handlers to single catch block
- Add tag existence assertion and cleanup in tag auto-creation tests
Test fixes:
- Update SetComponentProperties_ContinuesAfterException log regex for new error format
- Update test_manage_gameobject_param_coercion to test valid actions only
2026-01-07 04:58:17 +08:00
|
|
|
|
|
|
|
|
#region Prefab Asset Handling Tests
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void HandleCommand_WithPrefabPath_ReturnsGuidanceError_ForModifyAction()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - Attempt to modify a prefab asset directly
|
|
|
|
|
var modifyParams = new JObject
|
|
|
|
|
{
|
|
|
|
|
["action"] = "modify",
|
|
|
|
|
["target"] = "Assets/Prefabs/MyPrefab.prefab"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Act
|
|
|
|
|
var result = ManageGameObject.HandleCommand(modifyParams);
|
|
|
|
|
|
|
|
|
|
// Assert - Should return an error with guidance to use correct tools
|
|
|
|
|
Assert.IsNotNull(result, "Should return a result");
|
|
|
|
|
var errorResponse = result as MCPForUnity.Editor.Helpers.ErrorResponse;
|
|
|
|
|
Assert.IsNotNull(errorResponse, "Should return an ErrorResponse");
|
|
|
|
|
Assert.IsFalse(errorResponse.Success, "Should indicate failure");
|
|
|
|
|
Assert.That(errorResponse.Error, Does.Contain("prefab asset"), "Error should mention prefab asset");
|
|
|
|
|
Assert.That(errorResponse.Error, Does.Contain("manage_asset"), "Error should guide to manage_asset");
|
|
|
|
|
Assert.That(errorResponse.Error, Does.Contain("manage_prefabs"), "Error should guide to manage_prefabs");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void HandleCommand_WithPrefabPath_ReturnsGuidanceError_ForDeleteAction()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - Attempt to delete a prefab asset directly
|
|
|
|
|
var deleteParams = new JObject
|
|
|
|
|
{
|
|
|
|
|
["action"] = "delete",
|
|
|
|
|
["target"] = "Assets/Prefabs/SomePrefab.prefab"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Act
|
|
|
|
|
var result = ManageGameObject.HandleCommand(deleteParams);
|
|
|
|
|
|
|
|
|
|
// Assert - Should return an error with guidance
|
|
|
|
|
Assert.IsNotNull(result, "Should return a result");
|
|
|
|
|
var errorResponse = result as MCPForUnity.Editor.Helpers.ErrorResponse;
|
|
|
|
|
Assert.IsNotNull(errorResponse, "Should return an ErrorResponse");
|
|
|
|
|
Assert.IsFalse(errorResponse.Success, "Should indicate failure");
|
|
|
|
|
Assert.That(errorResponse.Error, Does.Contain("prefab asset"), "Error should mention prefab asset");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void HandleCommand_WithPrefabPath_AllowsCreateAction()
|
|
|
|
|
{
|
|
|
|
|
// Arrange - Create (instantiate) from a prefab should be allowed
|
|
|
|
|
// Note: This will fail because the prefab doesn't exist, but the error should NOT be
|
|
|
|
|
// the prefab redirection error - it should be a "prefab not found" type error
|
|
|
|
|
var createParams = new JObject
|
|
|
|
|
{
|
|
|
|
|
["action"] = "create",
|
|
|
|
|
["prefab_path"] = "Assets/Prefabs/NonExistent.prefab",
|
|
|
|
|
["name"] = "TestInstance"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Act
|
|
|
|
|
var result = ManageGameObject.HandleCommand(createParams);
|
|
|
|
|
|
|
|
|
|
// Assert - Should NOT return the prefab redirection error
|
|
|
|
|
// (It may fail for other reasons like prefab not found, but not due to redirection)
|
|
|
|
|
var errorResponse = result as MCPForUnity.Editor.Helpers.ErrorResponse;
|
|
|
|
|
if (errorResponse != null)
|
|
|
|
|
{
|
|
|
|
|
// If there's an error, it should NOT be the prefab asset guidance error
|
|
|
|
|
Assert.That(errorResponse.Error, Does.Not.Contain("Use 'manage_asset'"),
|
|
|
|
|
"Create action should not be blocked by prefab check");
|
|
|
|
|
}
|
|
|
|
|
// If it's not an error, that's also fine (means create was allowed)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-09-03 10:27:40 +08:00
|
|
|
}
|
2025-10-01 04:25:33 +08:00
|
|
|
}
|