Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
09661a8
refactor: Split ParseColorOrDefault into two overloads and change def…
msanatan Jan 7, 2026
e48879b
Auto-format Python code
msanatan Jan 7, 2026
69e62bb
Remove unused Python module
msanatan Jan 7, 2026
7ee51f6
Refactored VFX functionality into multiple files
msanatan Jan 7, 2026
e68fbb6
Rename ManageVfx folder to just Vfx
msanatan Jan 7, 2026
47ba35f
Clean up whitespace on plugin tools and resources
msanatan Jan 7, 2026
8321db2
Make ManageGameObject less of a monolith by splitting it out into dif…
msanatan Jan 7, 2026
c038996
Remove obsolete FindObjectByInstruction method
msanatan Jan 7, 2026
369c97f
Merge branch 'main' into pre-release-tidying
msanatan Jan 7, 2026
d83c439
refactor: Consolidate editor state resources into single canonical im…
msanatan Jan 7, 2026
0a95563
Validate editor state with Pydantic models in both C# and Python
msanatan Jan 7, 2026
bcbba05
Consolidate run_tests and run_tests_async into single async implement…
msanatan Jan 7, 2026
93f1084
Validate test job responses with Pydantic models in Python
msanatan Jan 7, 2026
88ed90a
Change resources URI from unity:// to mcpforunity://
msanatan Jan 7, 2026
07d1d9d
Update README with all tools + better listing for resources
msanatan Jan 7, 2026
c23412c
Update other references to resources
msanatan Jan 7, 2026
9569de6
Updated translated doc - unfortunately I cannot verify
msanatan Jan 7, 2026
21db63a
Update the Chinese translation of the dev docks
msanatan Jan 7, 2026
7e38e31
Change menu item from Setup Window to Local Setup Window
msanatan Jan 7, 2026
e155470
Fix URIs for menu items and tests
msanatan Jan 7, 2026
e03df44
Shouldn't have removed it
msanatan Jan 7, 2026
f12adda
Minor edits from CodeRabbit feedback
msanatan Jan 7, 2026
39c6234
Don't use reflection which takes longer
msanatan Jan 7, 2026
580af95
Fix failing python tests
msanatan Jan 7, 2026
9122e1e
Add serialization helpers for ParticleSystem curves and MinMaxCurve t…
msanatan Jan 7, 2026
98a261a
Use ctx param
msanatan Jan 7, 2026
93a6434
Update Server/src/services/tools/run_tests.py
msanatan Jan 7, 2026
89ea989
Minor fixes
msanatan Jan 7, 2026
0de9d2c
Rename anything EditorStateV2 to just EditorState
msanatan Jan 7, 2026
b3319a2
Make infer_single_instance_id public by removing underscore prefix
msanatan Jan 7, 2026
f270bee
Fix Python tests, again
msanatan Jan 7, 2026
07558e1
Replace AI generated .meta files with actual Unity ones
msanatan Jan 7, 2026
ce1fbc6
## Pre-Launch Enhancements: Testing Infrastructure & Tool Improvement…
dsarno Jan 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .claude/prompts/nl-gameobject-suite.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ AllowedTools: Write,mcp__UnityMCP__manage_editor,mcp__UnityMCP__manage_gameobjec
**Goal**: Test reading a single GameObject via resource
**Actions**:
- Use the instance ID from GO-1
- Call `mcp__UnityMCP__read_resource(uri="unity://scene/gameobject/{instanceID}")` replacing {instanceID} with the actual ID
- Call `mcp__UnityMCP__read_resource(uri="mcpforunity://scene/gameobject/{instanceID}")` replacing {instanceID} with the actual ID
- Verify response includes: instanceID, name, tag, layer, transform, path
- **Pass criteria**: All expected fields present

### GO-3. Components Resource Read
**Goal**: Test reading components via resource
**Actions**:
- Use the instance ID from GO-1
- Call `mcp__UnityMCP__read_resource(uri="unity://scene/gameobject/{instanceID}/components")` replacing {instanceID} with the actual ID
- Call `mcp__UnityMCP__read_resource(uri="mcpforunity://scene/gameobject/{instanceID}/components")` replacing {instanceID} with the actual ID
- Verify response includes paginated component list in `data.items`
- Verify at least one component has typeName and instanceID
- **Pass criteria**: Components list returned with proper pagination
Expand Down Expand Up @@ -94,7 +94,7 @@ AllowedTools: Write,mcp__UnityMCP__manage_editor,mcp__UnityMCP__manage_gameobjec
**Goal**: Test reading a single component via resource
**Actions**:
- Get instance ID of GO_Test_Object from GO-5
- Call `mcp__UnityMCP__read_resource(uri="unity://scene/gameobject/{instanceID}/component/Rigidbody")` replacing {instanceID}
- Call `mcp__UnityMCP__read_resource(uri="mcpforunity://scene/gameobject/{instanceID}/component/Rigidbody")` replacing {instanceID}
- Verify response includes component data with typeName="Rigidbody"
- Verify mass property is 5.0 (set in GO-4)
- **Pass criteria**: Component data returned with correct properties
Expand Down Expand Up @@ -131,9 +131,9 @@ AllowedTools: Write,mcp__UnityMCP__manage_editor,mcp__UnityMCP__manage_gameobjec
- `manage_components(action, target, component_type?, properties?)` - Add/remove/set_property/get_all/get_single

### New Resources
- `unity://scene/gameobject/{instanceID}` - Single GameObject data
- `unity://scene/gameobject/{instanceID}/components` - All components (paginated)
- `unity://scene/gameobject/{instanceID}/component/{componentName}` - Single component
- `mcpforunity://scene/gameobject/{instanceID}` - Single GameObject data
- `mcpforunity://scene/gameobject/{instanceID}/components` - All components (paginated)
- `mcpforunity://scene/gameobject/{instanceID}/component/{componentName}` - Single component

### Updated Resources
- `manage_scene(action="get_hierarchy")` - Now includes `componentTypes` array in each item
Expand Down
4 changes: 2 additions & 2 deletions .claude/prompts/nl-unity-suite-nl.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ AllowedTools: Write,mcp__UnityMCP__apply_text_edits,mcp__UnityMCP__script_apply_

## Mission
1) Pick target file (prefer):
- `unity://path/Assets/Scripts/LongUnityScriptClaudeTest.cs`
- `mcpforunity://path/Assets/Scripts/LongUnityScriptClaudeTest.cs`
2) Execute NL tests NL-0..NL-4 in order using minimal, precise edits that build on each other.
3) Validate each edit with `mcp__UnityMCP__validate_script(level:"standard")`.
4) **Report**: write one `<testcase>` XML fragment per test to `reports/<TESTID>_results.xml`. Do **not** read or edit `$JUNIT_OUT`.
Expand Down Expand Up @@ -38,7 +38,7 @@ AllowedTools: Write,mcp__UnityMCP__apply_text_edits,mcp__UnityMCP__script_apply_
## Environment & Paths (CI)
- Always pass: `project_root: "TestProjects/UnityMCPTests"` and `ctx: {}` on list/read/edit/validate.
- **Canonical URIs only**:
- Primary: `unity://path/Assets/...` (never embed `project_root` in the URI)
- Primary: `mcpforunity://path/Assets/...` (never embed `project_root` in the URI)
- Relative (when supported): `Assets/...`

CI provides:
Expand Down
6 changes: 3 additions & 3 deletions .claude/prompts/nl-unity-suite-t.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ AllowedTools: Write,mcp__UnityMCP__manage_editor,mcp__UnityMCP__list_resources,m

## Mission
1) Pick target file (prefer):
- `unity://path/Assets/Scripts/LongUnityScriptClaudeTest.cs`
- `mcpforunity://path/Assets/Scripts/LongUnityScriptClaudeTest.cs`
2) Execute T tests T-A..T-J in order using minimal, precise edits that build on the NL pass state.
3) Validate each edit with `mcp__UnityMCP__validate_script(level:"standard")`.
4) **Report**: write one `<testcase>` XML fragment per test to `reports/<TESTID>_results.xml`. Do **not** read or edit `$JUNIT_OUT`.
Expand Down Expand Up @@ -37,7 +37,7 @@ AllowedTools: Write,mcp__UnityMCP__manage_editor,mcp__UnityMCP__list_resources,m
## Environment & Paths (CI)
- Always pass: `project_root: "TestProjects/UnityMCPTests"` and `ctx: {}` on list/read/edit/validate.
- **Canonical URIs only**:
- Primary: `unity://path/Assets/...` (never embed `project_root` in the URI)
- Primary: `mcpforunity://path/Assets/...` (never embed `project_root` in the URI)
- Relative (when supported): `Assets/...`

CI provides:
Expand Down Expand Up @@ -151,7 +151,7 @@ STRICT OP GUARDRAILS
### T-G. Path Normalization Test (No State Change)
**Goal**: Verify URI forms work equivalently on modified file
**Actions**:
- Make identical edit using `unity://path/Assets/Scripts/LongUnityScriptClaudeTest.cs`
- Make identical edit using `mcpforunity://path/Assets/Scripts/LongUnityScriptClaudeTest.cs`
- Then using `Assets/Scripts/LongUnityScriptClaudeTest.cs`
- Second should return `stale_file`, retry with updated SHA
- Verify both URI forms target same file
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/mark_skipped.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
r"^MCP resources list is empty$",
r"No MCP resources detected",
r"aggregator.*returned\s*\[\s*\]",
r"Unknown resource:\s*unity://",
r"Unknown resource:\s*mcpforunity://",
r"Input should be a valid dictionary.*ctx",
r"validation error .* ctx",
]
Expand Down
2 changes: 1 addition & 1 deletion MCPForUnity/Editor/Dependencies/DependencyManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ private static void GenerateRecommendations(DependencyCheckResult result, IPlatf

if (result.GetMissingRequired().Count > 0)
{
result.RecommendedActions.Add("Use the Setup Window (Window > MCP for Unity > Setup Window) for guided installation.");
result.RecommendedActions.Add("Use the Setup Window (Window > MCP for Unity > Local Setup Window) for guided installation.");
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion MCPForUnity/Editor/Dependencies/DependencyManager.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 59 additions & 0 deletions MCPForUnity/Editor/Helpers/ParamCoercion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,65 @@ public static T CoerceEnum<T>(JToken token, T defaultValue) where T : struct, En
return defaultValue;
}

/// <summary>
/// Checks if a JToken represents a numeric value (integer or float).
/// Useful for validating JSON values before parsing.
/// </summary>
/// <param name="token">The JSON token to check</param>
/// <returns>True if the token is an integer or float, false otherwise</returns>
public static bool IsNumericToken(JToken token)
{
return token != null && (token.Type == JTokenType.Integer || token.Type == JTokenType.Float);
}

/// <summary>
/// Validates that an optional field in a JObject is numeric if present.
/// Used for dry-run validation of complex type formats.
/// </summary>
/// <param name="obj">The JSON object containing the field</param>
/// <param name="fieldName">The name of the field to validate</param>
/// <param name="error">Output error message if validation fails</param>
/// <returns>True if the field is absent, null, or numeric; false if present but non-numeric</returns>
public static bool ValidateNumericField(JObject obj, string fieldName, out string error)
{
error = null;
var token = obj[fieldName];
if (token == null || token.Type == JTokenType.Null)
{
return true; // Field not present, valid (will use default)
}
if (!IsNumericToken(token))
{
error = $"must be a number, got {token.Type}";
return false;
}
return true;
}

/// <summary>
/// Validates that an optional field in a JObject is an integer if present.
/// Used for dry-run validation of complex type formats.
/// </summary>
/// <param name="obj">The JSON object containing the field</param>
/// <param name="fieldName">The name of the field to validate</param>
/// <param name="error">Output error message if validation fails</param>
/// <returns>True if the field is absent, null, or integer; false if present but non-integer</returns>
public static bool ValidateIntegerField(JObject obj, string fieldName, out string error)
{
error = null;
var token = obj[fieldName];
if (token == null || token.Type == JTokenType.Null)
{
return true; // Field not present, valid
}
if (token.Type != JTokenType.Integer)
{
error = $"must be an integer, got {token.Type}";
return false;
}
return true;
}

/// <summary>
/// Normalizes a property name by removing separators and converting to camelCase.
/// Handles common naming variations from LLMs and humans.
Expand Down
Loading