diff --git a/.claude/skills/unity-mcp-skill/SKILL.md b/.claude/skills/unity-mcp-skill/SKILL.md
index 8e3467b87..5d86260e5 100644
--- a/.claude/skills/unity-mcp-skill/SKILL.md
+++ b/.claude/skills/unity-mcp-skill/SKILL.md
@@ -186,7 +186,7 @@ uri="file:///full/path/to/file.cs"
| **Scene** | `manage_scene`, `find_gameobjects` | Scene operations, finding objects. Multi-scene editing (additive load, close, set active, move GO between scenes), scene templates (`3d_basic`, `2d_basic`, `empty`, `default`), scene validation with `auto_repair`. For build settings, use `manage_build(action="scenes")`. |
| **Objects** | `manage_gameobject`, `manage_components` | Creating/modifying GameObjects |
| **Scripts** | `create_script`, `script_apply_edits`, `validate_script` | C# code management (auto-refreshes on create/edit) |
-| **Assets** | `manage_asset`, `manage_prefabs` | Asset operations. **Prefab instantiation** is done via `manage_gameobject(action="create", prefab_path="...")`, not `manage_prefabs`. |
+| **Assets** | `manage_asset`, `manage_prefabs` | Asset operations and read-only built-bundle exploration: `list_asset_bundles` takes a project directory; `get_asset_bundle_info` takes one bundle file. Both page results (default 25, max 200); details load no assets/scenes. **Prefab instantiation** is done via `manage_gameobject(action="create", prefab_path="...")`, not `manage_prefabs`. |
| **Editor** | `manage_editor`, `execute_menu_item`, `read_console` | Editor control, package deployment (`deploy_package`/`restore_package`), undo/redo (`undo`/`redo` actions) |
| **Testing** | `run_tests`, `get_test_job` | Unity Test Framework |
| **Batch** | `batch_execute` | Parallel/bulk operations |
diff --git a/MCPForUnity/Editor/Helpers/AssetBundleExplorer.cs b/MCPForUnity/Editor/Helpers/AssetBundleExplorer.cs
new file mode 100644
index 000000000..57a07ebac
--- /dev/null
+++ b/MCPForUnity/Editor/Helpers/AssetBundleExplorer.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using Newtonsoft.Json.Linq;
+using UnityEngine;
+
+namespace MCPForUnity.Editor.Helpers
+{
+ /// Read-only exploration of built bundles; no static dependency on AssetBundleModule.
+ internal static class AssetBundleExplorer
+ {
+ internal static object Handle(JObject parameters, bool inspect)
+ {
+ try
+ {
+ string root = Path.GetFullPath(Path.GetDirectoryName(Application.dataPath));
+ string requested = parameters["path"]?.ToString();
+ if (string.IsNullOrWhiteSpace(requested)) return new ErrorResponse("'path' is required for AssetBundle exploration.");
+ string path = Path.GetFullPath(Path.IsPathRooted(requested) ? requested : Path.Combine(root, requested));
+ var comparison = Path.DirectorySeparatorChar == '\\' ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
+ if (!path.Equals(root, comparison) && !path.StartsWith(root + Path.DirectorySeparatorChar, comparison))
+ return new ErrorResponse("AssetBundle paths must be inside the Unity project.");
+ if (HasLink(root, path)) return new ErrorResponse("AssetBundle paths cannot traverse symbolic links or reparse points.");
+ int pageSize = ParamCoercion.CoerceInt(parameters["pageSize"], 25);
+ int pageNumber = ParamCoercion.CoerceInt(parameters["pageNumber"], 1);
+ if (pageSize < 1 || pageSize > 200 || pageNumber < 1)
+ return new ErrorResponse("Use pageSize from 1 to 200 and a pageNumber of at least 1.");
+ return inspect ? Inspect(root, path, pageSize, pageNumber) : List(root, path, pageSize, pageNumber);
+ }
+ catch (Exception e) when (e is IOException || e is UnauthorizedAccessException || e is ArgumentException || e is NotSupportedException)
+ {
+ return new ErrorResponse("Could not read the selected AssetBundle path. Check that it exists and is accessible.");
+ }
+ }
+
+ private static bool HasLink(string root, string path)
+ {
+ string current = root;
+ foreach (string segment in path.Substring(root.Length).Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ current = Path.Combine(current, segment);
+ try
+ {
+ if ((File.GetAttributes(current) & FileAttributes.ReparsePoint) != 0) return true;
+ }
+ catch (FileNotFoundException) { break; }
+ catch (DirectoryNotFoundException) { break; }
+ }
+ return false;
+ }
+
+ private static string Relative(string root, string path) => path.Substring(root.Length).TrimStart(Path.DirectorySeparatorChar).Replace('\\', '/');
+
+ private static bool HasBundleHeader(string path)
+ {
+ // Stat before opening. Empty/short files and Unix FIFOs/sockets have no
+ // bundle header; opening a FIFO would wait for a writer on the Editor thread.
+ if (new FileInfo(path).Length < 8) return false;
+ var bytes = new byte[9];
+ using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
+ {
+ if (stream.Read(bytes, 0, bytes.Length) < 8) return false;
+ }
+ string header = Encoding.ASCII.GetString(bytes);
+ return header.StartsWith("UnityFS\0", StringComparison.Ordinal) ||
+ header.StartsWith("UnityRaw\0", StringComparison.Ordinal) ||
+ header.StartsWith("UnityWeb\0", StringComparison.Ordinal);
+ }
+
+ private static object List(string root, string path, int pageSize, int pageNumber)
+ {
+ if (!Directory.Exists(path)) return new ErrorResponse("'path' must identify an existing project directory for list_asset_bundles.");
+ var entries = new List