@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.
- package/LICENSE +21 -0
- package/README.md +206 -0
- package/bin/unity-mcp-server +2 -0
- package/package.json +73 -0
- package/src/core/codeIndex.js +163 -0
- package/src/core/codeIndexDb.js +96 -0
- package/src/core/config.js +165 -0
- package/src/core/indexWatcher.js +52 -0
- package/src/core/projectInfo.js +111 -0
- package/src/core/server.js +294 -0
- package/src/core/unityConnection.js +426 -0
- package/src/handlers/analysis/AnalyzeSceneContentsToolHandler.js +35 -0
- package/src/handlers/analysis/FindByComponentToolHandler.js +20 -0
- package/src/handlers/analysis/GetAnimatorStateToolHandler.js +37 -0
- package/src/handlers/analysis/GetComponentValuesToolHandler.js +20 -0
- package/src/handlers/analysis/GetGameObjectDetailsToolHandler.js +35 -0
- package/src/handlers/analysis/GetInputActionsStateToolHandler.js +37 -0
- package/src/handlers/analysis/GetObjectReferencesToolHandler.js +20 -0
- package/src/handlers/asset/AssetDatabaseToolHandler.js +221 -0
- package/src/handlers/asset/AssetDependencyToolHandler.js +201 -0
- package/src/handlers/asset/AssetImportSettingsToolHandler.js +170 -0
- package/src/handlers/asset/CreateMaterialToolHandler.js +96 -0
- package/src/handlers/asset/CreatePrefabToolHandler.js +78 -0
- package/src/handlers/asset/ExitPrefabModeToolHandler.js +83 -0
- package/src/handlers/asset/InstantiatePrefabToolHandler.js +133 -0
- package/src/handlers/asset/ModifyMaterialToolHandler.js +76 -0
- package/src/handlers/asset/ModifyPrefabToolHandler.js +72 -0
- package/src/handlers/asset/OpenPrefabToolHandler.js +121 -0
- package/src/handlers/asset/SavePrefabToolHandler.js +106 -0
- package/src/handlers/base/BaseToolHandler.js +133 -0
- package/src/handlers/compilation/GetCompilationStateToolHandler.js +90 -0
- package/src/handlers/component/AddComponentToolHandler.js +126 -0
- package/src/handlers/component/GetComponentTypesToolHandler.js +100 -0
- package/src/handlers/component/ListComponentsToolHandler.js +85 -0
- package/src/handlers/component/ModifyComponentToolHandler.js +143 -0
- package/src/handlers/component/RemoveComponentToolHandler.js +108 -0
- package/src/handlers/console/ClearConsoleToolHandler.js +160 -0
- package/src/handlers/console/ReadConsoleToolHandler.js +276 -0
- package/src/handlers/editor/LayerManagementToolHandler.js +160 -0
- package/src/handlers/editor/SelectionToolHandler.js +141 -0
- package/src/handlers/editor/TagManagementToolHandler.js +129 -0
- package/src/handlers/editor/ToolManagementToolHandler.js +135 -0
- package/src/handlers/editor/WindowManagementToolHandler.js +125 -0
- package/src/handlers/gameobject/CreateGameObjectToolHandler.js +131 -0
- package/src/handlers/gameobject/DeleteGameObjectToolHandler.js +101 -0
- package/src/handlers/gameobject/FindGameObjectToolHandler.js +119 -0
- package/src/handlers/gameobject/GetHierarchyToolHandler.js +132 -0
- package/src/handlers/gameobject/ModifyGameObjectToolHandler.js +128 -0
- package/src/handlers/index.js +389 -0
- package/src/handlers/input/AddInputActionToolHandler.js +20 -0
- package/src/handlers/input/AddInputBindingToolHandler.js +20 -0
- package/src/handlers/input/CreateActionMapToolHandler.js +20 -0
- package/src/handlers/input/CreateCompositeBindingToolHandler.js +20 -0
- package/src/handlers/input/GamepadSimulationHandler.js +116 -0
- package/src/handlers/input/InputSystemHandler.js +80 -0
- package/src/handlers/input/KeyboardSimulationHandler.js +79 -0
- package/src/handlers/input/ManageControlSchemesToolHandler.js +20 -0
- package/src/handlers/input/MouseSimulationHandler.js +107 -0
- package/src/handlers/input/RemoveActionMapToolHandler.js +20 -0
- package/src/handlers/input/RemoveAllBindingsToolHandler.js +20 -0
- package/src/handlers/input/RemoveInputActionToolHandler.js +20 -0
- package/src/handlers/input/RemoveInputBindingToolHandler.js +20 -0
- package/src/handlers/input/TouchSimulationHandler.js +142 -0
- package/src/handlers/menu/ExecuteMenuItemToolHandler.js +304 -0
- package/src/handlers/package/PackageManagerToolHandler.js +248 -0
- package/src/handlers/package/RegistryConfigToolHandler.js +198 -0
- package/src/handlers/playmode/GetEditorStateToolHandler.js +81 -0
- package/src/handlers/playmode/PauseToolHandler.js +44 -0
- package/src/handlers/playmode/PlayToolHandler.js +91 -0
- package/src/handlers/playmode/StopToolHandler.js +77 -0
- package/src/handlers/playmode/WaitForEditorStateToolHandler.js +45 -0
- package/src/handlers/scene/CreateSceneToolHandler.js +91 -0
- package/src/handlers/scene/GetSceneInfoToolHandler.js +20 -0
- package/src/handlers/scene/ListScenesToolHandler.js +58 -0
- package/src/handlers/scene/LoadSceneToolHandler.js +92 -0
- package/src/handlers/scene/SaveSceneToolHandler.js +76 -0
- package/src/handlers/screenshot/AnalyzeScreenshotToolHandler.js +238 -0
- package/src/handlers/screenshot/CaptureScreenshotToolHandler.js +692 -0
- package/src/handlers/script/BuildCodeIndexToolHandler.js +163 -0
- package/src/handlers/script/ScriptCreateClassFileToolHandler.js +60 -0
- package/src/handlers/script/ScriptEditStructuredToolHandler.js +173 -0
- package/src/handlers/script/ScriptIndexStatusToolHandler.js +61 -0
- package/src/handlers/script/ScriptPackagesListToolHandler.js +103 -0
- package/src/handlers/script/ScriptReadToolHandler.js +106 -0
- package/src/handlers/script/ScriptRefactorRenameToolHandler.js +83 -0
- package/src/handlers/script/ScriptRefsFindToolHandler.js +144 -0
- package/src/handlers/script/ScriptRemoveSymbolToolHandler.js +79 -0
- package/src/handlers/script/ScriptSearchToolHandler.js +320 -0
- package/src/handlers/script/ScriptSymbolFindToolHandler.js +117 -0
- package/src/handlers/script/ScriptSymbolsGetToolHandler.js +96 -0
- package/src/handlers/settings/GetProjectSettingsToolHandler.js +161 -0
- package/src/handlers/settings/UpdateProjectSettingsToolHandler.js +272 -0
- package/src/handlers/system/GetCommandStatsToolHandler.js +25 -0
- package/src/handlers/system/PingToolHandler.js +53 -0
- package/src/handlers/system/RefreshAssetsToolHandler.js +45 -0
- package/src/handlers/ui/ClickUIElementToolHandler.js +110 -0
- package/src/handlers/ui/FindUIElementsToolHandler.js +63 -0
- package/src/handlers/ui/GetUIElementStateToolHandler.js +50 -0
- package/src/handlers/ui/SetUIElementValueToolHandler.js +49 -0
- package/src/handlers/ui/SimulateUIInputToolHandler.js +156 -0
- package/src/handlers/video/CaptureVideoForToolHandler.js +96 -0
- package/src/handlers/video/CaptureVideoStartToolHandler.js +38 -0
- package/src/handlers/video/CaptureVideoStatusToolHandler.js +30 -0
- package/src/handlers/video/CaptureVideoStopToolHandler.js +32 -0
- package/src/lsp/CSharpLspUtils.js +134 -0
- package/src/lsp/LspProcessManager.js +60 -0
- package/src/lsp/LspRpcClient.js +133 -0
- package/src/tools/analysis/analyzeSceneContents.js +100 -0
- package/src/tools/analysis/findByComponent.js +87 -0
- package/src/tools/analysis/getAnimatorState.js +326 -0
- package/src/tools/analysis/getComponentValues.js +182 -0
- package/src/tools/analysis/getGameObjectDetails.js +159 -0
- package/src/tools/analysis/getInputActionsState.js +329 -0
- package/src/tools/analysis/getObjectReferences.js +86 -0
- package/src/tools/input/inputActionsEditor.js +556 -0
- package/src/tools/scene/createScene.js +112 -0
- package/src/tools/scene/getSceneInfo.js +95 -0
- package/src/tools/scene/listScenes.js +82 -0
- package/src/tools/scene/loadScene.js +122 -0
- package/src/tools/scene/saveScene.js +91 -0
- package/src/tools/system/ping.js +72 -0
- package/src/tools/video/recordFor.js +31 -0
- package/src/tools/video/recordPlayMode.js +61 -0
- package/src/utils/csharpParse.js +88 -0
- package/src/utils/validators.js +90 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool definition for get_scene_info
|
|
3
|
+
*/
|
|
4
|
+
export const getSceneInfoToolDefinition = {
|
|
5
|
+
name: 'get_scene_info',
|
|
6
|
+
description: 'Get detailed information about a scene',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
scenePath: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
description: 'Full path to the scene file. If not provided, gets info about current scene.'
|
|
13
|
+
},
|
|
14
|
+
sceneName: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Name of the scene. Use either scenePath or sceneName, not both.'
|
|
17
|
+
},
|
|
18
|
+
includeGameObjects: {
|
|
19
|
+
type: 'boolean',
|
|
20
|
+
description: 'Include list of root GameObjects in the scene (only for loaded scenes). Default: false'
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
required: []
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Handler for get_scene_info tool
|
|
29
|
+
*/
|
|
30
|
+
export async function getSceneInfoHandler(unityConnection, args) {
|
|
31
|
+
try {
|
|
32
|
+
// Check connection
|
|
33
|
+
if (!unityConnection.isConnected()) {
|
|
34
|
+
return {
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: 'text',
|
|
38
|
+
text: 'Failed to get scene info: Unity connection not available'
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
isError: true
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Validate that only one identifier is provided if any
|
|
46
|
+
if (args.scenePath && args.sceneName) {
|
|
47
|
+
return {
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
type: 'text',
|
|
51
|
+
text: 'Failed to get scene info: Provide either scenePath or sceneName, not both'
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
isError: true
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Send command to Unity
|
|
59
|
+
const result = await unityConnection.sendCommand('get_scene_info', args);
|
|
60
|
+
|
|
61
|
+
// Handle Unity response
|
|
62
|
+
if (result.status === 'error') {
|
|
63
|
+
return {
|
|
64
|
+
content: [
|
|
65
|
+
{
|
|
66
|
+
type: 'text',
|
|
67
|
+
text: `Failed to get scene info: ${result.error}`
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
isError: true
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Success response
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
text: result.result.summary || `Scene information retrieved`
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
isError: false
|
|
83
|
+
};
|
|
84
|
+
} catch (error) {
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: 'text',
|
|
89
|
+
text: `Failed to get scene info: ${error.message}`
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
isError: true
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool definition for list_scenes
|
|
3
|
+
*/
|
|
4
|
+
export const listScenesToolDefinition = {
|
|
5
|
+
name: 'list_scenes',
|
|
6
|
+
description: 'List all scenes in the Unity project',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
includeLoadedOnly: {
|
|
11
|
+
type: 'boolean',
|
|
12
|
+
description: 'Only include currently loaded scenes (default: false)'
|
|
13
|
+
},
|
|
14
|
+
includeBuildScenesOnly: {
|
|
15
|
+
type: 'boolean',
|
|
16
|
+
description: 'Only include scenes in build settings (default: false)'
|
|
17
|
+
},
|
|
18
|
+
includePath: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'Filter scenes by path pattern (e.g., "Levels" to find scenes in Levels folder)'
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
required: []
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Handler for list_scenes tool
|
|
29
|
+
*/
|
|
30
|
+
export async function listScenesHandler(unityConnection, args) {
|
|
31
|
+
try {
|
|
32
|
+
// Check connection
|
|
33
|
+
if (!unityConnection.isConnected()) {
|
|
34
|
+
return {
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: 'text',
|
|
38
|
+
text: 'Failed to list scenes: Unity connection not available'
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
isError: true
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Send command to Unity
|
|
46
|
+
const result = await unityConnection.sendCommand('list_scenes', args);
|
|
47
|
+
|
|
48
|
+
// Handle Unity response
|
|
49
|
+
if (result.status === 'error') {
|
|
50
|
+
return {
|
|
51
|
+
content: [
|
|
52
|
+
{
|
|
53
|
+
type: 'text',
|
|
54
|
+
text: `Failed to list scenes: ${result.error}`
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
isError: true
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Success response
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: 'text',
|
|
66
|
+
text: result.result.summary || `Found ${result.result.totalCount} scenes`
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
isError: false
|
|
70
|
+
};
|
|
71
|
+
} catch (error) {
|
|
72
|
+
return {
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: 'text',
|
|
76
|
+
text: `Failed to list scenes: ${error.message}`
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
isError: true
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool definition for load_scene
|
|
3
|
+
*/
|
|
4
|
+
export const loadSceneToolDefinition = {
|
|
5
|
+
name: 'load_scene',
|
|
6
|
+
description: 'Load a scene in Unity',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
scenePath: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
description: 'Full path to the scene file (e.g., "Assets/Scenes/MainMenu.unity")'
|
|
13
|
+
},
|
|
14
|
+
sceneName: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Name of the scene to load (must be in build settings). Use either scenePath or sceneName, not both.'
|
|
17
|
+
},
|
|
18
|
+
loadMode: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
enum: ['Single', 'Additive'],
|
|
21
|
+
description: 'How to load the scene. Single replaces current scene(s), Additive adds to current scene(s) (default: Single)'
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
required: []
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Handler for load_scene tool
|
|
30
|
+
*/
|
|
31
|
+
export async function loadSceneHandler(unityConnection, args) {
|
|
32
|
+
try {
|
|
33
|
+
// Check connection
|
|
34
|
+
if (!unityConnection.isConnected()) {
|
|
35
|
+
return {
|
|
36
|
+
content: [
|
|
37
|
+
{
|
|
38
|
+
type: 'text',
|
|
39
|
+
text: 'Failed to load scene: Unity connection not available'
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
isError: true
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Validate that either scenePath or sceneName is provided
|
|
47
|
+
if (!args.scenePath && !args.sceneName) {
|
|
48
|
+
return {
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: 'text',
|
|
52
|
+
text: 'Failed to load scene: Either scenePath or sceneName must be provided'
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
isError: true
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Validate that only one is provided
|
|
60
|
+
if (args.scenePath && args.sceneName) {
|
|
61
|
+
return {
|
|
62
|
+
content: [
|
|
63
|
+
{
|
|
64
|
+
type: 'text',
|
|
65
|
+
text: 'Failed to load scene: Provide either scenePath or sceneName, not both'
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
isError: true
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Validate load mode
|
|
73
|
+
if (args.loadMode && !['Single', 'Additive'].includes(args.loadMode)) {
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: 'text',
|
|
78
|
+
text: 'Failed to load scene: Invalid load mode. Must be "Single" or "Additive"'
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
isError: true
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Send command to Unity
|
|
86
|
+
const result = await unityConnection.sendCommand('load_scene', args);
|
|
87
|
+
|
|
88
|
+
// Handle Unity response
|
|
89
|
+
if (result.status === 'error') {
|
|
90
|
+
return {
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: 'text',
|
|
94
|
+
text: `Failed to load scene: ${result.error}`
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
isError: true
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Success response
|
|
102
|
+
return {
|
|
103
|
+
content: [
|
|
104
|
+
{
|
|
105
|
+
type: 'text',
|
|
106
|
+
text: result.result.summary || `Scene loaded successfully`
|
|
107
|
+
}
|
|
108
|
+
],
|
|
109
|
+
isError: false
|
|
110
|
+
};
|
|
111
|
+
} catch (error) {
|
|
112
|
+
return {
|
|
113
|
+
content: [
|
|
114
|
+
{
|
|
115
|
+
type: 'text',
|
|
116
|
+
text: `Failed to load scene: ${error.message}`
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
isError: true
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool definition for save_scene
|
|
3
|
+
*/
|
|
4
|
+
export const saveSceneToolDefinition = {
|
|
5
|
+
name: 'save_scene',
|
|
6
|
+
description: 'Save the current scene in Unity',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
scenePath: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
description: 'Path where to save the scene. If not provided, saves to current scene path. Required if saveAs is true.'
|
|
13
|
+
},
|
|
14
|
+
saveAs: {
|
|
15
|
+
type: 'boolean',
|
|
16
|
+
description: 'Whether to save as a new scene (creates a copy). Default: false'
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
required: []
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Handler for save_scene tool
|
|
25
|
+
*/
|
|
26
|
+
export async function saveSceneHandler(unityConnection, args) {
|
|
27
|
+
try {
|
|
28
|
+
// Check connection
|
|
29
|
+
if (!unityConnection.isConnected()) {
|
|
30
|
+
return {
|
|
31
|
+
content: [
|
|
32
|
+
{
|
|
33
|
+
type: 'text',
|
|
34
|
+
text: 'Failed to save scene: Unity connection not available'
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
isError: true
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Validate saveAs requires scenePath
|
|
42
|
+
if (args.saveAs && !args.scenePath) {
|
|
43
|
+
return {
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: 'text',
|
|
47
|
+
text: 'Failed to save scene: scenePath is required when saveAs is true'
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
isError: true
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Send command to Unity
|
|
55
|
+
const result = await unityConnection.sendCommand('save_scene', args);
|
|
56
|
+
|
|
57
|
+
// Handle Unity response
|
|
58
|
+
if (result.status === 'error') {
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{
|
|
62
|
+
type: 'text',
|
|
63
|
+
text: `Failed to save scene: ${result.error}`
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
isError: true
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Success response
|
|
71
|
+
return {
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: result.result.summary || `Scene saved successfully`
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
isError: false
|
|
79
|
+
};
|
|
80
|
+
} catch (error) {
|
|
81
|
+
return {
|
|
82
|
+
content: [
|
|
83
|
+
{
|
|
84
|
+
type: 'text',
|
|
85
|
+
text: `Failed to save scene: ${error.message}`
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
isError: true
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ListToolsRequestSchema,
|
|
3
|
+
CallToolRequestSchema
|
|
4
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Ping tool for testing Unity connection
|
|
8
|
+
*/
|
|
9
|
+
export function registerPingTool(server, unityConnection) {
|
|
10
|
+
// Tool definition
|
|
11
|
+
const pingTool = {
|
|
12
|
+
name: 'ping',
|
|
13
|
+
description: 'Test connection to Unity Editor',
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
message: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'Optional message to echo back'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
required: []
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Register list tools handler
|
|
27
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
28
|
+
return {
|
|
29
|
+
tools: [pingTool]
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Register call tool handler
|
|
34
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
35
|
+
const { name, arguments: args } = request.params;
|
|
36
|
+
|
|
37
|
+
if (name === 'ping') {
|
|
38
|
+
try {
|
|
39
|
+
// Ensure connected
|
|
40
|
+
if (!unityConnection.isConnected()) {
|
|
41
|
+
await unityConnection.connect();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Send ping with optional message
|
|
45
|
+
const result = await unityConnection.sendCommand('ping', {
|
|
46
|
+
message: args?.message || 'ping'
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: 'text',
|
|
53
|
+
text: `Unity responded: ${result.message} (echo: ${result.echo || args?.message || 'ping'})`
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
};
|
|
57
|
+
} catch (error) {
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: 'text',
|
|
62
|
+
text: `Failed to ping Unity: ${error.message}`
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
isError: true
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
throw new Error(`Tool not found: ${name}`);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { UnityConnection } from '../../core/unityConnection.js';
|
|
2
|
+
import { CaptureVideoForToolHandler } from '../../handlers/video/CaptureVideoForToolHandler.js';
|
|
3
|
+
|
|
4
|
+
async function main() {
|
|
5
|
+
const unity = new UnityConnection();
|
|
6
|
+
try { await unity.connect(); } catch (e) { console.error('connect failed:', e.message); process.exit(1); }
|
|
7
|
+
try {
|
|
8
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '').slice(0, 15);
|
|
9
|
+
const outputPath = `Assets/Screenshots/recordings/mcp_for_${ts}.mp4`;
|
|
10
|
+
const handler = new CaptureVideoForToolHandler(unity);
|
|
11
|
+
const result = await handler.execute({
|
|
12
|
+
captureMode: 'game',
|
|
13
|
+
width: 1280,
|
|
14
|
+
height: 720,
|
|
15
|
+
fps: 30,
|
|
16
|
+
durationSec: 2,
|
|
17
|
+
play: true
|
|
18
|
+
});
|
|
19
|
+
if (result && result.error) {
|
|
20
|
+
console.error('capture_video_for error:', result.error);
|
|
21
|
+
} else {
|
|
22
|
+
console.log('capture_video_for ok:', result && result.outputPath);
|
|
23
|
+
}
|
|
24
|
+
} catch (e) {
|
|
25
|
+
console.error('recordFor error:', e.message);
|
|
26
|
+
} finally {
|
|
27
|
+
unity.disconnect();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
main();
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { UnityConnection } from '../../core/unityConnection.js';
|
|
2
|
+
import { config } from '../../core/config.js';
|
|
3
|
+
|
|
4
|
+
async function main() {
|
|
5
|
+
const unity = new UnityConnection();
|
|
6
|
+
try {
|
|
7
|
+
await unity.connect();
|
|
8
|
+
} catch (e) {
|
|
9
|
+
console.error('[recordPlayMode] Failed to connect to Unity:', e.message);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// Enter Play Mode
|
|
15
|
+
await unity.sendCommand('play_game', {});
|
|
16
|
+
// Domain reload causes disconnect. Reconnect and wait for play.
|
|
17
|
+
for (let i = 0; i < 60; i++) {
|
|
18
|
+
if (!unity.isConnected()) {
|
|
19
|
+
try { await unity.connect(); } catch {}
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const s = await unity.sendCommand('get_editor_state', {});
|
|
23
|
+
if (s && s.isPlaying) break;
|
|
24
|
+
} catch {}
|
|
25
|
+
await new Promise(r => setTimeout(r, 500));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Start recording
|
|
29
|
+
const start = await unity.sendCommand('capture_video_start', {
|
|
30
|
+
captureMode: 'game',
|
|
31
|
+
width: 1280,
|
|
32
|
+
height: 720,
|
|
33
|
+
fps: 30,
|
|
34
|
+
maxDurationSec: 3
|
|
35
|
+
});
|
|
36
|
+
if (start && start.error) {
|
|
37
|
+
console.error('[recordPlayMode] start error:', start.error);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Poll status a few times
|
|
41
|
+
for (let i = 0; i < 16; i++) {
|
|
42
|
+
const st = await unity.sendCommand('capture_video_status', {});
|
|
43
|
+
// console.log('[recordPlayMode] status', st);
|
|
44
|
+
await new Promise(r => setTimeout(r, 250));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Ensure stopped
|
|
48
|
+
await unity.sendCommand('capture_video_stop', {});
|
|
49
|
+
|
|
50
|
+
} catch (e) {
|
|
51
|
+
console.error('[recordPlayMode] error:', e.message);
|
|
52
|
+
} finally {
|
|
53
|
+
try {
|
|
54
|
+
if (!unity.isConnected()) { await unity.connect(); }
|
|
55
|
+
await unity.sendCommand('stop_game', {});
|
|
56
|
+
} catch {}
|
|
57
|
+
unity.disconnect();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
main();
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Lightweight C# symbol extractor for Node-side fallback (not Roslyn-accurate)
|
|
2
|
+
export function parseFileSymbols(relPath, text) {
|
|
3
|
+
const lines = text.split('\n');
|
|
4
|
+
const result = { path: relPath, symbols: [] };
|
|
5
|
+
const nsRx = /^\s*namespace\s+([A-Za-z0-9_.]+)/;
|
|
6
|
+
const typeRx = /^\s*(?:public|internal|protected|private|abstract|sealed|static|partial|new|readonly|\s)*\s*(class|struct|interface|enum)\s+([A-Za-z0-9_]+)/;
|
|
7
|
+
const methodRx = /^\s*(?:public|internal|protected|private|static|virtual|override|async|sealed|extern|unsafe|new|readonly|\s)+[A-Za-z0-9_<>,\[\]\?\(\)\.:\s]+\s+([A-Za-z0-9_]+)\s*\(([^)]*)\)\s*(?:\{|=>|;)/;
|
|
8
|
+
const propRx = /^\s*(?:public|internal|protected|private|static|virtual|override|sealed|new|readonly|\s)+[A-Za-z0-9_<>,\[\]\?\.:\s]+\s+([A-Za-z0-9_]+)\s*\{/;
|
|
9
|
+
|
|
10
|
+
const nsStack = [];
|
|
11
|
+
const typeStack = [];
|
|
12
|
+
let braceDepth = 0;
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < lines.length; i++) {
|
|
15
|
+
const line = lines[i];
|
|
16
|
+
const nsM = line.match(nsRx);
|
|
17
|
+
if (nsM) nsStack.push({ name: nsM[1], line: i + 1 });
|
|
18
|
+
|
|
19
|
+
const tM = line.match(typeRx);
|
|
20
|
+
if (tM) {
|
|
21
|
+
const kind = tM[1];
|
|
22
|
+
const name = tM[2];
|
|
23
|
+
typeStack.push({ kind, name, startLine: i + 1, braceDepthAtStart: braceDepth });
|
|
24
|
+
result.symbols.push({
|
|
25
|
+
name,
|
|
26
|
+
kind,
|
|
27
|
+
namespace: nsStack.map(n => n.name).join('.'),
|
|
28
|
+
container: typeStack.length > 1 ? typeStack[typeStack.length - 2].name : null,
|
|
29
|
+
startLine: i + 1,
|
|
30
|
+
endLine: 0,
|
|
31
|
+
startColumn: 1,
|
|
32
|
+
endColumn: 1,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const mM = line.match(methodRx);
|
|
37
|
+
if (mM) {
|
|
38
|
+
const name = mM[1];
|
|
39
|
+
result.symbols.push({
|
|
40
|
+
name,
|
|
41
|
+
kind: 'method',
|
|
42
|
+
namespace: nsStack.map(n => n.name).join('.'),
|
|
43
|
+
container: typeStack.length ? typeStack[typeStack.length - 1].name : null,
|
|
44
|
+
startLine: i + 1,
|
|
45
|
+
endLine: i + 1,
|
|
46
|
+
startColumn: 1,
|
|
47
|
+
endColumn: 1,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const pM = line.match(propRx);
|
|
52
|
+
if (pM) {
|
|
53
|
+
const name = pM[1];
|
|
54
|
+
result.symbols.push({
|
|
55
|
+
name,
|
|
56
|
+
kind: 'property',
|
|
57
|
+
namespace: nsStack.map(n => n.name).join('.'),
|
|
58
|
+
container: typeStack.length ? typeStack[typeStack.length - 1].name : null,
|
|
59
|
+
startLine: i + 1,
|
|
60
|
+
endLine: i + 1,
|
|
61
|
+
startColumn: 1,
|
|
62
|
+
endColumn: 1,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// brace accounting
|
|
67
|
+
for (const ch of line) {
|
|
68
|
+
if (ch === '{') braceDepth++;
|
|
69
|
+
else if (ch === '}') braceDepth--;
|
|
70
|
+
}
|
|
71
|
+
// close types whose body ended
|
|
72
|
+
while (typeStack.length && braceDepth < typeStack[typeStack.length - 1].braceDepthAtStart) {
|
|
73
|
+
const closed = typeStack.pop();
|
|
74
|
+
// set endLine for the last matching symbol
|
|
75
|
+
for (let j = result.symbols.length - 1; j >= 0; j--) {
|
|
76
|
+
const s = result.symbols[j];
|
|
77
|
+
if (s.kind === closed.kind && s.name === closed.name && s.endLine === 0) { s.endLine = i + 1; break; }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const last = Math.max(1, lines.length);
|
|
82
|
+
for (const s of result.symbols) {
|
|
83
|
+
if (!s.endLine) s.endLine = last;
|
|
84
|
+
if (!s.endColumn) s.endColumn = 1;
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|