mcpforunityserver 8.7.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 (81) 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 +177 -62
  26. {mcpforunityserver-8.7.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.7.0.dist-info → mcpforunityserver-9.1.0.dist-info}/WHEEL +1 -1
  29. {mcpforunityserver-8.7.0.dist-info → mcpforunityserver-9.1.0.dist-info}/entry_points.txt +1 -0
  30. {mcpforunityserver-8.7.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 -30
  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 +3 -4
  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 +13 -44
  53. services/tools/manage_components.py +131 -0
  54. services/tools/manage_editor.py +9 -8
  55. services/tools/manage_gameobject.py +115 -79
  56. services/tools/manage_material.py +80 -31
  57. services/tools/manage_prefabs.py +7 -1
  58. services/tools/manage_scene.py +30 -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 +15 -12
  64. services/tools/read_console.py +70 -17
  65. services/tools/refresh_unity.py +92 -29
  66. services/tools/run_tests.py +187 -53
  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 +85 -24
  73. transport/unity_instance_middleware.py +4 -3
  74. transport/unity_transport.py +2 -1
  75. utils/focus_nudge.py +321 -0
  76. __init__.py +0 -0
  77. mcpforunityserver-8.7.0.dist-info/RECORD +0 -71
  78. routes/__init__.py +0 -0
  79. services/resources/editor_state_v2.py +0 -270
  80. services/tools/test_jobs.py +0 -94
  81. {mcpforunityserver-8.7.0.dist-info → mcpforunityserver-9.1.0.dist-info}/licenses/LICENSE +0 -0
cli/commands/scene.py ADDED
@@ -0,0 +1,255 @@
1
+ """Scene 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, UnityConnectionError
10
+
11
+
12
+ @click.group()
13
+ def scene():
14
+ """Scene operations - hierarchy, load, save, create scenes."""
15
+ pass
16
+
17
+
18
+ @scene.command("hierarchy")
19
+ @click.option(
20
+ "--parent",
21
+ default=None,
22
+ help="Parent GameObject to list children of (name, path, or instance ID)."
23
+ )
24
+ @click.option(
25
+ "--max-depth", "-d",
26
+ default=None,
27
+ type=int,
28
+ help="Maximum depth to traverse."
29
+ )
30
+ @click.option(
31
+ "--include-transform", "-t",
32
+ is_flag=True,
33
+ help="Include transform data for each node."
34
+ )
35
+ @click.option(
36
+ "--limit", "-l",
37
+ default=50,
38
+ type=int,
39
+ help="Maximum nodes to return."
40
+ )
41
+ @click.option(
42
+ "--cursor", "-c",
43
+ default=0,
44
+ type=int,
45
+ help="Pagination cursor."
46
+ )
47
+ def hierarchy(
48
+ parent: Optional[str],
49
+ max_depth: Optional[int],
50
+ include_transform: bool,
51
+ limit: int,
52
+ cursor: int,
53
+ ):
54
+ """Get the scene hierarchy.
55
+
56
+ \b
57
+ Examples:
58
+ unity-mcp scene hierarchy
59
+ unity-mcp scene hierarchy --max-depth 3
60
+ unity-mcp scene hierarchy --parent "Canvas" --include-transform
61
+ unity-mcp scene hierarchy --format json
62
+ """
63
+ config = get_config()
64
+
65
+ params: dict[str, Any] = {
66
+ "action": "get_hierarchy",
67
+ "pageSize": limit,
68
+ "cursor": cursor,
69
+ }
70
+
71
+ if parent:
72
+ params["parent"] = parent
73
+ if max_depth is not None:
74
+ params["maxDepth"] = max_depth
75
+ if include_transform:
76
+ params["includeTransform"] = True
77
+
78
+ try:
79
+ result = run_command("manage_scene", params, config)
80
+ click.echo(format_output(result, config.format))
81
+ except UnityConnectionError as e:
82
+ print_error(str(e))
83
+ sys.exit(1)
84
+
85
+
86
+ @scene.command("active")
87
+ def active():
88
+ """Get information about the active scene."""
89
+ config = get_config()
90
+
91
+ try:
92
+ result = run_command("manage_scene", {"action": "get_active"}, 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
+ @scene.command("load")
100
+ @click.argument("scene")
101
+ @click.option(
102
+ "--by-index", "-i",
103
+ is_flag=True,
104
+ help="Load by build index instead of path/name."
105
+ )
106
+ def load(scene: str, by_index: bool):
107
+ """Load a scene.
108
+
109
+ \b
110
+ Examples:
111
+ unity-mcp scene load "Assets/Scenes/Main.unity"
112
+ unity-mcp scene load "MainScene"
113
+ unity-mcp scene load 0 --by-index
114
+ """
115
+ config = get_config()
116
+
117
+ params: dict[str, Any] = {"action": "load"}
118
+
119
+ if by_index:
120
+ try:
121
+ params["buildIndex"] = int(scene)
122
+ except ValueError:
123
+ print_error(f"Invalid build index: {scene}")
124
+ sys.exit(1)
125
+ else:
126
+ if scene.endswith(".unity"):
127
+ params["path"] = scene
128
+ else:
129
+ params["name"] = scene
130
+
131
+ try:
132
+ result = run_command("manage_scene", params, config)
133
+ click.echo(format_output(result, config.format))
134
+ if result.get("success"):
135
+ print_success(f"Loaded scene: {scene}")
136
+ except UnityConnectionError as e:
137
+ print_error(str(e))
138
+ sys.exit(1)
139
+
140
+
141
+ @scene.command("save")
142
+ @click.option(
143
+ "--path",
144
+ default=None,
145
+ help="Path to save the scene to (for new scenes)."
146
+ )
147
+ def save(path: Optional[str]):
148
+ """Save the current scene.
149
+
150
+ \b
151
+ Examples:
152
+ unity-mcp scene save
153
+ unity-mcp scene save --path "Assets/Scenes/NewScene.unity"
154
+ """
155
+ config = get_config()
156
+
157
+ params: dict[str, Any] = {"action": "save"}
158
+ if path:
159
+ params["path"] = path
160
+
161
+ try:
162
+ result = run_command("manage_scene", params, config)
163
+ click.echo(format_output(result, config.format))
164
+ if result.get("success"):
165
+ print_success("Scene saved")
166
+ except UnityConnectionError as e:
167
+ print_error(str(e))
168
+ sys.exit(1)
169
+
170
+
171
+ @scene.command("create")
172
+ @click.argument("name")
173
+ @click.option(
174
+ "--path",
175
+ default=None,
176
+ help="Path to create the scene at."
177
+ )
178
+ def create(name: str, path: Optional[str]):
179
+ """Create a new scene.
180
+
181
+ \b
182
+ Examples:
183
+ unity-mcp scene create "NewLevel"
184
+ unity-mcp scene create "TestScene" --path "Assets/Scenes/Test"
185
+ """
186
+ config = get_config()
187
+
188
+ params: dict[str, Any] = {
189
+ "action": "create",
190
+ "name": name,
191
+ }
192
+ if path:
193
+ params["path"] = path
194
+
195
+ try:
196
+ result = run_command("manage_scene", params, config)
197
+ click.echo(format_output(result, config.format))
198
+ if result.get("success"):
199
+ print_success(f"Created scene: {name}")
200
+ except UnityConnectionError as e:
201
+ print_error(str(e))
202
+ sys.exit(1)
203
+
204
+
205
+ @scene.command("build-settings")
206
+ def build_settings():
207
+ """Get scenes in build settings."""
208
+ config = get_config()
209
+
210
+ try:
211
+ result = run_command(
212
+ "manage_scene", {"action": "get_build_settings"}, config)
213
+ click.echo(format_output(result, config.format))
214
+ except UnityConnectionError as e:
215
+ print_error(str(e))
216
+ sys.exit(1)
217
+
218
+
219
+ @scene.command("screenshot")
220
+ @click.option(
221
+ "--filename", "-f",
222
+ default=None,
223
+ help="Output filename (default: timestamp)."
224
+ )
225
+ @click.option(
226
+ "--supersize", "-s",
227
+ default=1,
228
+ type=int,
229
+ help="Supersize multiplier (1-4)."
230
+ )
231
+ def screenshot(filename: Optional[str], supersize: int):
232
+ """Capture a screenshot of the scene.
233
+
234
+ \b
235
+ Examples:
236
+ unity-mcp scene screenshot
237
+ unity-mcp scene screenshot --filename "level_preview"
238
+ unity-mcp scene screenshot --supersize 2
239
+ """
240
+ config = get_config()
241
+
242
+ params: dict[str, Any] = {"action": "screenshot"}
243
+ if filename:
244
+ params["fileName"] = filename
245
+ if supersize > 1:
246
+ params["superSize"] = supersize
247
+
248
+ try:
249
+ result = run_command("manage_scene", params, config)
250
+ click.echo(format_output(result, config.format))
251
+ if result.get("success"):
252
+ print_success("Screenshot captured")
253
+ except UnityConnectionError as e:
254
+ print_error(str(e))
255
+ sys.exit(1)
cli/commands/script.py ADDED
@@ -0,0 +1,240 @@
1
+ """Script 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 script():
15
+ """Script operations - create, read, edit C# scripts."""
16
+ pass
17
+
18
+
19
+ @script.command("create")
20
+ @click.argument("name")
21
+ @click.option(
22
+ "--path", "-p",
23
+ default="Assets/Scripts",
24
+ help="Directory to create the script in."
25
+ )
26
+ @click.option(
27
+ "--type", "-t",
28
+ "script_type",
29
+ type=click.Choice(["MonoBehaviour", "ScriptableObject",
30
+ "Editor", "EditorWindow", "Plain"]),
31
+ default="MonoBehaviour",
32
+ help="Type of script to create."
33
+ )
34
+ @click.option(
35
+ "--namespace", "-n",
36
+ default=None,
37
+ help="Namespace for the script."
38
+ )
39
+ @click.option(
40
+ "--contents", "-c",
41
+ default=None,
42
+ help="Full script contents (overrides template)."
43
+ )
44
+ def create(name: str, path: str, script_type: str, namespace: Optional[str], contents: Optional[str]):
45
+ """Create a new C# script.
46
+
47
+ \b
48
+ Examples:
49
+ unity-mcp script create "PlayerController"
50
+ unity-mcp script create "GameManager" --path "Assets/Scripts/Managers"
51
+ unity-mcp script create "EnemyData" --type ScriptableObject
52
+ unity-mcp script create "CustomEditor" --type Editor --namespace "MyGame.Editor"
53
+ """
54
+ config = get_config()
55
+
56
+ params: dict[str, Any] = {
57
+ "action": "create",
58
+ "name": name,
59
+ "path": path,
60
+ "scriptType": script_type,
61
+ }
62
+
63
+ if namespace:
64
+ params["namespace"] = namespace
65
+ if contents:
66
+ params["contents"] = contents
67
+
68
+ try:
69
+ result = run_command("manage_script", params, config)
70
+ click.echo(format_output(result, config.format))
71
+ if result.get("success"):
72
+ print_success(f"Created script: {name}.cs")
73
+ except UnityConnectionError as e:
74
+ print_error(str(e))
75
+ sys.exit(1)
76
+
77
+
78
+ @script.command("read")
79
+ @click.argument("path")
80
+ @click.option(
81
+ "--start-line", "-s",
82
+ default=None,
83
+ type=int,
84
+ help="Starting line number (1-based)."
85
+ )
86
+ @click.option(
87
+ "--line-count", "-n",
88
+ default=None,
89
+ type=int,
90
+ help="Number of lines to read."
91
+ )
92
+ def read(path: str, start_line: Optional[int], line_count: Optional[int]):
93
+ """Read a C# script file.
94
+
95
+ \b
96
+ Examples:
97
+ unity-mcp script read "Assets/Scripts/Player.cs"
98
+ unity-mcp script read "Assets/Scripts/Player.cs" --start-line 10 --line-count 20
99
+ """
100
+ config = get_config()
101
+
102
+ parts = path.rsplit("/", 1)
103
+ filename = parts[-1]
104
+ directory = parts[0] if len(parts) > 1 else "Assets"
105
+ name = filename[:-3] if filename.endswith(".cs") else filename
106
+
107
+ params: dict[str, Any] = {
108
+ "action": "read",
109
+ "name": name,
110
+ "path": directory,
111
+ }
112
+
113
+ if start_line:
114
+ params["startLine"] = start_line
115
+ if line_count:
116
+ params["lineCount"] = line_count
117
+
118
+ try:
119
+ result = run_command("manage_script", params, config)
120
+ # For read, just output the content directly
121
+ if result.get("success") and result.get("data"):
122
+ data = result.get("data", {})
123
+ if isinstance(data, dict) and "contents" in data:
124
+ click.echo(data["contents"])
125
+ else:
126
+ click.echo(format_output(result, config.format))
127
+ else:
128
+ click.echo(format_output(result, config.format))
129
+ except UnityConnectionError as e:
130
+ print_error(str(e))
131
+ sys.exit(1)
132
+
133
+
134
+ @script.command("delete")
135
+ @click.argument("path")
136
+ @click.option(
137
+ "--force", "-f",
138
+ is_flag=True,
139
+ help="Skip confirmation prompt."
140
+ )
141
+ def delete(path: str, force: bool):
142
+ """Delete a C# script.
143
+
144
+ \b
145
+ Examples:
146
+ unity-mcp script delete "Assets/Scripts/OldScript.cs"
147
+ """
148
+ config = get_config()
149
+
150
+ if not force:
151
+ click.confirm(f"Delete script '{path}'?", abort=True)
152
+
153
+ parts = path.rsplit("/", 1)
154
+ filename = parts[-1]
155
+ directory = parts[0] if len(parts) > 1 else "Assets"
156
+ name = filename[:-3] if filename.endswith(".cs") else filename
157
+
158
+ params: dict[str, Any] = {
159
+ "action": "delete",
160
+ "name": name,
161
+ "path": directory,
162
+ }
163
+
164
+ try:
165
+ result = run_command("manage_script", params, config)
166
+ click.echo(format_output(result, config.format))
167
+ if result.get("success"):
168
+ print_success(f"Deleted: {path}")
169
+ except UnityConnectionError as e:
170
+ print_error(str(e))
171
+ sys.exit(1)
172
+
173
+
174
+ @script.command("edit")
175
+ @click.argument("path")
176
+ @click.option(
177
+ "--edits", "-e",
178
+ required=True,
179
+ help='Edits as JSON array of {startLine, startCol, endLine, endCol, newText}.'
180
+ )
181
+ def edit(path: str, edits: str):
182
+ """Apply text edits to a script.
183
+
184
+ \b
185
+ Examples:
186
+ unity-mcp script edit "Assets/Scripts/Player.cs" --edits '[{"startLine": 10, "startCol": 1, "endLine": 10, "endCol": 20, "newText": "// Modified"}]'
187
+ """
188
+ config = get_config()
189
+
190
+ try:
191
+ edits_list = json.loads(edits)
192
+ except json.JSONDecodeError as e:
193
+ print_error(f"Invalid JSON for edits: {e}")
194
+ sys.exit(1)
195
+
196
+ params: dict[str, Any] = {
197
+ "uri": path,
198
+ "edits": edits_list,
199
+ }
200
+
201
+ try:
202
+ result = run_command("apply_text_edits", params, config)
203
+ click.echo(format_output(result, config.format))
204
+ if result.get("success"):
205
+ print_success(f"Applied edits to: {path}")
206
+ except UnityConnectionError as e:
207
+ print_error(str(e))
208
+ sys.exit(1)
209
+
210
+
211
+ @script.command("validate")
212
+ @click.argument("path")
213
+ @click.option(
214
+ "--level", "-l",
215
+ type=click.Choice(["basic", "standard"]),
216
+ default="basic",
217
+ help="Validation level."
218
+ )
219
+ def validate(path: str, level: str):
220
+ """Validate a C# script for errors.
221
+
222
+ \b
223
+ Examples:
224
+ unity-mcp script validate "Assets/Scripts/Player.cs"
225
+ unity-mcp script validate "Assets/Scripts/Player.cs" --level standard
226
+ """
227
+ config = get_config()
228
+
229
+ params: dict[str, Any] = {
230
+ "uri": path,
231
+ "level": level,
232
+ "include_diagnostics": True,
233
+ }
234
+
235
+ try:
236
+ result = run_command("validate_script", params, config)
237
+ click.echo(format_output(result, config.format))
238
+ except UnityConnectionError as e:
239
+ print_error(str(e))
240
+ sys.exit(1)