@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,221 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ /**
4
+ * Handler for Unity Asset Database operations
5
+ */
6
+ export class AssetDatabaseToolHandler extends BaseToolHandler {
7
+ constructor(unityConnection) {
8
+ super(
9
+ 'manage_asset_database',
10
+ 'Manage Unity Asset Database operations (find, info, create folders, move, copy, delete, refresh). NOTE: The "refresh" action may take 5-120+ seconds for large projects as Unity needs to scan all assets, reimport changed files, and compile scripts. Please wait for the operation to complete.',
11
+ {
12
+ type: 'object',
13
+ properties: {
14
+ action: {
15
+ type: 'string',
16
+ enum: ['find_assets', 'get_asset_info', 'create_folder', 'delete_asset', 'move_asset', 'copy_asset', 'refresh', 'save'],
17
+ description: 'The action to perform'
18
+ },
19
+ filter: {
20
+ type: 'string',
21
+ description: 'Search filter for find_assets (e.g., "t:Texture2D", "l:UI")'
22
+ },
23
+ searchInFolders: {
24
+ type: 'array',
25
+ items: { type: 'string' },
26
+ description: 'Folders to search in for find_assets (optional)'
27
+ },
28
+ assetPath: {
29
+ type: 'string',
30
+ description: 'Path to the asset (must start with "Assets/")'
31
+ },
32
+ folderPath: {
33
+ type: 'string',
34
+ description: 'Path for folder creation (must start with "Assets/")'
35
+ },
36
+ fromPath: {
37
+ type: 'string',
38
+ description: 'Source path for move/copy operations'
39
+ },
40
+ toPath: {
41
+ type: 'string',
42
+ description: 'Destination path for move/copy operations'
43
+ }
44
+ },
45
+ required: ['action']
46
+ }
47
+ );
48
+ this.unityConnection = unityConnection;
49
+ }
50
+
51
+ validate(params) {
52
+ if (!params.action) {
53
+ throw new Error('action is required');
54
+ }
55
+
56
+ const validActions = ['find_assets', 'get_asset_info', 'create_folder', 'delete_asset', 'move_asset', 'copy_asset', 'refresh', 'save'];
57
+ if (!validActions.includes(params.action)) {
58
+ throw new Error(`action must be one of: ${validActions.join(', ')}`);
59
+ }
60
+
61
+ // Validate action-specific requirements
62
+ switch (params.action) {
63
+ case 'find_assets':
64
+ if (params.filter === undefined || params.filter === null) {
65
+ throw new Error('filter is required for find_assets action');
66
+ }
67
+ if (params.filter === '') {
68
+ throw new Error('filter cannot be empty');
69
+ }
70
+ break;
71
+
72
+ case 'get_asset_info':
73
+ case 'delete_asset':
74
+ if (params.assetPath === undefined || params.assetPath === null) {
75
+ throw new Error(`assetPath is required for ${params.action} action`);
76
+ }
77
+ if (params.assetPath === '') {
78
+ throw new Error('assetPath cannot be empty');
79
+ }
80
+ this.validateAssetPath(params.assetPath);
81
+ break;
82
+
83
+ case 'create_folder':
84
+ if (params.folderPath === undefined || params.folderPath === null) {
85
+ throw new Error('folderPath is required for create_folder action');
86
+ }
87
+ if (params.folderPath === '') {
88
+ throw new Error('folderPath cannot be empty');
89
+ }
90
+ this.validateAssetPath(params.folderPath);
91
+ break;
92
+
93
+ case 'move_asset':
94
+ case 'copy_asset':
95
+ if (params.fromPath === undefined || params.fromPath === null) {
96
+ throw new Error(`fromPath is required for ${params.action} action`);
97
+ }
98
+ if (params.toPath === undefined || params.toPath === null) {
99
+ throw new Error(`toPath is required for ${params.action} action`);
100
+ }
101
+ if (params.fromPath === '') {
102
+ throw new Error('fromPath cannot be empty');
103
+ }
104
+ if (params.toPath === '') {
105
+ throw new Error('toPath cannot be empty');
106
+ }
107
+ this.validateAssetPath(params.fromPath);
108
+ this.validateAssetPath(params.toPath);
109
+ break;
110
+
111
+ case 'refresh':
112
+ case 'save':
113
+ // No additional validation needed
114
+ break;
115
+ }
116
+ }
117
+
118
+ validateAssetPath(path) {
119
+ if (!path.startsWith('Assets/')) {
120
+ throw new Error('assetPath must start with "Assets/"');
121
+ }
122
+ }
123
+
124
+ async execute(params) {
125
+ this.validate(params);
126
+
127
+ if (!this.unityConnection.isConnected()) {
128
+ await this.unityConnection.connect();
129
+ }
130
+
131
+ const result = await this.unityConnection.sendCommand('manage_asset_database', params);
132
+ return result;
133
+ }
134
+
135
+ getExamples() {
136
+ return [
137
+ {
138
+ input: { action: 'find_assets', filter: 't:Texture2D' },
139
+ output: {
140
+ success: true,
141
+ action: 'find_assets',
142
+ filter: 't:Texture2D',
143
+ assets: [
144
+ {
145
+ path: 'Assets/Textures/icon.png',
146
+ name: 'icon',
147
+ type: 'Texture2D',
148
+ guid: 'abc123',
149
+ size: 1024
150
+ }
151
+ ],
152
+ count: 1
153
+ }
154
+ },
155
+ {
156
+ input: { action: 'get_asset_info', assetPath: 'Assets/Textures/icon.png' },
157
+ output: {
158
+ success: true,
159
+ action: 'get_asset_info',
160
+ assetPath: 'Assets/Textures/icon.png',
161
+ info: {
162
+ name: 'icon',
163
+ type: 'Texture2D',
164
+ guid: 'abc123',
165
+ size: 1024,
166
+ lastModified: '2024-01-15T10:30:00Z',
167
+ importSettings: {
168
+ textureType: 'Sprite',
169
+ maxTextureSize: 2048
170
+ },
171
+ dependencies: ['Assets/Materials/UIMaterial.mat'],
172
+ isValid: true
173
+ }
174
+ }
175
+ },
176
+ {
177
+ input: { action: 'create_folder', folderPath: 'Assets/NewFolder' },
178
+ output: {
179
+ success: true,
180
+ action: 'create_folder',
181
+ folderPath: 'Assets/NewFolder',
182
+ guid: 'folder123',
183
+ message: 'Folder created: Assets/NewFolder'
184
+ }
185
+ },
186
+ {
187
+ input: {
188
+ action: 'move_asset',
189
+ fromPath: 'Assets/icon.png',
190
+ toPath: 'Assets/Textures/icon.png'
191
+ },
192
+ output: {
193
+ success: true,
194
+ action: 'move_asset',
195
+ fromPath: 'Assets/icon.png',
196
+ toPath: 'Assets/Textures/icon.png',
197
+ message: 'Asset moved from Assets/icon.png to Assets/Textures/icon.png'
198
+ }
199
+ },
200
+ {
201
+ input: { action: 'delete_asset', assetPath: 'Assets/old_file.png' },
202
+ output: {
203
+ success: true,
204
+ action: 'delete_asset',
205
+ assetPath: 'Assets/old_file.png',
206
+ message: 'Asset deleted: Assets/old_file.png'
207
+ }
208
+ },
209
+ {
210
+ input: { action: 'refresh' },
211
+ output: {
212
+ success: true,
213
+ action: 'refresh',
214
+ message: 'Asset database refreshed',
215
+ assetsFound: 1247,
216
+ duration: 2.34
217
+ }
218
+ }
219
+ ];
220
+ }
221
+ }
@@ -0,0 +1,201 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ /**
4
+ * Handler for Unity asset dependency analysis
5
+ */
6
+ export class AssetDependencyToolHandler extends BaseToolHandler {
7
+ constructor(unityConnection) {
8
+ super(
9
+ 'analyze_asset_dependencies',
10
+ 'Analyze Unity asset dependencies (get dependencies, dependents, circular deps, unused assets, size impact)',
11
+ {
12
+ type: 'object',
13
+ properties: {
14
+ action: {
15
+ type: 'string',
16
+ enum: ['get_dependencies', 'get_dependents', 'analyze_circular', 'find_unused', 'analyze_size_impact', 'validate_references'],
17
+ description: 'The analysis action to perform'
18
+ },
19
+ assetPath: {
20
+ type: 'string',
21
+ description: 'Path to the asset (required for specific asset analysis)'
22
+ },
23
+ recursive: {
24
+ type: 'boolean',
25
+ description: 'Whether to analyze dependencies recursively (for get_dependencies)'
26
+ },
27
+ includeBuiltIn: {
28
+ type: 'boolean',
29
+ description: 'Whether to include built-in assets in analysis (for find_unused)'
30
+ }
31
+ },
32
+ required: ['action']
33
+ }
34
+ );
35
+ this.unityConnection = unityConnection;
36
+ }
37
+
38
+ validate(params) {
39
+ if (!params.action) {
40
+ throw new Error('action is required');
41
+ }
42
+
43
+ const validActions = ['get_dependencies', 'get_dependents', 'analyze_circular', 'find_unused', 'analyze_size_impact', 'validate_references'];
44
+ if (!validActions.includes(params.action)) {
45
+ throw new Error(`action must be one of: ${validActions.join(', ')}`);
46
+ }
47
+
48
+ // Actions that require assetPath
49
+ const assetPathRequiredActions = ['get_dependencies', 'get_dependents', 'analyze_size_impact'];
50
+ if (assetPathRequiredActions.includes(params.action)) {
51
+ if (params.assetPath === undefined || params.assetPath === null) {
52
+ throw new Error(`assetPath is required for ${params.action} action`);
53
+ }
54
+
55
+ if (params.assetPath === '') {
56
+ throw new Error('assetPath cannot be empty');
57
+ }
58
+
59
+ // Validate assetPath starts with "Assets/"
60
+ if (!params.assetPath.startsWith('Assets/')) {
61
+ throw new Error('assetPath must start with "Assets/"');
62
+ }
63
+ }
64
+ }
65
+
66
+ async execute(params) {
67
+ this.validate(params);
68
+
69
+ if (!this.unityConnection.isConnected()) {
70
+ await this.unityConnection.connect();
71
+ }
72
+
73
+ const result = await this.unityConnection.sendCommand('analyze_asset_dependencies', params);
74
+ return result;
75
+ }
76
+
77
+ getExamples() {
78
+ return [
79
+ {
80
+ input: { action: 'get_dependencies', assetPath: 'Assets/Prefabs/Player.prefab' },
81
+ output: {
82
+ success: true,
83
+ action: 'get_dependencies',
84
+ assetPath: 'Assets/Prefabs/Player.prefab',
85
+ recursive: false,
86
+ dependencies: [
87
+ {
88
+ path: 'Assets/Materials/PlayerMaterial.mat',
89
+ type: 'Material',
90
+ isDirectDependency: true,
91
+ depth: 1
92
+ },
93
+ {
94
+ path: 'Assets/Scripts/PlayerController.cs',
95
+ type: 'MonoScript',
96
+ isDirectDependency: true,
97
+ depth: 1
98
+ }
99
+ ],
100
+ count: 2,
101
+ maxDepth: 1
102
+ }
103
+ },
104
+ {
105
+ input: { action: 'get_dependents', assetPath: 'Assets/Materials/PlayerMaterial.mat' },
106
+ output: {
107
+ success: true,
108
+ action: 'get_dependents',
109
+ assetPath: 'Assets/Materials/PlayerMaterial.mat',
110
+ dependents: [
111
+ {
112
+ path: 'Assets/Prefabs/Player.prefab',
113
+ type: 'GameObject',
114
+ usage: 'Renderer.material'
115
+ }
116
+ ],
117
+ count: 1
118
+ }
119
+ },
120
+ {
121
+ input: { action: 'analyze_circular' },
122
+ output: {
123
+ success: true,
124
+ action: 'analyze_circular',
125
+ circularDependencies: [
126
+ {
127
+ cycle: [
128
+ 'Assets/Scripts/A.cs',
129
+ 'Assets/Scripts/B.cs',
130
+ 'Assets/Scripts/A.cs'
131
+ ],
132
+ length: 3,
133
+ severity: 'warning'
134
+ }
135
+ ],
136
+ hasCircularDependencies: true,
137
+ totalCycles: 1
138
+ }
139
+ },
140
+ {
141
+ input: { action: 'find_unused' },
142
+ output: {
143
+ success: true,
144
+ action: 'find_unused',
145
+ includeBuiltIn: false,
146
+ unusedAssets: [
147
+ {
148
+ path: 'Assets/Textures/old_icon.png',
149
+ type: 'Texture2D',
150
+ size: 512,
151
+ lastModified: '2023-12-01T10:00:00Z'
152
+ }
153
+ ],
154
+ count: 1,
155
+ totalSizeKB: 512
156
+ }
157
+ },
158
+ {
159
+ input: { action: 'analyze_size_impact', assetPath: 'Assets/Textures/large_texture.png' },
160
+ output: {
161
+ success: true,
162
+ action: 'analyze_size_impact',
163
+ assetPath: 'Assets/Textures/large_texture.png',
164
+ analysis: {
165
+ directSize: 2048,
166
+ totalSize: 3072,
167
+ dependencyCount: 5,
168
+ largestDependency: {
169
+ path: 'Assets/Textures/dependency.png',
170
+ size: 1024
171
+ },
172
+ buildImpact: {
173
+ estimatedBuildSize: 3072,
174
+ compressionRatio: 0.75
175
+ }
176
+ }
177
+ }
178
+ },
179
+ {
180
+ input: { action: 'validate_references' },
181
+ output: {
182
+ success: true,
183
+ action: 'validate_references',
184
+ validation: {
185
+ totalAssets: 150,
186
+ validReferences: 145,
187
+ brokenReferences: [
188
+ {
189
+ asset: 'Assets/Prefabs/Broken.prefab',
190
+ missingReference: 'Assets/Scripts/DeletedScript.cs',
191
+ referenceType: 'MonoScript'
192
+ }
193
+ ],
194
+ missingReferences: 5,
195
+ validationTime: 1.25
196
+ }
197
+ }
198
+ }
199
+ ];
200
+ }
201
+ }
@@ -0,0 +1,170 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ /**
4
+ * Handler for Unity asset import settings management
5
+ */
6
+ export class AssetImportSettingsToolHandler extends BaseToolHandler {
7
+ constructor(unityConnection) {
8
+ super(
9
+ 'manage_asset_import_settings',
10
+ 'Manage Unity asset import settings (get, modify, apply presets, reimport)',
11
+ {
12
+ type: 'object',
13
+ properties: {
14
+ action: {
15
+ type: 'string',
16
+ enum: ['get', 'modify', 'apply_preset', 'reimport'],
17
+ description: 'The action to perform'
18
+ },
19
+ assetPath: {
20
+ type: 'string',
21
+ description: 'Path to the asset (must start with "Assets/")'
22
+ },
23
+ settings: {
24
+ type: 'object',
25
+ description: 'Import settings to apply (required for modify action)'
26
+ },
27
+ preset: {
28
+ type: 'string',
29
+ description: 'Name of the preset to apply (required for apply_preset action)'
30
+ }
31
+ },
32
+ required: ['action', 'assetPath']
33
+ }
34
+ );
35
+ this.unityConnection = unityConnection;
36
+ }
37
+
38
+ validate(params) {
39
+ if (!params.action) {
40
+ throw new Error('action is required');
41
+ }
42
+
43
+ const validActions = ['get', 'modify', 'apply_preset', 'reimport'];
44
+ if (!validActions.includes(params.action)) {
45
+ throw new Error(`action must be one of: ${validActions.join(', ')}`);
46
+ }
47
+
48
+ // Validate assetPath
49
+ if (params.assetPath === undefined || params.assetPath === null) {
50
+ throw new Error('assetPath is required');
51
+ }
52
+
53
+ if (params.assetPath === '') {
54
+ throw new Error('assetPath cannot be empty');
55
+ }
56
+
57
+ // Validate assetPath starts with "Assets/"
58
+ if (!params.assetPath.startsWith('Assets/')) {
59
+ throw new Error('assetPath must start with "Assets/"');
60
+ }
61
+
62
+ // Validate settings for modify action
63
+ if (params.action === 'modify') {
64
+ if (!params.settings) {
65
+ throw new Error('settings is required for modify action');
66
+ }
67
+ }
68
+
69
+ // Validate preset for apply_preset action
70
+ if (params.action === 'apply_preset') {
71
+ if (params.preset === undefined || params.preset === null) {
72
+ throw new Error('preset is required for apply_preset action');
73
+ }
74
+
75
+ if (params.preset === '') {
76
+ throw new Error('preset cannot be empty');
77
+ }
78
+ }
79
+ }
80
+
81
+ async execute(params) {
82
+ this.validate(params);
83
+
84
+ if (!this.unityConnection.isConnected()) {
85
+ await this.unityConnection.connect();
86
+ }
87
+
88
+ const result = await this.unityConnection.sendCommand('manage_asset_import_settings', params);
89
+ return result;
90
+ }
91
+
92
+ getExamples() {
93
+ return [
94
+ {
95
+ input: { action: 'get', assetPath: 'Assets/Textures/icon.png' },
96
+ output: {
97
+ success: true,
98
+ action: 'get',
99
+ assetPath: 'Assets/Textures/icon.png',
100
+ settings: {
101
+ assetType: 'Texture2D',
102
+ textureType: 'Sprite',
103
+ filterMode: 'Bilinear',
104
+ wrapMode: 'Clamp',
105
+ maxTextureSize: 2048,
106
+ compressionQuality: 50,
107
+ generateMipMaps: false,
108
+ readable: false,
109
+ crunchedCompression: false,
110
+ sRGBTexture: true
111
+ }
112
+ }
113
+ },
114
+ {
115
+ input: {
116
+ action: 'modify',
117
+ assetPath: 'Assets/Textures/icon.png',
118
+ settings: {
119
+ maxTextureSize: 1024,
120
+ compressionQuality: 75
121
+ }
122
+ },
123
+ output: {
124
+ success: true,
125
+ action: 'modify',
126
+ assetPath: 'Assets/Textures/icon.png',
127
+ previousSettings: {
128
+ maxTextureSize: 2048,
129
+ compressionQuality: 50
130
+ },
131
+ newSettings: {
132
+ maxTextureSize: 1024,
133
+ compressionQuality: 75
134
+ },
135
+ message: 'Import settings modified for: Assets/Textures/icon.png'
136
+ }
137
+ },
138
+ {
139
+ input: {
140
+ action: 'apply_preset',
141
+ assetPath: 'Assets/Textures/icon.png',
142
+ preset: 'UI_Sprite'
143
+ },
144
+ output: {
145
+ success: true,
146
+ action: 'apply_preset',
147
+ assetPath: 'Assets/Textures/icon.png',
148
+ preset: 'UI_Sprite',
149
+ appliedSettings: {
150
+ textureType: 'Sprite',
151
+ filterMode: 'Bilinear',
152
+ maxTextureSize: 2048,
153
+ generateMipMaps: false
154
+ },
155
+ message: 'Preset "UI_Sprite" applied to: Assets/Textures/icon.png'
156
+ }
157
+ },
158
+ {
159
+ input: { action: 'reimport', assetPath: 'Assets/Textures/icon.png' },
160
+ output: {
161
+ success: true,
162
+ action: 'reimport',
163
+ assetPath: 'Assets/Textures/icon.png',
164
+ message: 'Asset reimported: Assets/Textures/icon.png',
165
+ duration: 0.245
166
+ }
167
+ }
168
+ ];
169
+ }
170
+ }
@@ -0,0 +1,96 @@
1
+ import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
+
3
+ export class CreateMaterialToolHandler extends BaseToolHandler {
4
+ constructor(unityConnection) {
5
+ super(
6
+ 'create_material',
7
+ 'Create a material asset with a shader and property overrides (optional copyFrom).',
8
+ {
9
+ type: 'object',
10
+ properties: {
11
+ materialPath: {
12
+ type: 'string',
13
+ description: 'Asset path for the material. Must start with Assets/ and end with .mat.'
14
+ },
15
+ shader: {
16
+ type: 'string',
17
+ description: 'Shader to use (e.g., Standard, Unlit/Color, Universal Render Pipeline/Lit).'
18
+ },
19
+ properties: {
20
+ type: 'object',
21
+ description: 'Material property overrides (e.g., {"_Color":[1,0,0,1], "_Metallic":0.5}).'
22
+ },
23
+ copyFrom: {
24
+ type: 'string',
25
+ description: 'Optional: path to an existing material to clone before applying overrides.'
26
+ },
27
+ overwrite: {
28
+ type: 'boolean',
29
+ description: 'If true, overwrite existing material at the path.'
30
+ }
31
+ },
32
+ required: ['materialPath']
33
+ }
34
+ );
35
+ this.unityConnection = unityConnection;
36
+ }
37
+
38
+ validate(params) {
39
+ // Call parent validation for required fields
40
+ super.validate(params);
41
+
42
+ const { materialPath, shader, properties, copyFrom } = params;
43
+
44
+ // Validate materialPath format
45
+ if (!materialPath.startsWith('Assets/') || !materialPath.endsWith('.mat')) {
46
+ throw new Error('materialPath must start with Assets/ and end with .mat');
47
+ }
48
+
49
+ // Validate shader when provided
50
+ if (shader !== undefined && shader === '') {
51
+ throw new Error('shader cannot be empty when provided');
52
+ }
53
+
54
+ // Validate properties when provided
55
+ if (properties !== undefined) {
56
+ if (typeof properties !== 'object' || properties === null) {
57
+ throw new Error('properties must be an object');
58
+ }
59
+ }
60
+
61
+ // Validate copyFrom when provided
62
+ if (copyFrom !== undefined) {
63
+ if (copyFrom === '') {
64
+ throw new Error('copyFrom cannot be empty when provided');
65
+ }
66
+ if (!copyFrom.startsWith('Assets/') || !copyFrom.endsWith('.mat')) {
67
+ throw new Error('copyFrom must be a valid material path (Assets/.../.mat)');
68
+ }
69
+ }
70
+ }
71
+
72
+ async execute(params) {
73
+ const {
74
+ materialPath,
75
+ shader,
76
+ properties,
77
+ copyFrom,
78
+ overwrite
79
+ } = params;
80
+
81
+ // Ensure connected
82
+ if (!this.unityConnection.isConnected()) {
83
+ await this.unityConnection.connect();
84
+ }
85
+
86
+ const result = await this.unityConnection.sendCommand('create_material', {
87
+ materialPath,
88
+ shader,
89
+ properties,
90
+ copyFrom,
91
+ overwrite
92
+ });
93
+
94
+ return result;
95
+ }
96
+ }