diff --git a/godot-addon/addons/godotiq/godotiq_plugin.gd b/godot-addon/addons/godotiq/godotiq_plugin.gd
index f975177..300d9d8 100644
--- a/godot-addon/addons/godotiq/godotiq_plugin.gd
+++ b/godot-addon/addons/godotiq/godotiq_plugin.gd
@@ -21,7 +21,10 @@ func _enter_tree() -> void:
 	_server.debugger = _debugger
 	add_debugger_plugin(_debugger)
 
-	# 3. Register runtime autoload singleton
+	# 3. Wire undo/redo manager for node operations
+	_server.undo_redo = get_undo_redo()
+
+	# 4. Register runtime autoload singleton
 	add_autoload_singleton(AUTOLOAD_NAME, RUNTIME_PATH)
 
 
diff --git a/godot-addon/addons/godotiq/godotiq_server.gd b/godot-addon/addons/godotiq/godotiq_server.gd
index 6c84443..f7b010e 100644
--- a/godot-addon/addons/godotiq/godotiq_server.gd
+++ b/godot-addon/addons/godotiq/godotiq_server.gd
@@ -16,6 +16,7 @@ var _game_running: bool = false
 var _next_peer_id: int = 1
 var _port: int = DEFAULT_PORT
 var debugger  # untyped — set by godotiq_plugin.gd
+var undo_redo  # untyped — set by godotiq_plugin.gd (EditorUndoRedoManager)
 
 
 func _ready() -> void:
@@ -98,7 +99,7 @@ func _process(_delta: float) -> void:
 			timed_out.append(req_id)
 	for req_id in timed_out:
 		var entry: Dictionary = _pending_game_requests[req_id]
-		_send_error(entry["peer_id"], req_id, "TIMEOUT", "Game request timed out")
+		_send_error(entry["peer_id"], entry["request_id"], "TIMEOUT", "Game request timed out")
 		_pending_game_requests.erase(req_id)
 
 
@@ -189,6 +190,7 @@ func _handle_game_forward(peer_id: int, id: String, msg_type: String, params: Di
 	var req_key := "%d:%s" % [peer_id, id]
 	_pending_game_requests[req_key] = {
 		"peer_id": peer_id,
+		"request_id": id,
 		"method": msg_type,
 		"timeout_at": Time.get_ticks_msec() + timeout_ms,
 	}
@@ -224,7 +226,7 @@ func handle_game_response(response_type: String, data: Array) -> void:
 			result = {"raw": data[0]}
 	else:
 		result = {"data": data}
-	send_response(entry["peer_id"], matched_id, result)
+	send_response(entry["peer_id"], entry["request_id"], result)
 
 
 # --- Game lifecycle callbacks ---
@@ -239,7 +241,7 @@ func on_game_stopped() -> void:
 	# Fail all pending game requests
 	for req_id in _pending_game_requests.keys():
 		var entry: Dictionary = _pending_game_requests[req_id]
-		_send_error(entry["peer_id"], req_id, "GAME_STOPPED", "Game session ended")
+		_send_error(entry["peer_id"], entry["request_id"], "GAME_STOPPED", "Game session ended")
 	_pending_game_requests.clear()
 	send_event("game_stopped", {})
 
diff --git a/src/godotiq/bridge/protocol.py b/src/godotiq/bridge/protocol.py
index 76dbee2..d19bd39 100644
--- a/src/godotiq/bridge/protocol.py
+++ b/src/godotiq/bridge/protocol.py
@@ -13,6 +13,8 @@ TOOL_TIMEOUTS: dict[str, float] = {
     "editor_context": 5.0,
     "run": 10.0,
     "stop": 5.0,
+    "scene_tree": 5.0,
+    "node_ops": 10.0,
 }
 
 SCREENSHOT_MAX_RETRIES: int = 3
diff --git a/tests/test_bridge/test_protocol.py b/tests/test_bridge/test_protocol.py
index f50eb7d..f413b92 100644
--- a/tests/test_bridge/test_protocol.py
+++ b/tests/test_bridge/test_protocol.py
@@ -111,6 +111,14 @@ class TestTimeouts:
         """Unknown method returns default 5.0."""
         assert get_timeout("nonexistent_method") == 5.0
 
+    def test_scene_tree_timeout(self) -> None:
+        """scene_tree has a 5-second timeout configured."""
+        assert get_timeout("scene_tree") == 5.0
+
+    def test_node_ops_timeout(self) -> None:
+        """node_ops has a 10-second timeout configured."""
+        assert get_timeout("node_ops") == 10.0
+
     def test_all_timeouts_positive(self) -> None:
         """All configured timeouts are positive."""
         for method, timeout in TOOL_TIMEOUTS.items():
