Skip to content

Commit b5e0446

Browse files
authored
Allow the LLMs to read menu items, not just execute them (#263)
* Move the current test to a Tools folder * feat: add env object and disabled flag handling for MCP client configuration * Format manual config specially for Windsurf and Kiro * refactor: extract config JSON building logic into dedicated ConfigJsonBuilder class * refactor: extract unity node population logic into centralized helper method * refactor: only add env property to config for Windsurf and Kiro clients If it ain't broke with the other clients, don't fix... * fix: write UTF-8 without BOM encoding for config files to avoid Windows compatibility issues * fix: enforce UTF-8 encoding without BOM when writing files to disk * refactor: replace execute_menu_item with enhanced manage_menu_item tool supporting list/exists/refresh * Update meta files for older Unity versions * test: add unit tests for menu item management and execution * feat: add tips for paths, script compilation, and menu item usage in asset creation strategy * Use McpLog functionality instead of Unity's Debug * Add telemetry * Annotate parameters More info to LLMs + better validation * Remove the refresh command It's only ever useful in the context of listing menu items * Updated meta files since running in Unity 2021 * Slightly better README * fix: rename server-version.txt to server_version.txt and update menu item description
1 parent 2a99211 commit b5e0446

32 files changed

+600
-199
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ MCP for Unity acts as a bridge, allowing AI assistants (like Claude, Cursor) to
4242
* `manage_asset`: Performs asset operations (import, create, modify, delete, etc.).
4343
* `manage_shader`: Performs shader CRUD operations (create, read, modify, delete).
4444
* `manage_gameobject`: Manages GameObjects: create, modify, delete, find, and component operations.
45-
* `execute_menu_item`: Executes a menu item via its path (e.g., "File/Save Project").
45+
* `manage_menu_item`: List Unity Editor menu items; and check for their existence or execute them (e.g., execute "File/Save Project").
4646
* `apply_text_edits`: Precise text edits with precondition hashes and atomic multi-edit batches.
4747
* `script_apply_edits`: Structured C# method/class edits (insert/replace/delete) with safer boundaries.
4848
* `validate_script`: Fast validation (basic/standard) to catch syntax/structure issues before/after writes.

TestProjects/UnityMCPTests/Assets/Scripts/LongUnityScriptClaudeTest.cs.meta

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

TestProjects/UnityMCPTests/Assets/Scripts/TestAsmdef.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/AIPropertyMatchingTests.cs.meta

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ComponentResolverTests.cs.meta

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageGameObjectTests.cs.meta

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/MenuItems.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using NUnit.Framework;
2+
using Newtonsoft.Json.Linq;
3+
using MCPForUnity.Editor.Tools.MenuItems;
4+
5+
namespace MCPForUnityTests.Editor.Tools.MenuItems
6+
{
7+
public class ManageMenuItemTests
8+
{
9+
private static JObject ToJO(object o) => JObject.FromObject(o);
10+
11+
[Test]
12+
public void HandleCommand_UnknownAction_ReturnsError()
13+
{
14+
var res = ManageMenuItem.HandleCommand(new JObject { ["action"] = "unknown_action" });
15+
var jo = ToJO(res);
16+
Assert.IsFalse((bool)jo["success"], "Expected success false for unknown action");
17+
StringAssert.Contains("Unknown action", (string)jo["error"]);
18+
}
19+
20+
[Test]
21+
public void HandleCommand_List_RoutesAndReturnsArray()
22+
{
23+
var res = ManageMenuItem.HandleCommand(new JObject { ["action"] = "list" });
24+
var jo = ToJO(res);
25+
Assert.IsTrue((bool)jo["success"], "Expected success true");
26+
Assert.AreEqual(JTokenType.Array, jo["data"].Type, "Expected data to be an array");
27+
}
28+
29+
[Test]
30+
public void HandleCommand_Execute_Blacklisted_RoutesAndErrors()
31+
{
32+
var res = ManageMenuItem.HandleCommand(new JObject { ["action"] = "execute", ["menuPath"] = "File/Quit" });
33+
var jo = ToJO(res);
34+
Assert.IsFalse((bool)jo["success"], "Expected success false");
35+
StringAssert.Contains("blocked for safety", (string)jo["error"], "Expected blacklist message");
36+
}
37+
38+
[Test]
39+
public void HandleCommand_Exists_MissingParam_ReturnsError()
40+
{
41+
var res = ManageMenuItem.HandleCommand(new JObject { ["action"] = "exists" });
42+
var jo = ToJO(res);
43+
Assert.IsFalse((bool)jo["success"], "Expected success false when missing menuPath");
44+
StringAssert.Contains("Required parameter", (string)jo["error"]);
45+
}
46+
}
47+
}

UnityMcpBridge/Editor/Tools/ExecuteMenuItem.cs.meta renamed to TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/MenuItems/ManageMenuItemTests.cs.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: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using NUnit.Framework;
2+
using Newtonsoft.Json.Linq;
3+
using MCPForUnity.Editor.Tools.MenuItems;
4+
5+
namespace MCPForUnityTests.Editor.Tools.MenuItems
6+
{
7+
public class MenuItemExecutorTests
8+
{
9+
private static JObject ToJO(object o) => JObject.FromObject(o);
10+
11+
[Test]
12+
public void Execute_MissingParam_ReturnsError()
13+
{
14+
var res = MenuItemExecutor.Execute(new JObject());
15+
var jo = ToJO(res);
16+
Assert.IsFalse((bool)jo["success"], "Expected success false");
17+
StringAssert.Contains("Required parameter", (string)jo["error"]);
18+
}
19+
20+
[Test]
21+
public void Execute_Blacklisted_ReturnsError()
22+
{
23+
var res = MenuItemExecutor.Execute(new JObject { ["menuPath"] = "File/Quit" });
24+
var jo = ToJO(res);
25+
Assert.IsFalse((bool)jo["success"], "Expected success false for blacklisted menu");
26+
StringAssert.Contains("blocked for safety", (string)jo["error"], "Expected blacklist message");
27+
}
28+
29+
[Test]
30+
public void Execute_NonBlacklisted_ReturnsImmediateSuccess()
31+
{
32+
// We don't rely on the menu actually existing; execution is delayed and we only check the immediate response shape
33+
var res = MenuItemExecutor.Execute(new JObject { ["menuPath"] = "File/Save Project" });
34+
var jo = ToJO(res);
35+
Assert.IsTrue((bool)jo["success"], "Expected immediate success response");
36+
StringAssert.Contains("Attempted to execute menu item", (string)jo["message"], "Expected attempt message");
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)