coplay-mcp-server 1.4.1__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.
- coplay_mcp_server/__init__.py +3 -0
- coplay_mcp_server/code_generator.py +370 -0
- coplay_mcp_server/generated_tools/.gitignore +4 -0
- coplay_mcp_server/generated_tools/__init__.py +4 -0
- coplay_mcp_server/generated_tools/agent_tool_tools.py +347 -0
- coplay_mcp_server/generated_tools/coplay_tool_tools.py +58 -0
- coplay_mcp_server/generated_tools/image_tool_tools.py +146 -0
- coplay_mcp_server/generated_tools/input_action_tool_tools.py +718 -0
- coplay_mcp_server/generated_tools/package_tool_tools.py +240 -0
- coplay_mcp_server/generated_tools/profiler_functions_tools.py +63 -0
- coplay_mcp_server/generated_tools/scene_view_functions_tools.py +58 -0
- coplay_mcp_server/generated_tools/screenshot_tool_tools.py +87 -0
- coplay_mcp_server/generated_tools/snapping_functions_tools.py +409 -0
- coplay_mcp_server/generated_tools/ui_functions_tools.py +419 -0
- coplay_mcp_server/generated_tools/unity_functions_tools.py +1643 -0
- coplay_mcp_server/image_utils.py +96 -0
- coplay_mcp_server/process_discovery.py +168 -0
- coplay_mcp_server/server.py +236 -0
- coplay_mcp_server/unity_client.py +342 -0
- coplay_mcp_server-1.4.1.dist-info/METADATA +70 -0
- coplay_mcp_server-1.4.1.dist-info/RECORD +24 -0
- coplay_mcp_server-1.4.1.dist-info/WHEEL +4 -0
- coplay_mcp_server-1.4.1.dist-info/entry_points.txt +3 -0
- coplay_mcp_server-1.4.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"""Generated MCP tools from ui_functions_schema.json"""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Annotated, Optional, Any, Dict, Literal
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
from fastmcp import FastMCP
|
|
7
|
+
from ..unity_client import UnityRpcClient
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
# Global references to be set by register_tools
|
|
12
|
+
_mcp: Optional[FastMCP] = None
|
|
13
|
+
_unity_client: Optional[UnityRpcClient] = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def set_rect_transform(
|
|
17
|
+
gameobject_path: Annotated[
|
|
18
|
+
str,
|
|
19
|
+
Field(
|
|
20
|
+
description="""Path to the GameObject in the scene or in a prefab asset. e.g Body/Head/Eyes"""
|
|
21
|
+
),
|
|
22
|
+
],
|
|
23
|
+
anchor_min: Annotated[
|
|
24
|
+
str | None,
|
|
25
|
+
Field(
|
|
26
|
+
description="""Comma-separated anchor minimum values (x,y)."""
|
|
27
|
+
),
|
|
28
|
+
] = None,
|
|
29
|
+
anchor_max: Annotated[
|
|
30
|
+
str | None,
|
|
31
|
+
Field(
|
|
32
|
+
description="""Comma-separated anchor maximum values (x,y)."""
|
|
33
|
+
),
|
|
34
|
+
] = None,
|
|
35
|
+
pivot: Annotated[
|
|
36
|
+
str | None,
|
|
37
|
+
Field(
|
|
38
|
+
description="""Comma-separated pivot point values (x,y)."""
|
|
39
|
+
),
|
|
40
|
+
] = None,
|
|
41
|
+
size_delta: Annotated[
|
|
42
|
+
str | None,
|
|
43
|
+
Field(
|
|
44
|
+
description="""Comma-separated size delta values (width,height)."""
|
|
45
|
+
),
|
|
46
|
+
] = None,
|
|
47
|
+
anchored_position: Annotated[
|
|
48
|
+
str | None,
|
|
49
|
+
Field(
|
|
50
|
+
description="""Comma-separated anchored position values (x,y)."""
|
|
51
|
+
),
|
|
52
|
+
] = None,
|
|
53
|
+
prefab_path: Annotated[
|
|
54
|
+
str | None,
|
|
55
|
+
Field(
|
|
56
|
+
description="""Optional. Filesystem path to a prefab asset i.e. files that end in .prefab. Example: Assets/MyPrefab.prefab. Only used when reading/modifying a prefab."""
|
|
57
|
+
),
|
|
58
|
+
] = None,
|
|
59
|
+
) -> Any:
|
|
60
|
+
"""Sets RectTransform properties of a UI GameObject."""
|
|
61
|
+
try:
|
|
62
|
+
logger.debug(f"Executing set_rect_transform with parameters: {locals()}")
|
|
63
|
+
|
|
64
|
+
# Prepare parameters for Unity RPC call
|
|
65
|
+
params = {}
|
|
66
|
+
if gameobject_path is not None:
|
|
67
|
+
params['gameobject_path'] = str(gameobject_path)
|
|
68
|
+
if anchor_min is not None:
|
|
69
|
+
params['anchor_min'] = str(anchor_min)
|
|
70
|
+
if anchor_max is not None:
|
|
71
|
+
params['anchor_max'] = str(anchor_max)
|
|
72
|
+
if pivot is not None:
|
|
73
|
+
params['pivot'] = str(pivot)
|
|
74
|
+
if size_delta is not None:
|
|
75
|
+
params['size_delta'] = str(size_delta)
|
|
76
|
+
if anchored_position is not None:
|
|
77
|
+
params['anchored_position'] = str(anchored_position)
|
|
78
|
+
if prefab_path is not None:
|
|
79
|
+
params['prefab_path'] = str(prefab_path)
|
|
80
|
+
|
|
81
|
+
# Execute Unity RPC call
|
|
82
|
+
result = await _unity_client.execute_request('set_rect_transform', params)
|
|
83
|
+
logger.debug(f"set_rect_transform completed successfully")
|
|
84
|
+
return result
|
|
85
|
+
|
|
86
|
+
except Exception as e:
|
|
87
|
+
logger.error(f"Failed to execute set_rect_transform: {e}")
|
|
88
|
+
raise RuntimeError(f"Tool execution failed for set_rect_transform: {e}")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
async def create_ui_element(
|
|
92
|
+
element_type: Annotated[
|
|
93
|
+
Literal['button', 'text', 'image', 'panel', 'inputfield', 'dropdown', 'toggle', 'scrollview'],
|
|
94
|
+
Field(
|
|
95
|
+
description="""Type of UI element to create"""
|
|
96
|
+
),
|
|
97
|
+
],
|
|
98
|
+
element_name: Annotated[
|
|
99
|
+
str,
|
|
100
|
+
Field(
|
|
101
|
+
description="""Name for the new UI element"""
|
|
102
|
+
),
|
|
103
|
+
],
|
|
104
|
+
parent_path: Annotated[
|
|
105
|
+
str | None,
|
|
106
|
+
Field(
|
|
107
|
+
description="""Path to the parent GameObject e.g Body/Head/Eyes"""
|
|
108
|
+
),
|
|
109
|
+
] = None,
|
|
110
|
+
) -> Any:
|
|
111
|
+
"""Creates a new UI element in the scene and returns scene path where the object was created."""
|
|
112
|
+
try:
|
|
113
|
+
logger.debug(f"Executing create_ui_element with parameters: {locals()}")
|
|
114
|
+
|
|
115
|
+
# Prepare parameters for Unity RPC call
|
|
116
|
+
params = {}
|
|
117
|
+
if element_type is not None:
|
|
118
|
+
params['element_type'] = str(element_type)
|
|
119
|
+
if element_name is not None:
|
|
120
|
+
params['element_name'] = str(element_name)
|
|
121
|
+
if parent_path is not None:
|
|
122
|
+
params['parent_path'] = str(parent_path)
|
|
123
|
+
|
|
124
|
+
# Execute Unity RPC call
|
|
125
|
+
result = await _unity_client.execute_request('create_ui_element', params)
|
|
126
|
+
logger.debug(f"create_ui_element completed successfully")
|
|
127
|
+
return result
|
|
128
|
+
|
|
129
|
+
except Exception as e:
|
|
130
|
+
logger.error(f"Failed to execute create_ui_element: {e}")
|
|
131
|
+
raise RuntimeError(f"Tool execution failed for create_ui_element: {e}")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
async def set_ui_text(
|
|
135
|
+
gameobject_path: Annotated[
|
|
136
|
+
str,
|
|
137
|
+
Field(
|
|
138
|
+
description="""Path to the GameObject in the scene or in a prefab asset. e.g Body/Head/Eyes"""
|
|
139
|
+
),
|
|
140
|
+
],
|
|
141
|
+
text: Annotated[
|
|
142
|
+
str | None,
|
|
143
|
+
Field(
|
|
144
|
+
description="""Text content to set"""
|
|
145
|
+
),
|
|
146
|
+
] = None,
|
|
147
|
+
font_size: Annotated[
|
|
148
|
+
int | None,
|
|
149
|
+
Field(
|
|
150
|
+
description="""Font size"""
|
|
151
|
+
),
|
|
152
|
+
] = None,
|
|
153
|
+
color: Annotated[
|
|
154
|
+
str | None,
|
|
155
|
+
Field(
|
|
156
|
+
description="""Color in r,g,b,a format (0-1 values)"""
|
|
157
|
+
),
|
|
158
|
+
] = None,
|
|
159
|
+
alignment: Annotated[
|
|
160
|
+
Literal['left', 'center', 'right'] | None,
|
|
161
|
+
Field(
|
|
162
|
+
description="""Text alignment"""
|
|
163
|
+
),
|
|
164
|
+
] = None,
|
|
165
|
+
prefab_path: Annotated[
|
|
166
|
+
str | None,
|
|
167
|
+
Field(
|
|
168
|
+
description="""Optional. Filesystem path to a prefab asset i.e. files that end in .prefab. Example: Assets/MyPrefab.prefab. Only used when reading/modifying a prefab."""
|
|
169
|
+
),
|
|
170
|
+
] = None,
|
|
171
|
+
) -> Any:
|
|
172
|
+
"""Sets properties of a UI Text component."""
|
|
173
|
+
try:
|
|
174
|
+
logger.debug(f"Executing set_ui_text with parameters: {locals()}")
|
|
175
|
+
|
|
176
|
+
# Prepare parameters for Unity RPC call
|
|
177
|
+
params = {}
|
|
178
|
+
if gameobject_path is not None:
|
|
179
|
+
params['gameobject_path'] = str(gameobject_path)
|
|
180
|
+
if text is not None:
|
|
181
|
+
params['text'] = str(text)
|
|
182
|
+
if font_size is not None:
|
|
183
|
+
params['font_size'] = str(font_size)
|
|
184
|
+
if color is not None:
|
|
185
|
+
params['color'] = str(color)
|
|
186
|
+
if alignment is not None:
|
|
187
|
+
params['alignment'] = str(alignment)
|
|
188
|
+
if prefab_path is not None:
|
|
189
|
+
params['prefab_path'] = str(prefab_path)
|
|
190
|
+
|
|
191
|
+
# Execute Unity RPC call
|
|
192
|
+
result = await _unity_client.execute_request('set_ui_text', params)
|
|
193
|
+
logger.debug(f"set_ui_text completed successfully")
|
|
194
|
+
return result
|
|
195
|
+
|
|
196
|
+
except Exception as e:
|
|
197
|
+
logger.error(f"Failed to execute set_ui_text: {e}")
|
|
198
|
+
raise RuntimeError(f"Tool execution failed for set_ui_text: {e}")
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
async def set_ui_layout(
|
|
202
|
+
gameobject_path: Annotated[
|
|
203
|
+
str,
|
|
204
|
+
Field(
|
|
205
|
+
description="""Path to the GameObject in the scene or in a prefab asset. e.g Body/Head/Eyes"""
|
|
206
|
+
),
|
|
207
|
+
],
|
|
208
|
+
layout_type: Annotated[
|
|
209
|
+
Literal['vertical', 'horizontal', 'grid'],
|
|
210
|
+
Field(
|
|
211
|
+
description="""Type of layout to apply"""
|
|
212
|
+
),
|
|
213
|
+
],
|
|
214
|
+
spacing: Annotated[
|
|
215
|
+
str | None,
|
|
216
|
+
Field(
|
|
217
|
+
description="""Spacing between elements (single value for vertical/horizontal, 'x,y' for grid)"""
|
|
218
|
+
),
|
|
219
|
+
] = None,
|
|
220
|
+
padding: Annotated[
|
|
221
|
+
str | None,
|
|
222
|
+
Field(
|
|
223
|
+
description="""Padding in 'left,right,top,bottom' format"""
|
|
224
|
+
),
|
|
225
|
+
] = None,
|
|
226
|
+
alignment: Annotated[
|
|
227
|
+
Literal['upper_left', 'upper_center', 'upper_right', 'middle_left', 'middle_center', 'middle_right', 'lower_left', 'lower_center', 'lower_right'] | None,
|
|
228
|
+
Field(
|
|
229
|
+
description="""Alignment of children elements"""
|
|
230
|
+
),
|
|
231
|
+
] = None,
|
|
232
|
+
prefab_path: Annotated[
|
|
233
|
+
str | None,
|
|
234
|
+
Field(
|
|
235
|
+
description="""Optional. Filesystem path to a prefab asset i.e. files that end in .prefab. Example: Assets/MyPrefab.prefab. Only used when reading/modifying a prefab."""
|
|
236
|
+
),
|
|
237
|
+
] = None,
|
|
238
|
+
) -> Any:
|
|
239
|
+
"""Sets layout properties for UI elements."""
|
|
240
|
+
try:
|
|
241
|
+
logger.debug(f"Executing set_ui_layout with parameters: {locals()}")
|
|
242
|
+
|
|
243
|
+
# Prepare parameters for Unity RPC call
|
|
244
|
+
params = {}
|
|
245
|
+
if gameobject_path is not None:
|
|
246
|
+
params['gameobject_path'] = str(gameobject_path)
|
|
247
|
+
if layout_type is not None:
|
|
248
|
+
params['layout_type'] = str(layout_type)
|
|
249
|
+
if spacing is not None:
|
|
250
|
+
params['spacing'] = str(spacing)
|
|
251
|
+
if padding is not None:
|
|
252
|
+
params['padding'] = str(padding)
|
|
253
|
+
if alignment is not None:
|
|
254
|
+
params['alignment'] = str(alignment)
|
|
255
|
+
if prefab_path is not None:
|
|
256
|
+
params['prefab_path'] = str(prefab_path)
|
|
257
|
+
|
|
258
|
+
# Execute Unity RPC call
|
|
259
|
+
result = await _unity_client.execute_request('set_ui_layout', params)
|
|
260
|
+
logger.debug(f"set_ui_layout completed successfully")
|
|
261
|
+
return result
|
|
262
|
+
|
|
263
|
+
except Exception as e:
|
|
264
|
+
logger.error(f"Failed to execute set_ui_layout: {e}")
|
|
265
|
+
raise RuntimeError(f"Tool execution failed for set_ui_layout: {e}")
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
async def add_persistent_listener(
|
|
269
|
+
gameobject_path: Annotated[
|
|
270
|
+
str,
|
|
271
|
+
Field(
|
|
272
|
+
description="""Path to the GameObject in the scene or in a prefab asset. e.g Body/Head/Eyes, containing the component with the event."""
|
|
273
|
+
),
|
|
274
|
+
],
|
|
275
|
+
component_type: Annotated[
|
|
276
|
+
str,
|
|
277
|
+
Field(
|
|
278
|
+
description="""Type of component containing the event (e.g., 'Button', 'Toggle')."""
|
|
279
|
+
),
|
|
280
|
+
],
|
|
281
|
+
event_name: Annotated[
|
|
282
|
+
str,
|
|
283
|
+
Field(
|
|
284
|
+
description="""Name of the event property (e.g., 'onClick', 'onValueChanged')."""
|
|
285
|
+
),
|
|
286
|
+
],
|
|
287
|
+
target_gameobject_path: Annotated[
|
|
288
|
+
str,
|
|
289
|
+
Field(
|
|
290
|
+
description="""Path to the GameObject in the scene or path in a prefab asset, containing the component with the method to call."""
|
|
291
|
+
),
|
|
292
|
+
],
|
|
293
|
+
target_component_type: Annotated[
|
|
294
|
+
str,
|
|
295
|
+
Field(
|
|
296
|
+
description="""Type of component containing the method to call."""
|
|
297
|
+
),
|
|
298
|
+
],
|
|
299
|
+
method_name: Annotated[
|
|
300
|
+
str,
|
|
301
|
+
Field(
|
|
302
|
+
description="""Name of the method to call when the event is triggered."""
|
|
303
|
+
),
|
|
304
|
+
],
|
|
305
|
+
parameter_type: Annotated[
|
|
306
|
+
Literal['_none', '_bool', '_int', '_float', '_string', '_void'],
|
|
307
|
+
Field(
|
|
308
|
+
description="""Type of parameter the method accepts. Defaults to none."""
|
|
309
|
+
),
|
|
310
|
+
],
|
|
311
|
+
parameter_value: Annotated[
|
|
312
|
+
str | None,
|
|
313
|
+
Field(
|
|
314
|
+
description="""Value to pass to the method when called. Should match the parameter_type."""
|
|
315
|
+
),
|
|
316
|
+
] = None,
|
|
317
|
+
) -> Any:
|
|
318
|
+
"""Adds a persistent listener to a UnityEvent on a component. This allows configuring event callbacks like Button.onClick events."""
|
|
319
|
+
try:
|
|
320
|
+
logger.debug(f"Executing add_persistent_listener with parameters: {locals()}")
|
|
321
|
+
|
|
322
|
+
# Prepare parameters for Unity RPC call
|
|
323
|
+
params = {}
|
|
324
|
+
if gameobject_path is not None:
|
|
325
|
+
params['gameobject_path'] = str(gameobject_path)
|
|
326
|
+
if component_type is not None:
|
|
327
|
+
params['component_type'] = str(component_type)
|
|
328
|
+
if event_name is not None:
|
|
329
|
+
params['event_name'] = str(event_name)
|
|
330
|
+
if target_gameobject_path is not None:
|
|
331
|
+
params['target_gameobject_path'] = str(target_gameobject_path)
|
|
332
|
+
if target_component_type is not None:
|
|
333
|
+
params['target_component_type'] = str(target_component_type)
|
|
334
|
+
if method_name is not None:
|
|
335
|
+
params['method_name'] = str(method_name)
|
|
336
|
+
if parameter_type is not None:
|
|
337
|
+
params['parameter_type'] = str(parameter_type)
|
|
338
|
+
if parameter_value is not None:
|
|
339
|
+
params['parameter_value'] = str(parameter_value)
|
|
340
|
+
|
|
341
|
+
# Execute Unity RPC call
|
|
342
|
+
result = await _unity_client.execute_request('add_persistent_listener', params)
|
|
343
|
+
logger.debug(f"add_persistent_listener completed successfully")
|
|
344
|
+
return result
|
|
345
|
+
|
|
346
|
+
except Exception as e:
|
|
347
|
+
logger.error(f"Failed to execute add_persistent_listener: {e}")
|
|
348
|
+
raise RuntimeError(f"Tool execution failed for add_persistent_listener: {e}")
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
async def remove_persistent_listener(
|
|
352
|
+
gameobject_path: Annotated[
|
|
353
|
+
str,
|
|
354
|
+
Field(
|
|
355
|
+
description="""Path to the GameObject in the scene or in a prefab asset. e.g Body/Head/Eyes, containing the component with the event."""
|
|
356
|
+
),
|
|
357
|
+
],
|
|
358
|
+
component_type: Annotated[
|
|
359
|
+
str,
|
|
360
|
+
Field(
|
|
361
|
+
description="""Type of component containing the event (e.g., 'Button', 'Toggle')."""
|
|
362
|
+
),
|
|
363
|
+
],
|
|
364
|
+
event_name: Annotated[
|
|
365
|
+
str,
|
|
366
|
+
Field(
|
|
367
|
+
description="""Name of the event property (e.g., 'onClick', 'onValueChanged')."""
|
|
368
|
+
),
|
|
369
|
+
],
|
|
370
|
+
listener_index: Annotated[
|
|
371
|
+
int,
|
|
372
|
+
Field(
|
|
373
|
+
description="""Index of the listener to remove (0-based)."""
|
|
374
|
+
),
|
|
375
|
+
],
|
|
376
|
+
) -> Any:
|
|
377
|
+
"""Removes a persistent listener from a UnityEvent on a component."""
|
|
378
|
+
try:
|
|
379
|
+
logger.debug(f"Executing remove_persistent_listener with parameters: {locals()}")
|
|
380
|
+
|
|
381
|
+
# Prepare parameters for Unity RPC call
|
|
382
|
+
params = {}
|
|
383
|
+
if gameobject_path is not None:
|
|
384
|
+
params['gameobject_path'] = str(gameobject_path)
|
|
385
|
+
if component_type is not None:
|
|
386
|
+
params['component_type'] = str(component_type)
|
|
387
|
+
if event_name is not None:
|
|
388
|
+
params['event_name'] = str(event_name)
|
|
389
|
+
if listener_index is not None:
|
|
390
|
+
params['listener_index'] = str(listener_index)
|
|
391
|
+
|
|
392
|
+
# Execute Unity RPC call
|
|
393
|
+
result = await _unity_client.execute_request('remove_persistent_listener', params)
|
|
394
|
+
logger.debug(f"remove_persistent_listener completed successfully")
|
|
395
|
+
return result
|
|
396
|
+
|
|
397
|
+
except Exception as e:
|
|
398
|
+
logger.error(f"Failed to execute remove_persistent_listener: {e}")
|
|
399
|
+
raise RuntimeError(f"Tool execution failed for remove_persistent_listener: {e}")
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def register_tools(mcp: FastMCP, unity_client: UnityRpcClient) -> None:
|
|
403
|
+
"""Register all tools from ui_functions_schema with the MCP server."""
|
|
404
|
+
global _mcp, _unity_client
|
|
405
|
+
_mcp = mcp
|
|
406
|
+
_unity_client = unity_client
|
|
407
|
+
|
|
408
|
+
# Register set_rect_transform
|
|
409
|
+
mcp.tool()(set_rect_transform)
|
|
410
|
+
# Register create_ui_element
|
|
411
|
+
mcp.tool()(create_ui_element)
|
|
412
|
+
# Register set_ui_text
|
|
413
|
+
mcp.tool()(set_ui_text)
|
|
414
|
+
# Register set_ui_layout
|
|
415
|
+
mcp.tool()(set_ui_layout)
|
|
416
|
+
# Register add_persistent_listener
|
|
417
|
+
mcp.tool()(add_persistent_listener)
|
|
418
|
+
# Register remove_persistent_listener
|
|
419
|
+
mcp.tool()(remove_persistent_listener)
|