Skip to content

chore(deps): upgrade Unity MCP to 0.90.0 and add the ten extension packages - #175

Merged
Nghaiz merged 2 commits into
developfrom
chore/unity-mcp-0.90-upgrade
Aug 25, 2026
Merged

chore(deps): upgrade Unity MCP to 0.90.0 and add the ten extension packages#175
Nghaiz merged 2 commits into
developfrom
chore/unity-mcp-0.90-upgrade

Conversation

@Nghaiz

@Nghaiz Nghaiz commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Brings the Unity MCP plugin from 0.87.0 to 0.90.0 and installs the nine extension packages the project did not have, alongside the timeline bump.

The MCP surface the Editor now exposes, enumerated live rather than read off the manifest:

Before After
tools core only 187
prompts 46
resources 2
resource templates 1
extension packages 1 (timeline) 10

New extensions: inputsystem, navigation, animation, cinemachine, probuilder, particlesystem, splines, terrain, tilemap.

Why 0.88.0 was skipped

0.88.0 does not compile. UNITY_MCP_READY recorded only that the dependency resolver had run, never which DLL set it restored, so an upgrade saw "already installed", skipped the restore, and Unity built the new sources against the old McpPlugin DLLs. The resulting compile failure then blocked the domain reload, so the resolver could never run and unstick itself. Upstream fixed it in IvanMurzak/Unity-MCP#958 by moving the gate into a generation-numbered asmdef define that a stale install cannot satisfy.

That is what the UNITY_MCP_DEPS_3 addition in ProjectSettings.asset is. It is not a stray edit.

Files

ProjectSettings/Packages/com.unity.probuilder/Settings.json and ShaderGraphSettings.asset are Unity-generated and arrive with the new packages.

The second commit adds the BTL description document under tmp/, unrelated to the upgrade.

Verified

Unity 6000.3.21f1, plugin 0.90.0, server 9.2.5. Editor compiles clean, MCP connects, and all 187 tools are reachable. Smoke-tested unity-tool-list, editor-application-get-state, console-get-logs and resource enumeration against the live Editor.

One known defect rides along: console-clear-logs still fails whenever a Unity Asset Import Worker holds the log file open. Root-caused and fixed upstream in IvanMurzak/Unity-MCP#967; use UnityEditor.LogEntries.Clear() until that merges.

Nghaiz added 2 commits August 25, 2026 14:24
…ckages

Moves com.ivanmurzak.unity.mcp from 0.87.0 to 0.90.0 and pulls in the nine
extension packages that were not installed before (inputsystem, navigation,
animation, cinemachine, probuilder, particlesystem, splines, terrain, tilemap)
alongside the timeline bump. The MCP surface goes from core-only to 187 tools,
46 prompts, 2 resources and 1 resource template.

0.88.0 was skipped: it could not compile, because a stale dependency gate let
Unity build the new sources against the previous McpPlugin DLLs. 0.90.0 carries
the fix, which is what the new UNITY_MCP_DEPS_3 define in ProjectSettings is
for: a generation-numbered gate that a stale install cannot satisfy.

ProjectSettings/Packages/com.unity.probuilder/Settings.json and
ShaderGraphSettings.asset are Unity-generated and arrive with the new packages.
@Nghaiz
Nghaiz merged commit 0ab781d into develop Aug 25, 2026
5 of 8 checks passed
@Nghaiz
Nghaiz deleted the chore/unity-mcp-0.90-upgrade branch August 25, 2026 07:25
Nghaiz added a commit that referenced this pull request Aug 25, 2026
…cent file

`com.ivanmurzak.unity.mcp` 0.90.0 and its ten extension packages (#175) installed
McpPlugin.dll and McpPlugin.Common.dll with `defineConstraints: []`, while every
other DLL of the same closure -- R3, ReflectorNet, SignalR, Microsoft.CodeAnalysis
-- carried `- UNITY_EDITOR`. McpPlugin.dll references R3, so a player build included
the first, excluded the second, and UnityLinker died with

    Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'R3'

which names R3, the file that is correct, and never names McpPlugin.dll, the file
that is wrong. Two .meta lines fix it: same tree, same command, Failure -> Success.

Never only a compile problem. defineConstraints are evaluated per target and
UNITY_EDITOR is false in every player, so the shipping Linux dedicated server was
equally unbuildable -- and a build that HAD linked would have carried an HTTP bridge
hosting Roslyn into the game server image, the exact thing
EditorBuild.StripEditorOnlyDefines was written to prevent.

Nothing in CI could see it: no job builds a Unity player, images.yml downloads a
pre-built Linux artifact from a release, and build-test is `dotnet build` over the
pure-.NET libraries, which never reads Assets/Plugins. Four days, unnoticed. And
because these .meta files are generated by the MCP package's own NuGet installer,
the next upgrade would have silently undone a hand-fix.

So the fix ships with the gate. check-plugin-define-constraints.ps1 reads the
bridge's package list from .nuget-installed.json rather than hardcoding DLL names,
so a fourth bridge DLL is covered the day it lands. Mutation-proved, one fault, one
mutant, one red: reverting McpPlugin.dll.meta turns it red naming that exact file.

A first version of the gate was wrong in a way worth recording. It walked assembly
references and failed any player-included plugin referencing an editor-only one --
22 violations against a tree whose build succeeds. The BCL shims in that folder
reference each other, and in a player those names resolve against Unity's own
netstandard2.1 profile, not the excluded plugin copies (the same fact build-libs.ps1
records from the other direction). Separating a real break from a backfilled shim
needs the Editor's playback-engine assembly set, which CI does not have. That gate
would have blocked every PR on day one. The shipped one answers the narrower
question truthfully, and its header says which question it declines.
Nghaiz added a commit that referenced this pull request Aug 25, 2026
* fix(client): no player could be built, and the linker blamed the innocent file

`com.ivanmurzak.unity.mcp` 0.90.0 and its ten extension packages (#175) installed
McpPlugin.dll and McpPlugin.Common.dll with `defineConstraints: []`, while every
other DLL of the same closure -- R3, ReflectorNet, SignalR, Microsoft.CodeAnalysis
-- carried `- UNITY_EDITOR`. McpPlugin.dll references R3, so a player build included
the first, excluded the second, and UnityLinker died with

    Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'R3'

which names R3, the file that is correct, and never names McpPlugin.dll, the file
that is wrong. Two .meta lines fix it: same tree, same command, Failure -> Success.

Never only a compile problem. defineConstraints are evaluated per target and
UNITY_EDITOR is false in every player, so the shipping Linux dedicated server was
equally unbuildable -- and a build that HAD linked would have carried an HTTP bridge
hosting Roslyn into the game server image, the exact thing
EditorBuild.StripEditorOnlyDefines was written to prevent.

Nothing in CI could see it: no job builds a Unity player, images.yml downloads a
pre-built Linux artifact from a release, and build-test is `dotnet build` over the
pure-.NET libraries, which never reads Assets/Plugins. Four days, unnoticed. And
because these .meta files are generated by the MCP package's own NuGet installer,
the next upgrade would have silently undone a hand-fix.

So the fix ships with the gate. check-plugin-define-constraints.ps1 reads the
bridge's package list from .nuget-installed.json rather than hardcoding DLL names,
so a fourth bridge DLL is covered the day it lands. Mutation-proved, one fault, one
mutant, one red: reverting McpPlugin.dll.meta turns it red naming that exact file.

A first version of the gate was wrong in a way worth recording. It walked assembly
references and failed any player-included plugin referencing an editor-only one --
22 violations against a tree whose build succeeds. The BCL shims in that folder
reference each other, and in a player those names resolve against Unity's own
netstandard2.1 profile, not the excluded plugin copies (the same fact build-libs.ps1
records from the other direction). Separating a real break from a backfilled shim
needs the Editor's playback-engine assembly set, which CI does not have. That gate
would have blocked every PR on day one. The shipped one answers the narrower
question truthfully, and its header says which question it declines.

* docs(replication): X-20: the linecast blocked nothing, the shot threads a body seam

The row said the collider NAME would decide between two readings -- terrain or a
building for real cover, the victim's own body for the mask-2049 reading. It is
neither, because there was no occlusion to name.

artifacts/lane-b/x20-occlusion-01, spawn pinned to slot 0, 3 of 3 clients exit 0:
240 trigger frames, every one occlusionHit[none-this-shot], occluded=0
presentFallbacks=0 resolved=6 hits=0, victim on 100 health at all 7 checkpoints.
`none-this-shot` is the freshness path added on 2026-08-25, not a default -- the
instrument worked and reported that the thing it was built to describe did not
happen.

This does NOT retroactively settle the baseline. x19-fixed-04 held at 10.1 m on an
unpinned spawn; this run stands at 4.7 m pinned. Different geometry, so the question
is retired rather than won, and both readings die for this run rather than one
winning.

What the run exposed instead. Everything upstream is now correct and the artifact
says so: present.torso == frame.torso to seven digits, frame.tick == wanted.tick,
aim.resolved on actor 42 at 4.65 m, nothing in the way. And the shot still misses.
HitboxSet.FromSize stops torso AND arms at 1.550 and starts head at 1.580, so
nothing covers 1.550..1.580 -- a 3 cm seam across a standing body. A ray through it
returns Miss before the occlusion test runs, which is exactly why occluded stays 0.
The logged ray arrives 1.5684 m above the target's feet, inside the seam.
ScriptedTargetSolver raises BOTH endpoints by EYE_HEIGHT 1.6, which is 0.02 m inside
the head box's lower edge rather than centre of mass -- so the aim point is 1.6 m at
every range and the margin is two centimetres everywhere.

Stated honestly, because the arithmetic has a limit: the seam is a fact of the
source and needs no run. That THIS ray threaded it is derived from a log line whose
aim is rounded to two decimals, and +/-0.005 in y is +/-0.024 m at 4.74 m -- wider
than the seam. Consistent, not proven.

Next measurement, one line: LagCompensator.Resolve already loops all four boxes; on
a miss, record the nearest box and its signed miss distance instead of discarding
them. The same move 3F.1 made for X-19 and #180 made for occlusion. Fix nothing
before it exists -- widening a hitbox is a balance change, and guessing at 0.03 m is
how a box stops matching the mesh.

Filed rather than fixed, per phase-3 section 6:
  X-24  the 3 cm torso/head seam. A game defect: a human aiming at chest-to-chin
        height on a standing body gets the same nothing.
  X-25  the aim point. A harness defect, and the reason the seam is hit every time
        rather than occasionally -- it is why no lane-B combat run has ever scored
        a hit.

Also recorded, not filed: the shooter held SL_DEFENDER (clip 8, cooldown 1.5 s)
while both observers held RK44 (clip 30). Nothing in the programme selects a weapon,
so the loadout follows the slot the server hands out and pinning the spawn changed
which slot that was. The catalog is applied correctly -- 8-round clip and 1.5 s
cadence to the value -- but two combat runs are not comparable shot-for-shot until
the weapon is pinned too.

* docs(ci): require-status-check is on, and the reason it was off is gone

This page declined to require build-test because build-test was red, and build-test
stayed red because nothing required anyone to look -- eleven merges onto a red
develop. X-23 (#178) and #181 fixed the red, so the condition the page set for
itself was met and the rule is now on.

Done in the order section 1 asks for, with each step checked rather than assumed:
the red fixed, build-test watched green once on develop at 76734c5, the two check
names read back from GET /commits/{sha}/check-runs rather than copied off this page,
and ci.yml confirmed to run on pull_request with no workflow-level paths filter --
the deadlock this page warns about twice.

Added to the existing protect-shared-branches ruleset so main and develop stay one
object rather than two that drift. Verified after the write by asking which rules
apply to each ref rather than trusting the PUT: both shared branches return
deletion, non_fast_forward, required_status_checks; a feature branch returns none.

Two consequences recorded before they surprise someone. A direct push to main or
develop is now refused -- a fresh commit has no checks and there is no bypass --
which suits a PR-only workflow and would block a hotfix pushed straight at the
branch. And with no bypass actor, a CI outage blocks merging entirely; that is
section 1's deliberate choice, not an oversight.

Not proven, only configured, and the page says so -- the same caveat the force-push
row already carries. Nobody has opened a PR with a FAILING build-test and watched
the merge refuse. What is observed is the positive half.

Two rules stay off, with reasons rather than silence. Required approvals would
deadlock a single-owner repository, since GitHub forbids approving your own PR --
section 2's one-approval row was written for the four-person team. And strict
(up-to-date) mode costs an update-and-re-run on every PR that lands after another,
to prevent a failure that has not happened here; the eleven-merge streak was a
branch nobody was required to look at, which is what this change fixes.

* docs(replication): X-20 closed and handed its position to the defect it hid

The plan called X-20 "the only thing between here and 3D — a RUN away, not an
investigation away". The run happened. X-20 is closed and the arrow did not
shorten: X-25 now occupies that position, and it is the same shape of work, one
harness edit rather than an investigation.

So `X-20 ──▶ 3D` becomes `X-25 ──▶ 3D`. X-24 (the 3 cm torso/head seam) is a game
defect routed to phase 6 and deliberately NOT a blocker for 3D — X-25 stops the
harness aiming into the seam, which is exactly why X-24 needs its own row rather
than vanishing when the runs go green.

Also corrects a claim this plan has been carrying: that the pinned re-run yields
"3D's 11 verdicts". It does not. tools/lane-b/ holds combat-* and smoke and nothing
else, and the combat programmes contain no grenade step and no vehicle step, so
checks 4, 7, 9 and 12 are not exercised by a `-Set combat` run at all — check 7 also
needs `-Sim typical`, which it does not pass. A combat run can grade checks 1, 2, 3,
5, 6 and 13. A vehicle programme set does not exist yet and is unbuilt work; AC-2
grades all eleven, so it belongs in 3D's scope rather than being rediscovered at
verdict time.

* docs(replication): say which half of the MCP finding was run and which was derived

The report claimed the shipping Linux dedicated server "was equally unbuildable".
The mechanism is sound -- defineConstraints are evaluated per target, UNITY_EDITOR
is false in every player, and these .meta files carry no Server-specific platform
entry -- but no server build was attempted, so that sentence asserted as measured
something only reasoned.

What IS measured: the Windows player's linker input listed McpPlugin.dll and
McpPlugin.Common.dll among its allowed assemblies and did not list R3.

Reworded to separate the two, in the same shape the section 2 verdict already uses
for the ray arithmetic. The fix does not change either way, which is why this is a
wording correction and not a reason to run a Linux toolchain today.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant