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.
- cli/__init__.py +3 -0
- cli/commands/__init__.py +3 -0
- cli/commands/animation.py +87 -0
- cli/commands/asset.py +310 -0
- cli/commands/audio.py +133 -0
- cli/commands/batch.py +184 -0
- cli/commands/code.py +189 -0
- cli/commands/component.py +212 -0
- cli/commands/editor.py +487 -0
- cli/commands/gameobject.py +510 -0
- cli/commands/instance.py +101 -0
- cli/commands/lighting.py +128 -0
- cli/commands/material.py +268 -0
- cli/commands/prefab.py +144 -0
- cli/commands/scene.py +255 -0
- cli/commands/script.py +240 -0
- cli/commands/shader.py +238 -0
- cli/commands/ui.py +263 -0
- cli/commands/vfx.py +439 -0
- cli/main.py +248 -0
- cli/utils/__init__.py +31 -0
- cli/utils/config.py +58 -0
- cli/utils/connection.py +191 -0
- cli/utils/output.py +195 -0
- main.py +207 -62
- {mcpforunityserver-8.5.0.dist-info → mcpforunityserver-9.1.0.dist-info}/METADATA +4 -2
- mcpforunityserver-9.1.0.dist-info/RECORD +96 -0
- {mcpforunityserver-8.5.0.dist-info → mcpforunityserver-9.1.0.dist-info}/WHEEL +1 -1
- {mcpforunityserver-8.5.0.dist-info → mcpforunityserver-9.1.0.dist-info}/entry_points.txt +1 -0
- {mcpforunityserver-8.5.0.dist-info → mcpforunityserver-9.1.0.dist-info}/top_level.txt +1 -2
- services/custom_tool_service.py +179 -19
- services/resources/__init__.py +6 -1
- services/resources/active_tool.py +1 -1
- services/resources/custom_tools.py +2 -2
- services/resources/editor_state.py +283 -21
- services/resources/gameobject.py +243 -0
- services/resources/layers.py +1 -1
- services/resources/prefab_stage.py +1 -1
- services/resources/project_info.py +1 -1
- services/resources/selection.py +1 -1
- services/resources/tags.py +1 -1
- services/resources/unity_instances.py +1 -1
- services/resources/windows.py +1 -1
- services/state/external_changes_scanner.py +245 -0
- services/tools/__init__.py +6 -1
- services/tools/batch_execute.py +24 -9
- services/tools/debug_request_context.py +8 -2
- services/tools/execute_custom_tool.py +6 -1
- services/tools/execute_menu_item.py +6 -3
- services/tools/find_gameobjects.py +89 -0
- services/tools/find_in_file.py +26 -19
- services/tools/manage_asset.py +19 -43
- services/tools/manage_components.py +131 -0
- services/tools/manage_editor.py +9 -8
- services/tools/manage_gameobject.py +120 -79
- services/tools/manage_material.py +80 -31
- services/tools/manage_prefabs.py +7 -1
- services/tools/manage_scene.py +34 -13
- services/tools/manage_script.py +62 -19
- services/tools/manage_scriptable_object.py +22 -10
- services/tools/manage_shader.py +8 -1
- services/tools/manage_vfx.py +738 -0
- services/tools/preflight.py +110 -0
- services/tools/read_console.py +81 -18
- services/tools/refresh_unity.py +153 -0
- services/tools/run_tests.py +202 -41
- services/tools/script_apply_edits.py +15 -7
- services/tools/set_active_instance.py +12 -7
- services/tools/utils.py +60 -6
- transport/legacy/port_discovery.py +2 -2
- transport/legacy/unity_connection.py +129 -26
- transport/plugin_hub.py +191 -19
- transport/unity_instance_middleware.py +93 -2
- transport/unity_transport.py +17 -6
- utils/focus_nudge.py +321 -0
- __init__.py +0 -0
- mcpforunityserver-8.5.0.dist-info/RECORD +0 -66
- routes/__init__.py +0 -0
- {mcpforunityserver-8.5.0.dist-info → mcpforunityserver-9.1.0.dist-info}/licenses/LICENSE +0 -0
services/tools/manage_script.py
CHANGED
|
@@ -4,6 +4,7 @@ from typing import Annotated, Any, Literal
|
|
|
4
4
|
from urllib.parse import urlparse, unquote
|
|
5
5
|
|
|
6
6
|
from fastmcp import FastMCP, Context
|
|
7
|
+
from mcp.types import ToolAnnotations
|
|
7
8
|
|
|
8
9
|
from services.registry import mcp_for_unity_tool
|
|
9
10
|
from services.tools import get_unity_instance_from_context
|
|
@@ -15,7 +16,7 @@ def _split_uri(uri: str) -> tuple[str, str]:
|
|
|
15
16
|
"""Split an incoming URI or path into (name, directory) suitable for Unity.
|
|
16
17
|
|
|
17
18
|
Rules:
|
|
18
|
-
-
|
|
19
|
+
- mcpforunity://path/Assets/... → keep as Assets-relative (after decode/normalize)
|
|
19
20
|
- file://... → percent-decode, normalize, strip host and leading slashes,
|
|
20
21
|
then, if any 'Assets' segment exists, return path relative to that 'Assets' root.
|
|
21
22
|
Otherwise, fall back to original name/dir behavior.
|
|
@@ -23,8 +24,8 @@ def _split_uri(uri: str) -> tuple[str, str]:
|
|
|
23
24
|
return relative to 'Assets'.
|
|
24
25
|
"""
|
|
25
26
|
raw_path: str
|
|
26
|
-
if uri.startswith("
|
|
27
|
-
raw_path = uri[len("
|
|
27
|
+
if uri.startswith("mcpforunity://path/"):
|
|
28
|
+
raw_path = uri[len("mcpforunity://path/"):]
|
|
28
29
|
elif uri.startswith("file://"):
|
|
29
30
|
parsed = urlparse(uri)
|
|
30
31
|
host = (parsed.netloc or "").strip()
|
|
@@ -63,8 +64,9 @@ def _split_uri(uri: str) -> tuple[str, str]:
|
|
|
63
64
|
return name, directory
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
@mcp_for_unity_tool(
|
|
67
|
-
|
|
67
|
+
@mcp_for_unity_tool(
|
|
68
|
+
description=(
|
|
69
|
+
"""Apply small text edits to a C# script identified by URI.
|
|
68
70
|
IMPORTANT: This tool replaces EXACT character positions. Always verify content at target lines/columns BEFORE editing!
|
|
69
71
|
RECOMMENDED WORKFLOW:
|
|
70
72
|
1. First call resources/read with start_line/line_count to verify exact content
|
|
@@ -76,10 +78,15 @@ def _split_uri(uri: str) -> tuple[str, str]:
|
|
|
76
78
|
- For pattern-based replacements, consider anchor operations in script_apply_edits
|
|
77
79
|
- Lines, columns are 1-indexed
|
|
78
80
|
- Tabs count as 1 column"""
|
|
79
|
-
)
|
|
81
|
+
),
|
|
82
|
+
annotations=ToolAnnotations(
|
|
83
|
+
title="Apply Text Edits",
|
|
84
|
+
destructiveHint=True,
|
|
85
|
+
),
|
|
86
|
+
)
|
|
80
87
|
async def apply_text_edits(
|
|
81
88
|
ctx: Context,
|
|
82
|
-
uri: Annotated[str, "URI of the script to edit under Assets/ directory,
|
|
89
|
+
uri: Annotated[str, "URI of the script to edit under Assets/ directory, mcpforunity://path/Assets/... or file://... or Assets/..."],
|
|
83
90
|
edits: Annotated[list[dict[str, Any]], "List of edits to apply to the script, i.e. a list of {startLine,startCol,endLine,endCol,newText} (1-indexed!)"],
|
|
84
91
|
precondition_sha256: Annotated[str,
|
|
85
92
|
"Optional SHA256 of the script to edit, used to prevent concurrent edits"] | None = None,
|
|
@@ -367,7 +374,13 @@ async def apply_text_edits(
|
|
|
367
374
|
return {"success": False, "message": str(resp)}
|
|
368
375
|
|
|
369
376
|
|
|
370
|
-
@mcp_for_unity_tool(
|
|
377
|
+
@mcp_for_unity_tool(
|
|
378
|
+
description="Create a new C# script at the given project path.",
|
|
379
|
+
annotations=ToolAnnotations(
|
|
380
|
+
title="Create Script",
|
|
381
|
+
destructiveHint=True,
|
|
382
|
+
),
|
|
383
|
+
)
|
|
371
384
|
async def create_script(
|
|
372
385
|
ctx: Context,
|
|
373
386
|
path: Annotated[str, "Path under Assets/ to create the script at, e.g., 'Assets/Scripts/My.cs'"],
|
|
@@ -412,10 +425,16 @@ async def create_script(
|
|
|
412
425
|
return resp if isinstance(resp, dict) else {"success": False, "message": str(resp)}
|
|
413
426
|
|
|
414
427
|
|
|
415
|
-
@mcp_for_unity_tool(
|
|
428
|
+
@mcp_for_unity_tool(
|
|
429
|
+
description="Delete a C# script by URI or Assets-relative path.",
|
|
430
|
+
annotations=ToolAnnotations(
|
|
431
|
+
title="Delete Script",
|
|
432
|
+
destructiveHint=True,
|
|
433
|
+
),
|
|
434
|
+
)
|
|
416
435
|
async def delete_script(
|
|
417
436
|
ctx: Context,
|
|
418
|
-
uri: Annotated[str, "URI of the script to delete under Assets/ directory,
|
|
437
|
+
uri: Annotated[str, "URI of the script to delete under Assets/ directory, mcpforunity://path/Assets/... or file://... or Assets/..."],
|
|
419
438
|
) -> dict[str, Any]:
|
|
420
439
|
"""Delete a C# script by URI."""
|
|
421
440
|
unity_instance = get_unity_instance_from_context(ctx)
|
|
@@ -434,10 +453,16 @@ async def delete_script(
|
|
|
434
453
|
return resp if isinstance(resp, dict) else {"success": False, "message": str(resp)}
|
|
435
454
|
|
|
436
455
|
|
|
437
|
-
@mcp_for_unity_tool(
|
|
456
|
+
@mcp_for_unity_tool(
|
|
457
|
+
description="Validate a C# script and return diagnostics.",
|
|
458
|
+
annotations=ToolAnnotations(
|
|
459
|
+
title="Validate Script",
|
|
460
|
+
readOnlyHint=True,
|
|
461
|
+
),
|
|
462
|
+
)
|
|
438
463
|
async def validate_script(
|
|
439
464
|
ctx: Context,
|
|
440
|
-
uri: Annotated[str, "URI of the script to validate under Assets/ directory,
|
|
465
|
+
uri: Annotated[str, "URI of the script to validate under Assets/ directory, mcpforunity://path/Assets/... or file://... or Assets/..."],
|
|
441
466
|
level: Annotated[Literal['basic', 'standard'],
|
|
442
467
|
"Validation level"] = "basic",
|
|
443
468
|
include_diagnostics: Annotated[bool,
|
|
@@ -475,14 +500,20 @@ async def validate_script(
|
|
|
475
500
|
return resp if isinstance(resp, dict) else {"success": False, "message": str(resp)}
|
|
476
501
|
|
|
477
502
|
|
|
478
|
-
@mcp_for_unity_tool(
|
|
503
|
+
@mcp_for_unity_tool(
|
|
504
|
+
description="Compatibility router for legacy script operations. Prefer apply_text_edits (ranges) or script_apply_edits (structured) for edits. Read-only action: read. Modifying actions: create, delete.",
|
|
505
|
+
annotations=ToolAnnotations(
|
|
506
|
+
title="Manage Script",
|
|
507
|
+
destructiveHint=True,
|
|
508
|
+
),
|
|
509
|
+
)
|
|
479
510
|
async def manage_script(
|
|
480
511
|
ctx: Context,
|
|
481
512
|
action: Annotated[Literal['create', 'read', 'delete'], "Perform CRUD operations on C# scripts."],
|
|
482
513
|
name: Annotated[str, "Script name (no .cs extension)", "Name of the script to create"],
|
|
483
514
|
path: Annotated[str, "Asset path (default: 'Assets/')", "Path under Assets/ to create the script at, e.g., 'Assets/Scripts/My.cs'"],
|
|
484
515
|
contents: Annotated[str, "Contents of the script to create",
|
|
485
|
-
"C# code for 'create'
|
|
516
|
+
"C# code for 'create' action"] | None = None,
|
|
486
517
|
script_type: Annotated[str, "Script type (e.g., 'C#')",
|
|
487
518
|
"Type hint (e.g., 'MonoBehaviour')"] | None = None,
|
|
488
519
|
namespace: Annotated[str, "Namespace for the script"] | None = None,
|
|
@@ -543,14 +574,20 @@ async def manage_script(
|
|
|
543
574
|
}
|
|
544
575
|
|
|
545
576
|
|
|
546
|
-
@mcp_for_unity_tool(
|
|
547
|
-
|
|
577
|
+
@mcp_for_unity_tool(
|
|
578
|
+
description=(
|
|
579
|
+
"""Get manage_script capabilities (supported ops, limits, and guards).
|
|
548
580
|
Returns:
|
|
549
581
|
- ops: list of supported structured ops
|
|
550
582
|
- text_ops: list of supported text ops
|
|
551
583
|
- max_edit_payload_bytes: server edit payload cap
|
|
552
584
|
- guards: header/using guard enabled flag"""
|
|
553
|
-
)
|
|
585
|
+
),
|
|
586
|
+
annotations=ToolAnnotations(
|
|
587
|
+
title="Manage Script Capabilities",
|
|
588
|
+
readOnlyHint=True,
|
|
589
|
+
),
|
|
590
|
+
)
|
|
554
591
|
async def manage_script_capabilities(ctx: Context) -> dict[str, Any]:
|
|
555
592
|
await ctx.info("Processing manage_script_capabilities")
|
|
556
593
|
try:
|
|
@@ -575,10 +612,16 @@ async def manage_script_capabilities(ctx: Context) -> dict[str, Any]:
|
|
|
575
612
|
return {"success": False, "error": f"capabilities error: {e}"}
|
|
576
613
|
|
|
577
614
|
|
|
578
|
-
@mcp_for_unity_tool(
|
|
615
|
+
@mcp_for_unity_tool(
|
|
616
|
+
description="Get SHA256 and basic metadata for a Unity C# script without returning file contents",
|
|
617
|
+
annotations=ToolAnnotations(
|
|
618
|
+
title="Get SHA",
|
|
619
|
+
readOnlyHint=True,
|
|
620
|
+
),
|
|
621
|
+
)
|
|
579
622
|
async def get_sha(
|
|
580
623
|
ctx: Context,
|
|
581
|
-
uri: Annotated[str, "URI of the script to edit under Assets/ directory,
|
|
624
|
+
uri: Annotated[str, "URI of the script to edit under Assets/ directory, mcpforunity://path/Assets/... or file://... or Assets/..."],
|
|
582
625
|
) -> dict[str, Any]:
|
|
583
626
|
unity_instance = get_unity_instance_from_context(ctx)
|
|
584
627
|
await ctx.info(
|
|
@@ -13,6 +13,7 @@ from __future__ import annotations
|
|
|
13
13
|
from typing import Annotated, Any, Literal
|
|
14
14
|
|
|
15
15
|
from fastmcp import Context
|
|
16
|
+
from mcp.types import ToolAnnotations
|
|
16
17
|
|
|
17
18
|
from services.registry import mcp_for_unity_tool
|
|
18
19
|
from services.tools import get_unity_instance_from_context
|
|
@@ -22,20 +23,33 @@ from transport.legacy.unity_connection import async_send_command_with_retry
|
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
@mcp_for_unity_tool(
|
|
25
|
-
description="Creates and modifies ScriptableObject assets using Unity SerializedObject property paths."
|
|
26
|
+
description="Creates and modifies ScriptableObject assets using Unity SerializedObject property paths.",
|
|
27
|
+
annotations=ToolAnnotations(
|
|
28
|
+
title="Manage Scriptable Object",
|
|
29
|
+
destructiveHint=True,
|
|
30
|
+
),
|
|
26
31
|
)
|
|
27
32
|
async def manage_scriptable_object(
|
|
28
33
|
ctx: Context,
|
|
29
34
|
action: Annotated[Literal["create", "modify"], "Action to perform: create or modify."],
|
|
30
35
|
# --- create params ---
|
|
31
|
-
type_name: Annotated[str | None,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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,
|
|
35
44
|
# --- modify params ---
|
|
36
|
-
target: Annotated[dict[str, Any] | str | None,
|
|
45
|
+
target: Annotated[dict[str, Any] | str | None,
|
|
46
|
+
"Target asset reference {guid|path} (for modify)."] = None,
|
|
37
47
|
# --- shared ---
|
|
38
|
-
patches: Annotated[list[dict[str, Any]] | str | None,
|
|
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,
|
|
39
53
|
) -> dict[str, Any]:
|
|
40
54
|
unity_instance = get_unity_instance_from_context(ctx)
|
|
41
55
|
|
|
@@ -57,6 +71,7 @@ async def manage_scriptable_object(
|
|
|
57
71
|
"overwrite": coerce_bool(overwrite, default=None),
|
|
58
72
|
"target": parsed_target,
|
|
59
73
|
"patches": parsed_patches,
|
|
74
|
+
"dryRun": coerce_bool(dry_run, default=None),
|
|
60
75
|
}
|
|
61
76
|
|
|
62
77
|
# Remove None values to keep Unity handler simpler
|
|
@@ -70,6 +85,3 @@ async def manage_scriptable_object(
|
|
|
70
85
|
)
|
|
71
86
|
await ctx.info(f"Response {response}")
|
|
72
87
|
return response if isinstance(response, dict) else {"success": False, "message": "Unexpected response from Unity."}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
services/tools/manage_shader.py
CHANGED
|
@@ -2,6 +2,8 @@ import base64
|
|
|
2
2
|
from typing import Annotated, Any, Literal
|
|
3
3
|
|
|
4
4
|
from fastmcp import Context
|
|
5
|
+
from mcp.types import ToolAnnotations
|
|
6
|
+
|
|
5
7
|
from services.registry import mcp_for_unity_tool
|
|
6
8
|
from services.tools import get_unity_instance_from_context
|
|
7
9
|
from transport.unity_transport import send_with_unity_instance
|
|
@@ -9,7 +11,12 @@ from transport.legacy.unity_connection import async_send_command_with_retry
|
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
@mcp_for_unity_tool(
|
|
12
|
-
description="Manages shader scripts in Unity (create, read, update, delete)."
|
|
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
|
+
),
|
|
13
20
|
)
|
|
14
21
|
async def manage_shader(
|
|
15
22
|
ctx: Context,
|