mcpforunityserver 9.4.0b20260203025228__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. cli/__init__.py +3 -0
  2. cli/commands/__init__.py +3 -0
  3. cli/commands/animation.py +84 -0
  4. cli/commands/asset.py +280 -0
  5. cli/commands/audio.py +125 -0
  6. cli/commands/batch.py +171 -0
  7. cli/commands/code.py +182 -0
  8. cli/commands/component.py +190 -0
  9. cli/commands/editor.py +447 -0
  10. cli/commands/gameobject.py +487 -0
  11. cli/commands/instance.py +93 -0
  12. cli/commands/lighting.py +123 -0
  13. cli/commands/material.py +239 -0
  14. cli/commands/prefab.py +248 -0
  15. cli/commands/scene.py +231 -0
  16. cli/commands/script.py +222 -0
  17. cli/commands/shader.py +226 -0
  18. cli/commands/texture.py +540 -0
  19. cli/commands/tool.py +58 -0
  20. cli/commands/ui.py +258 -0
  21. cli/commands/vfx.py +421 -0
  22. cli/main.py +281 -0
  23. cli/utils/__init__.py +31 -0
  24. cli/utils/config.py +58 -0
  25. cli/utils/confirmation.py +37 -0
  26. cli/utils/connection.py +254 -0
  27. cli/utils/constants.py +23 -0
  28. cli/utils/output.py +195 -0
  29. cli/utils/parsers.py +112 -0
  30. cli/utils/suggestions.py +34 -0
  31. core/__init__.py +0 -0
  32. core/config.py +67 -0
  33. core/constants.py +4 -0
  34. core/logging_decorator.py +37 -0
  35. core/telemetry.py +551 -0
  36. core/telemetry_decorator.py +164 -0
  37. main.py +845 -0
  38. mcpforunityserver-9.4.0b20260203025228.dist-info/METADATA +328 -0
  39. mcpforunityserver-9.4.0b20260203025228.dist-info/RECORD +105 -0
  40. mcpforunityserver-9.4.0b20260203025228.dist-info/WHEEL +5 -0
  41. mcpforunityserver-9.4.0b20260203025228.dist-info/entry_points.txt +3 -0
  42. mcpforunityserver-9.4.0b20260203025228.dist-info/licenses/LICENSE +21 -0
  43. mcpforunityserver-9.4.0b20260203025228.dist-info/top_level.txt +7 -0
  44. models/__init__.py +4 -0
  45. models/models.py +56 -0
  46. models/unity_response.py +70 -0
  47. services/__init__.py +0 -0
  48. services/api_key_service.py +235 -0
  49. services/custom_tool_service.py +499 -0
  50. services/registry/__init__.py +22 -0
  51. services/registry/resource_registry.py +53 -0
  52. services/registry/tool_registry.py +51 -0
  53. services/resources/__init__.py +86 -0
  54. services/resources/active_tool.py +48 -0
  55. services/resources/custom_tools.py +57 -0
  56. services/resources/editor_state.py +304 -0
  57. services/resources/gameobject.py +243 -0
  58. services/resources/layers.py +30 -0
  59. services/resources/menu_items.py +35 -0
  60. services/resources/prefab.py +191 -0
  61. services/resources/prefab_stage.py +40 -0
  62. services/resources/project_info.py +40 -0
  63. services/resources/selection.py +56 -0
  64. services/resources/tags.py +31 -0
  65. services/resources/tests.py +88 -0
  66. services/resources/unity_instances.py +125 -0
  67. services/resources/windows.py +48 -0
  68. services/state/external_changes_scanner.py +245 -0
  69. services/tools/__init__.py +83 -0
  70. services/tools/batch_execute.py +93 -0
  71. services/tools/debug_request_context.py +86 -0
  72. services/tools/execute_custom_tool.py +43 -0
  73. services/tools/execute_menu_item.py +32 -0
  74. services/tools/find_gameobjects.py +110 -0
  75. services/tools/find_in_file.py +181 -0
  76. services/tools/manage_asset.py +119 -0
  77. services/tools/manage_components.py +131 -0
  78. services/tools/manage_editor.py +64 -0
  79. services/tools/manage_gameobject.py +260 -0
  80. services/tools/manage_material.py +111 -0
  81. services/tools/manage_prefabs.py +209 -0
  82. services/tools/manage_scene.py +111 -0
  83. services/tools/manage_script.py +645 -0
  84. services/tools/manage_scriptable_object.py +87 -0
  85. services/tools/manage_shader.py +71 -0
  86. services/tools/manage_texture.py +581 -0
  87. services/tools/manage_vfx.py +120 -0
  88. services/tools/preflight.py +110 -0
  89. services/tools/read_console.py +151 -0
  90. services/tools/refresh_unity.py +153 -0
  91. services/tools/run_tests.py +317 -0
  92. services/tools/script_apply_edits.py +1006 -0
  93. services/tools/set_active_instance.py +120 -0
  94. services/tools/utils.py +348 -0
  95. transport/__init__.py +0 -0
  96. transport/legacy/port_discovery.py +329 -0
  97. transport/legacy/stdio_port_registry.py +65 -0
  98. transport/legacy/unity_connection.py +910 -0
  99. transport/models.py +68 -0
  100. transport/plugin_hub.py +787 -0
  101. transport/plugin_registry.py +182 -0
  102. transport/unity_instance_middleware.py +262 -0
  103. transport/unity_transport.py +94 -0
  104. utils/focus_nudge.py +589 -0
  105. utils/module_discovery.py +55 -0
@@ -0,0 +1,87 @@
1
+ """
2
+ Tool wrapper for managing ScriptableObject assets via Unity MCP.
3
+
4
+ Unity-side handler: MCPForUnity.Editor.Tools.ManageScriptableObject
5
+ Command name: "manage_scriptable_object"
6
+ Actions:
7
+ - create: create an SO asset (optionally with patches)
8
+ - modify: apply serialized property patches to an existing SO asset
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import Annotated, Any, Literal
14
+
15
+ from fastmcp import Context
16
+ from mcp.types import ToolAnnotations
17
+
18
+ from services.registry import mcp_for_unity_tool
19
+ from services.tools import get_unity_instance_from_context
20
+ from services.tools.utils import coerce_bool, parse_json_payload
21
+ from transport.unity_transport import send_with_unity_instance
22
+ from transport.legacy.unity_connection import async_send_command_with_retry
23
+
24
+
25
+ @mcp_for_unity_tool(
26
+ description="Creates and modifies ScriptableObject assets using Unity SerializedObject property paths.",
27
+ annotations=ToolAnnotations(
28
+ title="Manage Scriptable Object",
29
+ destructiveHint=True,
30
+ ),
31
+ )
32
+ async def manage_scriptable_object(
33
+ ctx: Context,
34
+ action: Annotated[Literal["create", "modify"], "Action to perform: create or modify."],
35
+ # --- create params ---
36
+ type_name: Annotated[str | None,
37
+ "Namespace-qualified ScriptableObject type name (for create)."] = None,
38
+ folder_path: Annotated[str | None,
39
+ "Target folder under Assets/... (for create)."] = None,
40
+ asset_name: Annotated[str | None,
41
+ "Asset file name without extension (for create)."] = None,
42
+ overwrite: Annotated[bool | str | None,
43
+ "If true, overwrite existing asset at same path (for create)."] = None,
44
+ # --- modify params ---
45
+ target: Annotated[dict[str, Any] | str | None,
46
+ "Target asset reference {guid|path} (for modify)."] = None,
47
+ # --- shared ---
48
+ patches: Annotated[list[dict[str, Any]] | str | None,
49
+ "Patch list (or JSON string) to apply."] = None,
50
+ # --- validation ---
51
+ dry_run: Annotated[bool | str | None,
52
+ "If true, validate patches without applying (modify only)."] = None,
53
+ ) -> dict[str, Any]:
54
+ unity_instance = get_unity_instance_from_context(ctx)
55
+
56
+ # Tolerate JSON-string payloads (LLMs sometimes stringify complex objects)
57
+ parsed_target = parse_json_payload(target)
58
+ parsed_patches = parse_json_payload(patches)
59
+
60
+ if parsed_target is not None and not isinstance(parsed_target, dict):
61
+ return {"success": False, "message": "manage_scriptable_object: 'target' must be an object {guid|path} (or JSON string of such)."}
62
+
63
+ if parsed_patches is not None and not isinstance(parsed_patches, list):
64
+ return {"success": False, "message": "manage_scriptable_object: 'patches' must be a list (or JSON string of a list)."}
65
+
66
+ params: dict[str, Any] = {
67
+ "action": action,
68
+ "typeName": type_name,
69
+ "folderPath": folder_path,
70
+ "assetName": asset_name,
71
+ "overwrite": coerce_bool(overwrite, default=None),
72
+ "target": parsed_target,
73
+ "patches": parsed_patches,
74
+ "dryRun": coerce_bool(dry_run, default=None),
75
+ }
76
+
77
+ # Remove None values to keep Unity handler simpler
78
+ params = {k: v for k, v in params.items() if v is not None}
79
+
80
+ response = await send_with_unity_instance(
81
+ async_send_command_with_retry,
82
+ unity_instance,
83
+ "manage_scriptable_object",
84
+ params,
85
+ )
86
+ await ctx.info(f"Response {response}")
87
+ return response if isinstance(response, dict) else {"success": False, "message": "Unexpected response from Unity."}
@@ -0,0 +1,71 @@
1
+ import base64
2
+ from typing import Annotated, Any, Literal
3
+
4
+ from fastmcp import Context
5
+ from mcp.types import ToolAnnotations
6
+
7
+ from services.registry import mcp_for_unity_tool
8
+ from services.tools import get_unity_instance_from_context
9
+ from transport.unity_transport import send_with_unity_instance
10
+ from transport.legacy.unity_connection import async_send_command_with_retry
11
+
12
+
13
+ @mcp_for_unity_tool(
14
+ description="Manages shader scripts in Unity (create, read, update, delete). Read-only action: read. Modifying actions: create, update, delete.",
15
+ annotations=ToolAnnotations(
16
+ title="Manage Shader",
17
+ # Note: 'read' action is non-destructive; 'create', 'update', 'delete' are destructive
18
+ destructiveHint=True,
19
+ ),
20
+ )
21
+ async def manage_shader(
22
+ ctx: Context,
23
+ action: Annotated[Literal['create', 'read', 'update', 'delete'], "Perform CRUD operations on shader scripts."],
24
+ name: Annotated[str, "Shader name (no .cs extension)"],
25
+ path: Annotated[str, "Asset path (default: \"Assets/\")"],
26
+ contents: Annotated[str,
27
+ "Shader code for 'create'/'update'"] | None = None,
28
+ ) -> dict[str, Any]:
29
+ # Get active instance from session state
30
+ # Removed session_state import
31
+ unity_instance = get_unity_instance_from_context(ctx)
32
+ try:
33
+ # Prepare parameters for Unity
34
+ params = {
35
+ "action": action,
36
+ "name": name,
37
+ "path": path,
38
+ }
39
+
40
+ # Base64 encode the contents if they exist to avoid JSON escaping issues
41
+ if contents is not None:
42
+ if action in ['create', 'update']:
43
+ # Encode content for safer transmission
44
+ params["encodedContents"] = base64.b64encode(
45
+ contents.encode('utf-8')).decode('utf-8')
46
+ params["contentsEncoded"] = True
47
+ else:
48
+ params["contents"] = contents
49
+
50
+ # Remove None values so they don't get sent as null
51
+ params = {k: v for k, v in params.items() if v is not None}
52
+
53
+ # Send command via centralized retry helper with instance routing
54
+ response = await send_with_unity_instance(async_send_command_with_retry, unity_instance, "manage_shader", params)
55
+
56
+ # Process response from Unity
57
+ if isinstance(response, dict) and response.get("success"):
58
+ # If the response contains base64 encoded content, decode it
59
+ if response.get("data", {}).get("contentsEncoded"):
60
+ decoded_contents = base64.b64decode(
61
+ response["data"]["encodedContents"]).decode('utf-8')
62
+ response["data"]["contents"] = decoded_contents
63
+ del response["data"]["encodedContents"]
64
+ del response["data"]["contentsEncoded"]
65
+
66
+ return {"success": True, "message": response.get("message", "Operation successful."), "data": response.get("data")}
67
+ return response if isinstance(response, dict) else {"success": False, "message": str(response)}
68
+
69
+ except Exception as e:
70
+ # Handle Python-side errors (e.g., connection issues)
71
+ return {"success": False, "message": f"Python error managing shader: {str(e)}"}