Skip to main content
Glama

save_scene

Save changes to a Godot scene file, including creating variants by specifying a new path, with defined project and scene paths for precise control.

Instructions

Save changes to a scene file

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
newPathNoOptional: New path to save the scene to (for creating variants)
projectPathYesPath to the Godot project directory
scenePathYesPath to the scene file (relative to project)

Implementation Reference

  • src/index.ts:873-894 (registration)
    Registration of the save_scene tool in the list of available tools, including its description and input schema definition.
    { name: 'save_scene', description: 'Save changes to a scene file', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Path to the Godot project directory', }, scenePath: { type: 'string', description: 'Path to the scene file (relative to project)', }, newPath: { type: 'string', description: 'Optional: New path to save the scene to (for creating variants)', }, }, required: ['projectPath', 'scenePath'], }, },
  • src/index.ts:956-957 (registration)
    Routing in the CallToolRequestSchema handler that directs save_scene tool calls to the handleSaveScene method.
    case 'save_scene': return await this.handleSaveScene(request.params.arguments);
  • The primary handler for the save_scene tool. Validates arguments, checks project/scene existence, prepares parameters, executes the Godot operation 'save_scene' via executeOperation, and returns success/error responses.
    private async handleSaveScene(args: any) { // Normalize parameters to camelCase args = this.normalizeParameters(args); if (!args.projectPath || !args.scenePath) { return this.createErrorResponse( 'Missing required parameters', ['Provide projectPath and scenePath'] ); } if (!this.validatePath(args.projectPath) || !this.validatePath(args.scenePath)) { return this.createErrorResponse( 'Invalid path', ['Provide valid paths without ".." or other potentially unsafe characters'] ); } // If newPath is provided, validate it if (args.newPath && !this.validatePath(args.newPath)) { return this.createErrorResponse( 'Invalid new path', ['Provide a valid new path without ".." or other potentially unsafe characters'] ); } try { // Check if the project directory exists and contains a project.godot file const projectFile = join(args.projectPath, 'project.godot'); if (!existsSync(projectFile)) { return this.createErrorResponse( `Not a valid Godot project: ${args.projectPath}`, [ 'Ensure the path points to a directory containing a project.godot file', 'Use list_projects to find valid Godot projects', ] ); } // Check if the scene file exists const scenePath = join(args.projectPath, args.scenePath); if (!existsSync(scenePath)) { return this.createErrorResponse( `Scene file does not exist: ${args.scenePath}`, [ 'Ensure the scene path is correct', 'Use create_scene to create a new scene first', ] ); } // Prepare parameters for the operation (already in camelCase) const params: any = { scenePath: args.scenePath, }; // Add optional parameters if (args.newPath) { params.newPath = args.newPath; } // Execute the operation const { stdout, stderr } = await this.executeOperation('save_scene', params, args.projectPath); if (stderr && stderr.includes('Failed to')) { return this.createErrorResponse( `Failed to save scene: ${stderr}`, [ 'Check if the scene file is valid', 'Ensure you have write permissions to the output path', 'Verify the scene can be properly packed', ] ); } const savePath = args.newPath || args.scenePath; return { content: [ { type: 'text', text: `Scene saved successfully to: ${savePath}\n\nOutput: ${stdout}`, }, ], }; } catch (error: any) { return this.createErrorResponse( `Failed to save scene: ${error?.message || 'Unknown error'}`, [ 'Ensure Godot is installed correctly', 'Check if the GODOT_PATH environment variable is set correctly', 'Verify the project path is accessible', ] ); } }
  • Helper function that executes arbitrary Godot operations (including 'save_scene') by spawning Godot headless with the operations GD script, passing the operation name and JSON-serialized parameters.
    private async executeOperation( operation: string, params: OperationParams, projectPath: string ): Promise<{ stdout: string; stderr: string }> { this.logDebug(`Executing operation: ${operation} in project: ${projectPath}`); this.logDebug(`Original operation params: ${JSON.stringify(params)}`); // Convert camelCase parameters to snake_case for Godot script const snakeCaseParams = this.convertCamelToSnakeCase(params); this.logDebug(`Converted snake_case params: ${JSON.stringify(snakeCaseParams)}`); // Ensure godotPath is set if (!this.godotPath) { await this.detectGodotPath(); if (!this.godotPath) { throw new Error('Could not find a valid Godot executable path'); } } try { // Serialize the snake_case parameters to a valid JSON string const paramsJson = JSON.stringify(snakeCaseParams); // Escape single quotes in the JSON string to prevent command injection const escapedParams = paramsJson.replace(/'/g, "'\\''"); // On Windows, cmd.exe does not strip single quotes, so we use // double quotes and escape them to ensure the JSON is parsed // correctly by Godot. const isWindows = process.platform === 'win32'; const quotedParams = isWindows ? `\"${paramsJson.replace(/\"/g, '\\"')}\"` : `'${escapedParams}'`; // Add debug arguments if debug mode is enabled const debugArgs = GODOT_DEBUG_MODE ? ['--debug-godot'] : []; // Construct the command with the operation and JSON parameters const cmd = [ `"${this.godotPath}"`, '--headless', '--path', `"${projectPath}"`, '--script', `"${this.operationsScriptPath}"`, operation, quotedParams, // Pass the JSON string as a single argument ...debugArgs, ].join(' '); this.logDebug(`Command: ${cmd}`); const { stdout, stderr } = await execAsync(cmd); return { stdout, stderr }; } catch (error: unknown) { // If execAsync throws, it still contains stdout/stderr if (error instanceof Error && 'stdout' in error && 'stderr' in error) { const execError = error as Error & { stdout: string; stderr: string }; return { stdout: execError.stdout, stderr: execError.stderr, }; } throw error; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Coding-Solo/godot-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server