Unity Scope
Agent-native introspection runtime for Mono Unity games. BepInEx plugin + MCP server for AI coding agents.
Ask AI about Unity Scope
Powered by Claude ยท Grounded in docs
I know everything about Unity Scope. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
UnityScope
Agent-native introspection runtime for Mono Unity games. Think Unity Explorer, but designed for AI coding agents (Claude Code, Codex, Cursor) instead of humans clicking through a tree view.
A BepInEx plugin exposes the running game's scene graph, components, types, and (gated) method invocation via a local-only HTTP API. An MCP server wraps that API as tools any modern AI coding agent can call: unity_scene, unity_tree, unity_node, unity_find, unity_snapshot, unity_list_snapshots, unity_diff, unity_list_text_extractors, unity_register_text_extractor, unity_invoke.
Spun out from patterns developed in blackout-access โ an in-development screen-reader accessibility mod for Blackout Rugby that needed deep, repeatable Unity UI introspection. The introspection patterns generalized; the accessibility mod itself is still being built.
Why not just use Unity Explorer?
Unity Explorer is a human GUI: in-game windows, mouse-driven tree expansion, manual inspection. Agents need:
- Structured output โ JSON, not log lines.
- Queryable โ selectors and filters; agents OOM on full dumps.
- Stable addressing โ instance IDs that survive scene reloads.
- Diffs โ what changed between two snapshots is more valuable than any single snapshot. This is how an agent learns what a click did.
- Remote invocation โ no human in the loop pressing F12.
What you don't need
- Unity Editor. UnityScope runs inside the already-built game
.exe. The csproj references the Unity DLLs that ship with the game's_Data\Managed\folder. - Unity license, Unity Hub, or any Unity GUI. The toolchain is .NET SDK + a text editor. Same workflow as any BepInEx plugin.
Requirements
- A Unity game built with the Mono runtime (most pre-2020 commercial Unity titles). IL2CPP support is planned โ see docs/IL2CPP.md.
- BepInEx 5.x installed in the target game.
- .NET SDK (any recent version) for building the plugin.
- Node.js 20+ for running the MCP server.
Install
This guide is written so an AI coding agent can follow it end-to-end given only the repo URL and the user's game install path. No file edits required.
1. Confirm the game uses the Mono runtime
UnityScope V1 only supports Mono Unity games. Quick check from the game's install folder:
<GameDir>\GameAssembly.dllexists โ IL2CPP, not supported (see docs/IL2CPP.md).<GameDir>\<GameName>_Data\Managed\Assembly-CSharp.dllexists โ Mono, supported.
2. Install BepInEx 5.x into the game
Download from BepInEx/BepInEx releases. Pick the Mono build for your architecture (BepInEx_x64_5.4.x.x.zip for most modern games). Extract the contents directly into <GameDir> so that <GameDir>\BepInEx\ and <GameDir>\winhttp.dll (or equivalent) sit next to the game's .exe. Launch the game once so BepInEx generates its config folders, then close it.
3. Clone this repo
git clone https://github.com/Orinks/unity-scope.git
cd unity-scope
Anywhere on disk is fine.
4. Build and deploy the plugin
The build accepts the game path as a parameter โ no need to edit any project files.
# Windows:
build.bat release "C:\Program Files (x86)\Steam\steamapps\common\YourGame"
# Mac/Linux (rare for Unity Mono games, but works):
./build.sh release "/path/to/your/game"
# Or call dotnet directly:
dotnet build src/UnityScope.Runtime/UnityScope.Runtime.csproj -c Release \
-p:GameDir="C:\path\to\your\game"
The build auto-detects the *_Data\Managed folder under <GameDir> and deploys UnityScope.dll to <GameDir>\BepInEx\plugins\UnityScope\. Helpful errors fire if BepInEx isn't installed or if the game is IL2CPP.
5. Launch the game once
BepInEx loads the plugin. Confirm in <GameDir>\BepInEx\LogOutput.log:
[Info :UnityScope] UnityScope listening: http://127.0.0.1:<port>/ (http, token-protected)
A discovery file appears under the platform's local app data folder (%LOCALAPPDATA%\UnityScope\ on Windows) containing the port and auth token. MCP clients find it automatically.
6. Build the MCP server
cd src/UnityScope.Mcp
npm install
npm run build
7. Register with your AI coding agent
Claude Code:
claude mcp add unityscope -- node <absolute-path-to-clone>/src/UnityScope.Mcp/dist/index.js
Cursor / Windsurf / any other MCP-aware client: add an entry pointing to the same dist/index.js.
Once registered, the agent has tools unity_scene, unity_tree, etc. Sanity-check by asking: "What canvases are active in the game right now?"
A typical agent workflow
1. unity_scene โ orient (active scene + canvases)
2. unity_find selector="*Continue*" โ locate the Continue button
3. unity_snapshot label="before-continue" โ baseline state (returns id)
4. <user clicks Continue, or unity_invoke>
5. unity_diff since=<id> โ exactly what changed
The diff shows added/removed/modified nodes with per-field before/after values. Agents learn the consequences of actions instead of guessing.
Configuration
Settings live in <GameDir>\BepInEx\config\com.orinks.unityscope.cfg (created on first launch):
| Key | Default | Purpose |
|---|---|---|
Transport | http | http (loopback HTTP, default) or pipe (named pipe stub โ not yet implemented) |
HttpPort | 17897 | Preferred loopback port for the http transport. Stable across restarts so MCP clients don't have to re-resolve discovery every launch. Falls back to an OS-assigned free port if this one is in use (e.g. a second game instance). |
AllowInvoke | false | Set true to allow POST /invoke to call methods and set fields. Logged on every call. |
AutoDetectText | true | Convention-based auto-detection of text on unknown UI types. See below. |
TextExtractors | empty | Optional explicit text-extractor rules. Agents normally register these at runtime instead. |
Reading text from custom UI types
UnityScope reads text from three layers, in order:
- Built-in.
UnityEngine.UI.TextandTMPro.TextMeshPro*work without any setup. - Convention-based auto-detection. For any other component type, UnityScope tries common property names (
text,Text,Label,Caption,DisplayText) and no-arg method names (GetText,GetLabel,GetCaption,GetDisplayText) returning a string. The result is cached per type so reflection only runs once. Catches the great majority of custom UI types without configuration. - Explicit rules. For types that don't follow conventions, register a rule.
The expected workflow is agentic, not manual. When an agent encounters a UI element whose text isn't surfaced, it inspects the component with unity_node, identifies the relevant property/method, and registers the rule via unity_register_text_extractor. The rule persists to <plugins>\UnityScope\text-extractors.txt so it survives restarts. No human needs to know UI type names.
If you'd rather seed rules manually, the same rules can also go in the TextExtractors cfg key:
TextExtractors = BlackoutButton:method:GetText,MyGame.SignText:property:Caption
Disable convention-based auto-detection if it produces false positives by setting AutoDetectText = false in the cfg.
Security model
- HTTP listener binds only to
127.0.0.1โ not reachable from other machines. - Every request must carry the
X-UnityScope-Tokenheader; the token is generated per-launch and written to the discovery file. Other local users can't read your%LOCALAPPDATA%. /invokeis off by default. When enabled, every successful invocation is logged with target id, type, member, and arg count.
This is sufficient for single-user dev machines. Not designed for shared/CI environments.
Layout
src/
UnityScope.Runtime/ BepInEx Mono plugin
Endpoints/ /scene /tree /node /snapshot /diff /find /invoke
Inspection/ Hierarchy walker, component serializer, snapshot store, selector
Server/ Request router, main-thread dispatcher
Transport/ HTTP, named-pipe stub, discovery file
Json/ Streaming JSON writer
UnityScope.Mcp/ TypeScript MCP server (10 tools, stdio transport)
docs/
ARCHITECTURE.md Three-layer design + endpoint catalog
TRANSPORT.md Why loopback HTTP, port discovery, named pipe rationale
IL2CPP.md Plan for IL2CPP runtime support (Mono is V1)
Status
V1. Runtime endpoints validated against a live game. MCP server speaks proper MCP/JSON-RPC. IL2CPP support, named-pipe transport, /events SSE, and a CLI client are roadmap.
Note for Git Bash / MSYS users
If you call the runtime via curl from Git Bash on Windows, MSYS translates leading-slash paths into Windows paths (/Canvas โ C:/Program Files/Git/Canvas). Either pre-encode the slash (%2FCanvas), prefix the env (MSYS_NO_PATHCONV=1 curl ...), or just use instance IDs (recommended for agents anyway โ they're stable and unambiguous). MCP clients are unaffected.
License
GPL-3.0 โ see LICENSE.
