mcpforunityserver 8.5.0__py3-none-any.whl → 9.1.0__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 (79) hide show
  1. cli/__init__.py +3 -0
  2. cli/commands/__init__.py +3 -0
  3. cli/commands/animation.py +87 -0
  4. cli/commands/asset.py +310 -0
  5. cli/commands/audio.py +133 -0
  6. cli/commands/batch.py +184 -0
  7. cli/commands/code.py +189 -0
  8. cli/commands/component.py +212 -0
  9. cli/commands/editor.py +487 -0
  10. cli/commands/gameobject.py +510 -0
  11. cli/commands/instance.py +101 -0
  12. cli/commands/lighting.py +128 -0
  13. cli/commands/material.py +268 -0
  14. cli/commands/prefab.py +144 -0
  15. cli/commands/scene.py +255 -0
  16. cli/commands/script.py +240 -0
  17. cli/commands/shader.py +238 -0
  18. cli/commands/ui.py +263 -0
  19. cli/commands/vfx.py +439 -0
  20. cli/main.py +248 -0
  21. cli/utils/__init__.py +31 -0
  22. cli/utils/config.py +58 -0
  23. cli/utils/connection.py +191 -0
  24. cli/utils/output.py +195 -0
  25. main.py +207 -62
  26. {mcpforunityserver-8.5.0.dist-info → mcpforunityserver-9.1.0.dist-info}/METADATA +4 -2
  27. mcpforunityserver-9.1.0.dist-info/RECORD +96 -0
  28. {mcpforunityserver-8.5.0.dist-info → mcpforunityserver-9.1.0.dist-info}/WHEEL +1 -1
  29. {mcpforunityserver-8.5.0.dist-info → mcpforunityserver-9.1.0.dist-info}/entry_points.txt +1 -0
  30. {mcpforunityserver-8.5.0.dist-info → mcpforunityserver-9.1.0.dist-info}/top_level.txt +1 -2
  31. services/custom_tool_service.py +179 -19
  32. services/resources/__init__.py +6 -1
  33. services/resources/active_tool.py +1 -1
  34. services/resources/custom_tools.py +2 -2
  35. services/resources/editor_state.py +283 -21
  36. services/resources/gameobject.py +243 -0
  37. services/resources/layers.py +1 -1
  38. services/resources/prefab_stage.py +1 -1
  39. services/resources/project_info.py +1 -1
  40. services/resources/selection.py +1 -1
  41. services/resources/tags.py +1 -1
  42. services/resources/unity_instances.py +1 -1
  43. services/resources/windows.py +1 -1
  44. services/state/external_changes_scanner.py +245 -0
  45. services/tools/__init__.py +6 -1
  46. services/tools/batch_execute.py +24 -9
  47. services/tools/debug_request_context.py +8 -2
  48. services/tools/execute_custom_tool.py +6 -1
  49. services/tools/execute_menu_item.py +6 -3
  50. services/tools/find_gameobjects.py +89 -0
  51. services/tools/find_in_file.py +26 -19
  52. services/tools/manage_asset.py +19 -43
  53. services/tools/manage_components.py +131 -0
  54. services/tools/manage_editor.py +9 -8
  55. services/tools/manage_gameobject.py +120 -79
  56. services/tools/manage_material.py +80 -31
  57. services/tools/manage_prefabs.py +7 -1
  58. services/tools/manage_scene.py +34 -13
  59. services/tools/manage_script.py +62 -19
  60. services/tools/manage_scriptable_object.py +22 -10
  61. services/tools/manage_shader.py +8 -1
  62. services/tools/manage_vfx.py +738 -0
  63. services/tools/preflight.py +110 -0
  64. services/tools/read_console.py +81 -18
  65. services/tools/refresh_unity.py +153 -0
  66. services/tools/run_tests.py +202 -41
  67. services/tools/script_apply_edits.py +15 -7
  68. services/tools/set_active_instance.py +12 -7
  69. services/tools/utils.py +60 -6
  70. transport/legacy/port_discovery.py +2 -2
  71. transport/legacy/unity_connection.py +129 -26
  72. transport/plugin_hub.py +191 -19
  73. transport/unity_instance_middleware.py +93 -2
  74. transport/unity_transport.py +17 -6
  75. utils/focus_nudge.py +321 -0
  76. __init__.py +0 -0
  77. mcpforunityserver-8.5.0.dist-info/RECORD +0 -66
  78. routes/__init__.py +0 -0
  79. {mcpforunityserver-8.5.0.dist-info → mcpforunityserver-9.1.0.dist-info}/licenses/LICENSE +0 -0
cli/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """Unity MCP Command Line Interface."""
2
+
3
+ __version__ = "1.0.0"
@@ -0,0 +1,3 @@
1
+ """CLI command modules."""
2
+
3
+ # Commands will be registered in main.py
@@ -0,0 +1,87 @@
1
+ """Animation CLI commands - placeholder for future implementation."""
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_info
9
+ from cli.utils.connection import run_command, UnityConnectionError
10
+
11
+
12
+ @click.group()
13
+ def animation():
14
+ """Animation operations - control Animator, play animations."""
15
+ pass
16
+
17
+
18
+ @animation.command("play")
19
+ @click.argument("target")
20
+ @click.argument("state_name")
21
+ @click.option(
22
+ "--layer", "-l",
23
+ default=0,
24
+ type=int,
25
+ help="Animator layer(TODO)."
26
+ )
27
+ @click.option(
28
+ "--search-method",
29
+ type=click.Choice(["by_name", "by_path", "by_id"]),
30
+ default=None,
31
+ help="How to find the target."
32
+ )
33
+ def play(target: str, state_name: str, layer: int, search_method: Optional[str]):
34
+ """Play an animation state on a target's Animator.
35
+
36
+ \b
37
+ Examples:
38
+ unity-mcp animation play "Player" "Walk"
39
+ unity-mcp animation play "Enemy" "Attack" --layer 1
40
+ """
41
+ config = get_config()
42
+
43
+ # Set Animator parameter to trigger state
44
+ params: dict[str, Any] = {
45
+ "action": "set_property",
46
+ "target": target,
47
+ "componentType": "Animator",
48
+ "property": "Play",
49
+ "value": state_name,
50
+ "layer": layer,
51
+ }
52
+
53
+ if search_method:
54
+ params["searchMethod"] = search_method
55
+
56
+ try:
57
+ result = run_command("manage_components", params, config)
58
+ click.echo(format_output(result, config.format))
59
+ except UnityConnectionError as e:
60
+ print_error(str(e))
61
+ sys.exit(1)
62
+
63
+
64
+ @animation.command("set-parameter")
65
+ @click.argument("target")
66
+ @click.argument("param_name")
67
+ @click.argument("value")
68
+ @click.option(
69
+ "--type", "-t",
70
+ "param_type",
71
+ type=click.Choice(["float", "int", "bool", "trigger"]),
72
+ default="float",
73
+ help="Parameter type."
74
+ )
75
+ def set_parameter(target: str, param_name: str, value: str, param_type: str):
76
+ """Set an Animator parameter.
77
+
78
+ \b
79
+ Examples:
80
+ unity-mcp animation set-parameter "Player" "Speed" 5.0
81
+ unity-mcp animation set-parameter "Player" "IsRunning" true --type bool
82
+ unity-mcp animation set-parameter "Player" "Jump" "" --type trigger
83
+ """
84
+ config = get_config()
85
+ print_info(
86
+ "Animation parameter command - requires custom Unity implementation")
87
+ click.echo(f"Would set {param_name}={value} ({param_type}) on {target}")
cli/commands/asset.py ADDED
@@ -0,0 +1,310 @@
1
+ """Asset CLI commands."""
2
+
3
+ import sys
4
+ import json
5
+ import click
6
+ from typing import Optional, Any
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, UnityConnectionError
11
+
12
+
13
+ @click.group()
14
+ def asset():
15
+ """Asset operations - search, import, create, delete assets."""
16
+ pass
17
+
18
+
19
+ @asset.command("search")
20
+ @click.argument("pattern", default="*")
21
+ @click.option(
22
+ "--path", "-p",
23
+ default="Assets",
24
+ help="Folder path to search in."
25
+ )
26
+ @click.option(
27
+ "--type", "-t",
28
+ "filter_type",
29
+ default=None,
30
+ help="Filter by asset type (e.g., Material, Prefab, MonoScript)."
31
+ )
32
+ @click.option(
33
+ "--limit", "-l",
34
+ default=25,
35
+ type=int,
36
+ help="Maximum results per page."
37
+ )
38
+ @click.option(
39
+ "--page",
40
+ default=1,
41
+ type=int,
42
+ help="Page number (1-based)."
43
+ )
44
+ def search(pattern: str, path: str, filter_type: Optional[str], limit: int, page: int):
45
+ """Search for assets.
46
+
47
+ \b
48
+ Examples:
49
+ unity-mcp asset search "*.prefab"
50
+ unity-mcp asset search "Player*" --path "Assets/Characters"
51
+ unity-mcp asset search "*" --type Material
52
+ unity-mcp asset search "t:MonoScript" --path "Assets/Scripts"
53
+ """
54
+ config = get_config()
55
+
56
+ params: dict[str, Any] = {
57
+ "action": "search",
58
+ "path": path,
59
+ "searchPattern": pattern,
60
+ "pageSize": limit,
61
+ "pageNumber": page,
62
+ }
63
+
64
+ if filter_type:
65
+ params["filterType"] = filter_type
66
+
67
+ try:
68
+ result = run_command("manage_asset", params, config)
69
+ click.echo(format_output(result, config.format))
70
+ except UnityConnectionError as e:
71
+ print_error(str(e))
72
+ sys.exit(1)
73
+
74
+
75
+ @asset.command("info")
76
+ @click.argument("path")
77
+ @click.option(
78
+ "--preview",
79
+ is_flag=True,
80
+ help="Generate preview thumbnail (may be large)."
81
+ )
82
+ def info(path: str, preview: bool):
83
+ """Get detailed information about an asset.
84
+
85
+ \b
86
+ Examples:
87
+ unity-mcp asset info "Assets/Materials/Red.mat"
88
+ unity-mcp asset info "Assets/Prefabs/Player.prefab" --preview
89
+ """
90
+ config = get_config()
91
+
92
+ params: dict[str, Any] = {
93
+ "action": "get_info",
94
+ "path": path,
95
+ "generatePreview": preview,
96
+ }
97
+
98
+ try:
99
+ result = run_command("manage_asset", params, config)
100
+ click.echo(format_output(result, config.format))
101
+ except UnityConnectionError as e:
102
+ print_error(str(e))
103
+ sys.exit(1)
104
+
105
+
106
+ @asset.command("create")
107
+ @click.argument("path")
108
+ @click.argument("asset_type")
109
+ @click.option(
110
+ "--properties", "-p",
111
+ default=None,
112
+ help='Initial properties as JSON.'
113
+ )
114
+ def create(path: str, asset_type: str, properties: Optional[str]):
115
+ """Create a new asset.
116
+
117
+ \b
118
+ Examples:
119
+ unity-mcp asset create "Assets/Materials/Blue.mat" Material
120
+ unity-mcp asset create "Assets/NewFolder" Folder
121
+ unity-mcp asset create "Assets/Materials/Custom.mat" Material --properties '{"color": [0,0,1,1]}'
122
+ """
123
+ config = get_config()
124
+
125
+ params: dict[str, Any] = {
126
+ "action": "create",
127
+ "path": path,
128
+ "assetType": asset_type,
129
+ }
130
+
131
+ if properties:
132
+ try:
133
+ params["properties"] = json.loads(properties)
134
+ except json.JSONDecodeError as e:
135
+ print_error(f"Invalid JSON for properties: {e}")
136
+ sys.exit(1)
137
+
138
+ try:
139
+ result = run_command("manage_asset", params, config)
140
+ click.echo(format_output(result, config.format))
141
+ if result.get("success"):
142
+ print_success(f"Created {asset_type}: {path}")
143
+ except UnityConnectionError as e:
144
+ print_error(str(e))
145
+ sys.exit(1)
146
+
147
+
148
+ @asset.command("delete")
149
+ @click.argument("path")
150
+ @click.option(
151
+ "--force", "-f",
152
+ is_flag=True,
153
+ help="Skip confirmation prompt."
154
+ )
155
+ def delete(path: str, force: bool):
156
+ """Delete an asset.
157
+
158
+ \b
159
+ Examples:
160
+ unity-mcp asset delete "Assets/OldMaterial.mat"
161
+ unity-mcp asset delete "Assets/Unused" --force
162
+ """
163
+ config = get_config()
164
+
165
+ if not force:
166
+ click.confirm(f"Delete asset '{path}'?", abort=True)
167
+
168
+ try:
169
+ result = run_command(
170
+ "manage_asset", {"action": "delete", "path": path}, config)
171
+ click.echo(format_output(result, config.format))
172
+ if result.get("success"):
173
+ print_success(f"Deleted: {path}")
174
+ except UnityConnectionError as e:
175
+ print_error(str(e))
176
+ sys.exit(1)
177
+
178
+
179
+ @asset.command("duplicate")
180
+ @click.argument("source")
181
+ @click.argument("destination")
182
+ def duplicate(source: str, destination: str):
183
+ """Duplicate an asset.
184
+
185
+ \b
186
+ Examples:
187
+ unity-mcp asset duplicate "Assets/Materials/Red.mat" "Assets/Materials/RedCopy.mat"
188
+ """
189
+ config = get_config()
190
+
191
+ params: dict[str, Any] = {
192
+ "action": "duplicate",
193
+ "path": source,
194
+ "destination": destination,
195
+ }
196
+
197
+ try:
198
+ result = run_command("manage_asset", params, config)
199
+ click.echo(format_output(result, config.format))
200
+ if result.get("success"):
201
+ print_success(f"Duplicated to: {destination}")
202
+ except UnityConnectionError as e:
203
+ print_error(str(e))
204
+ sys.exit(1)
205
+
206
+
207
+ @asset.command("move")
208
+ @click.argument("source")
209
+ @click.argument("destination")
210
+ def move(source: str, destination: str):
211
+ """Move an asset to a new location.
212
+
213
+ \b
214
+ Examples:
215
+ unity-mcp asset move "Assets/Old/Material.mat" "Assets/New/Material.mat"
216
+ """
217
+ config = get_config()
218
+
219
+ params: dict[str, Any] = {
220
+ "action": "move",
221
+ "path": source,
222
+ "destination": destination,
223
+ }
224
+
225
+ try:
226
+ result = run_command("manage_asset", params, config)
227
+ click.echo(format_output(result, config.format))
228
+ if result.get("success"):
229
+ print_success(f"Moved to: {destination}")
230
+ except UnityConnectionError as e:
231
+ print_error(str(e))
232
+ sys.exit(1)
233
+
234
+
235
+ @asset.command("rename")
236
+ @click.argument("path")
237
+ @click.argument("new_name")
238
+ def rename(path: str, new_name: str):
239
+ """Rename an asset.
240
+
241
+ \b
242
+ Examples:
243
+ unity-mcp asset rename "Assets/Materials/Old.mat" "New.mat"
244
+ """
245
+ config = get_config()
246
+
247
+ # Construct destination path
248
+ import os
249
+ dir_path = os.path.dirname(path)
250
+ destination = os.path.join(dir_path, new_name).replace("\\", "/")
251
+
252
+ params: dict[str, Any] = {
253
+ "action": "rename",
254
+ "path": path,
255
+ "destination": destination,
256
+ }
257
+
258
+ try:
259
+ result = run_command("manage_asset", params, config)
260
+ click.echo(format_output(result, config.format))
261
+ if result.get("success"):
262
+ print_success(f"Renamed to: {new_name}")
263
+ except UnityConnectionError as e:
264
+ print_error(str(e))
265
+ sys.exit(1)
266
+
267
+
268
+ @asset.command("import")
269
+ @click.argument("path")
270
+ def import_asset(path: str):
271
+ """Import/reimport an asset.
272
+
273
+ \b
274
+ Examples:
275
+ unity-mcp asset import "Assets/Textures/NewTexture.png"
276
+ """
277
+ config = get_config()
278
+
279
+ try:
280
+ result = run_command(
281
+ "manage_asset", {"action": "import", "path": path}, config)
282
+ click.echo(format_output(result, config.format))
283
+ if result.get("success"):
284
+ print_success(f"Imported: {path}")
285
+ except UnityConnectionError as e:
286
+ print_error(str(e))
287
+ sys.exit(1)
288
+
289
+
290
+ @asset.command("mkdir")
291
+ @click.argument("path")
292
+ def mkdir(path: str):
293
+ """Create a folder.
294
+
295
+ \b
296
+ Examples:
297
+ unity-mcp asset mkdir "Assets/NewFolder"
298
+ unity-mcp asset mkdir "Assets/Levels/Chapter1"
299
+ """
300
+ config = get_config()
301
+
302
+ try:
303
+ result = run_command(
304
+ "manage_asset", {"action": "create_folder", "path": path}, config)
305
+ click.echo(format_output(result, config.format))
306
+ if result.get("success"):
307
+ print_success(f"Created folder: {path}")
308
+ except UnityConnectionError as e:
309
+ print_error(str(e))
310
+ sys.exit(1)
cli/commands/audio.py ADDED
@@ -0,0 +1,133 @@
1
+ """Audio CLI commands - placeholder for future implementation."""
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_info
9
+ from cli.utils.connection import run_command, UnityConnectionError
10
+
11
+
12
+ @click.group()
13
+ def audio():
14
+ """Audio operations - AudioSource control, audio settings."""
15
+ pass
16
+
17
+
18
+ @audio.command("play")
19
+ @click.argument("target")
20
+ @click.option(
21
+ "--clip", "-c",
22
+ default=None,
23
+ help="Audio clip path to play."
24
+ )
25
+ @click.option(
26
+ "--search-method",
27
+ type=click.Choice(["by_name", "by_path", "by_id"]),
28
+ default=None,
29
+ help="How to find the target."
30
+ )
31
+ def play(target: str, clip: Optional[str], search_method: Optional[str]):
32
+ """Play audio on a target's AudioSource.
33
+
34
+ \b
35
+ Examples:
36
+ unity-mcp audio play "MusicPlayer"
37
+ unity-mcp audio play "SFXSource" --clip "Assets/Audio/explosion.wav"
38
+ """
39
+ config = get_config()
40
+
41
+ params: dict[str, Any] = {
42
+ "action": "set_property",
43
+ "target": target,
44
+ "componentType": "AudioSource",
45
+ "property": "Play",
46
+ "value": True,
47
+ }
48
+
49
+ if clip:
50
+ params["clip"] = clip
51
+
52
+ if search_method:
53
+ params["searchMethod"] = search_method
54
+
55
+ try:
56
+ result = run_command("manage_components", params, config)
57
+ click.echo(format_output(result, config.format))
58
+ except UnityConnectionError as e:
59
+ print_error(str(e))
60
+ sys.exit(1)
61
+
62
+
63
+ @audio.command("stop")
64
+ @click.argument("target")
65
+ @click.option(
66
+ "--search-method",
67
+ type=click.Choice(["by_name", "by_path", "by_id"]),
68
+ default=None,
69
+ help="How to find the target."
70
+ )
71
+ def stop(target: str, search_method: Optional[str]):
72
+ """Stop audio on a target's AudioSource.
73
+
74
+ \b
75
+ Examples:
76
+ unity-mcp audio stop "MusicPlayer"
77
+ """
78
+ config = get_config()
79
+
80
+ params: dict[str, Any] = {
81
+ "action": "set_property",
82
+ "target": target,
83
+ "componentType": "AudioSource",
84
+ "property": "Stop",
85
+ "value": True,
86
+ }
87
+
88
+ if search_method:
89
+ params["searchMethod"] = search_method
90
+
91
+ try:
92
+ result = run_command("manage_components", params, config)
93
+ click.echo(format_output(result, config.format))
94
+ except UnityConnectionError as e:
95
+ print_error(str(e))
96
+ sys.exit(1)
97
+
98
+
99
+ @audio.command("volume")
100
+ @click.argument("target")
101
+ @click.argument("level", type=float)
102
+ @click.option(
103
+ "--search-method",
104
+ type=click.Choice(["by_name", "by_path", "by_id"]),
105
+ default=None,
106
+ help="How to find the target."
107
+ )
108
+ def volume(target: str, level: float, search_method: Optional[str]):
109
+ """Set audio volume on a target's AudioSource.
110
+
111
+ \b
112
+ Examples:
113
+ unity-mcp audio volume "MusicPlayer" 0.5
114
+ """
115
+ config = get_config()
116
+
117
+ params: dict[str, Any] = {
118
+ "action": "set_property",
119
+ "target": target,
120
+ "componentType": "AudioSource",
121
+ "property": "volume",
122
+ "value": level,
123
+ }
124
+
125
+ if search_method:
126
+ params["searchMethod"] = search_method
127
+
128
+ try:
129
+ result = run_command("manage_components", params, config)
130
+ click.echo(format_output(result, config.format))
131
+ except UnityConnectionError as e:
132
+ print_error(str(e))
133
+ sys.exit(1)