mcpforunityserver 9.3.0b20260129104751__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 (103) 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 +258 -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 +52 -0
  33. core/logging_decorator.py +37 -0
  34. core/telemetry.py +551 -0
  35. core/telemetry_decorator.py +164 -0
  36. main.py +713 -0
  37. mcpforunityserver-9.3.0b20260129104751.dist-info/METADATA +216 -0
  38. mcpforunityserver-9.3.0b20260129104751.dist-info/RECORD +103 -0
  39. mcpforunityserver-9.3.0b20260129104751.dist-info/WHEEL +5 -0
  40. mcpforunityserver-9.3.0b20260129104751.dist-info/entry_points.txt +3 -0
  41. mcpforunityserver-9.3.0b20260129104751.dist-info/licenses/LICENSE +21 -0
  42. mcpforunityserver-9.3.0b20260129104751.dist-info/top_level.txt +7 -0
  43. models/__init__.py +4 -0
  44. models/models.py +56 -0
  45. models/unity_response.py +47 -0
  46. services/__init__.py +0 -0
  47. services/custom_tool_service.py +499 -0
  48. services/registry/__init__.py +22 -0
  49. services/registry/resource_registry.py +53 -0
  50. services/registry/tool_registry.py +51 -0
  51. services/resources/__init__.py +86 -0
  52. services/resources/active_tool.py +47 -0
  53. services/resources/custom_tools.py +57 -0
  54. services/resources/editor_state.py +304 -0
  55. services/resources/gameobject.py +243 -0
  56. services/resources/layers.py +29 -0
  57. services/resources/menu_items.py +34 -0
  58. services/resources/prefab.py +191 -0
  59. services/resources/prefab_stage.py +39 -0
  60. services/resources/project_info.py +39 -0
  61. services/resources/selection.py +55 -0
  62. services/resources/tags.py +30 -0
  63. services/resources/tests.py +87 -0
  64. services/resources/unity_instances.py +122 -0
  65. services/resources/windows.py +47 -0
  66. services/state/external_changes_scanner.py +245 -0
  67. services/tools/__init__.py +83 -0
  68. services/tools/batch_execute.py +93 -0
  69. services/tools/debug_request_context.py +86 -0
  70. services/tools/execute_custom_tool.py +43 -0
  71. services/tools/execute_menu_item.py +32 -0
  72. services/tools/find_gameobjects.py +110 -0
  73. services/tools/find_in_file.py +181 -0
  74. services/tools/manage_asset.py +119 -0
  75. services/tools/manage_components.py +131 -0
  76. services/tools/manage_editor.py +64 -0
  77. services/tools/manage_gameobject.py +260 -0
  78. services/tools/manage_material.py +111 -0
  79. services/tools/manage_prefabs.py +174 -0
  80. services/tools/manage_scene.py +111 -0
  81. services/tools/manage_script.py +645 -0
  82. services/tools/manage_scriptable_object.py +87 -0
  83. services/tools/manage_shader.py +71 -0
  84. services/tools/manage_texture.py +581 -0
  85. services/tools/manage_vfx.py +120 -0
  86. services/tools/preflight.py +110 -0
  87. services/tools/read_console.py +151 -0
  88. services/tools/refresh_unity.py +153 -0
  89. services/tools/run_tests.py +317 -0
  90. services/tools/script_apply_edits.py +1006 -0
  91. services/tools/set_active_instance.py +117 -0
  92. services/tools/utils.py +348 -0
  93. transport/__init__.py +0 -0
  94. transport/legacy/port_discovery.py +329 -0
  95. transport/legacy/stdio_port_registry.py +65 -0
  96. transport/legacy/unity_connection.py +888 -0
  97. transport/models.py +63 -0
  98. transport/plugin_hub.py +585 -0
  99. transport/plugin_registry.py +126 -0
  100. transport/unity_instance_middleware.py +232 -0
  101. transport/unity_transport.py +63 -0
  102. utils/focus_nudge.py +589 -0
  103. utils/module_discovery.py +55 -0
@@ -0,0 +1,239 @@
1
+ """Material CLI commands."""
2
+
3
+ import sys
4
+ import json
5
+ import click
6
+ from typing import Optional, Any, Tuple
7
+
8
+ from cli.utils.config import get_config
9
+ from cli.utils.output import format_output, print_error, print_success
10
+ from cli.utils.connection import run_command, handle_unity_errors
11
+ from cli.utils.parsers import parse_value_safe, parse_json_dict_or_exit
12
+ from cli.utils.constants import SEARCH_METHOD_CHOICE_RENDERER
13
+
14
+
15
+ @click.group()
16
+ def material():
17
+ """Material operations - create, modify, assign materials."""
18
+ pass
19
+
20
+
21
+ @material.command("info")
22
+ @click.argument("path")
23
+ @handle_unity_errors
24
+ def info(path: str):
25
+ """Get information about a material.
26
+
27
+ \b
28
+ Examples:
29
+ unity-mcp material info "Assets/Materials/Red.mat"
30
+ """
31
+ config = get_config()
32
+
33
+ result = run_command("manage_material", {
34
+ "action": "get_material_info",
35
+ "materialPath": path,
36
+ }, config)
37
+ click.echo(format_output(result, config.format))
38
+
39
+
40
+ @material.command("create")
41
+ @click.argument("path")
42
+ @click.option(
43
+ "--shader", "-s",
44
+ default="Standard",
45
+ help="Shader to use (default: Standard)."
46
+ )
47
+ @click.option(
48
+ "--properties", "-p",
49
+ default=None,
50
+ help='Initial properties as JSON.'
51
+ )
52
+ @handle_unity_errors
53
+ def create(path: str, shader: str, properties: Optional[str]):
54
+ """Create a new material.
55
+
56
+ \b
57
+ Examples:
58
+ unity-mcp material create "Assets/Materials/NewMat.mat"
59
+ unity-mcp material create "Assets/Materials/Red.mat" --shader "Universal Render Pipeline/Lit"
60
+ unity-mcp material create "Assets/Materials/Blue.mat" --properties '{"_Color": [0,0,1,1]}'
61
+ """
62
+ config = get_config()
63
+
64
+ params: dict[str, Any] = {
65
+ "action": "create",
66
+ "materialPath": path,
67
+ "shader": shader,
68
+ }
69
+
70
+ if properties:
71
+ params["properties"] = parse_json_dict_or_exit(properties, "properties")
72
+
73
+ result = run_command("manage_material", params, config)
74
+ click.echo(format_output(result, config.format))
75
+ if result.get("success"):
76
+ print_success(f"Created material: {path}")
77
+
78
+
79
+ @material.command("set-color")
80
+ @click.argument("path")
81
+ @click.argument("r", type=float)
82
+ @click.argument("g", type=float)
83
+ @click.argument("b", type=float)
84
+ @click.argument("a", type=float, default=1.0)
85
+ @click.option(
86
+ "--property", "-p",
87
+ default="_Color",
88
+ help="Color property name (default: _Color)."
89
+ )
90
+ @handle_unity_errors
91
+ def set_color(path: str, r: float, g: float, b: float, a: float, property: str):
92
+ """Set a material's color.
93
+
94
+ \b
95
+ Examples:
96
+ unity-mcp material set-color "Assets/Materials/Red.mat" 1 0 0
97
+ unity-mcp material set-color "Assets/Materials/Blue.mat" 0 0 1 0.5
98
+ unity-mcp material set-color "Assets/Materials/Mat.mat" 1 1 0 --property "_BaseColor"
99
+ """
100
+ config = get_config()
101
+
102
+ params: dict[str, Any] = {
103
+ "action": "set_material_color",
104
+ "materialPath": path,
105
+ "property": property,
106
+ "color": [r, g, b, a],
107
+ }
108
+
109
+ result = run_command("manage_material", params, config)
110
+ click.echo(format_output(result, config.format))
111
+ if result.get("success"):
112
+ print_success(f"Set color on: {path}")
113
+
114
+
115
+ @material.command("set-property")
116
+ @click.argument("path")
117
+ @click.argument("property_name")
118
+ @click.argument("value")
119
+ @handle_unity_errors
120
+ def set_property(path: str, property_name: str, value: str):
121
+ """Set a shader property on a material.
122
+
123
+ \b
124
+ Examples:
125
+ unity-mcp material set-property "Assets/Materials/Mat.mat" _Metallic 0.5
126
+ unity-mcp material set-property "Assets/Materials/Mat.mat" _Smoothness 0.8
127
+ unity-mcp material set-property "Assets/Materials/Mat.mat" _MainTex "Assets/Textures/Tex.png"
128
+ """
129
+ config = get_config()
130
+
131
+ # Try to parse value as JSON for complex types
132
+ parsed_value = parse_value_safe(value)
133
+
134
+ params: dict[str, Any] = {
135
+ "action": "set_material_shader_property",
136
+ "materialPath": path,
137
+ "property": property_name,
138
+ "value": parsed_value,
139
+ }
140
+
141
+ result = run_command("manage_material", params, config)
142
+ click.echo(format_output(result, config.format))
143
+ if result.get("success"):
144
+ print_success(f"Set {property_name} on: {path}")
145
+
146
+
147
+ @material.command("assign")
148
+ @click.argument("material_path")
149
+ @click.argument("target")
150
+ @click.option(
151
+ "--search-method",
152
+ type=SEARCH_METHOD_CHOICE_RENDERER,
153
+ default=None,
154
+ help="How to find the target GameObject."
155
+ )
156
+ @click.option(
157
+ "--slot", "-s",
158
+ default=0,
159
+ type=int,
160
+ help="Material slot index (default: 0)."
161
+ )
162
+ @click.option(
163
+ "--mode", "-m",
164
+ type=click.Choice(["shared", "instance", "property_block"]),
165
+ default="shared",
166
+ help="Assignment mode."
167
+ )
168
+ @handle_unity_errors
169
+ def assign(material_path: str, target: str, search_method: Optional[str], slot: int, mode: str):
170
+ """Assign a material to a GameObject's renderer.
171
+
172
+ \b
173
+ Examples:
174
+ unity-mcp material assign "Assets/Materials/Red.mat" "Cube"
175
+ unity-mcp material assign "Assets/Materials/Blue.mat" "Player" --mode instance
176
+ unity-mcp material assign "Assets/Materials/Mat.mat" "-81840" --search-method by_id --slot 1
177
+ """
178
+ config = get_config()
179
+
180
+ params: dict[str, Any] = {
181
+ "action": "assign_material_to_renderer",
182
+ "materialPath": material_path,
183
+ "target": target,
184
+ "slot": slot,
185
+ "mode": mode,
186
+ }
187
+
188
+ if search_method:
189
+ params["searchMethod"] = search_method
190
+
191
+ result = run_command("manage_material", params, config)
192
+ click.echo(format_output(result, config.format))
193
+ if result.get("success"):
194
+ print_success(f"Assigned material to: {target}")
195
+
196
+
197
+ @material.command("set-renderer-color")
198
+ @click.argument("target")
199
+ @click.argument("r", type=float)
200
+ @click.argument("g", type=float)
201
+ @click.argument("b", type=float)
202
+ @click.argument("a", type=float, default=1.0)
203
+ @click.option(
204
+ "--search-method",
205
+ type=SEARCH_METHOD_CHOICE_RENDERER,
206
+ default=None,
207
+ help="How to find the target GameObject."
208
+ )
209
+ @click.option(
210
+ "--mode", "-m",
211
+ type=click.Choice(["shared", "instance", "property_block"]),
212
+ default="property_block",
213
+ help="Modification mode."
214
+ )
215
+ @handle_unity_errors
216
+ def set_renderer_color(target: str, r: float, g: float, b: float, a: float, search_method: Optional[str], mode: str):
217
+ """Set a renderer's material color directly.
218
+
219
+ \b
220
+ Examples:
221
+ unity-mcp material set-renderer-color "Cube" 1 0 0
222
+ unity-mcp material set-renderer-color "Player" 0 1 0 --mode instance
223
+ """
224
+ config = get_config()
225
+
226
+ params: dict[str, Any] = {
227
+ "action": "set_renderer_color",
228
+ "target": target,
229
+ "color": [r, g, b, a],
230
+ "mode": mode,
231
+ }
232
+
233
+ if search_method:
234
+ params["searchMethod"] = search_method
235
+
236
+ result = run_command("manage_material", params, config)
237
+ click.echo(format_output(result, config.format))
238
+ if result.get("success"):
239
+ print_success(f"Set renderer color on: {target}")
cli/commands/prefab.py ADDED
@@ -0,0 +1,248 @@
1
+ """Prefab CLI commands."""
2
+
3
+ import sys
4
+ import click
5
+ from typing import Optional, Any
6
+
7
+ from cli.utils.config import get_config
8
+ from cli.utils.output import format_output, print_error, print_success
9
+ from cli.utils.connection import run_command, handle_unity_errors
10
+
11
+
12
+ @click.group()
13
+ def prefab():
14
+ """Prefab operations - info, hierarchy, open, save, close, create prefabs."""
15
+ pass
16
+
17
+
18
+ @prefab.command("open")
19
+ @click.argument("path")
20
+ @handle_unity_errors
21
+ def open_stage(path: str):
22
+ """Open a prefab in the prefab stage for editing.
23
+
24
+ \b
25
+ Examples:
26
+ unity-mcp prefab open "Assets/Prefabs/Player.prefab"
27
+ """
28
+ config = get_config()
29
+
30
+ params: dict[str, Any] = {
31
+ "action": "open_stage",
32
+ "prefabPath": path,
33
+ }
34
+
35
+ result = run_command("manage_prefabs", params, config)
36
+ click.echo(format_output(result, config.format))
37
+ if result.get("success"):
38
+ print_success(f"Opened prefab: {path}")
39
+
40
+
41
+ @prefab.command("close")
42
+ @click.option(
43
+ "--save", "-s",
44
+ is_flag=True,
45
+ help="Save the prefab before closing."
46
+ )
47
+ @handle_unity_errors
48
+ def close_stage(save: bool):
49
+ """Close the current prefab stage.
50
+
51
+ \b
52
+ Examples:
53
+ unity-mcp prefab close
54
+ unity-mcp prefab close --save
55
+ """
56
+ config = get_config()
57
+
58
+ params: dict[str, Any] = {
59
+ "action": "close_stage",
60
+ }
61
+ if save:
62
+ params["saveBeforeClose"] = True
63
+
64
+ result = run_command("manage_prefabs", params, config)
65
+ click.echo(format_output(result, config.format))
66
+ if result.get("success"):
67
+ print_success("Closed prefab stage")
68
+
69
+
70
+ @prefab.command("save")
71
+ @click.option(
72
+ "--force", "-f",
73
+ is_flag=True,
74
+ help="Force save even if no changes detected. Useful for automated workflows."
75
+ )
76
+ @handle_unity_errors
77
+ def save_stage(force: bool):
78
+ """Save the currently open prefab stage.
79
+
80
+ \b
81
+ Examples:
82
+ unity-mcp prefab save
83
+ unity-mcp prefab save --force
84
+ """
85
+ config = get_config()
86
+
87
+ params: dict[str, Any] = {
88
+ "action": "save_open_stage",
89
+ }
90
+ if force:
91
+ params["force"] = True
92
+
93
+ result = run_command("manage_prefabs", params, config)
94
+ click.echo(format_output(result, config.format))
95
+ if result.get("success"):
96
+ print_success("Saved prefab")
97
+
98
+
99
+ @prefab.command("info")
100
+ @click.argument("path")
101
+ @click.option(
102
+ "--compact", "-c",
103
+ is_flag=True,
104
+ help="Show compact output (key values only)."
105
+ )
106
+ @handle_unity_errors
107
+ def info(path: str, compact: bool):
108
+ """Get information about a prefab asset.
109
+
110
+ \b
111
+ Examples:
112
+ unity-mcp prefab info "Assets/Prefabs/Player.prefab"
113
+ unity-mcp prefab info "Assets/Prefabs/UI.prefab" --compact
114
+ """
115
+ config = get_config()
116
+
117
+ params: dict[str, Any] = {
118
+ "action": "get_info",
119
+ "prefabPath": path,
120
+ }
121
+
122
+ result = run_command("manage_prefabs", params, config)
123
+ # Get the actual response data from the wrapped result structure
124
+ response_data = result.get("result", result)
125
+ if compact and response_data.get("success") and response_data.get("data"):
126
+ data = response_data["data"]
127
+ click.echo(f"Prefab: {data.get('assetPath', path)}")
128
+ click.echo(f" Type: {data.get('prefabType', 'Unknown')}")
129
+ click.echo(f" Root: {data.get('rootObjectName', 'N/A')}")
130
+ click.echo(f" GUID: {data.get('guid', 'N/A')}")
131
+ click.echo(
132
+ f" Components: {len(data.get('rootComponentTypes', []))}")
133
+ click.echo(f" Children: {data.get('childCount', 0)}")
134
+ if data.get('isVariant'):
135
+ click.echo(f" Variant of: {data.get('parentPrefab', 'N/A')}")
136
+ else:
137
+ click.echo(format_output(result, config.format))
138
+
139
+
140
+ @prefab.command("hierarchy")
141
+ @click.argument("path")
142
+ @click.option(
143
+ "--compact", "-c",
144
+ is_flag=True,
145
+ help="Show compact output (names and paths only)."
146
+ )
147
+ @click.option(
148
+ "--show-prefab-info", "-p",
149
+ is_flag=True,
150
+ help="Show prefab nesting information."
151
+ )
152
+ @handle_unity_errors
153
+ def hierarchy(path: str, compact: bool, show_prefab_info: bool):
154
+ """Get the hierarchical structure of a prefab.
155
+
156
+ \b
157
+ Examples:
158
+ unity-mcp prefab hierarchy "Assets/Prefabs/Player.prefab"
159
+ unity-mcp prefab hierarchy "Assets/Prefabs/UI.prefab" --compact
160
+ unity-mcp prefab hierarchy "Assets/Prefabs/Complex.prefab" --show-prefab-info
161
+ """
162
+ config = get_config()
163
+
164
+ params: dict[str, Any] = {
165
+ "action": "get_hierarchy",
166
+ "prefabPath": path,
167
+ }
168
+
169
+ result = run_command("manage_prefabs", params, config)
170
+ # Get the actual response data from the wrapped result structure
171
+ response_data = result.get("result", result)
172
+ if compact and response_data.get("success") and response_data.get("data"):
173
+ data = response_data["data"]
174
+ items = data.get("items", [])
175
+ for item in items:
176
+ indent = " " * item.get("path", "").count("/")
177
+ prefab_info = ""
178
+ if show_prefab_info and item.get("prefab", {}).get("isNestedRoot"):
179
+ prefab_info = f" [nested: {item['prefab']['assetPath']}]"
180
+ click.echo(f"{indent}{item.get('name')}{prefab_info}")
181
+ click.echo(f"\nTotal: {data.get('total', 0)} objects")
182
+ elif show_prefab_info:
183
+ # Show prefab info in readable format
184
+ if response_data.get("success") and response_data.get("data"):
185
+ data = response_data["data"]
186
+ items = data.get("items", [])
187
+ for item in items:
188
+ prefab = item.get("prefab", {})
189
+ prefab_info = ""
190
+ if prefab.get("isRoot"):
191
+ prefab_info = " [root]"
192
+ elif prefab.get("isNestedRoot"):
193
+ prefab_info = f" [nested: {prefab.get('nestingDepth', 0)}]"
194
+ click.echo(f"{item.get('path')}{prefab_info}")
195
+ click.echo(f"\nTotal: {data.get('total', 0)} objects")
196
+ else:
197
+ click.echo(format_output(result, config.format))
198
+ else:
199
+ click.echo(format_output(result, config.format))
200
+
201
+
202
+ @prefab.command("create")
203
+ @click.argument("target")
204
+ @click.argument("path")
205
+ @click.option(
206
+ "--overwrite",
207
+ is_flag=True,
208
+ help="Overwrite existing prefab at path."
209
+ )
210
+ @click.option(
211
+ "--include-inactive",
212
+ is_flag=True,
213
+ help="Include inactive objects when finding target."
214
+ )
215
+ @click.option(
216
+ "--unlink-if-instance",
217
+ is_flag=True,
218
+ help="Unlink from existing prefab before creating new one."
219
+ )
220
+ @handle_unity_errors
221
+ def create(target: str, path: str, overwrite: bool, include_inactive: bool, unlink_if_instance: bool):
222
+ """Create a prefab from a scene GameObject.
223
+
224
+ \b
225
+ Examples:
226
+ unity-mcp prefab create "Player" "Assets/Prefabs/Player.prefab"
227
+ unity-mcp prefab create "Enemy" "Assets/Prefabs/Enemy.prefab" --overwrite
228
+ unity-mcp prefab create "EnemyInstance" "Assets/Prefabs/BossEnemy.prefab" --unlink-if-instance
229
+ """
230
+ config = get_config()
231
+
232
+ params: dict[str, Any] = {
233
+ "action": "create_from_gameobject",
234
+ "target": target,
235
+ "prefabPath": path,
236
+ }
237
+
238
+ if overwrite:
239
+ params["allowOverwrite"] = True
240
+ if include_inactive:
241
+ params["searchInactive"] = True
242
+ if unlink_if_instance:
243
+ params["unlinkIfInstance"] = True
244
+
245
+ result = run_command("manage_prefabs", params, config)
246
+ click.echo(format_output(result, config.format))
247
+ if result.get("success"):
248
+ print_success(f"Created prefab: {path}")