91b878f347
- Added 6 Quaternius weapon models (Pistol, Revolver, Rifle, Shotgun, P90, SniperRifle) - Created weapon resource files with balanced stats - Wired Pistol + Rifle into player.tscn replacing Kenney blasters - Fixed WASD input (matched input map action names) - Fixed Escape key toggles mouse capture - Added Audio autoload singleton - Fixed broken sound asset paths across all scripts - Fixed all scene ext_resource text paths (nested under assets/kenney-fps/) - Fixed all .import source_file paths - Deleted stale .import files (will be regenerated by editor on open)
114 lines
5.7 KiB
JavaScript
114 lines
5.7 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Godot MCP Server
|
|
*
|
|
* This MCP server provides tools for interacting with the Godot game engine.
|
|
* It enables AI assistants to launch the Godot editor, run Godot projects,
|
|
* capture debug output, manipulate scenes and nodes, and more.
|
|
*/
|
|
// Lower-level `Server` is deliberate; see CONTRIBUTING.md "MCP SDK: Server vs McpServer".
|
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
import { GodotRunner, getErrorMessage } from './utils/godot-runner.js';
|
|
import { dispatchToolCall } from './dispatch.js';
|
|
import { runtimeToolDefinitions } from './tools/runtime-tools.js';
|
|
import { autoloadToolDefinitions } from './tools/autoload-tools.js';
|
|
import { projectToolDefinitions } from './tools/project-tools.js';
|
|
import { sceneToolDefinitions } from './tools/scene-tools.js';
|
|
import { nodeToolDefinitions } from './tools/node-tools.js';
|
|
import { validateToolDefinitions } from './tools/validate-tools.js';
|
|
export const allToolDefinitions = [
|
|
...runtimeToolDefinitions,
|
|
...autoloadToolDefinitions,
|
|
...projectToolDefinitions,
|
|
...sceneToolDefinitions,
|
|
...nodeToolDefinitions,
|
|
...validateToolDefinitions,
|
|
];
|
|
export const serverInstructions = `Godot MCP Server — AI-driven Godot 4.x project manipulation.
|
|
|
|
Tool categories:
|
|
- Project management: launch_editor, run_project, attach_project, detach_project, stop_project, get_debug_output, list_projects, get_project_info
|
|
- Scene editing (headless): create_scene, add_node, load_sprite, save_scene, export_mesh_library, batch_scene_operations
|
|
- Node editing (headless): delete_nodes, set_node_properties, get_node_properties, attach_script, get_scene_tree, duplicate_node, get_node_signals, connect_signal, disconnect_signal
|
|
- Runtime (requires run_project or attach_project): take_screenshot, simulate_input, get_ui_elements, run_script
|
|
- Project config (no Godot process): list_autoloads, add_autoload, remove_autoload, update_autoload, get_project_files, search_project, get_scene_dependencies, get_project_settings
|
|
- Validation: validate
|
|
|
|
Key behaviors:
|
|
- All mutation operations (add_node, set_node_properties, delete_nodes, etc.) save the scene automatically. Only use save_scene for save-as (newPath) or re-canonicalization.
|
|
- Headless Godot initializes ALL registered autoloads. If any autoload is broken, headless operations will fail. Use list_autoloads / remove_autoload to diagnose.
|
|
- run_project verifies bridge readiness before returning success. If it reports degraded status, retry runtime tools after a moment or check get_debug_output.
|
|
- attach_project is the fallback path for a manually launched Godot process. It injects the bridge and marks the project active, but it does not spawn Godot or capture stdout/stderr.
|
|
- click_element in simulate_input resolves by node path or node name (BFS search), NOT by visible text. Use get_ui_elements to discover valid element identifiers.
|
|
- run_script expects GDScript with "extends RefCounted" and "func execute(scene_tree: SceneTree) -> Variant".
|
|
- run_project spawns Godot without -d so runtime errors do not pause execution; the \`breakpoint\` keyword in user code is a no-op (no debugger is attached). SCRIPT ERROR output and GDScript backtraces still appear in stderr.`;
|
|
class GodotMcpServer {
|
|
server;
|
|
runner;
|
|
constructor(config) {
|
|
this.runner = new GodotRunner(config);
|
|
this.server = new Server({
|
|
name: 'godot-mcp',
|
|
version: '3.1.2',
|
|
}, {
|
|
capabilities: {
|
|
tools: {},
|
|
},
|
|
instructions: serverInstructions,
|
|
});
|
|
this.setupToolHandlers();
|
|
this.server.onerror = (error) => console.error('[MCP Error]', error);
|
|
process.on('SIGINT', async () => {
|
|
await this.cleanup();
|
|
process.exit(0);
|
|
});
|
|
process.on('SIGTERM', async () => {
|
|
await this.cleanup();
|
|
process.exit(0);
|
|
});
|
|
}
|
|
async cleanup() {
|
|
console.error('[SERVER] Cleaning up resources');
|
|
await this.runner.stopProject();
|
|
await this.server.close();
|
|
}
|
|
setupToolHandlers() {
|
|
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
tools: allToolDefinitions,
|
|
}));
|
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
const toolName = request.params.name;
|
|
const args = request.params.arguments || {};
|
|
console.error(`[SERVER] Handling tool request: ${toolName}`);
|
|
return await dispatchToolCall(this.runner, toolName, args);
|
|
});
|
|
}
|
|
async run() {
|
|
try {
|
|
await this.runner.detectGodotPath();
|
|
const godotPath = this.runner.getGodotPath();
|
|
if (godotPath) {
|
|
console.error(`[SERVER] Using Godot at: ${godotPath}`);
|
|
}
|
|
// detectGodotPath() already emits a specific logError on failure (bad
|
|
// GODOT_PATH, no binary found, etc.). Don't duplicate with a generic
|
|
// warning here — the runner's message names the actual cause.
|
|
const transport = new StdioServerTransport();
|
|
await this.server.connect(transport);
|
|
console.error('Godot MCP server running on stdio');
|
|
}
|
|
catch (error) {
|
|
console.error('[SERVER] Failed to start:', getErrorMessage(error));
|
|
process.exit(1);
|
|
}
|
|
}
|
|
}
|
|
// Create and run the server
|
|
const server = new GodotMcpServer();
|
|
server.run().catch((error) => {
|
|
console.error('Failed to run server:', getErrorMessage(error));
|
|
process.exit(1);
|
|
});
|
|
//# sourceMappingURL=index.js.map
|