Skip to main content
Glama
executor.ts4.26 kB
import { spawn } from "child_process"; import * as path from "path"; import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); export interface ExecutionResult { success: boolean; output: string; error?: string; } export class GodotExecutor { private godotPath: string; private operationsScriptPath: string; constructor(godotPath: string) { this.godotPath = godotPath; // Path to our bundled GDScript operations handler this.operationsScriptPath = path.join(__dirname, "..", "..", "scripts", "godot_operations.gd"); } /** * Execute a Godot operation in headless mode */ async execute( projectPath: string, operation: string, params: Record<string, unknown> = {} ): Promise<ExecutionResult> { return new Promise((resolve) => { const args = [ "--headless", "--path", projectPath, "-s", this.operationsScriptPath, "--", operation, JSON.stringify(params), ]; let stdout = ""; let stderr = ""; const proc = spawn(this.godotPath, args, { cwd: projectPath, env: { ...process.env }, }); proc.stdout.on("data", (data) => { stdout += data.toString(); }); proc.stderr.on("data", (data) => { stderr += data.toString(); }); proc.on("close", (code) => { // Parse the output for our JSON result marker const resultMatch = stdout.match(/\[GODOT_MCP_RESULT\](.*)\[\/GODOT_MCP_RESULT\]/s); if (resultMatch) { try { const result = JSON.parse(resultMatch[1].trim()); resolve({ success: result.success ?? true, output: result.output ?? result.message ?? JSON.stringify(result), error: result.error, }); return; } catch { // Failed to parse JSON result } } resolve({ success: code === 0, output: stdout.trim(), error: stderr.trim() || undefined, }); }); proc.on("error", (error) => { resolve({ success: false, output: "", error: error.message, }); }); }); } /** * Execute a raw Godot command without the operations script */ async executeRaw(args: string[], cwd?: string): Promise<ExecutionResult> { return new Promise((resolve) => { let stdout = ""; let stderr = ""; const proc = spawn(this.godotPath, args, { cwd, env: { ...process.env }, }); proc.stdout.on("data", (data) => { stdout += data.toString(); }); proc.stderr.on("data", (data) => { stderr += data.toString(); }); proc.on("close", (code) => { resolve({ success: code === 0, output: stdout.trim(), error: stderr.trim() || undefined, }); }); proc.on("error", (error) => { resolve({ success: false, output: "", error: error.message, }); }); }); } /** * Launch the Godot editor for a project */ async launchEditor(projectPath: string): Promise<ExecutionResult> { return new Promise((resolve) => { const proc = spawn(this.godotPath, ["--editor", "--path", projectPath], { detached: true, stdio: "ignore", }); proc.unref(); resolve({ success: true, output: `Launched Godot editor for project at ${projectPath}`, }); }); } /** * Run the project */ async runProject(projectPath: string): Promise<ExecutionResult> { return new Promise((resolve) => { const proc = spawn(this.godotPath, ["--path", projectPath], { detached: true, stdio: "ignore", }); proc.unref(); resolve({ success: true, output: `Running project at ${projectPath}`, }); }); } /** * Get Godot version */ async getVersion(): Promise<string> { const result = await this.executeRaw(["--version"]); return result.output || "unknown"; } getGodotPath(): string { return this.godotPath; } }

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/koltyakov/godot-mcp'

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