@baixfeng/godot-mcp-cli 1.0.11

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 (115) hide show
  1. package/README.md +187 -0
  2. package/addons/godot_mcp/command_handler.gd +161 -0
  3. package/addons/godot_mcp/command_handler.gd.uid +1 -0
  4. package/addons/godot_mcp/commands/base_command_processor.gd +221 -0
  5. package/addons/godot_mcp/commands/base_command_processor.gd.uid +1 -0
  6. package/addons/godot_mcp/commands/debugger_commands.gd +221 -0
  7. package/addons/godot_mcp/commands/debugger_commands.gd.uid +1 -0
  8. package/addons/godot_mcp/commands/editor_commands.gd +237 -0
  9. package/addons/godot_mcp/commands/editor_commands.gd.uid +1 -0
  10. package/addons/godot_mcp/commands/editor_script_commands.gd +365 -0
  11. package/addons/godot_mcp/commands/editor_script_commands.gd.uid +1 -0
  12. package/addons/godot_mcp/commands/input_commands.gd +337 -0
  13. package/addons/godot_mcp/commands/input_commands.gd.uid +1 -0
  14. package/addons/godot_mcp/commands/node_commands.gd +222 -0
  15. package/addons/godot_mcp/commands/node_commands.gd.uid +1 -0
  16. package/addons/godot_mcp/commands/project_commands.gd +298 -0
  17. package/addons/godot_mcp/commands/project_commands.gd.uid +1 -0
  18. package/addons/godot_mcp/commands/scene_commands.gd +337 -0
  19. package/addons/godot_mcp/commands/scene_commands.gd.uid +1 -0
  20. package/addons/godot_mcp/commands/script_commands.gd +349 -0
  21. package/addons/godot_mcp/commands/script_commands.gd.uid +1 -0
  22. package/addons/godot_mcp/mcp_asset_commands.gd +153 -0
  23. package/addons/godot_mcp/mcp_asset_commands.gd.uid +1 -0
  24. package/addons/godot_mcp/mcp_debug_output_publisher.gd +1669 -0
  25. package/addons/godot_mcp/mcp_debug_output_publisher.gd.uid +1 -0
  26. package/addons/godot_mcp/mcp_debugger_bridge.gd +1455 -0
  27. package/addons/godot_mcp/mcp_debugger_bridge.gd.uid +1 -0
  28. package/addons/godot_mcp/mcp_enhanced_commands.gd +1083 -0
  29. package/addons/godot_mcp/mcp_enhanced_commands.gd.uid +1 -0
  30. package/addons/godot_mcp/mcp_input_handler.gd +545 -0
  31. package/addons/godot_mcp/mcp_input_handler.gd.uid +1 -0
  32. package/addons/godot_mcp/mcp_runtime_debugger_bridge.gd +464 -0
  33. package/addons/godot_mcp/mcp_runtime_debugger_bridge.gd.uid +1 -0
  34. package/addons/godot_mcp/mcp_script_resource_commands.gd +165 -0
  35. package/addons/godot_mcp/mcp_script_resource_commands.gd.uid +1 -0
  36. package/addons/godot_mcp/mcp_server.gd +260 -0
  37. package/addons/godot_mcp/mcp_server.gd.uid +1 -0
  38. package/addons/godot_mcp/plugin.cfg +7 -0
  39. package/addons/godot_mcp/runtime_debugger.gd +81 -0
  40. package/addons/godot_mcp/runtime_debugger.gd.uid +1 -0
  41. package/addons/godot_mcp/ui/mcp_panel.gd +94 -0
  42. package/addons/godot_mcp/ui/mcp_panel.gd.uid +1 -0
  43. package/addons/godot_mcp/ui/mcp_panel.tscn +96 -0
  44. package/addons/godot_mcp/utils/node_utils.gd +82 -0
  45. package/addons/godot_mcp/utils/node_utils.gd.uid +1 -0
  46. package/addons/godot_mcp/utils/resource_utils.gd +81 -0
  47. package/addons/godot_mcp/utils/resource_utils.gd.uid +1 -0
  48. package/addons/godot_mcp/utils/script_utils.gd +114 -0
  49. package/addons/godot_mcp/utils/script_utils.gd.uid +1 -0
  50. package/addons/godot_mcp/websocket_server.gd +197 -0
  51. package/addons/godot_mcp/websocket_server.gd.uid +1 -0
  52. package/dist/cli.d.ts +2 -0
  53. package/dist/cli.js +561 -0
  54. package/dist/cli.js.map +1 -0
  55. package/dist/index.d.ts +1 -0
  56. package/dist/index.js +156 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/resources/asset_resources.d.ts +29 -0
  59. package/dist/resources/asset_resources.js +145 -0
  60. package/dist/resources/asset_resources.js.map +1 -0
  61. package/dist/resources/debug_resources.d.ts +11 -0
  62. package/dist/resources/debug_resources.js +106 -0
  63. package/dist/resources/debug_resources.js.map +1 -0
  64. package/dist/resources/debugger_resources.d.ts +62 -0
  65. package/dist/resources/debugger_resources.js +201 -0
  66. package/dist/resources/debugger_resources.js.map +1 -0
  67. package/dist/resources/editor_resources.d.ts +47 -0
  68. package/dist/resources/editor_resources.js +155 -0
  69. package/dist/resources/editor_resources.js.map +1 -0
  70. package/dist/resources/project_resources.d.ts +33 -0
  71. package/dist/resources/project_resources.js +137 -0
  72. package/dist/resources/project_resources.js.map +1 -0
  73. package/dist/resources/scene_resources.d.ts +33 -0
  74. package/dist/resources/scene_resources.js +160 -0
  75. package/dist/resources/scene_resources.js.map +1 -0
  76. package/dist/resources/script_resources.d.ts +51 -0
  77. package/dist/resources/script_resources.js +203 -0
  78. package/dist/resources/script_resources.js.map +1 -0
  79. package/dist/tools/asset_tools.d.ts +5 -0
  80. package/dist/tools/asset_tools.js +125 -0
  81. package/dist/tools/asset_tools.js.map +1 -0
  82. package/dist/tools/debugger_tools.d.ts +2 -0
  83. package/dist/tools/debugger_tools.js +342 -0
  84. package/dist/tools/debugger_tools.js.map +1 -0
  85. package/dist/tools/editor_tools.d.ts +2 -0
  86. package/dist/tools/editor_tools.js +165 -0
  87. package/dist/tools/editor_tools.js.map +1 -0
  88. package/dist/tools/enhanced_tools.d.ts +5 -0
  89. package/dist/tools/enhanced_tools.js +706 -0
  90. package/dist/tools/enhanced_tools.js.map +1 -0
  91. package/dist/tools/input_tools.d.ts +2 -0
  92. package/dist/tools/input_tools.js +408 -0
  93. package/dist/tools/input_tools.js.map +1 -0
  94. package/dist/tools/node_tools.d.ts +5 -0
  95. package/dist/tools/node_tools.js +217 -0
  96. package/dist/tools/node_tools.js.map +1 -0
  97. package/dist/tools/project_tools.d.ts +5 -0
  98. package/dist/tools/project_tools.js +162 -0
  99. package/dist/tools/project_tools.js.map +1 -0
  100. package/dist/tools/scene_tools.d.ts +5 -0
  101. package/dist/tools/scene_tools.js +260 -0
  102. package/dist/tools/scene_tools.js.map +1 -0
  103. package/dist/tools/script_resource_tools.d.ts +5 -0
  104. package/dist/tools/script_resource_tools.js +5 -0
  105. package/dist/tools/script_resource_tools.js.map +1 -0
  106. package/dist/tools/script_tools.d.ts +5 -0
  107. package/dist/tools/script_tools.js +154 -0
  108. package/dist/tools/script_tools.js.map +1 -0
  109. package/dist/utils/godot_connection.d.ts +30 -0
  110. package/dist/utils/godot_connection.js +285 -0
  111. package/dist/utils/godot_connection.js.map +1 -0
  112. package/dist/utils/types.d.ts +16 -0
  113. package/dist/utils/types.js +2 -0
  114. package/dist/utils/types.js.map +1 -0
  115. package/package.json +58 -0
@@ -0,0 +1,222 @@
1
+ @tool
2
+ class_name MCPNodeCommands
3
+ extends MCPBaseCommandProcessor
4
+
5
+ func process_command(client_id: int, command_type: String, params: Dictionary, command_id: String) -> bool:
6
+ match command_type:
7
+ "create_node":
8
+ _create_node(client_id, params, command_id)
9
+ return true
10
+ "delete_node":
11
+ _delete_node(client_id, params, command_id)
12
+ return true
13
+ "update_node_property":
14
+ _update_node_property(client_id, params, command_id)
15
+ return true
16
+ "get_node_properties":
17
+ _get_node_properties(client_id, params, command_id)
18
+ return true
19
+ "list_nodes":
20
+ _list_nodes(client_id, params, command_id)
21
+ return true
22
+ return false # Command not handled
23
+
24
+ func _create_node(client_id: int, params: Dictionary, command_id: String) -> void:
25
+ var parent_path = params.get("parent_path", ".")
26
+ var node_type = params.get("node_type", "Node")
27
+ var node_name = params.get("node_name", "NewNode")
28
+
29
+ # Validation
30
+ if not ClassDB.class_exists(node_type):
31
+ return _send_error(client_id, "Invalid node type: %s" % node_type, command_id)
32
+
33
+ # Get editor plugin and interfaces
34
+ var plugin = Engine.get_meta("GodotMCPPlugin")
35
+ if not plugin:
36
+ return _send_error(client_id, "GodotMCPPlugin not found in Engine metadata", command_id)
37
+
38
+ var editor_interface = plugin.get_editor_interface()
39
+ var edited_scene_root = editor_interface.get_edited_scene_root()
40
+
41
+ if not edited_scene_root:
42
+ return _send_error(client_id, "No scene is currently being edited", command_id)
43
+
44
+ # Get the parent node using the editor node helper
45
+ var parent = _get_editor_node(parent_path)
46
+ if not parent:
47
+ return _send_error(client_id, "Parent node not found: %s" % parent_path, command_id)
48
+
49
+ # Create the node
50
+ var node
51
+ if ClassDB.can_instantiate(node_type):
52
+ node = ClassDB.instantiate(node_type)
53
+ else:
54
+ return _send_error(client_id, "Cannot instantiate node of type: %s" % node_type, command_id)
55
+
56
+ if not node:
57
+ return _send_error(client_id, "Failed to create node of type: %s" % node_type, command_id)
58
+
59
+ # Set the node name
60
+ node.name = node_name
61
+
62
+ # Add the node to the parent
63
+ parent.add_child(node)
64
+
65
+ # Set owner for proper serialization
66
+ node.owner = edited_scene_root
67
+
68
+ # Mark the scene as modified
69
+ _mark_scene_modified()
70
+
71
+ _send_success(client_id, {
72
+ "node_path": parent_path + "/" + node_name
73
+ }, command_id)
74
+
75
+ func _delete_node(client_id: int, params: Dictionary, command_id: String) -> void:
76
+ var node_path = params.get("node_path", "")
77
+
78
+ # Validation
79
+ if node_path.is_empty():
80
+ return _send_error(client_id, "Node path cannot be empty", command_id)
81
+
82
+ # Get editor plugin and interfaces
83
+ var plugin = Engine.get_meta("GodotMCPPlugin")
84
+ if not plugin:
85
+ return _send_error(client_id, "GodotMCPPlugin not found in Engine metadata", command_id)
86
+
87
+ var editor_interface = plugin.get_editor_interface()
88
+ var edited_scene_root = editor_interface.get_edited_scene_root()
89
+
90
+ if not edited_scene_root:
91
+ return _send_error(client_id, "No scene is currently being edited", command_id)
92
+
93
+ # Get the node using the editor node helper
94
+ var node = _get_editor_node(node_path)
95
+ if not node:
96
+ return _send_error(client_id, "Node not found: %s" % node_path, command_id)
97
+
98
+ # Cannot delete the root node
99
+ if node == edited_scene_root:
100
+ return _send_error(client_id, "Cannot delete the root node", command_id)
101
+
102
+ # Get parent for operation
103
+ var parent = node.get_parent()
104
+ if not parent:
105
+ return _send_error(client_id, "Node has no parent: %s" % node_path, command_id)
106
+
107
+ # Remove the node
108
+ parent.remove_child(node)
109
+ node.queue_free()
110
+
111
+ # Mark the scene as modified
112
+ _mark_scene_modified()
113
+
114
+ _send_success(client_id, {
115
+ "deleted_node_path": node_path
116
+ }, command_id)
117
+
118
+ func _update_node_property(client_id: int, params: Dictionary, command_id: String) -> void:
119
+ var node_path = params.get("node_path", "")
120
+ var property_name = params.get("property", "")
121
+ var property_value = params.get("value")
122
+
123
+ # Validation
124
+ if node_path.is_empty():
125
+ return _send_error(client_id, "Node path cannot be empty", command_id)
126
+
127
+ if property_name.is_empty():
128
+ return _send_error(client_id, "Property name cannot be empty", command_id)
129
+
130
+ if property_value == null:
131
+ return _send_error(client_id, "Property value cannot be null", command_id)
132
+
133
+ # Get editor plugin and interfaces
134
+ var plugin = Engine.get_meta("GodotMCPPlugin")
135
+ if not plugin:
136
+ return _send_error(client_id, "GodotMCPPlugin not found in Engine metadata", command_id)
137
+
138
+ # Get the node using the editor node helper
139
+ var node = _get_editor_node(node_path)
140
+ if not node:
141
+ return _send_error(client_id, "Node not found: %s" % node_path, command_id)
142
+
143
+ # Check if the property exists
144
+ if not property_name in node:
145
+ return _send_error(client_id, "Property %s does not exist on node %s" % [property_name, node_path], command_id)
146
+
147
+ # Parse property value for Godot types
148
+ var parsed_value = _parse_property_value(property_value)
149
+
150
+ # Get current property value for undo
151
+ var old_value = node.get(property_name)
152
+
153
+ # Get undo/redo system
154
+ var undo_redo = _get_undo_redo()
155
+ if not undo_redo:
156
+ # Fallback method if we can't get undo/redo
157
+ node.set(property_name, parsed_value)
158
+ _mark_scene_modified()
159
+ else:
160
+ # Use undo/redo for proper editor integration
161
+ undo_redo.create_action("Update Property: " + property_name)
162
+ undo_redo.add_do_property(node, property_name, parsed_value)
163
+ undo_redo.add_undo_property(node, property_name, old_value)
164
+ undo_redo.commit_action()
165
+
166
+ # Mark the scene as modified
167
+ _mark_scene_modified()
168
+
169
+ _send_success(client_id, {
170
+ "node_path": node_path,
171
+ "property": property_name,
172
+ "value": property_value,
173
+ "parsed_value": str(parsed_value)
174
+ }, command_id)
175
+
176
+ func _get_node_properties(client_id: int, params: Dictionary, command_id: String) -> void:
177
+ var node_path = params.get("node_path", "")
178
+
179
+ # Validation
180
+ if node_path.is_empty():
181
+ return _send_error(client_id, "Node path cannot be empty", command_id)
182
+
183
+ # Get the node using the editor node helper
184
+ var node = _get_editor_node(node_path)
185
+ if not node:
186
+ return _send_error(client_id, "Node not found: %s" % node_path, command_id)
187
+
188
+ # Get all properties
189
+ var properties = {}
190
+ var property_list = node.get_property_list()
191
+
192
+ for prop in property_list:
193
+ var name = prop["name"]
194
+ if not name.begins_with("_"): # Skip internal properties
195
+ properties[name] = node.get(name)
196
+
197
+ _send_success(client_id, {
198
+ "node_path": node_path,
199
+ "properties": properties
200
+ }, command_id)
201
+
202
+ func _list_nodes(client_id: int, params: Dictionary, command_id: String) -> void:
203
+ var parent_path = params.get("parent_path", ".")
204
+
205
+ # Get the parent node using the editor node helper
206
+ var parent = _get_editor_node(parent_path)
207
+ if not parent:
208
+ return _send_error(client_id, "Parent node not found: %s" % parent_path, command_id)
209
+
210
+ # Get children
211
+ var children = []
212
+ for child in parent.get_children():
213
+ children.append({
214
+ "name": child.name,
215
+ "type": child.get_class(),
216
+ "path": str(child.get_path()).replace(str(parent.get_path()), parent_path)
217
+ })
218
+
219
+ _send_success(client_id, {
220
+ "parent_path": parent_path,
221
+ "children": children
222
+ }, command_id)
@@ -0,0 +1 @@
1
+ uid://b4u0m3t8o03jt
@@ -0,0 +1,298 @@
1
+ @tool
2
+ class_name MCPProjectCommands
3
+ extends MCPBaseCommandProcessor
4
+
5
+ func process_command(client_id: int, command_type: String, params: Dictionary, command_id: String) -> bool:
6
+ match command_type:
7
+ "get_project_info":
8
+ _get_project_info(client_id, params, command_id)
9
+ return true
10
+ "list_project_files":
11
+ _list_project_files(client_id, params, command_id)
12
+ return true
13
+ "get_project_structure":
14
+ _get_project_structure(client_id, params, command_id)
15
+ return true
16
+ "get_project_settings":
17
+ _get_project_settings(client_id, params, command_id)
18
+ return true
19
+ "list_project_resources":
20
+ _list_project_resources(client_id, params, command_id)
21
+ return true
22
+ "run_project":
23
+ _run_project(client_id, params, command_id)
24
+ return true
25
+ "stop_running_project":
26
+ _stop_running_project(client_id, params, command_id)
27
+ return true
28
+ "run_current_scene":
29
+ _run_current_scene(client_id, params, command_id)
30
+ return true
31
+ "run_specific_scene":
32
+ _run_specific_scene(client_id, params, command_id)
33
+ return true
34
+ return false # Command not handled
35
+
36
+ func _get_project_info(client_id: int, _params: Dictionary, command_id: String) -> void:
37
+ var project_name = ProjectSettings.get_setting("application/config/name", "Untitled Project")
38
+ var project_version = ProjectSettings.get_setting("application/config/version", "1.0.0")
39
+ var project_path = ProjectSettings.globalize_path("res://")
40
+
41
+ # Get Godot version info and structure it as expected by the server
42
+ var version_info = Engine.get_version_info()
43
+ print("Raw Godot version info: ", version_info)
44
+
45
+ # Create structured version object with the expected properties
46
+ var structured_version = {
47
+ "major": version_info.get("major", 0),
48
+ "minor": version_info.get("minor", 0),
49
+ "patch": version_info.get("patch", 0)
50
+ }
51
+
52
+ _send_success(client_id, {
53
+ "project_name": project_name,
54
+ "project_version": project_version,
55
+ "project_path": project_path,
56
+ "godot_version": structured_version,
57
+ "current_scene": get_tree().edited_scene_root.scene_file_path if get_tree().edited_scene_root else ""
58
+ }, command_id)
59
+
60
+ func _list_project_files(client_id: int, params: Dictionary, command_id: String) -> void:
61
+ var extensions = params.get("extensions", [])
62
+ var files = []
63
+
64
+ # Get all files with the specified extensions
65
+ var dir = DirAccess.open("res://")
66
+ if dir:
67
+ _scan_directory(dir, "", extensions, files)
68
+ else:
69
+ return _send_error(client_id, "Failed to open res:// directory", command_id)
70
+
71
+ _send_success(client_id, {
72
+ "files": files
73
+ }, command_id)
74
+
75
+ func _scan_directory(dir: DirAccess, path: String, extensions: Array, files: Array) -> void:
76
+ dir.list_dir_begin()
77
+ var file_name = dir.get_next()
78
+
79
+ while file_name != "":
80
+ if dir.current_is_dir():
81
+ var subdir = DirAccess.open("res://" + path + file_name)
82
+ if subdir:
83
+ _scan_directory(subdir, path + file_name + "/", extensions, files)
84
+ else:
85
+ var file_path = path + file_name
86
+ var has_valid_extension = extensions.is_empty()
87
+
88
+ for ext in extensions:
89
+ if file_name.ends_with(ext):
90
+ has_valid_extension = true
91
+ break
92
+
93
+ if has_valid_extension:
94
+ files.append("res://" + file_path)
95
+
96
+ file_name = dir.get_next()
97
+
98
+ dir.list_dir_end()
99
+
100
+ func _get_project_structure(client_id: int, params: Dictionary, command_id: String) -> void:
101
+ var structure = {
102
+ "directories": [],
103
+ "file_counts": {},
104
+ "total_files": 0
105
+ }
106
+
107
+ var dir = DirAccess.open("res://")
108
+ if dir:
109
+ _analyze_project_structure(dir, "", structure)
110
+ else:
111
+ return _send_error(client_id, "Failed to open res:// directory", command_id)
112
+
113
+ _send_success(client_id, structure, command_id)
114
+
115
+ func _analyze_project_structure(dir: DirAccess, path: String, structure: Dictionary) -> void:
116
+ dir.list_dir_begin()
117
+ var file_name = dir.get_next()
118
+
119
+ while file_name != "":
120
+ if dir.current_is_dir():
121
+ var dir_path = path + file_name + "/"
122
+ structure["directories"].append("res://" + dir_path)
123
+
124
+ var subdir = DirAccess.open("res://" + dir_path)
125
+ if subdir:
126
+ _analyze_project_structure(subdir, dir_path, structure)
127
+ else:
128
+ structure["total_files"] += 1
129
+
130
+ var extension = file_name.get_extension()
131
+ if extension in structure["file_counts"]:
132
+ structure["file_counts"][extension] += 1
133
+ else:
134
+ structure["file_counts"][extension] = 1
135
+
136
+ file_name = dir.get_next()
137
+
138
+ dir.list_dir_end()
139
+
140
+ func _get_project_settings(client_id: int, params: Dictionary, command_id: String) -> void:
141
+ # Get relevant project settings
142
+ var settings = {
143
+ "project_name": ProjectSettings.get_setting("application/config/name", "Untitled Project"),
144
+ "project_version": ProjectSettings.get_setting("application/config/version", "1.0.0"),
145
+ "display": {
146
+ "width": ProjectSettings.get_setting("display/window/size/viewport_width", 1024),
147
+ "height": ProjectSettings.get_setting("display/window/size/viewport_height", 600),
148
+ "mode": ProjectSettings.get_setting("display/window/size/mode", 0),
149
+ "resizable": ProjectSettings.get_setting("display/window/size/resizable", true)
150
+ },
151
+ "physics": {
152
+ "2d": {
153
+ "default_gravity": ProjectSettings.get_setting("physics/2d/default_gravity", 980)
154
+ },
155
+ "3d": {
156
+ "default_gravity": ProjectSettings.get_setting("physics/3d/default_gravity", 9.8)
157
+ }
158
+ },
159
+ "rendering": {
160
+ "quality": {
161
+ "msaa": ProjectSettings.get_setting("rendering/anti_aliasing/quality/msaa_2d", 0)
162
+ }
163
+ },
164
+ "input_map": {}
165
+ }
166
+
167
+ # Get input mappings
168
+ var input_map = ProjectSettings.get_setting("input")
169
+ if input_map:
170
+ settings["input_map"] = input_map
171
+
172
+ _send_success(client_id, settings, command_id)
173
+
174
+ func _list_project_resources(client_id: int, params: Dictionary, command_id: String) -> void:
175
+ var resources = {
176
+ "scenes": [],
177
+ "scripts": [],
178
+ "textures": [],
179
+ "audio": [],
180
+ "models": [],
181
+ "resources": []
182
+ }
183
+
184
+ var dir = DirAccess.open("res://")
185
+ if dir:
186
+ _scan_resources(dir, "", resources)
187
+ else:
188
+ return _send_error(client_id, "Failed to open res:// directory", command_id)
189
+
190
+ _send_success(client_id, resources, command_id)
191
+
192
+ func _scan_resources(dir: DirAccess, path: String, resources: Dictionary) -> void:
193
+ dir.list_dir_begin()
194
+ var file_name = dir.get_next()
195
+
196
+ while file_name != "":
197
+ if dir.current_is_dir():
198
+ var subdir = DirAccess.open("res://" + path + file_name)
199
+ if subdir:
200
+ _scan_resources(subdir, path + file_name + "/", resources)
201
+ else:
202
+ var file_path = "res://" + path + file_name
203
+
204
+ # Categorize by extension
205
+ if file_name.ends_with(".tscn") or file_name.ends_with(".scn"):
206
+ resources["scenes"].append(file_path)
207
+ elif file_name.ends_with(".gd") or file_name.ends_with(".cs"):
208
+ resources["scripts"].append(file_path)
209
+ elif file_name.ends_with(".png") or file_name.ends_with(".jpg") or file_name.ends_with(".jpeg"):
210
+ resources["textures"].append(file_path)
211
+ elif file_name.ends_with(".wav") or file_name.ends_with(".ogg") or file_name.ends_with(".mp3"):
212
+ resources["audio"].append(file_path)
213
+ elif file_name.ends_with(".obj") or file_name.ends_with(".glb") or file_name.ends_with(".gltf"):
214
+ resources["models"].append(file_path)
215
+ elif file_name.ends_with(".tres") or file_name.ends_with(".res"):
216
+ resources["resources"].append(file_path)
217
+
218
+ file_name = dir.get_next()
219
+
220
+ dir.list_dir_end()
221
+
222
+ func _run_project(client_id: int, _params: Dictionary, command_id: String) -> void:
223
+ var editor_interface = _get_editor_interface()
224
+ if not editor_interface:
225
+ return _send_error(client_id, "Editor interface not available", command_id)
226
+
227
+ var main_scene: String = ProjectSettings.get_setting("application/run/main_scene", "")
228
+ if main_scene.is_empty():
229
+ return _send_error(client_id, "No main scene configured in project settings", command_id)
230
+
231
+ editor_interface.play_main_scene()
232
+ _send_success(client_id, {
233
+ "status": "running",
234
+ "scene_path": main_scene
235
+ }, command_id)
236
+
237
+ func _stop_running_project(client_id: int, _params: Dictionary, command_id: String) -> void:
238
+ var editor_interface = _get_editor_interface()
239
+ if not editor_interface:
240
+ return _send_error(client_id, "Editor interface not available", command_id)
241
+
242
+ if not editor_interface.is_playing_scene():
243
+ return _send_success(client_id, {
244
+ "status": "idle",
245
+ "message": "Editor is not currently running a scene"
246
+ }, command_id)
247
+
248
+ editor_interface.stop_playing_scene()
249
+ _send_success(client_id, {
250
+ "status": "stopped"
251
+ }, command_id)
252
+
253
+ func _run_current_scene(client_id: int, _params: Dictionary, command_id: String) -> void:
254
+ var editor_interface = _get_editor_interface()
255
+ if not editor_interface:
256
+ return _send_error(client_id, "Editor interface not available", command_id)
257
+
258
+ var scene_root = editor_interface.get_edited_scene_root()
259
+ if not scene_root:
260
+ return _send_error(client_id, "No scene is currently open in the editor", command_id)
261
+
262
+ var scene_path: String = scene_root.scene_file_path
263
+ if scene_path.is_empty():
264
+ return _send_error(client_id, "Current scene must be saved before it can be run", command_id)
265
+
266
+ editor_interface.play_current_scene()
267
+ _send_success(client_id, {
268
+ "status": "running",
269
+ "scene_path": scene_path
270
+ }, command_id)
271
+
272
+ func _run_specific_scene(client_id: int, params: Dictionary, command_id: String) -> void:
273
+ var editor_interface = _get_editor_interface()
274
+ if not editor_interface:
275
+ return _send_error(client_id, "Editor interface not available", command_id)
276
+
277
+ var scene_path: String = params.get("scene_path", "")
278
+ if scene_path.is_empty():
279
+ return _send_error(client_id, "scene_path parameter is required", command_id)
280
+
281
+ if not ResourceLoader.exists(scene_path):
282
+ return _send_error(client_id, "Scene does not exist: %s" % scene_path, command_id)
283
+
284
+ editor_interface.play_custom_scene(scene_path)
285
+ _send_success(client_id, {
286
+ "status": "running",
287
+ "scene_path": scene_path
288
+ }, command_id)
289
+
290
+ func _get_editor_interface():
291
+ if not Engine.has_meta("GodotMCPPlugin"):
292
+ return null
293
+
294
+ var plugin = Engine.get_meta("GodotMCPPlugin") as EditorPlugin
295
+ if not plugin:
296
+ return null
297
+
298
+ return plugin.get_editor_interface()
@@ -0,0 +1 @@
1
+ uid://bfww1c3grmul3