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,342 @@
|
|
|
1
|
+
"""Unity RPC client for file-based communication with Unity Editor."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import uuid
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
import concurrent.futures
|
|
10
|
+
|
|
11
|
+
import aiofiles
|
|
12
|
+
from watchdog.events import FileSystemEventHandler
|
|
13
|
+
from watchdog.observers import Observer
|
|
14
|
+
|
|
15
|
+
from mcp.server.fastmcp.utilities.types import Image
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class UnityProjectRootError(Exception):
|
|
21
|
+
"""Base exception for Unity project root related errors."""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class NoUnityInstancesError(UnityProjectRootError):
|
|
26
|
+
"""Raised when no Unity Editor instances are found."""
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MultipleUnityInstancesError(UnityProjectRootError):
|
|
31
|
+
"""Raised when multiple Unity Editor instances are found and auto-detection cannot proceed."""
|
|
32
|
+
|
|
33
|
+
def __init__(self, message: str, project_roots: list[str]):
|
|
34
|
+
super().__init__(message)
|
|
35
|
+
self.project_roots = project_roots
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def discover_unity_project_roots():
|
|
39
|
+
"""Import and call the discover_unity_project_roots function."""
|
|
40
|
+
from coplay_mcp_server.process_discovery import discover_unity_project_roots as _discover
|
|
41
|
+
return _discover()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class UnityRpcClient:
|
|
45
|
+
"""Client for communicating with Unity Editor via file-based RPC."""
|
|
46
|
+
|
|
47
|
+
def __init__(self) -> None:
|
|
48
|
+
self._unity_project_root: Optional[str] = None
|
|
49
|
+
self._pending_requests: Dict[str, concurrent.futures.Future[Any]] = {}
|
|
50
|
+
self._observer: Optional[Observer] = None
|
|
51
|
+
self._response_handler: Optional[ResponseFileHandler] = None
|
|
52
|
+
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
|
53
|
+
|
|
54
|
+
def set_unity_project_root(self, project_root: str) -> None:
|
|
55
|
+
"""Set the Unity project root and start watching for responses."""
|
|
56
|
+
if self._unity_project_root == project_root:
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
# Stop existing watcher if any
|
|
60
|
+
self._stop_file_watcher()
|
|
61
|
+
|
|
62
|
+
self._unity_project_root = project_root
|
|
63
|
+
self._start_file_watcher()
|
|
64
|
+
logger.info(f"Unity project root set to: {project_root}")
|
|
65
|
+
|
|
66
|
+
def auto_detect_unity_project_root(self) -> bool:
|
|
67
|
+
"""
|
|
68
|
+
Automatically detect and set Unity project root if exactly one Unity instance is running.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
bool: True if successfully auto-detected and set, False otherwise.
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
project_roots = discover_unity_project_roots()
|
|
75
|
+
|
|
76
|
+
if len(project_roots) == 1:
|
|
77
|
+
# Exactly one Unity instance found - auto-set it
|
|
78
|
+
project_root = project_roots[0]
|
|
79
|
+
self.set_unity_project_root(project_root)
|
|
80
|
+
logger.info(f"Auto-detected Unity project root: {project_root}")
|
|
81
|
+
return True
|
|
82
|
+
elif len(project_roots) == 0:
|
|
83
|
+
logger.warning("No Unity instances found for auto-detection")
|
|
84
|
+
return False
|
|
85
|
+
else:
|
|
86
|
+
logger.warning(f"Multiple Unity instances found ({len(project_roots)}), cannot auto-detect. Available projects: {project_roots}")
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.error(f"Failed to auto-detect Unity project root: {e}")
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
def _start_file_watcher(self) -> None:
|
|
94
|
+
"""Start watching for response files."""
|
|
95
|
+
if not self._unity_project_root:
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
requests_dir = (
|
|
99
|
+
Path(self._unity_project_root) / "Temp" / "Coplay" / "MCPRequests"
|
|
100
|
+
)
|
|
101
|
+
if not requests_dir.exists():
|
|
102
|
+
logger.warning(f"Unity requests directory does not exist: {requests_dir}")
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
# Store the current event loop for thread-safe communication
|
|
106
|
+
try:
|
|
107
|
+
self._loop = asyncio.get_running_loop()
|
|
108
|
+
except RuntimeError:
|
|
109
|
+
logger.warning(
|
|
110
|
+
"No running event loop found, file watching may not work properly"
|
|
111
|
+
)
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
self._response_handler = ResponseFileHandler(
|
|
115
|
+
self._handle_response_file_sync, self._loop
|
|
116
|
+
)
|
|
117
|
+
self._observer = Observer()
|
|
118
|
+
self._observer.schedule(
|
|
119
|
+
self._response_handler, str(requests_dir), recursive=False
|
|
120
|
+
)
|
|
121
|
+
self._observer.start()
|
|
122
|
+
logger.info(f"Started watching for responses in: {requests_dir}")
|
|
123
|
+
|
|
124
|
+
def _stop_file_watcher(self) -> None:
|
|
125
|
+
"""Stop watching for response files."""
|
|
126
|
+
if self._observer:
|
|
127
|
+
self._observer.stop()
|
|
128
|
+
self._observer.join()
|
|
129
|
+
self._observer = None
|
|
130
|
+
self._response_handler = None
|
|
131
|
+
|
|
132
|
+
def _handle_response_file_sync(self, file_path: Path) -> None:
|
|
133
|
+
"""Handle a response file from Unity (synchronous version for thread safety)."""
|
|
134
|
+
try:
|
|
135
|
+
logger.info(f"Handling file change: {file_path}")
|
|
136
|
+
|
|
137
|
+
if not file_path.name.startswith(
|
|
138
|
+
"response_"
|
|
139
|
+
) or not file_path.name.endswith(".json"):
|
|
140
|
+
return
|
|
141
|
+
|
|
142
|
+
# Read response file synchronously
|
|
143
|
+
try:
|
|
144
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
145
|
+
response_json = f.read()
|
|
146
|
+
except Exception as e:
|
|
147
|
+
logger.error(f"Failed to read response file {file_path}: {e}")
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
response_data = json.loads(response_json)
|
|
151
|
+
request_id = response_data.get("id")
|
|
152
|
+
if request_id not in self._pending_requests:
|
|
153
|
+
logger.warning(f"No pending request found for ID: {request_id}")
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
future = self._pending_requests.pop(request_id)
|
|
157
|
+
|
|
158
|
+
if "error" in response_data and response_data["error"]:
|
|
159
|
+
error_msg = response_data["error"]
|
|
160
|
+
if isinstance(error_msg, dict):
|
|
161
|
+
error_msg = error_msg.get("message", str(error_msg))
|
|
162
|
+
future.set_exception(Exception(str(error_msg)))
|
|
163
|
+
else:
|
|
164
|
+
future.set_result(response_data.get("result"))
|
|
165
|
+
|
|
166
|
+
# Clean up response file
|
|
167
|
+
try:
|
|
168
|
+
file_path.unlink()
|
|
169
|
+
logger.debug(f"Deleted response file: {file_path}")
|
|
170
|
+
except Exception as e:
|
|
171
|
+
logger.warning(f"Failed to delete response file {file_path}: {e}")
|
|
172
|
+
|
|
173
|
+
except Exception as e:
|
|
174
|
+
logger.error(f"Error handling response file {file_path}: {e}")
|
|
175
|
+
|
|
176
|
+
def _is_image_function(self, method: str) -> bool:
|
|
177
|
+
"""Check if this is a function that returns images."""
|
|
178
|
+
image_functions = {
|
|
179
|
+
"get_scene_view_screenshot",
|
|
180
|
+
"capture_ui_canvas",
|
|
181
|
+
}
|
|
182
|
+
return method in image_functions
|
|
183
|
+
|
|
184
|
+
def _process_image_response(self, response: Any) -> Any:
|
|
185
|
+
"""Convert ImagePath to FastMCP Image object for proper MCP compatibility."""
|
|
186
|
+
if isinstance(response, dict) and "ImagePath" in response:
|
|
187
|
+
image_path = response["ImagePath"]
|
|
188
|
+
if image_path and isinstance(image_path, str):
|
|
189
|
+
logger.debug(f"Processing image response with path: {image_path}")
|
|
190
|
+
try:
|
|
191
|
+
# Create FastMCP Image object from the file path
|
|
192
|
+
return Image(path=image_path)
|
|
193
|
+
except Exception as e:
|
|
194
|
+
logger.warning(
|
|
195
|
+
f"Failed to create FastMCP Image from path {image_path}: {e}"
|
|
196
|
+
)
|
|
197
|
+
return response
|
|
198
|
+
|
|
199
|
+
async def execute_request(
|
|
200
|
+
self,
|
|
201
|
+
method: str,
|
|
202
|
+
params: Optional[Dict[str, Any]] = None,
|
|
203
|
+
timeout: float = 60.0,
|
|
204
|
+
) -> Any:
|
|
205
|
+
"""Execute an RPC request to Unity Editor."""
|
|
206
|
+
if not self._unity_project_root:
|
|
207
|
+
# Try to auto-detect Unity project root
|
|
208
|
+
if not self.auto_detect_unity_project_root():
|
|
209
|
+
# Auto-detection failed, provide helpful error message
|
|
210
|
+
try:
|
|
211
|
+
project_roots = discover_unity_project_roots()
|
|
212
|
+
if len(project_roots) == 0:
|
|
213
|
+
raise NoUnityInstancesError(
|
|
214
|
+
"No Unity Editor instances found. Please start Unity Editor and call set_unity_project_root with the project path."
|
|
215
|
+
)
|
|
216
|
+
else:
|
|
217
|
+
project_list = "\n".join([f" - {root}" for root in project_roots])
|
|
218
|
+
raise MultipleUnityInstancesError(
|
|
219
|
+
f"Multiple Unity Editor instances found. Please call set_unity_project_root with one of these project paths:\n{project_list}",
|
|
220
|
+
project_roots
|
|
221
|
+
)
|
|
222
|
+
except UnityProjectRootError:
|
|
223
|
+
# Re-raise our custom exceptions as-is
|
|
224
|
+
raise
|
|
225
|
+
except Exception as e:
|
|
226
|
+
raise RuntimeError(
|
|
227
|
+
"Unity project root is not set and auto-detection failed. Call set_unity_project_root first."
|
|
228
|
+
) from e
|
|
229
|
+
|
|
230
|
+
requests_dir = (
|
|
231
|
+
Path(self._unity_project_root) / "Temp" / "Coplay" / "MCPRequests"
|
|
232
|
+
)
|
|
233
|
+
if not requests_dir.exists():
|
|
234
|
+
raise RuntimeError(
|
|
235
|
+
"Unity Editor is not running at the specified project root"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
request_id = str(uuid.uuid4())
|
|
239
|
+
request_file = requests_dir / f"req_{request_id}.json"
|
|
240
|
+
|
|
241
|
+
# Create request data
|
|
242
|
+
request_data = {
|
|
243
|
+
"jsonrpc": "2.0",
|
|
244
|
+
"id": request_id,
|
|
245
|
+
"method": method,
|
|
246
|
+
"params": params or {},
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
# Create concurrent.futures.Future for thread-safe completion
|
|
250
|
+
future: concurrent.futures.Future[Any] = concurrent.futures.Future()
|
|
251
|
+
self._pending_requests[request_id] = future
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
# Write request file
|
|
255
|
+
async with aiofiles.open(request_file, "w", encoding="utf-8") as f:
|
|
256
|
+
await f.write(json.dumps(request_data, indent=2))
|
|
257
|
+
|
|
258
|
+
logger.debug(f"Created request file: {request_file}")
|
|
259
|
+
|
|
260
|
+
# Wait for response with timeout using asyncio.wrap_future
|
|
261
|
+
try:
|
|
262
|
+
wrapped_future = asyncio.wrap_future(future)
|
|
263
|
+
result = await asyncio.wait_for(wrapped_future, timeout=timeout)
|
|
264
|
+
|
|
265
|
+
# Post-process response for image functions
|
|
266
|
+
if self._is_image_function(method):
|
|
267
|
+
result = self._process_image_response(result)
|
|
268
|
+
|
|
269
|
+
return result
|
|
270
|
+
except asyncio.TimeoutError:
|
|
271
|
+
raise TimeoutError(
|
|
272
|
+
f"Request {method} timed out after {timeout} seconds"
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
except Exception as e:
|
|
276
|
+
# Clean up on error
|
|
277
|
+
self._pending_requests.pop(request_id, None)
|
|
278
|
+
try:
|
|
279
|
+
if request_file.exists():
|
|
280
|
+
request_file.unlink()
|
|
281
|
+
except Exception:
|
|
282
|
+
pass
|
|
283
|
+
raise e
|
|
284
|
+
|
|
285
|
+
def close(self) -> None:
|
|
286
|
+
"""Close the Unity RPC client and clean up resources."""
|
|
287
|
+
self._stop_file_watcher()
|
|
288
|
+
|
|
289
|
+
# Cancel any pending requests
|
|
290
|
+
for future in self._pending_requests.values():
|
|
291
|
+
if not future.done():
|
|
292
|
+
future.cancel()
|
|
293
|
+
self._pending_requests.clear()
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class ResponseFileHandler(FileSystemEventHandler):
|
|
297
|
+
"""File system event handler for Unity response files."""
|
|
298
|
+
|
|
299
|
+
def __init__(
|
|
300
|
+
self, callback, loop: Optional[asyncio.AbstractEventLoop] = None
|
|
301
|
+
) -> None:
|
|
302
|
+
super().__init__()
|
|
303
|
+
self._callback = callback
|
|
304
|
+
self._loop = loop
|
|
305
|
+
self._processed_files: set[str] = set()
|
|
306
|
+
self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=2)
|
|
307
|
+
|
|
308
|
+
def on_created(self, event) -> None:
|
|
309
|
+
"""Handle file creation events."""
|
|
310
|
+
if event.is_directory:
|
|
311
|
+
return
|
|
312
|
+
|
|
313
|
+
file_path = Path(event.src_path)
|
|
314
|
+
if file_path.name.startswith("response_") and file_path.name.endswith(".json"):
|
|
315
|
+
self._process_file_threadsafe(file_path)
|
|
316
|
+
|
|
317
|
+
def on_modified(self, event) -> None:
|
|
318
|
+
"""Handle file modification events."""
|
|
319
|
+
if event.is_directory:
|
|
320
|
+
return
|
|
321
|
+
|
|
322
|
+
file_path = Path(event.src_path)
|
|
323
|
+
if file_path.name.startswith("response_") and file_path.name.endswith(".json"):
|
|
324
|
+
# Avoid processing the same file multiple times
|
|
325
|
+
if str(file_path) not in self._processed_files:
|
|
326
|
+
self._processed_files.add(str(file_path))
|
|
327
|
+
self._process_file_threadsafe(file_path)
|
|
328
|
+
|
|
329
|
+
def _process_file_threadsafe(self, file_path: Path) -> None:
|
|
330
|
+
"""Process a response file in a thread-safe manner."""
|
|
331
|
+
|
|
332
|
+
def process_with_delay():
|
|
333
|
+
# Small delay to ensure file is fully written
|
|
334
|
+
import time
|
|
335
|
+
|
|
336
|
+
time.sleep(0.1)
|
|
337
|
+
|
|
338
|
+
if file_path.exists():
|
|
339
|
+
self._callback(file_path)
|
|
340
|
+
|
|
341
|
+
# Submit to thread pool to avoid blocking the file watcher
|
|
342
|
+
self._executor.submit(process_with_delay)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: coplay-mcp-server
|
|
3
|
+
Version: 1.4.1
|
|
4
|
+
Summary: A Model Context Protocol (MCP) server for Coplay, providing Unity integration capabilities
|
|
5
|
+
Project-URL: Homepage, https://coplay.dev/
|
|
6
|
+
Project-URL: Repository, https://github.com/CoplayDev/coplay-unity-plugin
|
|
7
|
+
Project-URL: Documentation, https://docs.coplay.dev/
|
|
8
|
+
Project-URL: Issues, https://github.com/CoplayDev/coplay-unity-plugin/issues
|
|
9
|
+
Author-email: Coplay Dev <dev@coplay.com>
|
|
10
|
+
Maintainer-email: Coplay Dev <dev@coplay.com>
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: coplay,mcp,model-context-protocol,unity,unity-editor
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Topic :: Games/Entertainment
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: aiofiles>=24.1.0
|
|
24
|
+
Requires-Dist: anyio>=4.10.0
|
|
25
|
+
Requires-Dist: fastmcp>=2.0.0
|
|
26
|
+
Requires-Dist: psutil>=7.0.0
|
|
27
|
+
Requires-Dist: pydantic>=2.11.7
|
|
28
|
+
Requires-Dist: watchdog>=6.0.0
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# Coplay MCP Server
|
|
32
|
+
|
|
33
|
+
A Model Context Protocol (MCP) server for Coplay, providing Unity Editor integration capabilities through MCP tools.
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- **Schema-Based Tool Registration**: Dynamically registers tools from JSON schema files, ensuring compatibility with Backend's AssistantMode.NORMAL
|
|
38
|
+
- **Unity Project Discovery**: Automatically discover running Unity Editor instances and their project roots
|
|
39
|
+
- **Unity Editor State**: Retrieve current Unity Editor state and scene hierarchy information
|
|
40
|
+
- **Script Execution**: Execute arbitrary C# scripts within the Unity Editor
|
|
41
|
+
- **Log Management**: Access and filter Unity console logs
|
|
42
|
+
- **GameObject Hierarchy**: List and filter GameObjects in the scene hierarchy
|
|
43
|
+
- **Task Creation**: Create new Coplay tasks directly from MCP clients
|
|
44
|
+
- **Parameter Validation**: Automatic parameter validation and type conversion based on tool schemas
|
|
45
|
+
- **Version Compatibility**: Tools are locked to specific schema versions, ensuring compatibility with Unity plugin versions
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
### As an MCP server
|
|
50
|
+
|
|
51
|
+
Add to your MCP client configuration:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"mcpServers": {
|
|
56
|
+
"coplay-mcp": {
|
|
57
|
+
"autoApprove": [],
|
|
58
|
+
"disabled": false,
|
|
59
|
+
"timeout": 60,
|
|
60
|
+
"type": "stdio",
|
|
61
|
+
"command": "uvx",
|
|
62
|
+
"args": [
|
|
63
|
+
"coplay-mcp-server@latest"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
coplay_mcp_server/__init__.py,sha256=S7pbUyOcTUgBTjPhI-Nll37HXJaqgLcjf0rhlb1BrnE,92
|
|
2
|
+
coplay_mcp_server/code_generator.py,sha256=eZhnehQFsE-kMkPVESyzKDLOuTmdnTyX_ZTSljmIj9M,13070
|
|
3
|
+
coplay_mcp_server/image_utils.py,sha256=0IGwazKwkhS95S1LsFweuFOgXH0uHlZtlfqt0547Xbo,2800
|
|
4
|
+
coplay_mcp_server/process_discovery.py,sha256=RnmVPNfYZsJoKGpaZYpxJLbco24_LZlr-oM-zQ3lXkg,5983
|
|
5
|
+
coplay_mcp_server/server.py,sha256=lHG85J55bPu8Cdx_BojHvCdpi2udTB_UflOOpdFWz3M,7626
|
|
6
|
+
coplay_mcp_server/unity_client.py,sha256=apjP7-icQFuMP8vNzAZdMFu-HNJbSNT0vXTthwX-vus,12959
|
|
7
|
+
coplay_mcp_server/generated_tools/.gitignore,sha256=TlBJtSSzMbAK1WY8wWpckwcbQjWH1JpsI6-5dJ8ve_g,103
|
|
8
|
+
coplay_mcp_server/generated_tools/__init__.py,sha256=WzV0HQqurRGPjGJi1bUboLIYafTd_QFqegcM-iL557k,159
|
|
9
|
+
coplay_mcp_server/generated_tools/agent_tool_tools.py,sha256=coWVRszqrk2BrmjXhWsnYmwCMBvAEACUjhBGM6S7GP8,13161
|
|
10
|
+
coplay_mcp_server/generated_tools/coplay_tool_tools.py,sha256=REyx3cLHJ1MzElhmM5JEsFZZRD0nV8dH1D7vDE9ADNM,2151
|
|
11
|
+
coplay_mcp_server/generated_tools/image_tool_tools.py,sha256=WGbKcTqejJxPSJvKa3GzlGPsFnjrrBHF0HifmfFnDQU,6079
|
|
12
|
+
coplay_mcp_server/generated_tools/input_action_tool_tools.py,sha256=zuDJjnVGqYSOLErZUMj0d3QM1-nQXLEomk7s3iOF4eU,22979
|
|
13
|
+
coplay_mcp_server/generated_tools/package_tool_tools.py,sha256=7-rbM3yLgjbomHhSwLapPqWWhJJG62N7E3_Oc7n8PHA,7865
|
|
14
|
+
coplay_mcp_server/generated_tools/profiler_functions_tools.py,sha256=lXW8-ms8VKcsRlkOmRfjmFouJvGAT9b57D8Y4eOhW48,2250
|
|
15
|
+
coplay_mcp_server/generated_tools/scene_view_functions_tools.py,sha256=QOU0-BuU_Ey-rvuT-OspmDZywFnKA0P51LYAp4hFJVI,2103
|
|
16
|
+
coplay_mcp_server/generated_tools/screenshot_tool_tools.py,sha256=IOc1pPTJheG40JqK-0AmGVdYTsMUNnoRSRSc_Fn9qA8,3582
|
|
17
|
+
coplay_mcp_server/generated_tools/snapping_functions_tools.py,sha256=7iAz5C_CEQb5VON9TlbKK8NaKPNxgDA8LDndUrE4RhM,14956
|
|
18
|
+
coplay_mcp_server/generated_tools/ui_functions_tools.py,sha256=wTEvi0xc2chk9Ta3hyWCwRyalksDpXaWIFuYzpigVPo,14454
|
|
19
|
+
coplay_mcp_server/generated_tools/unity_functions_tools.py,sha256=QkQswrZQxDrnyLO-d4QMmGY6i8bY08C_P3Zd1Lipef8,59290
|
|
20
|
+
coplay_mcp_server-1.4.1.dist-info/METADATA,sha256=6PtqXCH-wEaADDpmV9eu9CUTOZi7BZ4KqEyOTcerWT0,2571
|
|
21
|
+
coplay_mcp_server-1.4.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
22
|
+
coplay_mcp_server-1.4.1.dist-info/entry_points.txt,sha256=SKRD69ycL3CtXfaBghc8QIicPFCvO5XzqDyUSn25Eqs,130
|
|
23
|
+
coplay_mcp_server-1.4.1.dist-info/licenses/LICENSE,sha256=JOvqcPTq0pJwgFmq0GSYUZOvZu4rPfmiRG20bGTlx6o,1067
|
|
24
|
+
coplay_mcp_server-1.4.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Coplay Dev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|