godot_attach_script
Attach GDScript files to Godot scene nodes, creating scripts automatically when needed to streamline game development workflows.
Instructions
Attach a GDScript file to a specific node in a saved scene, creating the script file first when needed.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_path | Yes | Path to the Godot project directory or its project.godot file. | |
| scene_path | Yes | Path to the target .tscn file. Absolute, relative, and res:// paths are supported. | |
| node_path | No | Scene-relative node path to receive the script. Use '.' for the root node. | . |
| script_path | No | Optional absolute, relative, or res:// path for the target `.gd` file inside the project. | |
| script_name | No | Optional human-friendly script name or filename when creating a new script, such as 'Hero Controller' or 'hero_controller.gd'. | |
| folder | No | Project-relative folder where a new script should be created when `script_path` is omitted. | scripts |
| script_code | No | Optional explicit GDScript source. When omitted and the script does not exist yet, a starter template is generated. | |
| overwrite | No | Whether to replace an existing script file when `script_code` is provided. | |
| godot_executable | No | Optional explicit path to the Godot executable or .app bundle. |
Implementation Reference
- src/godot_mcp/godot.py:1718-1823 (handler)Implementation of the 'attach_script' tool, which attaches a GDScript file to a node in a Godot scene.
def attach_script( self, project_path: str, scene_path: str, node_path: str = ".", script_path: str | None = None, script_name: str | None = None, folder: str = "scripts", script_code: str | None = None, overwrite: bool = False, godot_executable: str | None = None, ) -> dict[str, Any]: project_dir = ensure_project_path(project_path) executable, version = resolve_godot_executable(godot_executable) 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}") normalized_node_path = normalize_scene_node_path(node_path) scene_tree = self.get_scene_tree( project_path=str(project_dir), scene_path=resource_scene_path, godot_executable=str(executable), ) node_info = next( (node for node in scene_tree["nodes"] if node.get("path") == normalized_node_path), None, ) if node_info is None: raise GodotError( f"Node not found at path `{normalized_node_path}` in scene {resource_scene_path}." ) node_name = str(node_info.get("name", "")).strip() or "Node" node_type = str(node_info.get("type", "")).strip() or "Node" if script_path: absolute_script_path, resource_script_path = resolve_project_file_path(project_dir, script_path) else: normalized_folder = normalize_project_subdir(folder) script_dir = project_dir / normalized_folder if normalized_folder else project_dir base_name = (script_name or "").strip() or node_name filename_base = base_name[:-3] if base_name.lower().endswith(".gd") else base_name filename = f"{snake_case_name(filename_base, default='script')}.gd" absolute_script_path = (script_dir / filename).resolve() relative_script_path = absolute_script_path.relative_to(project_dir) resource_script_path = f"res://{relative_script_path.as_posix()}" if absolute_script_path.suffix.lower() != ".gd": raise GodotError("Attached scripts must point to a `.gd` file.") absolute_script_path.parent.mkdir(parents=True, exist_ok=True) existed_before = absolute_script_path.exists() wrote_script = False created_from_template = False if script_code is not None: if existed_before and not overwrite: raise GodotError( f"Script already exists at {absolute_script_path}. Pass `overwrite=true` to replace it." ) final_script_code = script_code if script_code.endswith("\n") else script_code + "\n" absolute_script_path.write_text(final_script_code, encoding="utf-8") wrote_script = True elif not existed_before: absolute_script_path.write_text(_default_script_source(node_type), encoding="utf-8") wrote_script = True created_from_template = True if not absolute_script_path.exists(): raise GodotError(f"Script not found: {absolute_script_path}") output = _run_godot_script( executable=executable, project_dir=project_dir, script_name="attach_script.gd", user_args=[ "--scene-path", resource_scene_path, "--node-path", normalized_node_path, "--script-path", resource_script_path, ], ) parsed = _parse_script_json_output(output, "attach_script.gd") return { "project_path": str(project_dir), "scene_path": str(absolute_scene_path), "scene_resource_path": resource_scene_path, "node_path": parsed.get("node_path", normalized_node_path), "node_name": parsed.get("node_name", node_name), "node_type": parsed.get("node_type", node_type), "script_path": str(absolute_script_path), "script_resource_path": resource_script_path, "created_script": wrote_script and not existed_before, "updated_script": wrote_script and existed_before, "created_from_template": created_from_template, "previous_script_resource_path": parsed.get("previous_script_path", ""), "replaced_existing_script": bool(parsed.get("previous_script_path")), "godot_executable": str(executable), "godot_version": version, } - src/godot_mcp/server.py:386-445 (registration)Registration of the 'godot_attach_script' tool in the Godot MCP server.
name="godot_attach_script", description="Attach a GDScript file to a specific node in a saved scene, creating the script file first when needed.", 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": "Path to the target .tscn file. Absolute, relative, and res:// paths are supported.", }, "node_path": { "type": "string", "description": "Scene-relative node path to receive the script. Use '.' for the root node.", "default": ".", }, "script_path": { "type": "string", "description": "Optional absolute, relative, or res:// path for the target `.gd` file inside the project.", }, "script_name": { "type": "string", "description": "Optional human-friendly script name or filename when creating a new script, such as 'Hero Controller' or 'hero_controller.gd'.", }, "folder": { "type": "string", "description": "Project-relative folder where a new script should be created when `script_path` is omitted.", "default": "scripts", }, "script_code": { "type": "string", "description": "Optional explicit GDScript source. When omitted and the script does not exist yet, a starter template is generated.", }, "overwrite": { "type": "boolean", "description": "Whether to replace an existing script file when `script_code` is provided.", "default": False, }, "godot_executable": { "type": "string", "description": "Optional explicit path to the Godot executable or .app bundle.", }, }, "required": ["project_path", "scene_path"], "additionalProperties": False, }, handler=lambda args: self.controller.attach_script( project_path=args["project_path"], scene_path=args["scene_path"], node_path=args.get("node_path", "."), script_path=args.get("script_path"), script_name=args.get("script_name"), folder=args.get("folder", "scripts"), script_code=args.get("script_code"), overwrite=bool(args.get("overwrite", False)), godot_executable=args.get("godot_executable"), ), ),