1700 Commits

Author SHA1 Message Date
Shutong Wu 4ce7dd3cc5 Merge pull request #1312 from CoplayDev/release/v10.1.2
chore: bump version to 10.1.2
v10.1.2
2026-08-02 16:48:02 -04:00
GitHub Actions 1ad15ae0c4 chore: bump version to 10.1.2 2026-08-02 20:47:32 +00:00
github-actions[bot] c36b0e8570 Merge pull request #1310 from CoplayDev/beta-version-10.1.1-beta.6-30765582021
chore: update Unity package to beta version 10.1.1-beta.6
2026-08-02 20:36:50 +00:00
GitHub Actions ee0bf57095 chore: update Unity package to beta version 10.1.1-beta.6 2026-08-02 20:36:46 +00:00
Shutong Wu 07e8680df9 Merge pull request #1298 from asavs/fix/gameobject-create-component-properties
fix: make component properties reachable on manage_gameobject create
2026-08-02 16:25:25 -04:00
github-actions[bot] 61c4122bb5 Merge pull request #1309 from CoplayDev/beta-version-10.1.1-beta.5-30756436245
chore: update Unity package to beta version 10.1.1-beta.5
2026-08-02 16:32:50 +00:00
GitHub Actions d3810df17d chore: update Unity package to beta version 10.1.1-beta.5 2026-08-02 16:32:46 +00:00
Shutong Wu 25e5f7e965 Merge pull request #1308 from Scriptwonder/fix/ci-fork-pr-signal
ci: retire safe-to-test gate, make skipped Unity checks visible
2026-08-02 12:29:01 -04:00
Shutong Wu 32428e820e Merge pull request #1302 from KamilDev/fix/resource-uri-prose
fix(server): address resources by URI in agent-facing prose
2026-08-02 12:21:12 -04:00
Shutong Wu 0b1f50db0c ci: retire safe-to-test gate, make skipped Unity checks visible
Fork PRs touching MCPForUnity/** get green Unity checks that verified
nothing. GitHub withholds secrets from pull_request runs originating in
a fork, so the detect step writes unity_ok=false and every real step is
gated off. Step-level `if:` produces step-conclusion `skipped`, which
contributes nothing to the job conclusion, so the job reports success
having compiled and tested nothing.

Make the skip unmissable: both workflows now emit ::warning:: and a
$GITHUB_STEP_SUMMARY block stating the check is not a pass.

Retire the safe-to-test label gate. It was the intended escape hatch but
never worked in practice -- actions/checkout's floating v4 tag has since
rolled forward to v4.4.0, which refuses to check out fork code under
pull_request_target without allow-unsafe-pr-checkout: true. Repairing it
would mean running fork-authored C# through game-ci/unity-test-runner
with UNITY_* secrets in scope, which is the classic pwn-request shape.
Removing the trigger makes both job-level `if:` gates dead code (each
began with `github.event_name != 'pull_request_target' ||`), so they go
too. To test a fork PR, review the diff and push its branch into this
repo; the push trigger runs the full suite in a trusted context.

Known tradeoff: the full-matrix label now takes effect on the next push
rather than on application, since nothing re-triggers on `labeled`.

This does not give fork PRs real signal -- it stops the absence of
signal from looking like success. A license-free compile job is the
follow-up.
2026-08-02 12:20:15 -04:00
github-actions[bot] ffd7ff7602 Merge pull request #1307 from CoplayDev/beta-version-10.1.1-beta.4-30755957460
chore: update Unity package to beta version 10.1.1-beta.4
2026-08-02 16:19:46 +00:00
GitHub Actions aa0f8729da chore: update Unity package to beta version 10.1.1-beta.4 2026-08-02 16:19:40 +00:00
Shutong Wu f7ef56602c Merge pull request #1304 from Scriptwonder/fix/1288-tool-annotations
fix: stop 34 tools forcing an approval prompt on every call (#1288)
2026-08-02 12:08:34 -04:00
github-actions[bot] fbc4894265 Merge pull request #1306 from CoplayDev/beta-version-10.1.1-beta.3-30753972755
chore: update Unity package to beta version 10.1.1-beta.3
2026-08-02 15:28:40 +00:00
GitHub Actions 5aa8e66dd3 chore: update Unity package to beta version 10.1.1-beta.3 2026-08-02 15:28:33 +00:00
Shutong Wu c82502f1e6 test: fail on duplicate tool registrations instead of silently collapsing them
Copilot review on #1304. The tools fixture keyed a dict by tool name, so two
tools registering the same name would drop one entry — hiding the registry bug
and skipping the lost entry's annotations, in a guard whose whole purpose is
catching silent regressions.

No duplicates today (48 registrations, 48 unique names — the 49th
@mcp_for_unity_tool occurrence is a docstring mention at
services/tools/__init__.py:28, not a decoration), so this is a guard hardening
rather than a fix.

Also corrects the docstring grammar Copilot flagged.
2026-08-02 11:21:05 -04:00
Shutong Wu 5f8c806414 Merge pull request #1305 from Scriptwonder/fix/1193-restore-codex-http
fix: restore HTTP transport for Codex (#1193)
2026-08-02 11:16:21 -04:00
KamilDev a0e489beec test: cover agent-facing markdown, drop dead type-hint guard
Review feedback on #1302.

The prose rule now also runs over the surfaces that tell a reader to go read a
resource: the skill agents load, and the per-tool reference pages whose example
blocks this PR fixed. Reverting those four lines makes it fail.

Scoped there deliberately. `website/docs/reference/resources/` is a generated
catalog that puts each name in a heading and its URI on the next line, and the
guides and getting-started pages name resources as the subject of a sentence
rather than instructing anyone to build a URI -- a blanket scan flags 38 lines,
none of them the defect.

Also drops the try/except around get_type_hints: it resolves for all 48
registered tools (266 annotated strings), so the except only had the power to
skip a tool's parameters silently. Without it a resolution failure surfaces as
the real error.
2026-08-01 13:36:03 +10:00
KamilDev 69267c536c fix(server): address resources by URI in agent-facing prose
A resource's name and its URI are deliberately different (`editor_state` vs
`mcpforunity://editor/state`), and the URI scheme is not derivable from the
name -- most resources are `category/thing` but several are flat
(`mcpforunity://instances`, `mcpforunity://menu-items`, `mcpforunity://tests`).

Several agent-facing strings still named resources without their URI, so an
agent following them built `mcpforunity://editor_state` and got a 404:

- server instructions listed resources by bare name and told the reader to
  "poll the `editor_state` resource's `isCompiling` field" (that field path is
  also wrong -- payloads are wrapped, so it is `data.compilation.is_compiling`)
- `refresh_unity`'s `wait_for_ready` parameter description referred to
  `editor_state.advice.ready_for_tools`
- the hint Unity returns in the `refresh_unity` result said "poll editor_state
  until ready_for_tools is true"

#1244 added a warning that names and URIs are not interchangeable, but left the
strings that trigger the mistake unchanged. Spell every resource reference as a
full URI instead, and correct the field paths while here.

Adds a regression test asserting that no agent-facing prose -- server
instructions, resource descriptions, tool and parameter descriptions, and
multi-word string literals under MCPForUnity/Editor -- mentions a resource by
its snake_case name without also giving that resource's URI.
2026-08-01 13:23:23 +10:00
Shutong Wu 267b465109 fix: restore HTTP transport for Codex (#1193)
#1292 declared Codex stdio-only. Tested against Codex CLI 0.47.0 with an
isolated CODEX_HOME, that is wrong: a bare

    [mcp_servers.unityMCP]
    url = "http://127.0.0.1:8123/mcp"

reports `transport: streamable_http` from `codex mcp get`, and Codex completes a
full MCP handshake against a live mcp-for-unity HTTP server - initialize 200,
notifications/initialized 202, SSE GET 200, tools/list 200 - with no feature flag
set at all. Adding [features] rmcp_client, the deprecated root-level
experimental_use_rmcp_client, both, or a deliberately bogus feature key all give
byte-identical results; unknown feature keys are silently ignored.

So #1292 removed a capability Codex has, for every Codex user.

Drop SupportsHttpTransport = false (the McpClient default is already true) and
delete the SupportedTransports override, since the base default is already
{ Stdio, Http }.

Delete the GetManualSnippet stdio coercion too. It was added by #1292 to stop a
stdio-only client rendering a url block, and CodexConfigurator is the only
subclass of CodexMcpConfigurator, so once Codex is HTTP-capable that branch is
unreachable.

Leave [features] rmcp_client = true alone: it is the current key name (the root
experimental_use_rmcp_client form is deprecated per openai/codex#6995), it is
harmless, and it enables the RMCP client that OAuth needs. Deliberately not
adding the deprecated key - it does nothing on current Codex and would just
linger in users' configs.

Tests now assert both transports and cover the snippet in both directions.

Caveat for review: this was verified against the Codex CLI. #1193 was reported
against Codex Desktop on Windows 11, which is untested here. #1292's remedy was
too broad, which does not mean the reporter was wrong - ask for their version and
CLI-vs-Desktop before closing #1193. If Desktop genuinely cannot do HTTP, that
belongs in Desktop-specific handling, not a blanket capability removal.
2026-07-29 00:18:25 -04:00
Shutong Wu 835bfcdd06 fix: stop 34 tools forcing an approval prompt on every call (#1288)
MCP clients gate a tool behind human approval unless it is read-only or
explicitly non-destructive, and destructiveHint defaults to true when omitted.
PR #480 set only `title=` on read_console, manage_editor and set_active_instance
despite its description claiming otherwise, so the spec default supplied
destructiveHint: true and nobody noticed.

Registering all 48 tools and dumping tools/list showed 34 of them serializing as
neither read-only nor explicitly non-destructive. find_gameobjects emitted
`annotations: null` outright.

State the hints explicitly across 10 modules. Four genuinely safe tools become
destructiveHint=False; the read-only set gets explicit hints instead of relying
on defaults; manage_editor and manage_components get explicit destructiveHint=True,
which changes no behaviour but stops them depending on the implicit default that
caused this. 34 gated -> 30, and the remaining 30 all write to the project.

find_gameobjects is deliberately not readOnlyHint=True: it calls
preflight(refresh_if_dirty=True), which can trigger a domain reload, and a
read-only promise would let a client do that unattended.

Add test_tool_annotations.py as the durable guard - it requires every tool to
state title and destructiveHint, and pins the auto-approvable set so a future
edit cannot silently flip one. Verified it fails by replaying the #480 regression.

test_tool_test_symmetry.py now excludes registry-wide guards from counting as
per-tool coverage, so one such file cannot satisfy the coverage guard for every
tool it happens to mention.

Does not fix the whole report: manage_asset(action="search") stays gated because
manage_asset can also delete. A read-only find_assets tool is the follow-up.
2026-07-29 00:18:06 -04:00
asavschaeffer 503d938b4a fix: make manage_gameobject component properties reachable on create
Fixes #1297. At action:"create", component_properties was accepted and
coerced by the C# dispatcher (ManageGameObject.cs) but only ever consumed
by the "modify" handler, so it silently did nothing. Meanwhile the shape
"create" already reads directly out of each componentsToAdd entry
({typeName, properties}) was rejected before it reached Unity, because the
Python schema typed components_to_add as list[str].

- GameObjectComponentHelpers.cs: factor the componentProperties loop +
  error aggregation out of GameObjectModify.cs into a shared
  ApplyComponentProperties helper, so both actions apply it identically.
- GameObjectCreate.cs: call the new helper after components are added,
  destroying the partially-created object and returning the error if any
  property fails to set (matching how component-add failures are handled).
- GameObjectModify.cs: switch to the shared helper (behavior-preserving
  refactor, no functional change on the modify path).
- manage_gameobject.py: widen components_to_add to accept
  {"typeName": ..., "properties": {...}} objects alongside plain strings,
  matching what GameObjectCreate.cs already reads.
- Regenerated website/docs/reference/tools/core/manage_gameobject.md via
  tools/generate_docs_reference.py for the updated parameter docs.

Tested: Server/tests/test_manage_gameobject.py exercises the Python
contract end-to-end, including a real fastmcp/pydantic schema validation
run of the issue's exact repro payloads (confirmed the pre-fix
ValidationError reproduces on the unmodified file, and is gone after).
Added TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/
ManageGameObjectCreateTests.cs coverage for the C# side, but this was not
run against a live Editor.
2026-07-28 15:59:38 -07:00
Shutong Wu fc70dda75d Merge pull request #1281 from ananttheant/fix/typos-migration-v8-docs
Beta Release (PyPI Pre-release) / Unity tests gate (push) Failing after 1s
Beta Release (PyPI Pre-release) / Python tests gate (push) Failing after 0s
Beta Release (PyPI Pre-release) / Update Unity package to beta version (push) Has been cancelled
Beta Release (PyPI Pre-release) / Publish beta to PyPI (pre-release) (push) Has been cancelled
Docs — Reference Drift Check / Check docs reference is fresh (push) Has been cancelled
Docs — Build & Deploy / Build site (push) Has been cancelled
Docs — Build & Deploy / Deploy to GitHub Pages (push) Has been cancelled
docs: fix typos in v8 migration guide
2026-07-28 18:15:35 -04:00
github-actions[bot] 5fdf544e94 Merge pull request #1296 from CoplayDev/beta-version-10.1.1-beta.2-30388780929
chore: update Unity package to beta version 10.1.1-beta.2
2026-07-28 18:56:11 +00:00
GitHub Actions 2d3b099165 chore: update Unity package to beta version 10.1.1-beta.2 2026-07-28 18:56:05 +00:00
Shutong Wu 94f192bfa3 Merge pull request #1291 from Scriptwonder/fix/1276-deferred-reload-compiling
fix: trust the pipeline flag when a domain reload is deferred (#1276)
2026-07-28 14:44:04 -04:00
Shutong Wu 70a96ec362 Merge pull request #1290 from Scriptwonder/fix/1279-windows-headless-stdin
fix: redirect stdin from NUL when launching the server on Windows (#1279)
2026-07-28 14:42:01 -04:00
Shutong Wu 334f3c0805 Merge pull request #1292 from Scriptwonder/fix/1193-codex-stdio-only
fix: advertise Codex as stdio-only (#1193)
2026-07-28 14:41:28 -04:00
Shutong Wu 5496c1243f Merge pull request #1293 from Scriptwonder/fix/server-cli-run-tests-and-camera
fix: repair dead camera CLI, add run_tests clear_stuck (#1272), refresh uv.lock
2026-07-28 14:40:26 -04:00
Shutong Wu e8fe7fe034 Merge pull request #1294 from Scriptwonder/test/graphics-assume-to-ignore
test: report unavailable-pipeline graphics tests as Skipped, not Inconclusive
2026-07-28 14:39:37 -04:00
Shutong Wu afc51b53e9 fix: force stdio in the Codex manual snippet, assert the exact transport set
Two review findings on #1292.

Copilot: advertising Codex as stdio-only was not enough. GetManualSnippet()
calls BuildCodexServerBlock directly, which reads the global UseHttpTransport
pref itself. Configure() gets that pref coerced for it by
ClientConfigurationService.ConfigureWithTransportCoercion; the snippet path
does not. With the HTTP pref on, the copyable snippet still rendered

    [features]
    rmcp_client = true
    [mcp_servers.unityMCP]
    url = "http://127.0.0.1:8080/mcp"

reintroducing the exact silent-failure path via manual setup. Coerce to stdio
around the call for any client that does not support HTTP, restoring the pref
afterwards, mirroring ConfigureWithTransportCoercion.

Deliberately not removing the HTTP branch from CodexConfigHelper: it is covered
by BuildCodexServerBlock_HttpMode_GeneratesUrlField and is a general-purpose
helper, so narrowing the caller is the smaller and more honest change.

CodeRabbit: assert SupportedTransports equals exactly { Stdio } rather than
contains-stdio plus not-contains-http, which would also pass if a third
transport were added.

Adds Codex_ManualSnippet_IsStdio_EvenWhenHttpPreferred, which fails with the
url block above before this change.
2026-07-28 13:12:00 -04:00
Shutong Wu e2aacdf35d fix: camera CLI discarded its output and ignored --format
Follow-up to the inverted-argument fix in this branch: repairing the
run_command call order was necessary but not sufficient, and the group was
still effectively dead.

format_output(data, format_type: str = "text") returns a string. All 18 call
sites called format_output(result, config) and dropped the return value, so
every `unity-mcp camera` subcommand printed nothing at all. Passing the whole
CLIConfig where a format string was expected also meant the branch always fell
through to text, silently ignoring --format/UNITY_MCP_FORMAT.

Use click.echo(format_output(result, config.format)), matching every other
command module.

Adds two regression tests: one asserting the group emits non-empty output, one
asserting --format json yields parseable JSON. Both fail without this change.

Reported by Copilot on #1293.
2026-07-28 13:09:17 -04:00
Shutong Wu a36c9917bc docs: regenerate tool reference for run_tests clear_stuck
Generated by tools/generate_docs_reference.py; the "Check docs reference is
fresh" CI job flagged testing/run_tests.md as stale after clear_stuck was added.
2026-07-28 13:05:08 -04:00
Shutong Wu aaef1df968 test: report unavailable-pipeline graphics tests as Skipped, not Inconclusive
The 18 environment guards in ManageGraphicsTests used Assume.That, which
yields Inconclusive. Three consumers disagree about what that means: the
Test Runner window paints it with a failure icon, run_tests drops it from
summary.total while progress.total still counts it (1150 vs 1168), and
failures_so_far ignores it. A clean suite therefore reads as 18 failures.

Use Assert.Ignore behind an explicit condition instead, matching the
existing convention in WriteToConfigTests, StdioBridgeReconnectTests and
ManageSceneMultiSceneTests. The helpers are renamed Require* since Assume*
named the very API being dropped.

Full EditMode suite on 2021.3.45f2 before: 1150 total / 1094 passed / 0 failed
/ 56 skipped, with 18 inconclusive unaccounted for. After: 1168 / 1094 / 0 / 74,
and the two totals reconcile.
2026-07-28 12:06:01 -04:00
Shutong Wu 172d3e203b chore: refresh uv.lock to match the pyproject version
The lockfile pinned mcpforunityserver 10.0.0 while pyproject.toml declared
10.1.0, and no workflow runs `uv lock`, so every contributor's first `uv run`
dirtied their working tree.
2026-07-28 12:05:53 -04:00
Shutong Wu 2b2ca8a6f3 feat: add a clear_stuck escape hatch to run_tests (#1272)
A test job orphaned by a domain reload leaves TestRunStatus pinned with a
CurrentJobId that blocks every subsequent run, and there was no way to clear
it from the client side.

Add clear_stuck to the run_tests MCP tool and --clear-stuck to the editor CLI.
Both short-circuit ahead of the init_timeout validation and preflight, because
neither applies to clearing and preflight's requires_no_tests gate would reject
the very call that exists to release it.
2026-07-28 12:05:53 -04:00
Shutong Wu 82b1b732e2 fix: correct inverted run_command arguments in the camera CLI
All 18 call sites passed run_command(config, "manage_camera", params) while
the signature is run_command(tool, params, config), so the entire
`unity-mcp camera` command group was dead at beta HEAD.

test_cli.py asserted against call_args[0][2], which encoded the bug rather
than catching it; it now asserts the tool name at [0][0] and params at [0][1].
2026-07-28 12:05:53 -04:00
Shutong Wu 4ff8ff85b1 fix: advertise Codex as stdio-only (#1193)
Codex does not expose MCP tools that are configured through the HTTP block,
so writing an HTTP config produces a client that connects but surfaces no
tools.

Declare SupportsHttpTransport = false and restrict SupportedTransports to
stdio, so CoerceTransportFor settles on stdio before Configure() runs.
2026-07-28 12:05:43 -04:00
Shutong Wu 777e8a9c7a fix: trust the pipeline flag when a domain reload is deferred (#1276)
EditorApplication.isCompiling conflates three states: actually compiling,
compilation queued, and finished-but-reload-deferred. A project holding
EditorApplication.LockReloadAssemblies sits in the third state for as long
as the lock is held, with no compilation running, and isCompiling stays
true the whole time.

Eight call sites gated on that raw flag, so they refused work indefinitely:
the stdio bridge would not start, unity_reflect and manage_scriptable_object
returned "Unity is compiling", refresh_unity reported the wrong resulting
state and never completed its wait, the stdio reload handler deferred its
resume, and TestJobManager both mis-attributed its init timeout and reported
a bogus "compiling" block reason.

Route all eight through EditorStateCache.GetActualIsCompiling(), which falls
back to the event-tracked CompilationPipeline flag, and drop the isPlaying
gate that previously limited the workaround to play mode.

Verified live: with LockReloadAssemblies held after RequestScriptCompilation,
EditorApplication.isCompiling is true while the pipeline flag is false, so
CompilationPipeline.compilationFinished does fire while the reload is held.
2026-07-28 12:05:30 -04:00
Shutong Wu b954897efd fix: redirect stdin from NUL when launching the server on Windows (#1279)
The Editor is a console-less GUI process. TerminalLauncher spawned cmd.exe
with UseShellExecute=false and CreateNoWindow=true and never redirected
stdin, so uvx.exe inherited an invalid stdin handle and died with
"The handle is invalid. (os error 6)" before the server could start.

Redirect stdin from NUL inside the cmd.exe payload so the child gets a
valid handle regardless of whether the Editor has a console.

Regression from #1201, shipped in v10.1.0.
2026-07-28 12:05:19 -04:00
Anant Sharma d39536369c docs: fix typos in v8 migration guide
Fix spelling in website/docs/migrations/v8.md:
compatability->compatibility, isntances->instances, releated->related,
maintanable->maintainable, andn->and, indepdendent->independent.
2026-07-21 13:50:17 +01:00
github-actions[bot] bd72241ab9 Merge pull request #1271 from CoplayDev/sync/main-v10.1.0-into-beta-29284763400
chore: sync main (v10.1.0) into beta
2026-07-13 21:15:58 +00:00
GitHub Actions 64e61ee2e6 chore: set beta version to 10.1.1-beta.1 after release v10.1.0 2026-07-13 21:15:52 +00:00
GitHub Actions 7912891667 chore: sync main (v10.1.0) into beta 2026-07-13 21:15:52 +00:00
github-actions[bot] c14de1e6dc Merge pull request #1270 from CoplayDev/release/v10.1.0
chore: bump version to 10.1.0
v10.1.0
2026-07-13 21:15:32 +00:00
GitHub Actions 31a226b930 chore: bump version to 10.1.0 2026-07-13 21:13:19 +00:00
github-actions[bot] 63c7439535 Merge pull request #1269 from CoplayDev/beta-version-10.0.3-beta.2-29283113713
chore: update Unity package to beta version 10.0.3-beta.2
2026-07-13 20:48:44 +00:00
GitHub Actions c42d162bae chore: update Unity package to beta version 10.0.3-beta.2 2026-07-13 20:48:39 +00:00
Shutong Wu 3db6b267f8 Merge pull request #1264 from Scriptwonder/feat/assetgen-audio-model-panel
feat(asset-gen): AI audio generation + shared model panel (hardened)
2026-07-13 13:37:16 -07:00
Shutong Wu 55f357bd02 Merge remote-tracking branch 'upstream/beta' into feat/assetgen-audio-model-panel 2026-07-13 12:18:35 -07:00