UAsset Reference MCP v0.4.0 adds an interactive viewer for the asset graph. It renders the dependency graph in three modes, points at what already looks wrong, and starts with no arguments from anywhere inside a Unity project.
The first three releases made the graph queryable. find_references, get_dependencies, trace_path, and find_unused_assets all answer a question precisely, and all of them require the same thing first: a name. On a project with 32,579 indexed assets, naming the right asset is the hard part. Answering “what references BattleFloor.mat” is cheap once you already suspect BattleFloor.mat.
A Query Answers a Question You Already Have
The graph in that project holds 32,579 assets and 28,842 edges. There is no useful way to read that as a list. Sorting by reference count gives you the top of the list and nothing about shape. Sorting by path gives you the Project window, which is the view you already had when you got stuck.
What a developer usually wants before a refactor is not one answer but a direction: which corner of the project is dense, which assets sit at the center of everything, which references are already broken, which folders nothing points at. Those are shape questions, and the reason they are hard to ask through a query API is that you cannot name the answer in advance.
So v0.4.0 stops requiring the name. The viewer draws the graph, and the first thing it draws is a short list of things that already deserve attention.
The Attention Panel Answers the Unasked Question
The panel is deliberately narrow. It reports three categories, each one already computable from the index:
Broken references edges whose target GUID resolves to nothing
Unused candidates assets with no incoming serialized edge
Most referenced dependency hubs, ranked by incoming edge count
Broken references are the least ambiguous. If an asset serialized a {fileID, guid, type} record and no asset in the graph owns that GUID, something was deleted or moved outside Unity, and the index can say so without judgment.
Unused candidates are a review signal, not a delete list, for the same reason described in the Addressables post: an asset with no incoming edge can still be loaded by an Addressables address or a Resources.Load string. The panel sorts those candidates by size, because the ones worth reviewing first are the ones costing the most.
Most-referenced assets are the opposite signal. They are the assets where a change is expensive, which makes them the assets worth looking at before planning one.
Clicking any row selects that asset in the graph, so the panel is an entry point into the picture rather than a separate report.
Three Renderings, One Graph
The viewer draws the same graph three ways:
2D force-directed, inline SVG cluster and density
DAG layered hierarchy, inline SVG direction of dependency
3D three.js, loaded on demand structure of a large neighborhood
2D and DAG are plain inline SVG, so they cost nothing beyond the page. 3D pulls in three.js, and it does so only when the mode is selected — the module is not on the initial load path.
The important part is what the modes do not mean. They are three ways to draw one graph, not three levels of detail. Switching to 3D does not reveal edges that 2D was hiding. DAG is useful when the question is “what flows into what” and 2D is useful when the question is “what is clumped together,” and both are reading the same rows from the same SQLite index.
The Node Budget Bounds the Drawing, Not the Index
A 32,000-node force layout is a hairball, and a hairball is not a visualization. The viewer keeps large projects readable with two controls.
Filters restrict the graph by asset type and by origin, where origin is project, package, or builtin — the same distinction the indexer records when it walks project assets, embedded and external UPM packages, and Unity’s built-in resources.
The node budget caps how many nodes are requested at all. It defaults to 320 and is clamped between 50 and 5,000:
setNodeBudget: (nodeBudget) =>
set({ nodeBudget: Number.isFinite(nodeBudget) ? Math.max(50, Math.min(5000, Math.trunc(nodeBudget))) : 320 }),
The budget is a rendering bound, not an indexing bound. Nothing is dropped from .asset-memory/index.db, and no query result is silently truncated on the server’s behalf — the viewer asks for a bounded slice because a bounded slice is the only kind a person can read.
Starting It Takes No Path, No Port, and No Config
The viewer used to want a database path and a port. Both are now inferred.
Project discovery walks up from the working directory the way git finds a repository. A directory counts as a project scope if it already holds an index, or if it looks like a Unity project root:
export function isProjectRoot(dir: string, exists = existsSync): boolean {
if (exists(join(dir, ".asset-memory"))) return true;
return exists(join(dir, "Assets")) && exists(join(dir, "ProjectSettings"));
}
.asset-memory is checked first, so a project that has already been indexed is recognized even when its layout is unusual.
Port selection starts at 7777 and advances to the first free port. Previously a second viewer died on an unhandled EADDRINUSE; now it binds the next port and prints where it landed. If --port was passed explicitly and that port was taken, it says so rather than pretending.
The result is that the whole workflow is two commands from inside the project:
unity-asset-reference-mcp-index index .
unity-asset-reference-mcp-web
asset graph viewer → http://localhost:7777 (db: /path/to/UnityProject/.asset-memory/index.db)
--project <root> still works, and now matches the argument the MCP server and indexer already accept, so none of the three binaries asks the user to spell out .asset-memory/index.db.
Five Routes, and No New MCP Tools
The viewer is a client of the same HTTP API the tool already served. v0.4.0 adds five routes to support it:
/api/asset-detail
/api/broken-references
/api/graph
/api/index-status
/api/root-trace
The MCP tool count is unchanged at 15. Nothing about the agent-facing surface moved to make room for a UI, because the UI is reading the same index through the same query layer.
What It Does Not Do
The viewer is read-only. It does not edit, move, refactor, or delete anything in the Unity project, and it never writes to the index. It reports what the graph contains and leaves every production decision in the Editor where it belongs.
Two changes are worth knowing before upgrading. The new viewer is served at /, and the previous Cytoscape viewer is still bundled at /legacy.html. The server-less WASM viewer left the npm package: it exists to be opened directly from the filesystem, so it was charging every install roughly 706 KB of WASM that a server-backed install would never load. It is now a release-page download, asset-graph-viewer-static-<version>.zip, and nothing about that flavor itself changed.
Upgrading from 0.3.x needs nothing else. The index schema is still version 3, so an existing .asset-memory/index.db is read as-is.
Three releases of query tools were the right order to build this in. The graph had to be trustworthy before it was worth looking at. But a trustworthy graph you can only address by name is still a graph you have to already understand, and drawing it is the cheapest way to stop needing to.