Skip to main content
Glama

godot_screenshot

Capture screenshots from Godot projects by running them briefly and saving the last rendered frame as an image file.

Instructions

Run a Godot project or specific scene for a short duration, keep the last rendered frame, and return the screenshot path.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_pathYesPath to the Godot project directory or its project.godot file.
scene_pathNoOptional scene to run instead of the project's configured main scene.
capture_secondsNoHow long to let the project run before selecting the last rendered frame as the screenshot.
fpsNoMovie-capture framerate used to determine which frame to keep.
godot_executableNoOptional explicit path to the Godot executable or .app bundle.

Implementation Reference

  • The 'screenshot' method in the GodotController class implements the screenshot functionality by launching Godot with the '--write-movie' flag to capture frames, saving the final frame, and returning the screenshot path.
    def screenshot(
        self,
        project_path: str,
        scene_path: str | None = None,
        capture_seconds: float = 2.0,
        fps: int = 60,
        godot_executable: str | None = None,
    ) -> dict[str, Any]:
        project_dir = ensure_project_path(project_path)
        executable, version = resolve_godot_executable(godot_executable)
    
        if capture_seconds <= 0:
            raise GodotError("`capture_seconds` must be greater than 0.")
        if fps < 1:
            raise GodotError("`fps` must be at least 1.")
    
        absolute_scene_path: Path | None = None
        resource_scene_path: str | None = None
        run_target = "project"
        scene_label = "project"
    
        command = [
            str(executable),
            "--path",
            str(project_dir),
            "--windowed",
            "--fixed-fps",
            str(fps),
            "--disable-vsync",
        ]
    
        if scene_path:
            absolute_scene_path, resource_scene_path = resolve_scene_path(project_dir, scene_path)
            if not absolute_scene_path.exists():
                raise GodotError(f"Scene not found: {absolute_scene_path}")
            relative_scene_path = absolute_scene_path.relative_to(project_dir).as_posix()
            command.extend(["--scene", relative_scene_path])
            run_target = "scene"
            scene_label = absolute_scene_path.stem
    
        frame_count = max(1, int(round(capture_seconds * fps)))
        actual_capture_seconds = frame_count / float(fps)
    
        screenshots_dir = project_dir / ".godot-mcp" / "screenshots"
        screenshots_dir.mkdir(parents=True, exist_ok=True)
        timestamp = time.strftime("%Y%m%d-%H%M%S")
        stem = f"{timestamp}-{run_target}-{snake_case_name(scene_label, default=run_target)}"
        movie_output_path = screenshots_dir / f"{stem}.png"
        final_screenshot_path = screenshots_dir / f"{stem}-screenshot.png"
        log_path = _create_log_path(project_dir, "screenshot")
    
        command_with_capture = [
            command[0],
            "--log-file",
            str(log_path),
            *command[1:],
            "--write-movie",
            str(movie_output_path),
            "--quit-after",
            str(frame_count),
        ]
    
        timeout_seconds = max(60, int(actual_capture_seconds * 20) + 30)
        result = subprocess.run(
            command_with_capture,
            cwd=project_dir,
            check=False,
            capture_output=True,
            text=True,
            timeout=timeout_seconds,
        )
    
        frame_files = sorted(screenshots_dir.glob(f"{stem}" + "[0-9]" * 8 + ".png"))
        if not frame_files and movie_output_path.exists():
            frame_files = [movie_output_path]
    
        if result.returncode != 0 or not frame_files:
            details = "\n".join(part for part in [result.stdout.strip(), result.stderr.strip()] if part).strip()
            raise GodotError(
                "Failed to capture a Godot screenshot.\n"
                f"Log file: {log_path}\n"
                f"{details or 'No output was returned.'}"
            )
    
        final_frame = frame_files[-1]
        if final_screenshot_path.exists():
            final_screenshot_path.unlink()
        final_frame.replace(final_screenshot_path)
    
        for frame_path in frame_files[:-1]:
            frame_path.unlink(missing_ok=True)
        movie_output_path.unlink(missing_ok=True)
        (screenshots_dir / f"{stem}.wav").unlink(missing_ok=True)
    
        return {
            "project_path": str(project_dir),
            "scene_path": str(absolute_scene_path) if absolute_scene_path is not None else None,
            "scene_resource_path": resource_scene_path,
            "run_target": run_target,
            "capture_seconds": actual_capture_seconds,
            "requested_capture_seconds": capture_seconds,
            "fps": fps,
            "frame_count": frame_count,
            "frame_index": frame_count - 1,
            "screenshot_path": str(final_screenshot_path),
            "image_format": "png",
            "size_bytes": final_screenshot_path.stat().st_size,
            "command": command_with_capture,
            "log_path": str(log_path),
            "godot_executable": str(executable),
            "godot_version": version,
        }
  • The 'godot_screenshot' tool is registered in the GodotMcpServer class, mapping the tool to the controller's screenshot method.
        name="godot_screenshot",
        description="Run a Godot project or specific scene for a short duration, keep the last rendered frame, and return the screenshot path.",
        input_schema={
            "type": "object",
            "properties": {
                "project_path": {
                    "type": "string",
                    "description": "Path to the Godot project directory or its project.godot file.",
                },
                "scene_path": {
                    "type": "string",
                    "description": "Optional scene to run instead of the project's configured main scene.",
                },
                "capture_seconds": {
                    "type": "number",
                    "description": "How long to let the project run before selecting the last rendered frame as the screenshot.",
                    "default": 2.0,
                },
                "fps": {
                    "type": "integer",
                    "description": "Movie-capture framerate used to determine which frame to keep.",
                    "default": 60,
                    "minimum": 1,
                },
                "godot_executable": {
                    "type": "string",
                    "description": "Optional explicit path to the Godot executable or .app bundle.",
                },
            },
            "required": ["project_path"],
            "additionalProperties": False,
        },
        handler=lambda args: self.controller.screenshot(
            project_path=args["project_path"],
            scene_path=args.get("scene_path"),
            capture_seconds=float(args.get("capture_seconds", 2.0)),
            fps=int(args.get("fps", 60)),
            godot_executable=args.get("godot_executable"),
        ),
    ),

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

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