mcpforunityserver 9.4.0b20260203025228__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.
- cli/__init__.py +3 -0
- cli/commands/__init__.py +3 -0
- cli/commands/animation.py +84 -0
- cli/commands/asset.py +280 -0
- cli/commands/audio.py +125 -0
- cli/commands/batch.py +171 -0
- cli/commands/code.py +182 -0
- cli/commands/component.py +190 -0
- cli/commands/editor.py +447 -0
- cli/commands/gameobject.py +487 -0
- cli/commands/instance.py +93 -0
- cli/commands/lighting.py +123 -0
- cli/commands/material.py +239 -0
- cli/commands/prefab.py +248 -0
- cli/commands/scene.py +231 -0
- cli/commands/script.py +222 -0
- cli/commands/shader.py +226 -0
- cli/commands/texture.py +540 -0
- cli/commands/tool.py +58 -0
- cli/commands/ui.py +258 -0
- cli/commands/vfx.py +421 -0
- cli/main.py +281 -0
- cli/utils/__init__.py +31 -0
- cli/utils/config.py +58 -0
- cli/utils/confirmation.py +37 -0
- cli/utils/connection.py +254 -0
- cli/utils/constants.py +23 -0
- cli/utils/output.py +195 -0
- cli/utils/parsers.py +112 -0
- cli/utils/suggestions.py +34 -0
- core/__init__.py +0 -0
- core/config.py +67 -0
- core/constants.py +4 -0
- core/logging_decorator.py +37 -0
- core/telemetry.py +551 -0
- core/telemetry_decorator.py +164 -0
- main.py +845 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/METADATA +328 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/RECORD +105 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/WHEEL +5 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/entry_points.txt +3 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/licenses/LICENSE +21 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/top_level.txt +7 -0
- models/__init__.py +4 -0
- models/models.py +56 -0
- models/unity_response.py +70 -0
- services/__init__.py +0 -0
- services/api_key_service.py +235 -0
- services/custom_tool_service.py +499 -0
- services/registry/__init__.py +22 -0
- services/registry/resource_registry.py +53 -0
- services/registry/tool_registry.py +51 -0
- services/resources/__init__.py +86 -0
- services/resources/active_tool.py +48 -0
- services/resources/custom_tools.py +57 -0
- services/resources/editor_state.py +304 -0
- services/resources/gameobject.py +243 -0
- services/resources/layers.py +30 -0
- services/resources/menu_items.py +35 -0
- services/resources/prefab.py +191 -0
- services/resources/prefab_stage.py +40 -0
- services/resources/project_info.py +40 -0
- services/resources/selection.py +56 -0
- services/resources/tags.py +31 -0
- services/resources/tests.py +88 -0
- services/resources/unity_instances.py +125 -0
- services/resources/windows.py +48 -0
- services/state/external_changes_scanner.py +245 -0
- services/tools/__init__.py +83 -0
- services/tools/batch_execute.py +93 -0
- services/tools/debug_request_context.py +86 -0
- services/tools/execute_custom_tool.py +43 -0
- services/tools/execute_menu_item.py +32 -0
- services/tools/find_gameobjects.py +110 -0
- services/tools/find_in_file.py +181 -0
- services/tools/manage_asset.py +119 -0
- services/tools/manage_components.py +131 -0
- services/tools/manage_editor.py +64 -0
- services/tools/manage_gameobject.py +260 -0
- services/tools/manage_material.py +111 -0
- services/tools/manage_prefabs.py +209 -0
- services/tools/manage_scene.py +111 -0
- services/tools/manage_script.py +645 -0
- services/tools/manage_scriptable_object.py +87 -0
- services/tools/manage_shader.py +71 -0
- services/tools/manage_texture.py +581 -0
- services/tools/manage_vfx.py +120 -0
- services/tools/preflight.py +110 -0
- services/tools/read_console.py +151 -0
- services/tools/refresh_unity.py +153 -0
- services/tools/run_tests.py +317 -0
- services/tools/script_apply_edits.py +1006 -0
- services/tools/set_active_instance.py +120 -0
- services/tools/utils.py +348 -0
- transport/__init__.py +0 -0
- transport/legacy/port_discovery.py +329 -0
- transport/legacy/stdio_port_registry.py +65 -0
- transport/legacy/unity_connection.py +910 -0
- transport/models.py +68 -0
- transport/plugin_hub.py +787 -0
- transport/plugin_registry.py +182 -0
- transport/unity_instance_middleware.py +262 -0
- transport/unity_transport.py +94 -0
- utils/focus_nudge.py +589 -0
- utils/module_discovery.py +55 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool wrapper for managing ScriptableObject assets via Unity MCP.
|
|
3
|
+
|
|
4
|
+
Unity-side handler: MCPForUnity.Editor.Tools.ManageScriptableObject
|
|
5
|
+
Command name: "manage_scriptable_object"
|
|
6
|
+
Actions:
|
|
7
|
+
- create: create an SO asset (optionally with patches)
|
|
8
|
+
- modify: apply serialized property patches to an existing SO asset
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Annotated, Any, Literal
|
|
14
|
+
|
|
15
|
+
from fastmcp import Context
|
|
16
|
+
from mcp.types import ToolAnnotations
|
|
17
|
+
|
|
18
|
+
from services.registry import mcp_for_unity_tool
|
|
19
|
+
from services.tools import get_unity_instance_from_context
|
|
20
|
+
from services.tools.utils import coerce_bool, parse_json_payload
|
|
21
|
+
from transport.unity_transport import send_with_unity_instance
|
|
22
|
+
from transport.legacy.unity_connection import async_send_command_with_retry
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@mcp_for_unity_tool(
|
|
26
|
+
description="Creates and modifies ScriptableObject assets using Unity SerializedObject property paths.",
|
|
27
|
+
annotations=ToolAnnotations(
|
|
28
|
+
title="Manage Scriptable Object",
|
|
29
|
+
destructiveHint=True,
|
|
30
|
+
),
|
|
31
|
+
)
|
|
32
|
+
async def manage_scriptable_object(
|
|
33
|
+
ctx: Context,
|
|
34
|
+
action: Annotated[Literal["create", "modify"], "Action to perform: create or modify."],
|
|
35
|
+
# --- create params ---
|
|
36
|
+
type_name: Annotated[str | None,
|
|
37
|
+
"Namespace-qualified ScriptableObject type name (for create)."] = None,
|
|
38
|
+
folder_path: Annotated[str | None,
|
|
39
|
+
"Target folder under Assets/... (for create)."] = None,
|
|
40
|
+
asset_name: Annotated[str | None,
|
|
41
|
+
"Asset file name without extension (for create)."] = None,
|
|
42
|
+
overwrite: Annotated[bool | str | None,
|
|
43
|
+
"If true, overwrite existing asset at same path (for create)."] = None,
|
|
44
|
+
# --- modify params ---
|
|
45
|
+
target: Annotated[dict[str, Any] | str | None,
|
|
46
|
+
"Target asset reference {guid|path} (for modify)."] = None,
|
|
47
|
+
# --- shared ---
|
|
48
|
+
patches: Annotated[list[dict[str, Any]] | str | None,
|
|
49
|
+
"Patch list (or JSON string) to apply."] = None,
|
|
50
|
+
# --- validation ---
|
|
51
|
+
dry_run: Annotated[bool | str | None,
|
|
52
|
+
"If true, validate patches without applying (modify only)."] = None,
|
|
53
|
+
) -> dict[str, Any]:
|
|
54
|
+
unity_instance = get_unity_instance_from_context(ctx)
|
|
55
|
+
|
|
56
|
+
# Tolerate JSON-string payloads (LLMs sometimes stringify complex objects)
|
|
57
|
+
parsed_target = parse_json_payload(target)
|
|
58
|
+
parsed_patches = parse_json_payload(patches)
|
|
59
|
+
|
|
60
|
+
if parsed_target is not None and not isinstance(parsed_target, dict):
|
|
61
|
+
return {"success": False, "message": "manage_scriptable_object: 'target' must be an object {guid|path} (or JSON string of such)."}
|
|
62
|
+
|
|
63
|
+
if parsed_patches is not None and not isinstance(parsed_patches, list):
|
|
64
|
+
return {"success": False, "message": "manage_scriptable_object: 'patches' must be a list (or JSON string of a list)."}
|
|
65
|
+
|
|
66
|
+
params: dict[str, Any] = {
|
|
67
|
+
"action": action,
|
|
68
|
+
"typeName": type_name,
|
|
69
|
+
"folderPath": folder_path,
|
|
70
|
+
"assetName": asset_name,
|
|
71
|
+
"overwrite": coerce_bool(overwrite, default=None),
|
|
72
|
+
"target": parsed_target,
|
|
73
|
+
"patches": parsed_patches,
|
|
74
|
+
"dryRun": coerce_bool(dry_run, default=None),
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Remove None values to keep Unity handler simpler
|
|
78
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
79
|
+
|
|
80
|
+
response = await send_with_unity_instance(
|
|
81
|
+
async_send_command_with_retry,
|
|
82
|
+
unity_instance,
|
|
83
|
+
"manage_scriptable_object",
|
|
84
|
+
params,
|
|
85
|
+
)
|
|
86
|
+
await ctx.info(f"Response {response}")
|
|
87
|
+
return response if isinstance(response, dict) else {"success": False, "message": "Unexpected response from Unity."}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
from typing import Annotated, Any, Literal
|
|
3
|
+
|
|
4
|
+
from fastmcp import Context
|
|
5
|
+
from mcp.types import ToolAnnotations
|
|
6
|
+
|
|
7
|
+
from services.registry import mcp_for_unity_tool
|
|
8
|
+
from services.tools import get_unity_instance_from_context
|
|
9
|
+
from transport.unity_transport import send_with_unity_instance
|
|
10
|
+
from transport.legacy.unity_connection import async_send_command_with_retry
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@mcp_for_unity_tool(
|
|
14
|
+
description="Manages shader scripts in Unity (create, read, update, delete). Read-only action: read. Modifying actions: create, update, delete.",
|
|
15
|
+
annotations=ToolAnnotations(
|
|
16
|
+
title="Manage Shader",
|
|
17
|
+
# Note: 'read' action is non-destructive; 'create', 'update', 'delete' are destructive
|
|
18
|
+
destructiveHint=True,
|
|
19
|
+
),
|
|
20
|
+
)
|
|
21
|
+
async def manage_shader(
|
|
22
|
+
ctx: Context,
|
|
23
|
+
action: Annotated[Literal['create', 'read', 'update', 'delete'], "Perform CRUD operations on shader scripts."],
|
|
24
|
+
name: Annotated[str, "Shader name (no .cs extension)"],
|
|
25
|
+
path: Annotated[str, "Asset path (default: \"Assets/\")"],
|
|
26
|
+
contents: Annotated[str,
|
|
27
|
+
"Shader code for 'create'/'update'"] | None = None,
|
|
28
|
+
) -> dict[str, Any]:
|
|
29
|
+
# Get active instance from session state
|
|
30
|
+
# Removed session_state import
|
|
31
|
+
unity_instance = get_unity_instance_from_context(ctx)
|
|
32
|
+
try:
|
|
33
|
+
# Prepare parameters for Unity
|
|
34
|
+
params = {
|
|
35
|
+
"action": action,
|
|
36
|
+
"name": name,
|
|
37
|
+
"path": path,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Base64 encode the contents if they exist to avoid JSON escaping issues
|
|
41
|
+
if contents is not None:
|
|
42
|
+
if action in ['create', 'update']:
|
|
43
|
+
# Encode content for safer transmission
|
|
44
|
+
params["encodedContents"] = base64.b64encode(
|
|
45
|
+
contents.encode('utf-8')).decode('utf-8')
|
|
46
|
+
params["contentsEncoded"] = True
|
|
47
|
+
else:
|
|
48
|
+
params["contents"] = contents
|
|
49
|
+
|
|
50
|
+
# Remove None values so they don't get sent as null
|
|
51
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
52
|
+
|
|
53
|
+
# Send command via centralized retry helper with instance routing
|
|
54
|
+
response = await send_with_unity_instance(async_send_command_with_retry, unity_instance, "manage_shader", params)
|
|
55
|
+
|
|
56
|
+
# Process response from Unity
|
|
57
|
+
if isinstance(response, dict) and response.get("success"):
|
|
58
|
+
# If the response contains base64 encoded content, decode it
|
|
59
|
+
if response.get("data", {}).get("contentsEncoded"):
|
|
60
|
+
decoded_contents = base64.b64decode(
|
|
61
|
+
response["data"]["encodedContents"]).decode('utf-8')
|
|
62
|
+
response["data"]["contents"] = decoded_contents
|
|
63
|
+
del response["data"]["encodedContents"]
|
|
64
|
+
del response["data"]["contentsEncoded"]
|
|
65
|
+
|
|
66
|
+
return {"success": True, "message": response.get("message", "Operation successful."), "data": response.get("data")}
|
|
67
|
+
return response if isinstance(response, dict) else {"success": False, "message": str(response)}
|
|
68
|
+
|
|
69
|
+
except Exception as e:
|
|
70
|
+
# Handle Python-side errors (e.g., connection issues)
|
|
71
|
+
return {"success": False, "message": f"Python error managing shader: {str(e)}"}
|