@akiojin/unity-mcp-server 2.14.14

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 (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +206 -0
  3. package/bin/unity-mcp-server +2 -0
  4. package/package.json +73 -0
  5. package/src/core/codeIndex.js +163 -0
  6. package/src/core/codeIndexDb.js +96 -0
  7. package/src/core/config.js +165 -0
  8. package/src/core/indexWatcher.js +52 -0
  9. package/src/core/projectInfo.js +111 -0
  10. package/src/core/server.js +294 -0
  11. package/src/core/unityConnection.js +426 -0
  12. package/src/handlers/analysis/AnalyzeSceneContentsToolHandler.js +35 -0
  13. package/src/handlers/analysis/FindByComponentToolHandler.js +20 -0
  14. package/src/handlers/analysis/GetAnimatorStateToolHandler.js +37 -0
  15. package/src/handlers/analysis/GetComponentValuesToolHandler.js +20 -0
  16. package/src/handlers/analysis/GetGameObjectDetailsToolHandler.js +35 -0
  17. package/src/handlers/analysis/GetInputActionsStateToolHandler.js +37 -0
  18. package/src/handlers/analysis/GetObjectReferencesToolHandler.js +20 -0
  19. package/src/handlers/asset/AssetDatabaseToolHandler.js +221 -0
  20. package/src/handlers/asset/AssetDependencyToolHandler.js +201 -0
  21. package/src/handlers/asset/AssetImportSettingsToolHandler.js +170 -0
  22. package/src/handlers/asset/CreateMaterialToolHandler.js +96 -0
  23. package/src/handlers/asset/CreatePrefabToolHandler.js +78 -0
  24. package/src/handlers/asset/ExitPrefabModeToolHandler.js +83 -0
  25. package/src/handlers/asset/InstantiatePrefabToolHandler.js +133 -0
  26. package/src/handlers/asset/ModifyMaterialToolHandler.js +76 -0
  27. package/src/handlers/asset/ModifyPrefabToolHandler.js +72 -0
  28. package/src/handlers/asset/OpenPrefabToolHandler.js +121 -0
  29. package/src/handlers/asset/SavePrefabToolHandler.js +106 -0
  30. package/src/handlers/base/BaseToolHandler.js +133 -0
  31. package/src/handlers/compilation/GetCompilationStateToolHandler.js +90 -0
  32. package/src/handlers/component/AddComponentToolHandler.js +126 -0
  33. package/src/handlers/component/GetComponentTypesToolHandler.js +100 -0
  34. package/src/handlers/component/ListComponentsToolHandler.js +85 -0
  35. package/src/handlers/component/ModifyComponentToolHandler.js +143 -0
  36. package/src/handlers/component/RemoveComponentToolHandler.js +108 -0
  37. package/src/handlers/console/ClearConsoleToolHandler.js +160 -0
  38. package/src/handlers/console/ReadConsoleToolHandler.js +276 -0
  39. package/src/handlers/editor/LayerManagementToolHandler.js +160 -0
  40. package/src/handlers/editor/SelectionToolHandler.js +141 -0
  41. package/src/handlers/editor/TagManagementToolHandler.js +129 -0
  42. package/src/handlers/editor/ToolManagementToolHandler.js +135 -0
  43. package/src/handlers/editor/WindowManagementToolHandler.js +125 -0
  44. package/src/handlers/gameobject/CreateGameObjectToolHandler.js +131 -0
  45. package/src/handlers/gameobject/DeleteGameObjectToolHandler.js +101 -0
  46. package/src/handlers/gameobject/FindGameObjectToolHandler.js +119 -0
  47. package/src/handlers/gameobject/GetHierarchyToolHandler.js +132 -0
  48. package/src/handlers/gameobject/ModifyGameObjectToolHandler.js +128 -0
  49. package/src/handlers/index.js +389 -0
  50. package/src/handlers/input/AddInputActionToolHandler.js +20 -0
  51. package/src/handlers/input/AddInputBindingToolHandler.js +20 -0
  52. package/src/handlers/input/CreateActionMapToolHandler.js +20 -0
  53. package/src/handlers/input/CreateCompositeBindingToolHandler.js +20 -0
  54. package/src/handlers/input/GamepadSimulationHandler.js +116 -0
  55. package/src/handlers/input/InputSystemHandler.js +80 -0
  56. package/src/handlers/input/KeyboardSimulationHandler.js +79 -0
  57. package/src/handlers/input/ManageControlSchemesToolHandler.js +20 -0
  58. package/src/handlers/input/MouseSimulationHandler.js +107 -0
  59. package/src/handlers/input/RemoveActionMapToolHandler.js +20 -0
  60. package/src/handlers/input/RemoveAllBindingsToolHandler.js +20 -0
  61. package/src/handlers/input/RemoveInputActionToolHandler.js +20 -0
  62. package/src/handlers/input/RemoveInputBindingToolHandler.js +20 -0
  63. package/src/handlers/input/TouchSimulationHandler.js +142 -0
  64. package/src/handlers/menu/ExecuteMenuItemToolHandler.js +304 -0
  65. package/src/handlers/package/PackageManagerToolHandler.js +248 -0
  66. package/src/handlers/package/RegistryConfigToolHandler.js +198 -0
  67. package/src/handlers/playmode/GetEditorStateToolHandler.js +81 -0
  68. package/src/handlers/playmode/PauseToolHandler.js +44 -0
  69. package/src/handlers/playmode/PlayToolHandler.js +91 -0
  70. package/src/handlers/playmode/StopToolHandler.js +77 -0
  71. package/src/handlers/playmode/WaitForEditorStateToolHandler.js +45 -0
  72. package/src/handlers/scene/CreateSceneToolHandler.js +91 -0
  73. package/src/handlers/scene/GetSceneInfoToolHandler.js +20 -0
  74. package/src/handlers/scene/ListScenesToolHandler.js +58 -0
  75. package/src/handlers/scene/LoadSceneToolHandler.js +92 -0
  76. package/src/handlers/scene/SaveSceneToolHandler.js +76 -0
  77. package/src/handlers/screenshot/AnalyzeScreenshotToolHandler.js +238 -0
  78. package/src/handlers/screenshot/CaptureScreenshotToolHandler.js +692 -0
  79. package/src/handlers/script/BuildCodeIndexToolHandler.js +163 -0
  80. package/src/handlers/script/ScriptCreateClassFileToolHandler.js +60 -0
  81. package/src/handlers/script/ScriptEditStructuredToolHandler.js +173 -0
  82. package/src/handlers/script/ScriptIndexStatusToolHandler.js +61 -0
  83. package/src/handlers/script/ScriptPackagesListToolHandler.js +103 -0
  84. package/src/handlers/script/ScriptReadToolHandler.js +106 -0
  85. package/src/handlers/script/ScriptRefactorRenameToolHandler.js +83 -0
  86. package/src/handlers/script/ScriptRefsFindToolHandler.js +144 -0
  87. package/src/handlers/script/ScriptRemoveSymbolToolHandler.js +79 -0
  88. package/src/handlers/script/ScriptSearchToolHandler.js +320 -0
  89. package/src/handlers/script/ScriptSymbolFindToolHandler.js +117 -0
  90. package/src/handlers/script/ScriptSymbolsGetToolHandler.js +96 -0
  91. package/src/handlers/settings/GetProjectSettingsToolHandler.js +161 -0
  92. package/src/handlers/settings/UpdateProjectSettingsToolHandler.js +272 -0
  93. package/src/handlers/system/GetCommandStatsToolHandler.js +25 -0
  94. package/src/handlers/system/PingToolHandler.js +53 -0
  95. package/src/handlers/system/RefreshAssetsToolHandler.js +45 -0
  96. package/src/handlers/ui/ClickUIElementToolHandler.js +110 -0
  97. package/src/handlers/ui/FindUIElementsToolHandler.js +63 -0
  98. package/src/handlers/ui/GetUIElementStateToolHandler.js +50 -0
  99. package/src/handlers/ui/SetUIElementValueToolHandler.js +49 -0
  100. package/src/handlers/ui/SimulateUIInputToolHandler.js +156 -0
  101. package/src/handlers/video/CaptureVideoForToolHandler.js +96 -0
  102. package/src/handlers/video/CaptureVideoStartToolHandler.js +38 -0
  103. package/src/handlers/video/CaptureVideoStatusToolHandler.js +30 -0
  104. package/src/handlers/video/CaptureVideoStopToolHandler.js +32 -0
  105. package/src/lsp/CSharpLspUtils.js +134 -0
  106. package/src/lsp/LspProcessManager.js +60 -0
  107. package/src/lsp/LspRpcClient.js +133 -0
  108. package/src/tools/analysis/analyzeSceneContents.js +100 -0
  109. package/src/tools/analysis/findByComponent.js +87 -0
  110. package/src/tools/analysis/getAnimatorState.js +326 -0
  111. package/src/tools/analysis/getComponentValues.js +182 -0
  112. package/src/tools/analysis/getGameObjectDetails.js +159 -0
  113. package/src/tools/analysis/getInputActionsState.js +329 -0
  114. package/src/tools/analysis/getObjectReferences.js +86 -0
  115. package/src/tools/input/inputActionsEditor.js +556 -0
  116. package/src/tools/scene/createScene.js +112 -0
  117. package/src/tools/scene/getSceneInfo.js +95 -0
  118. package/src/tools/scene/listScenes.js +82 -0
  119. package/src/tools/scene/loadScene.js +122 -0
  120. package/src/tools/scene/saveScene.js +91 -0
  121. package/src/tools/system/ping.js +72 -0
  122. package/src/tools/video/recordFor.js +31 -0
  123. package/src/tools/video/recordPlayMode.js +61 -0
  124. package/src/utils/csharpParse.js +88 -0
  125. package/src/utils/validators.js +90 -0
@@ -0,0 +1,78 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ export class CreatePrefabToolHandler extends BaseToolHandler {
4
+ constructor(unityConnection) {
5
+ super(
6
+ 'create_prefab',
7
+ 'Create a prefab from a GameObject path or create an empty prefab at a target asset path.',
8
+ {
9
+ type: 'object',
10
+ properties: {
11
+ gameObjectPath: {
12
+ type: 'string',
13
+ description: 'Scene path to convert (e.g., "/Root/Player"). Mutually exclusive with createFromTemplate.'
14
+ },
15
+ prefabPath: {
16
+ type: 'string',
17
+ description: 'Asset path for the prefab. Must start with Assets/ and end with .prefab.'
18
+ },
19
+ createFromTemplate: {
20
+ type: 'boolean',
21
+ description: 'If true, create an empty prefab (no source GameObject) (default: false).'
22
+ },
23
+ overwrite: {
24
+ type: 'boolean',
25
+ description: 'If true, overwrite existing prefab at the destination path (default: false).'
26
+ }
27
+ },
28
+ required: ['prefabPath']
29
+ }
30
+ );
31
+ this.unityConnection = unityConnection;
32
+ }
33
+
34
+ validate(params) {
35
+ // Call parent validation for required fields
36
+ super.validate(params);
37
+
38
+ const { prefabPath, gameObjectPath, createFromTemplate } = params;
39
+
40
+ // Validate prefabPath format
41
+ if (!prefabPath.startsWith('Assets/') || !prefabPath.endsWith('.prefab')) {
42
+ throw new Error('prefabPath must start with Assets/ and end with .prefab');
43
+ }
44
+
45
+ // Validate gameObjectPath when provided
46
+ if (gameObjectPath !== undefined && gameObjectPath === '') {
47
+ throw new Error('gameObjectPath cannot be empty when provided');
48
+ }
49
+
50
+ // Validate mutually exclusive options
51
+ if (gameObjectPath && createFromTemplate) {
52
+ throw new Error('Cannot specify both gameObjectPath and createFromTemplate');
53
+ }
54
+ }
55
+
56
+ async execute(params) {
57
+ const {
58
+ gameObjectPath,
59
+ prefabPath,
60
+ createFromTemplate = false,
61
+ overwrite = false
62
+ } = params;
63
+
64
+ // Ensure connected
65
+ if (!this.unityConnection.isConnected()) {
66
+ await this.unityConnection.connect();
67
+ }
68
+
69
+ const result = await this.unityConnection.sendCommand('create_prefab', {
70
+ gameObjectPath,
71
+ prefabPath,
72
+ createFromTemplate,
73
+ overwrite
74
+ });
75
+
76
+ return result;
77
+ }
78
+ }
@@ -0,0 +1,83 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ /**
4
+ * Handler for exiting Unity's prefab mode
5
+ */
6
+ export class ExitPrefabModeToolHandler extends BaseToolHandler {
7
+ constructor(unityConnection) {
8
+ super(
9
+ 'exit_prefab_mode',
10
+ 'Exit prefab mode and return to the main scene',
11
+ {
12
+ type: 'object',
13
+ properties: {
14
+ saveChanges: {
15
+ type: 'boolean',
16
+ description: 'Save changes before exiting (default: true)'
17
+ }
18
+ }
19
+ }
20
+ );
21
+
22
+ this.unityConnection = unityConnection;
23
+ }
24
+
25
+ /**
26
+ * Executes the exit prefab mode operation
27
+ * @param {Object} params - The validated input parameters
28
+ * @returns {Promise<Object>} The result of exiting prefab mode
29
+ */
30
+ async execute(params) {
31
+ // Ensure connection to Unity
32
+ if (!this.unityConnection.isConnected()) {
33
+ await this.unityConnection.connect();
34
+ }
35
+
36
+ // Default saveChanges to true
37
+ const executeParams = {
38
+ saveChanges: params.saveChanges !== undefined ? params.saveChanges : true
39
+ };
40
+
41
+ // Send command to Unity
42
+ const response = await this.unityConnection.sendCommand('exit_prefab_mode', executeParams);
43
+
44
+ // Handle Unity response
45
+ if (response.error) {
46
+ throw new Error(response.error);
47
+ }
48
+
49
+ // Return result
50
+ return {
51
+ success: response.success,
52
+ wasInPrefabMode: response.wasInPrefabMode,
53
+ message: response.message || 'Exited prefab mode',
54
+ ...(response.changesSaved !== undefined && { changesSaved: response.changesSaved }),
55
+ ...(response.prefabPath !== undefined && { prefabPath: response.prefabPath })
56
+ };
57
+ }
58
+
59
+ /**
60
+ * Gets example usage for this tool
61
+ * @returns {Object} Example usage scenarios
62
+ */
63
+ getExamples() {
64
+ return {
65
+ exitAndSave: {
66
+ description: 'Exit prefab mode and save changes',
67
+ params: {
68
+ saveChanges: true
69
+ }
70
+ },
71
+ exitWithoutSave: {
72
+ description: 'Exit prefab mode without saving changes',
73
+ params: {
74
+ saveChanges: false
75
+ }
76
+ },
77
+ exitDefault: {
78
+ description: 'Exit prefab mode (saves by default)',
79
+ params: {}
80
+ }
81
+ };
82
+ }
83
+ }
@@ -0,0 +1,133 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ export class InstantiatePrefabToolHandler extends BaseToolHandler {
4
+ constructor(unityConnection) {
5
+ super(
6
+ 'instantiate_prefab',
7
+ 'Instantiate a prefab in the scene with optional transform, parent, and name override.',
8
+ {
9
+ type: 'object',
10
+ properties: {
11
+ prefabPath: {
12
+ type: 'string',
13
+ description: 'Asset path to the prefab. Must start with Assets/ and end with .prefab.'
14
+ },
15
+ position: {
16
+ type: 'object',
17
+ properties: {
18
+ x: { type: 'number' },
19
+ y: { type: 'number' },
20
+ z: { type: 'number' }
21
+ },
22
+ description: 'World position for the instance (requires x,y,z).'
23
+ },
24
+ rotation: {
25
+ type: 'object',
26
+ properties: {
27
+ x: { type: 'number' },
28
+ y: { type: 'number' },
29
+ z: { type: 'number' }
30
+ },
31
+ description: 'Euler rotation for the instance (x,y,z).'
32
+ },
33
+ parent: {
34
+ type: 'string',
35
+ description: 'Parent GameObject scene path (optional).'
36
+ },
37
+ name: {
38
+ type: 'string',
39
+ description: 'Override name for the instantiated object.'
40
+ }
41
+ },
42
+ required: ['prefabPath']
43
+ }
44
+ );
45
+ this.unityConnection = unityConnection;
46
+ }
47
+
48
+ validate(params) {
49
+ // Call parent validation for required fields
50
+ super.validate(params);
51
+
52
+ const { prefabPath, parent, position, rotation } = params;
53
+
54
+ // Validate prefabPath format
55
+ if (!prefabPath.startsWith('Assets/') || !prefabPath.endsWith('.prefab')) {
56
+ throw new Error('prefabPath must start with Assets/ and end with .prefab');
57
+ }
58
+
59
+ // Validate parent when provided
60
+ if (parent !== undefined && parent === '') {
61
+ throw new Error('parent cannot be empty when provided');
62
+ }
63
+
64
+ // Validate position object when provided
65
+ if (position !== undefined) {
66
+ if (typeof position !== 'object' || position === null) {
67
+ throw new Error('position must be an object');
68
+ }
69
+
70
+ // Check individual properties first for better error messages
71
+ if ('x' in position && typeof position.x !== 'number') {
72
+ throw new Error('position.x must be a number');
73
+ }
74
+ if ('y' in position && typeof position.y !== 'number') {
75
+ throw new Error('position.y must be a number');
76
+ }
77
+ if ('z' in position && typeof position.z !== 'number') {
78
+ throw new Error('position.z must be a number');
79
+ }
80
+
81
+ // Then check for missing properties
82
+ if (!('x' in position) || !('y' in position) || !('z' in position)) {
83
+ throw new Error('position must have x, y, and z properties');
84
+ }
85
+ }
86
+
87
+ // Validate rotation object when provided
88
+ if (rotation !== undefined) {
89
+ if (typeof rotation !== 'object' || rotation === null) {
90
+ throw new Error('rotation must be an object');
91
+ }
92
+
93
+ if (!('x' in rotation) || !('y' in rotation) || !('z' in rotation)) {
94
+ throw new Error('rotation must have x, y, and z properties');
95
+ }
96
+
97
+ if (typeof rotation.x !== 'number') {
98
+ throw new Error('rotation.x must be a number');
99
+ }
100
+ if (typeof rotation.y !== 'number') {
101
+ throw new Error('rotation.y must be a number');
102
+ }
103
+ if (typeof rotation.z !== 'number') {
104
+ throw new Error('rotation.z must be a number');
105
+ }
106
+ }
107
+ }
108
+
109
+ async execute(params) {
110
+ const {
111
+ prefabPath,
112
+ position,
113
+ rotation,
114
+ parent,
115
+ name
116
+ } = params;
117
+
118
+ // Ensure connected
119
+ if (!this.unityConnection.isConnected()) {
120
+ await this.unityConnection.connect();
121
+ }
122
+
123
+ const result = await this.unityConnection.sendCommand('instantiate_prefab', {
124
+ prefabPath,
125
+ position,
126
+ rotation,
127
+ parent,
128
+ name
129
+ });
130
+
131
+ return result;
132
+ }
133
+ }
@@ -0,0 +1,76 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ export class ModifyMaterialToolHandler extends BaseToolHandler {
4
+ constructor(unityConnection) {
5
+ super(
6
+ 'modify_material',
7
+ 'Modify a material by updating property values and/or changing the shader.',
8
+ {
9
+ type: 'object',
10
+ properties: {
11
+ materialPath: {
12
+ type: 'string',
13
+ description: 'Asset path to the material. Must start with Assets/ and end with .mat.'
14
+ },
15
+ properties: {
16
+ type: 'object',
17
+ description: 'Property updates (e.g., {"_Color":[1,0,0,1], "_Metallic":0.5}).'
18
+ },
19
+ shader: {
20
+ type: 'string',
21
+ description: 'Optional: change the shader (e.g., Standard, Unlit/Color).'
22
+ }
23
+ },
24
+ required: ['materialPath', 'properties']
25
+ }
26
+ );
27
+ this.unityConnection = unityConnection;
28
+ }
29
+
30
+ validate(params) {
31
+ // Call parent validation for required fields
32
+ super.validate(params);
33
+
34
+ const { materialPath, properties, shader } = params;
35
+
36
+ // Validate materialPath format
37
+ if (!materialPath.startsWith('Assets/') || !materialPath.endsWith('.mat')) {
38
+ throw new Error('materialPath must start with Assets/ and end with .mat');
39
+ }
40
+
41
+ // Validate properties
42
+ if (typeof properties !== 'object' || properties === null || Array.isArray(properties)) {
43
+ throw new Error('properties must be an object');
44
+ }
45
+
46
+ if (Object.keys(properties).length === 0) {
47
+ throw new Error('properties cannot be empty');
48
+ }
49
+
50
+ // Validate shader when provided
51
+ if (shader !== undefined && shader === '') {
52
+ throw new Error('shader cannot be empty when provided');
53
+ }
54
+ }
55
+
56
+ async execute(params) {
57
+ const {
58
+ materialPath,
59
+ properties,
60
+ shader
61
+ } = params;
62
+
63
+ // Ensure connected
64
+ if (!this.unityConnection.isConnected()) {
65
+ await this.unityConnection.connect();
66
+ }
67
+
68
+ const result = await this.unityConnection.sendCommand('modify_material', {
69
+ materialPath,
70
+ properties,
71
+ shader
72
+ });
73
+
74
+ return result;
75
+ }
76
+ }
@@ -0,0 +1,72 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ export class ModifyPrefabToolHandler extends BaseToolHandler {
4
+ constructor(unityConnection) {
5
+ super(
6
+ 'modify_prefab',
7
+ 'Modify an existing prefab by applying property changes (optionally to instances).',
8
+ {
9
+ type: 'object',
10
+ properties: {
11
+ prefabPath: {
12
+ type: 'string',
13
+ description: 'Asset path to the prefab. Must start with Assets/ and end with .prefab.'
14
+ },
15
+ modifications: {
16
+ type: 'object',
17
+ description: 'Key/value object of properties to modify on the prefab.'
18
+ },
19
+ applyToInstances: {
20
+ type: 'boolean',
21
+ description: 'If true, also apply to existing scene instances (default: true).'
22
+ }
23
+ },
24
+ required: ['prefabPath', 'modifications']
25
+ }
26
+ );
27
+ this.unityConnection = unityConnection;
28
+ }
29
+
30
+ validate(params) {
31
+ // Call parent validation for required fields
32
+ super.validate(params);
33
+
34
+ const { prefabPath, modifications } = params;
35
+
36
+ // Validate prefabPath format
37
+ if (!prefabPath.startsWith('Assets/') || !prefabPath.endsWith('.prefab')) {
38
+ throw new Error('prefabPath must start with Assets/ and end with .prefab');
39
+ }
40
+
41
+ // Validate modifications is object
42
+ if (typeof modifications !== 'object' || modifications === null || Array.isArray(modifications)) {
43
+ throw new Error('modifications must be an object');
44
+ }
45
+
46
+ // Validate modifications is not empty
47
+ if (Object.keys(modifications).length === 0) {
48
+ throw new Error('modifications cannot be empty');
49
+ }
50
+ }
51
+
52
+ async execute(params) {
53
+ const {
54
+ prefabPath,
55
+ modifications,
56
+ applyToInstances = true
57
+ } = params;
58
+
59
+ // Ensure connected
60
+ if (!this.unityConnection.isConnected()) {
61
+ await this.unityConnection.connect();
62
+ }
63
+
64
+ const result = await this.unityConnection.sendCommand('modify_prefab', {
65
+ prefabPath,
66
+ modifications,
67
+ applyToInstances
68
+ });
69
+
70
+ return result;
71
+ }
72
+ }
@@ -0,0 +1,121 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ /**
4
+ * Handler for opening prefabs in Unity's prefab mode
5
+ */
6
+ export class OpenPrefabToolHandler extends BaseToolHandler {
7
+ constructor(unityConnection) {
8
+ super(
9
+ 'open_prefab',
10
+ 'Open a prefab asset in prefab mode for editing. Once in prefab mode, use component tools (list_components, add_component, etc.) to inspect and modify components.',
11
+ {
12
+ type: 'object',
13
+ properties: {
14
+ prefabPath: {
15
+ type: 'string',
16
+ description: 'Asset path to the prefab (must start with Assets/ and end with .prefab)'
17
+ },
18
+ focusObject: {
19
+ type: 'string',
20
+ description: 'Optional path to object within prefab to focus on (relative to prefab root)'
21
+ },
22
+ isolateObject: {
23
+ type: 'boolean',
24
+ description: 'Isolate the focused object in the hierarchy (default: false)'
25
+ }
26
+ },
27
+ required: ['prefabPath']
28
+ }
29
+ );
30
+
31
+ this.unityConnection = unityConnection;
32
+ }
33
+
34
+ /**
35
+ * Validates the input parameters
36
+ * @param {Object} params - The input parameters
37
+ * @throws {Error} If validation fails
38
+ */
39
+ validate(params) {
40
+ super.validate(params); // Check required fields
41
+
42
+ const { prefabPath } = params;
43
+
44
+ // Validate prefabPath is not empty
45
+ if (!prefabPath || prefabPath.trim() === '') {
46
+ throw new Error('prefabPath cannot be empty');
47
+ }
48
+
49
+ // Validate prefabPath format
50
+ if (!prefabPath.startsWith('Assets/') || !prefabPath.endsWith('.prefab')) {
51
+ throw new Error('prefabPath must start with Assets/ and end with .prefab');
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Executes the open prefab operation
57
+ * @param {Object} params - The validated input parameters
58
+ * @returns {Promise<Object>} The result of opening the prefab
59
+ */
60
+ async execute(params) {
61
+ // Ensure connection to Unity
62
+ if (!this.unityConnection.isConnected()) {
63
+ await this.unityConnection.connect();
64
+ }
65
+
66
+ // Send command to Unity
67
+ const response = await this.unityConnection.sendCommand('open_prefab', params);
68
+
69
+ // Handle Unity response
70
+ if (response.error) {
71
+ throw new Error(response.error);
72
+ }
73
+
74
+ // Return result
75
+ return {
76
+ success: response.success,
77
+ prefabPath: response.prefabPath,
78
+ isInPrefabMode: response.isInPrefabMode,
79
+ prefabContentsRoot: response.prefabContentsRoot,
80
+ message: response.message || 'Prefab opened',
81
+ ...(response.focusedObject !== undefined && { focusedObject: response.focusedObject }),
82
+ ...(response.wasAlreadyOpen !== undefined && { wasAlreadyOpen: response.wasAlreadyOpen })
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Gets example usage for this tool
88
+ * @returns {Object} Example usage scenarios
89
+ */
90
+ getExamples() {
91
+ return {
92
+ openSimple: {
93
+ description: 'Open a prefab for editing',
94
+ params: {
95
+ prefabPath: 'Assets/Prefabs/PlayerCharacter.prefab'
96
+ }
97
+ },
98
+ openWithFocus: {
99
+ description: 'Open prefab and focus on specific object',
100
+ params: {
101
+ prefabPath: 'Assets/Prefabs/UI/MainMenu.prefab',
102
+ focusObject: '/Canvas/Buttons/StartButton'
103
+ }
104
+ },
105
+ openWithIsolation: {
106
+ description: 'Open prefab and isolate specific object',
107
+ params: {
108
+ prefabPath: 'Assets/Prefabs/Enemies/Boss.prefab',
109
+ focusObject: '/Armature/Hips/Spine',
110
+ isolateObject: true
111
+ }
112
+ },
113
+ openForComponentWork: {
114
+ description: 'Open prefab for component inspection and modification (use with component tools like list_components, add_component, etc.)',
115
+ params: {
116
+ prefabPath: 'Assets/Prefabs/Weapons/Sword.prefab'
117
+ }
118
+ }
119
+ };
120
+ }
121
+ }
@@ -0,0 +1,106 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ /**
4
+ * Handler for saving prefab changes in Unity
5
+ */
6
+ export class SavePrefabToolHandler extends BaseToolHandler {
7
+ constructor(unityConnection) {
8
+ super(
9
+ 'save_prefab',
10
+ 'Save current prefab changes in prefab mode or save a GameObject as prefab override',
11
+ {
12
+ type: 'object',
13
+ properties: {
14
+ gameObjectPath: {
15
+ type: 'string',
16
+ description: 'Path to GameObject to save as prefab override (optional - if not provided, saves current prefab in prefab mode)'
17
+ },
18
+ includeChildren: {
19
+ type: 'boolean',
20
+ description: 'Include child object overrides when saving (default: true)'
21
+ }
22
+ }
23
+ }
24
+ );
25
+
26
+ this.unityConnection = unityConnection;
27
+ }
28
+
29
+ /**
30
+ * Validates the input parameters
31
+ * @param {Object} params - The input parameters
32
+ * @throws {Error} If validation fails
33
+ */
34
+ validate(params) {
35
+ const { gameObjectPath } = params;
36
+
37
+ // If gameObjectPath is provided, ensure it's not empty
38
+ if (gameObjectPath !== undefined && gameObjectPath.trim() === '') {
39
+ throw new Error('gameObjectPath cannot be empty when provided');
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Executes the save prefab operation
45
+ * @param {Object} params - The validated input parameters
46
+ * @returns {Promise<Object>} The result of saving the prefab
47
+ */
48
+ async execute(params) {
49
+ // Ensure connection to Unity
50
+ if (!this.unityConnection.isConnected()) {
51
+ await this.unityConnection.connect();
52
+ }
53
+
54
+ // Send command to Unity
55
+ const response = await this.unityConnection.sendCommand('save_prefab', params);
56
+
57
+ // Handle Unity response
58
+ if (response.error) {
59
+ throw new Error(response.error);
60
+ }
61
+
62
+ // Return result
63
+ return {
64
+ success: response.success,
65
+ message: response.message || 'Prefab saved',
66
+ ...(response.savedInPrefabMode !== undefined && { savedInPrefabMode: response.savedInPrefabMode }),
67
+ ...(response.prefabPath !== undefined && { prefabPath: response.prefabPath }),
68
+ ...(response.gameObjectPath !== undefined && { gameObjectPath: response.gameObjectPath }),
69
+ ...(response.overridesApplied !== undefined && { overridesApplied: response.overridesApplied }),
70
+ ...(response.includedChildren !== undefined && { includedChildren: response.includedChildren })
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Gets example usage for this tool
76
+ * @returns {Object} Example usage scenarios
77
+ */
78
+ getExamples() {
79
+ return {
80
+ saveInPrefabMode: {
81
+ description: 'Save changes while in prefab mode',
82
+ params: {}
83
+ },
84
+ savePrefabInstance: {
85
+ description: 'Save GameObject prefab instance overrides',
86
+ params: {
87
+ gameObjectPath: '/Player'
88
+ }
89
+ },
90
+ saveWithChildren: {
91
+ description: 'Save prefab instance including all child overrides',
92
+ params: {
93
+ gameObjectPath: '/UI/MainMenu',
94
+ includeChildren: true
95
+ }
96
+ },
97
+ saveWithoutChildren: {
98
+ description: 'Save only the root GameObject overrides',
99
+ params: {
100
+ gameObjectPath: '/Enemies/Boss',
101
+ includeChildren: false
102
+ }
103
+ }
104
+ };
105
+ }
106
+ }