Skip to content

Commit 2649d9c

Browse files
Move Get commands to editor resources + Run Python tests every update (#368)
* Add a function to reload the domain Closes #357 * feat: restructure server instructions into workflow-focused format - Reorganized instructions from flat bullet list into categorized workflow sections - Emphasized critical script management workflow with numbered steps - Improved readability and scannability for AI agents using the MCP server It doesn't make sense to repeat the fucnction tools, they're already parsed * docs: reorder tool list alphabetically in README + add reload_domain tool * feat: add Unity editor state and project info resources - Implemented resources for querying active tool, editor state, prefab stage, selection, and open windows - Added project configuration resources for layers and project metadata - Organized new resources into Editor and Project namespaces for better structure * feat: clarify script management workflow in system prompt - Expanded guidance to include scripts created by any tool, not just manage_script - Added "etc" to tools examples for better clarity * refactor: remove reload_domain tool and update script management workflow - Removed reload_domain tool as Unity automatically recompiles scripts when modified - Updated script management instructions to rely on editor_state polling and console checking instead of manual domain reload - Simplified workflow by removing unnecessary manual recompilation step * Change name of menu items resource as the LLM seems it * refactor: reorganize tests into src/tests/integration directory - Moved all test files from root tests/ to MCPForUnity/UnityMcpServer~/src/tests/integration/ for better organization - Added conftest.py with telemetry and dependency stubs to simplify test setup - Removed redundant path manipulation and module loading code from individual test files * feat: expand Unity test workflow triggers - Run tests on all branches instead of only main - Add pull request trigger to catch issues before merge - Maintain path filtering to run only when relevant files change * chore: add GitHub Actions workflow for Python tests - Configured automated testing on push and pull requests using pytest - Set up uv for dependency management and Python 3.10 environment - Added test results artifact upload for debugging failed runs * refactor: update import path for fastmcp Context * docs: update development setup instructions to use uv - Changed installation commands from pip to uv pip for better dependency management - Updated test running instructions to use uv run pytest - Added examples for running integration and unit tests separately * Formatting [skip ci] * refactor: optimize CI workflow with path filters and dependency installation - Added path filters to only trigger tests when Python source or workflow files change - Split dependency installation into sync and dev install steps for better clarity - Fixed YAML indentation for improved readability * Update .github/workflows/python-tests.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: standardize test mode values to match Unity's naming convention - Changed default mode from "edit" to "EditMode" in C# code - Updated Python tool to use "EditMode" and "PlayMode" instead of lowercase variants * refactor: convert test imports to relative imports - Changed absolute imports to relative imports in integration tests for better package structure - Removed test packages from pyproject.toml package list * refactor: use Field with default_factory for mutable default in TagsResponse * refactor: remove duplicate PrefabStageUtility call * Update this as well [skip ci] * Update MCPForUnity/UnityMcpServer~/src/tests/integration/test_script_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: remove pull_request triggers from test workflows [skip ci] It's already covered by pushes * refactor: update resource function return types to include MCPResponse union * refactor: remove manual domain reload tool - Removed reload_domain tool as Unity handles script recompilation automatically - Updated documentation to reflect automatic compilation workflow - Simplified script management workflow instructions in server description * refactor: add context support to resource handlers - Updated all resource handlers to accept Context parameter for Unity instance routing - Replaced direct async_send_command_with_retry calls with async_send_with_unity_instance wrapper - Added imports for get_unity_instance_from_context and async_send_with_unity_instance helpers * fix: correct grammar in menu items documentation * docs: update README with expanded tools and resources documentation - Added new tools: manage_prefabs, create_script, delete_script, get_sha - Added new resources: editor state, windows, project info, layers, and tags - Clarified manage_script as compatibility router with recommendation to use newer edit tools - Fixed run_test to run_tests for consistency * refactor: convert unity_instances function to async [skip ci] - Changed function signature from synchronous to async - Added await keywords to ctx.info() and ctx.error() calls to properly handle async context methods --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent f667582 commit 2649d9c

File tree

84 files changed

+1434
-1203
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+1434
-1203
lines changed

.github/workflows/python-tests.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Python Tests
2+
3+
on:
4+
push:
5+
branches: ["**"]
6+
paths:
7+
- MCPForUnity/UnityMcpServer~/src/**
8+
- .github/workflows/python-tests.yml
9+
workflow_dispatch: {}
10+
11+
jobs:
12+
test:
13+
name: Run Python Tests
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v4
18+
19+
- name: Install uv
20+
uses: astral-sh/setup-uv@v4
21+
with:
22+
version: "latest"
23+
24+
- name: Set up Python
25+
run: uv python install 3.10
26+
27+
- name: Install dependencies
28+
run: |
29+
cd MCPForUnity/UnityMcpServer~/src
30+
uv sync
31+
uv pip install -e ".[dev]"
32+
33+
- name: Run tests
34+
run: |
35+
cd MCPForUnity/UnityMcpServer~/src
36+
uv run pytest tests/ -v --tb=short
37+
38+
- name: Upload test results
39+
uses: actions/upload-artifact@v4
40+
if: always()
41+
with:
42+
name: pytest-results
43+
path: |
44+
MCPForUnity/UnityMcpServer~/src/.pytest_cache/
45+
MCPForUnity/UnityMcpServer~/src/tests/

.github/workflows/unity-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Unity Tests
33
on:
44
workflow_dispatch: {}
55
push:
6-
branches: [main]
6+
branches: ["**"]
77
paths:
88
- TestProjects/UnityMCPTests/**
99
- MCPForUnity/Editor/**

TestProjects/UnityMCPTests/Assets/Materials.meta renamed to MCPForUnity/Editor/Resources/Editor.meta

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using MCPForUnity.Editor.Helpers;
3+
using Newtonsoft.Json.Linq;
4+
using UnityEditor;
5+
6+
namespace MCPForUnity.Editor.Resources.Editor
7+
{
8+
/// <summary>
9+
/// Provides information about the currently active editor tool.
10+
/// </summary>
11+
[McpForUnityResource("get_active_tool")]
12+
public static class ActiveTool
13+
{
14+
public static object HandleCommand(JObject @params)
15+
{
16+
try
17+
{
18+
Tool currentTool = UnityEditor.Tools.current;
19+
string toolName = currentTool.ToString();
20+
bool customToolActive = UnityEditor.Tools.current == Tool.Custom;
21+
string activeToolName = customToolActive ? EditorTools.GetActiveToolName() : toolName;
22+
23+
var toolInfo = new
24+
{
25+
activeTool = activeToolName,
26+
isCustom = customToolActive,
27+
pivotMode = UnityEditor.Tools.pivotMode.ToString(),
28+
pivotRotation = UnityEditor.Tools.pivotRotation.ToString(),
29+
handleRotation = new
30+
{
31+
x = UnityEditor.Tools.handleRotation.eulerAngles.x,
32+
y = UnityEditor.Tools.handleRotation.eulerAngles.y,
33+
z = UnityEditor.Tools.handleRotation.eulerAngles.z
34+
},
35+
handlePosition = new
36+
{
37+
x = UnityEditor.Tools.handlePosition.x,
38+
y = UnityEditor.Tools.handlePosition.y,
39+
z = UnityEditor.Tools.handlePosition.z
40+
}
41+
};
42+
43+
return Response.Success("Retrieved active tool information.", toolInfo);
44+
}
45+
catch (Exception e)
46+
{
47+
return Response.Error($"Error getting active tool: {e.Message}");
48+
}
49+
}
50+
}
51+
52+
// Helper class for custom tool names
53+
internal static class EditorTools
54+
{
55+
public static string GetActiveToolName()
56+
{
57+
if (UnityEditor.Tools.current == Tool.Custom)
58+
{
59+
return "Unknown Custom Tool";
60+
}
61+
return UnityEditor.Tools.current.ToString();
62+
}
63+
}
64+
}

MCPForUnity/Editor/Resources/Editor/ActiveTool.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using MCPForUnity.Editor.Helpers;
3+
using Newtonsoft.Json.Linq;
4+
using UnityEditor;
5+
using UnityEditor.SceneManagement;
6+
7+
namespace MCPForUnity.Editor.Resources.Editor
8+
{
9+
/// <summary>
10+
/// Provides dynamic editor state information that changes frequently.
11+
/// </summary>
12+
[McpForUnityResource("get_editor_state")]
13+
public static class EditorState
14+
{
15+
public static object HandleCommand(JObject @params)
16+
{
17+
try
18+
{
19+
var activeScene = EditorSceneManager.GetActiveScene();
20+
var state = new
21+
{
22+
isPlaying = EditorApplication.isPlaying,
23+
isPaused = EditorApplication.isPaused,
24+
isCompiling = EditorApplication.isCompiling,
25+
isUpdating = EditorApplication.isUpdating,
26+
timeSinceStartup = EditorApplication.timeSinceStartup,
27+
activeSceneName = activeScene.name ?? "",
28+
selectionCount = UnityEditor.Selection.count,
29+
activeObjectName = UnityEditor.Selection.activeObject?.name
30+
};
31+
32+
return Response.Success("Retrieved editor state.", state);
33+
}
34+
catch (Exception e)
35+
{
36+
return Response.Error($"Error getting editor state: {e.Message}");
37+
}
38+
}
39+
}
40+
}

MCPForUnity/Editor/Resources/Editor/EditorState.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using MCPForUnity.Editor.Helpers;
3+
using Newtonsoft.Json.Linq;
4+
using UnityEditor.SceneManagement;
5+
6+
namespace MCPForUnity.Editor.Resources.Editor
7+
{
8+
/// <summary>
9+
/// Provides information about the current prefab editing context.
10+
/// </summary>
11+
[McpForUnityResource("get_prefab_stage")]
12+
public static class PrefabStage
13+
{
14+
public static object HandleCommand(JObject @params)
15+
{
16+
try
17+
{
18+
var stage = PrefabStageUtility.GetCurrentPrefabStage();
19+
20+
if (stage == null)
21+
{
22+
return Response.Success("No prefab stage is currently open.", new { isOpen = false });
23+
}
24+
25+
var stageInfo = new
26+
{
27+
isOpen = true,
28+
assetPath = stage.assetPath,
29+
prefabRootName = stage.prefabContentsRoot?.name,
30+
mode = stage.mode.ToString(),
31+
isDirty = stage.scene.isDirty
32+
};
33+
34+
return Response.Success("Prefab stage info retrieved.", stageInfo);
35+
}
36+
catch (Exception e)
37+
{
38+
return Response.Error($"Error getting prefab stage info: {e.Message}");
39+
}
40+
}
41+
}
42+
}

MCPForUnity/Editor/Resources/Editor/PrefabStage.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.Linq;
3+
using MCPForUnity.Editor.Helpers;
4+
using Newtonsoft.Json.Linq;
5+
using UnityEditor;
6+
7+
namespace MCPForUnity.Editor.Resources.Editor
8+
{
9+
/// <summary>
10+
/// Provides detailed information about the current editor selection.
11+
/// </summary>
12+
[McpForUnityResource("get_selection")]
13+
public static class Selection
14+
{
15+
public static object HandleCommand(JObject @params)
16+
{
17+
try
18+
{
19+
var selectionInfo = new
20+
{
21+
activeObject = UnityEditor.Selection.activeObject?.name,
22+
activeGameObject = UnityEditor.Selection.activeGameObject?.name,
23+
activeTransform = UnityEditor.Selection.activeTransform?.name,
24+
activeInstanceID = UnityEditor.Selection.activeInstanceID,
25+
count = UnityEditor.Selection.count,
26+
objects = UnityEditor.Selection.objects
27+
.Select(obj => new
28+
{
29+
name = obj?.name,
30+
type = obj?.GetType().FullName,
31+
instanceID = obj?.GetInstanceID()
32+
})
33+
.ToList(),
34+
gameObjects = UnityEditor.Selection.gameObjects
35+
.Select(go => new
36+
{
37+
name = go?.name,
38+
instanceID = go?.GetInstanceID()
39+
})
40+
.ToList(),
41+
assetGUIDs = UnityEditor.Selection.assetGUIDs
42+
};
43+
44+
return Response.Success("Retrieved current selection details.", selectionInfo);
45+
}
46+
catch (Exception e)
47+
{
48+
return Response.Error($"Error getting selection: {e.Message}");
49+
}
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)