Skip to content

chore: bump version to 9.7.1#1158

Merged
github-actions[bot] merged 55 commits into
mainfrom
release/v9.7.1
May 24, 2026
Merged

chore: bump version to 9.7.1#1158
github-actions[bot] merged 55 commits into
mainfrom
release/v9.7.1

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Automated version bump to 9.7.1.

JMartinezRuiz and others added 30 commits May 4, 2026 02:26
…nd surface inner errors

The RoslynInstaller downloads only 4 NuGet packages but Microsoft.CodeAnalysis 4.12.0
on netstandard2.0 also references System.Runtime.CompilerServices.Unsafe v6.0.0.0,
which is NOT what Unity ships (Unity bundles v4.x). The reference is unresolved at
runtime, so Roslyn's StringTable static cctor throws FileNotFoundException, which
in turn poisons CSharpSyntaxTree's cctor: every parse / compile attempt then
throws TypeInitializationException.

The error is invisible because RoslynCompiler.Compile's catch block only logs
e.Message, and for TargetInvocationException that string is the generic
"Exception has been thrown by the target of an invocation." — the real cause
in InnerException is silently dropped.

Repro:
  1. Trigger Tools > MCP for Unity > Install Roslyn on a fresh project.
  2. Ask the MCP execute_code tool to compile any Roslyn-only snippet.
  3. Observe: "Compilation failed: Roslyn compilation error: Exception has been
     thrown by the target of an invocation." — with no further detail.
  4. Drilling via reflection reveals:
       TypeInitializationException for CSharpSyntaxTree
        └─ TypeInitializationException for Roslyn.Utilities.StringTable
            └─ FileNotFoundException: Could not load file or assembly
                'System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0'

Fix:
  * RoslynInstaller.NuGetEntries: add the missing dependency so a fresh install
    drops all 5 DLLs into Assets/Plugins/Roslyn/.
  * RoslynCompiler.Compile catch: walk the InnerException chain so a future
    bootstrap regression surfaces the actual cause (type + message) instead of
    the generic invocation wrapper.

Verified locally: after dropping System.Runtime.CompilerServices.Unsafe.dll v6
into the plugins folder and forcing a domain reload, the execute_code tool
compiles C# 7+ snippets via the Roslyn backend successfully.
Address PR review: file-existence alone treats a stale v4 of
System.Runtime.CompilerServices.Unsafe (or any other downgraded plugin) as
"installed" and silently masks the bootstrap failure this PR is meant to fix.

Read each on-disk DLL's manifest via AssemblyName.GetAssemblyName(...).Version
and compare to the NuGet entry's declared version; if the file is older than
declared or its manifest can't be read, return false so Install() rewrites it.
Applied uniformly to all entries (defense-in-depth, per the optional suggestion
in the review).

Notes:
- System.Version comparison handles "6.0.0" (Revision=-1) vs "6.0.0.0"
  (Revision=0) correctly: the higher-revision actual passes; a stale v4 fails.
- AssemblyName.GetAssemblyName only reads the manifest, no assembly load into
  the AppDomain, so this is cheap and side-effect-free.
- Validated locally: with the v6 DLL in Plugins/Roslyn/, IsInstalled returns
  true; manually swapping in a v4 placeholder causes it to return false and
  Install() proceeds.
…297942253

chore: sync main (v9.7.0) into beta
… migration)

Antigravity 2.x moved its MCP config from ~/.gemini/antigravity/mcp_config.json
to a dedicated ~/.gemini/config/mcp_config.json. The migration drops a
`.migrated` marker in the new location and renames the prior folder to
`antigravity-backup`; the old path keeps Antigravity's runtime state
(conversations/, scratch/, brain/, etc.) but is no longer read for MCP.
Confirmed empirically on a real machine: ~/.gemini/config/mcp_config.json
shows `mcpServers: {}` (Antigravity reads from here) while our writes have
been landing in the legacy ~/.gemini/antigravity/mcp_config.json that
Antigravity now ignores. Community report matches this exactly: "in
.gemini there are two folders, antigravity and config; antigravity is not
where mcp.json is supposed to be, there is another config folder."

Also override IsInstalled. The inherited ParentDirectoryExists check
points at ~/.gemini/config/, which is only created on Antigravity's first
launch — on a fresh machine that has the app installed but never opened,
detection false-negatives and ConfigureAllDetectedClients skips
Antigravity entirely. Check ~/.antigravity/ (installer-created), the new
config dir, the legacy config dir, or /Applications/Antigravity.app on
macOS; any one of those is conclusive.
Community report: "the Unregister button was removed in 9.7.0 — it did a
wrong registration with stdio transport and now it's difficult to
re-register; something is stuck on stdio and I can't switch to local."

The button wasn't actually removed — the 9.7.0 UI shuffle put the
single-client Configure (which toggles to Unregister for CLI-based
clients like Claude Code) inside a "Per-client setup" foldout that
defaulted to collapsed. With Configure All sitting prominently above it,
the foldout looked like terminal styling rather than the entry point to
manual per-client management, so users who needed to wipe a bad stdio
registration and re-add with HTTP couldn't find the button.

Flip the default to expanded in both UXML and the EditorPrefs fallback.
The state still persists per-user, so anyone who explicitly collapses it
keeps that preference — only the never-touched default changes.
… IDE"

The two Antigravity apps coexist on the same machine and use different
MCP config paths, so they need to be separate configurators in the
client list.

- AntigravityConfigurator: renamed display label to "Antigravity 2.0"
  (path now ~/.gemini/config/mcp_config.json, already changed in the
  parent commit) and updated the installation-steps copy to match.
- AntigravityIdeConfigurator (new): same JsonFile shape with serverUrl
  HTTP property, points at ~/.gemini/antigravity-ide/mcp_config.json
  where the IDE build keeps both its runtime state and its mcp_config.
  IsInstalled checks for that dedicated dir.

Manual configuration guidance updated in README, README-zh, and
MCP_CLIENT_CONFIGURATORS.md to reflect both clients side by side and
spell out which path each one writes to.
…h-migrated

fix(clients): point Antigravity at ~/.gemini/config/ after the 2.x migration
… toggle)

The 9.7.0 community complaint about "Unregister was removed" was actually
two stacked issues: the foldout default hid the existing toggle (fixed
in the previous commit), and the toggle never existed for JSON-based
clients in the first place. Only ClaudeCliMcpConfigurator overrode
GetConfigureActionLabel and routed Configure() through register/unregister
based on status; every JsonFileMcpConfigurator-derived client (Antigravity,
Antigravity IDE, Claude Desktop, Cursor, Windsurf, Kiro, Trae, VS Code,
the various Copilot configs, etc.) always showed "Configure" and
re-wrote the file on every click — there was no way to actually clean a
bad entry out of the JSON without manually editing the file.

Move the toggle logic into JsonFileMcpConfigurator so every JSON client
inherits it:

- GetConfigureActionLabel() flips to "Unregister" when status == Configured.
- Configure() routes to a new UnregisterFromConfig() helper in that case,
  which parses the file and removes the unityMCP entry from mcpServers
  (standard layout) or servers / mcp.servers (VS Code layout). The file
  itself is preserved so the user's other MCP servers stay intact, and
  the cleanup re-uses the same JsonConvert / Newtonsoft path the existing
  CheckStatus / ConfigJsonBuilder code already uses.
- Status flips to NotConfigured after a successful Unregister; the next
  CheckStatus reads the file, sees mcpServers no longer contains
  unityMCP, and reports MissingConfig — so the startup auto-rewrite does
  not silently undo the user's Unregister.

Codex (TOML) clients still don't get the toggle in this commit — the
TOML helpers don't have a remove path and adding one would risk breaking
the file shape. Codex is a small enough surface that hand-editing is
acceptable; a proper Codex remove can be a follow-up.
…50516979

chore: update Unity package to beta version 9.7.1-beta.2
…r via UI

User-reported regression from the previous commit on this PR:
"Configure All Detected Clients does not actually configure all IDEs;
after I click Configure each individual IDE still shows missing
configs, and if one is configured Configure All resets it."

Root cause was the toggle I'd put inside JsonFileMcpConfigurator.Configure():
when ConfigureAllDetectedClients walked the registry and called
configurator.Configure() on each one, any client whose status was
already Configured took the Unregister branch — so the bulk action
wiped every already-configured JSON client instead of refreshing it.
(The same trap existed for ClaudeCli even before this PR, but Claude
Code's CLI registration path is rarely hit through the bulk button so
nobody had reported it.)

Fix: move the Configure↔Unregister toggle out of the configurator and
into the UI handler. The configurator API now has two clearly-split
operations:

- IMcpClientConfigurator.Configure(): always idempotent-write. Safe to
  call repeatedly. This is what ConfigureAllDetectedClients calls and
  what makes the "refresh transport / server version drift" use case
  work without resetting anything.

- IMcpClientConfigurator.Unregister(): removes UnityMCP from this
  client's config. McpClientConfiguratorBase ships a no-op default;
  JsonFileMcpConfigurator overrides with the JObject-parse + remove
  path that used to be the private UnregisterFromConfig helper.
  Codex's TOML still has no remove path so it inherits the no-op,
  matching the previous commit's stance.

UI per-client click (OnConfigureClicked) now reads client.Status and
routes: Configured → client.Unregister(); else →
MCPServiceLocator.Client.ConfigureClient(client). The button label
toggle from GetConfigureActionLabel is preserved — it's purely
informational and stays consistent with the routed action.

Secondary fix in OnConfigureAllClientsClicked: clear the
lastStatusChecks cache after the bulk run so dropdown-switching to
any non-currently-selected client immediately reads its post-bulk
status from disk instead of waiting out the 45-second throttle. This
was the "after clicking Configure All each individual IDE still shows
missing configs" symptom even when the writes had actually succeeded.

ClaudeCli's existing internal toggle is preserved (its async path in
ConfigureClaudeCliAsync handles the Configuring…/Unregistering… UX
itself, and OnConfigureClicked still early-routes to that helper).
Two review items from CodeRabbit on PR #1152:

1) ClaudeCliMcpConfigurator.Unregister was declared `private` while
   the base class defines `public virtual void Unregister()`. Per C#
   rules that hides the base rather than overriding it — so a
   polymorphic IMcpClientConfigurator.Unregister() call on a ClaudeCli
   instance would land on the base's no-op default and the existing
   `claude mcp remove --scope ...` logic would be unreachable through
   the interface. Promote it to `public override` so the interface
   contract resolves correctly; the body is unchanged.

2) JsonFileMcpConfigurator.Unregister rethrew with only the message
   string, dropping the original stack/context. Pass `ex` through as
   InnerException so diagnostics are preserved.
…up-visibility

fix(ui): default the per-client setup foldout to expanded so Unregister is visible
…52158622

chore: update Unity package to beta version 9.7.1-beta.3
Stand up /website with Docusaurus 3.x, hand-written so the scaffold ships
exactly what we need (no default blog, no tutorial-basics clutter).

What lands in M1:
- /website/ structure: package.json, docusaurus.config.js, sidebars.js,
  src/css/custom.css, static/{logo,favicon,social-card,.nojekyll}
- Getting Started: Overview + Install pages (extracted from README §1-2)
- .github/workflows/docs-deploy.yml: builds on PR, deploys to
  https://coplaydev.github.io/unity-mcp/ on push to beta
- @easyops-cn/docusaurus-search-local for day-1 search (Algolia DocSearch
  application is M5)

URL strategy is brand-neutral: slugs like /getting-started/ and (later)
/reference/tools/manage-script — never /mcp-for-unity/... — so a future
product rename touches docusaurus.config.js, not URLs.

Subsequent milestones:
- M2: migrate /docs/* into /website/docs/ per locked IA
- M3: tools/generate_docs_reference.py + auto-generated tool catalog
- M4: net-new content pages (First Prompt, Multi-Instance, etc.)
- M5: slim root README to a landing card + governance files

See /Users/scriptwonder/.claude/plans/as-unity-mcp-coming-close-indexed-karp.md
for the full plan.
15 existing markdown files moved with git mv (history preserved), wired
into the Docusaurus sidebar across Guides, Architecture, Contributing,
and Migrations categories. Images that the migration docs reference
copied into website/static/img/ and refs rewritten to /img/...

Brand-neutral URL strategy holds: every slug omits "mcp-for-unity" /
"unity-mcp" — e.g. /guides/cli, /architecture/remote-auth,
/migrations/v8. A future rename touches docusaurus.config.js, not URLs.

Deferred to a follow-up:
- docs/development/README-DEV-zh.md (Chinese dev guide)
- docs/i18n/README-zh.md (Chinese overview)
  These need Docusaurus i18n config (defaultLocale + zh in locales) and
  a full translation pass before they make sense on the site.

Minor edits limited to making files build-clean (M2 plan: no content
rewrites):
- Front-matter added to cli-examples.md and cursor.md (no top-level H1)
- v8.md's [CUSTOM_TOOLS.md] link repointed at /guides/custom-tools
- dev-setup.md's broken language switcher repointed at GitHub source
- install.md's M2 forward-reference link now goes to /guides/client-configurators

Root README still points at docs/images/ for its hero gif — that path
keeps working because the images remain in docs/images/ for now and
will move only when README is slimmed in M5.
Introduces tools/generate_docs_reference.py — the single Python script
that emits every reference page under website/docs/reference/ from the
live @mcp_for_unity_tool and @mcp_for_unity_resource registries.

What lands:
- tools/generate_docs_reference.py: introspects function signatures
  (Annotated[Type, "description"]), preserves hand-authored examples
  between <!-- examples:start --><!-- examples:end --> markers, supports
  --write (default) and --check (CI drift detection) modes.
- tools/hooks/pre-commit: installed via tools/install-hooks.sh; when a
  staged change touches Server/src/services/{tools,resources,registry},
  regenerates the reference and re-stages it. Contributors don't have
  to remember.
- .github/workflows/docs-generate.yml: runs --check on every PR and on
  pushes to beta. Fails with a one-line fix command if the committed
  reference drifts from the registry. Also runs a count sanity check
  (#decorators must equal #generated md files).
- website/docs/reference/: 43 tool pages across 9 groups (animation,
  core, docs, probuilder, profiling, scripting_ext, testing, ui, vfx)
  + group landing pages + 25-resource catalog. Sidebar wired with
  Docusaurus's autogenerated mode so new tools appear automatically.
- README.md: "Available Tools" / "Available Resources" lists retired —
  these were drifting on every release. Replaced with a single link to
  the generated reference. (Root README slim is M5.)

Source of truth: Python. The C# attributes carry only Name/Group/
Description; the Python @decorator owns the richest typing via
Annotated[...], which is what MCP clients actually see over the wire.

Tested:
- generator runs clean (43 tools, 9 groups, 25 resources, deterministic)
- --check exits 0 against committed output
- pre-commit hook installs via existing tools/install-hooks.sh path
The repo was missing the standard governance files that a 10K-star
project typically has. Adding them now — they're entirely additive,
no removal of existing content. Full README slim is the rest of M5,
deferred until the live docs site can be previewed.

What lands:
- CONTRIBUTING.md: branch-off-beta workflow, dev quickstart, pre-commit
  hook reference, PR checklist, places that need help
- CODE_OF_CONDUCT.md: Contributor Covenant 2.1 with conduct@coplay.dev
  enforcement contact
- SECURITY.md: private reporting via security@coplay.dev, supported
  versions, what counts vs doesn't, fail-closed network defaults
- .github/ISSUE_TEMPLATE/bug_report.yml: structured bug form with
  Unity/package/client/transport/OS dropdowns
- .github/ISSUE_TEMPLATE/feature_request.yml: structured feature form
  with scope hint and contribution willingness
- .github/ISSUE_TEMPLATE/config.yml: routes Discord/docs/security/
  discussions away from the issue tracker, disables blank issues
Two M1 follow-ups uncovered by the first local `npm run build`:

1. MDX 3 was treating `{name: value}`, `{r, g, b, a}`, `<T>` and the
   multi-line JSON examples in tool descriptions as JS expressions /
   JSX tags. All 7 generated reference pages failed to compile.
   Fix: markdown.format = 'detect' — .md uses CommonMark (no expression
   parsing), .mdx keeps full MDX for future interactive components.

2. Visiting localhost:3000/unity-mcp/ landed on an empty docs index.
   Fix: getting-started/index.md slug '/getting-started' → '/'. Now
   the site root IS the Overview page; install stays at
   /getting-started/install/. Footer link updated to match.

Also nests onBrokenMarkdownLinks under markdown.hooks (the deprecated
top-level option is removed in Docusaurus v4).
Generated by the first successful `npm install` in /website/. Required
by `npm ci` in .github/workflows/docs-deploy.yml so the CI build pins
exact dependency versions and doesn't surprise us on a fresh tree.
Typography upgrade matching modern AI-product docs sites (e.g. benchflow):
- Satoshi (Fontshare, weights 300/400/500/700/900) for body and headings
- JetBrains Mono (Google Fonts, 400/500/700) for monospace
- Loaded via stylesheet links + preconnect hints in docusaurus.config.js
- custom.css updates: --ifm-font-family-base, --ifm-font-family-monospace,
  tighter heading letter-spacing, slightly bumped line-height for Satoshi,
  brand color shifted to indigo (#4f46e5) to pair with the new sans
- Inline code nudged 0.88em to sit on Satoshi's baseline

Emojis removed across all in-house content for a cleaner, professional
tone:
- generator banner: dropped the gear glyph
- generator parameter table: required column is now "yes" / "—" instead
  of an emoji checkbox (regenerated all 43 tool pages)
- install.md: status-text instead of green-dot emoji
- SECURITY.md: Yes / No instead of check/cross
- ISSUE_TEMPLATE/config.yml: plain link labels, no leading emoji

Verified:
- npm run build succeeds (5.7s client, 4.5s server)
- generator --check exits 0 (deterministic regeneration)
- HTML head includes both font stylesheets + preconnect hints
- CSS bundle resolves Satoshi and JetBrains Mono font-family stacks
9 hand-written pages flagged NEW in the locked IA. All wired into
sidebars.js and verified by `npm run build`.

Getting Started:
- first-prompt.md: end-to-end "build a red cube" walkthrough with the
  exact MCP tool chain the assistant should call, common failure modes,
  and escalating prompts that exercise other groups.
- clients.md: capability matrix across all 12 supported MCP clients
  (transport, auto-config, streaming, free tier, per-client toggles).

Guides:
- multi-instance.md: set_active_instance semantics — Name@hash, hash
  prefix, port shorthand; HTTP vs stdio isolation; per-call unity_instance
  routing for cross-project prompts.
- tool-groups.md: the 9 groups, how manage_tools(activate/deactivate/
  list_groups/sync/reset) works, why per-session visibility exists
  (prompt economy, routing clarity, package hygiene), server vs session
  state reconciliation.

Architecture:
- transports.md: HTTP vs stdio decision matrix, the architecture of each,
  what instance routing semantics each gives you, network security guards
  (loopback by default, LAN/remote opt-in).
- python-layers.md: the three Python surfaces (MCP tools, CLI commands,
  resources), why they're hand-maintained instead of auto-generated,
  domain symmetry rule.
- unity-compat.md: the four active shims, when to add a new shim, what
  doesn't belong in a shim, static-dispatch vs reflection patterns,
  link to the canonical UnityCompatShims.cs marker class.

Contributing:
- testing.md: Python pytest, Unity EditMode/PlayMode, multi-version
  compile matrix, pre-push/pre-commit hooks, stress scripts, CI surface.
- docs.md: hand-written vs auto-generated split, examples block
  preservation rule, slug discipline (brand-neutral), redirect protocol
  for slug renames, CommonMark vs MDX.

sidebars.js: uncommented the NEW entries; left reference/cli and
reference/manifest TODOs in place for a follow-up.

Verified:
- npm run build succeeds (Client 2.4s, Server 1.1s) with no errors
…yn (M5b)

Brings the root README in line with the live docs site. Everything
optional or reference-y now lives in docs; the README is the landing
card a 10K-star repo deserves.

What survives in README (118 lines, ~120 target):
- Logo + language selector
- Aura sponsorship (unchanged)
- Badges row, now with a Docs badge as first item
- Tagline + hero gif
- Big "Read the Docs" CTA after the gif (per discussion)
- One-liner install (git URL only — Asset Store/OpenUPM moved to docs)
- "Try it" example with one prompt + link to First Prompt walkthrough
- Collapsed Recent Updates (last 4 entries only)
- Community block (Discord/Issues/Discussions/SECURITY.md)
- Contributing pointer (CONTRIBUTING.md + dev-setup docs)
- Advanced block with links to Multi-Instance, Tool Groups, Roslyn,
  Remote Server Auth
- License, Star History, Citation, Aura Tools block, Disclaimer

What moved to docs:
- Prerequisites + Asset Store/OpenUPM install paths → /getting-started/install
- Setup wizard walkthrough → /getting-started/install
- Per-client gotchas → /getting-started/install + /getting-started/clients
- Manual Configuration JSON snippets → /getting-started/install
- Multiple Unity Instances → /guides/multi-instance
- Roslyn Script Validation → new /guides/roslyn page (NEW)
- Troubleshooting → /guides/cursor + GitHub Wiki link
- Telemetry + Security → SECURITY.md + /architecture/telemetry
- Full release history → new /releases page (NEW), seeded from the
  current Recent Updates section

Also: emoji removal pass on README (Godot AI line).

Verified:
- README is 118 lines (vs target ~120)
- npm run build succeeds
- All links resolve (no onBrokenLinks throws)
Scriptwonder and others added 25 commits May 24, 2026 18:11
…me-compilerservices-unsafe

fix(roslyn): install missing System.Runtime.CompilerServices.Unsafe v6 + surface inner errors
- docs-deploy.yml: actions/checkout with fetch-depth: 0 so Docusaurus's
  showLastUpdateTime / showLastUpdateAuthor resolves real per-file
  commit metadata. Shallow clones make every page report the latest
  build commit, which is useless to readers.
- website/static/robots.txt: allow-all crawlers + sitemap reference.
  Required by Algolia DocSearch's crawler when the application gets
  approved; harmless before then.
- /contributing/docs page: new sections covering first-time GitHub
  Pages enablement (Settings → Pages → Source: GitHub Actions) and
  the custom-domain CNAME path. Maintainers reading this would
  otherwise hit a 404 on first deploy and not know why.

Verified:
- npm run build succeeds (Server 935ms, Client 1.8s)
- sitemap.xml lists all 80+ URLs
- robots.txt copies to build/ correctly
…58441243

chore: update Unity package to beta version 9.7.1-beta.4
Replaces AI-skeleton content with the actual CoplayDev/unity-mcp.wiki
pages so the docs site has the real install/repair/troubleshooting
material people have been linking to.

Wiki pages absorbed:
- 1.-Fix-Unity-MCP-and-Cursor,-VSCode,-Windsurf,-Rider → new
  /guides/uv-setup page. Covers Python 3.12+ install, uv install on
  macOS/Linux/Windows, common uv locations, the MCP for Unity window's
  "Choose UV Install Location" + "Repair Python Env" buttons, where
  the server lives per OS, macOS PATH gotchas. Replaces the shallow
  /guides/cursor page (deleted) — the cursor-specific Windows uv path
  fix moved into the new troubleshooting FAQ.

- 2.-Fix-Unity-MCP-and-Claude-Code → new /guides/claude-code-cli page.
  Native installer + NVM + Homebrew Node paths, macOS PATH workaround.

- 3.-Common-Setup-Problems → new /guides/troubleshooting page. macOS
  dyld ICU error, WSL2-to-Windows bridging (@aollivier82 contribution
  with port-proxy + firewall + WSL host IP discovery), Unity AI
  Assistant DLL conflict (@rkroska report), Claude Code / VS Code /
  Cursor FAQs.

- Project-Roadmap (wiki) → new /architecture/project-roadmap page.
  Distinct from the existing /architecture/roadmap (2026 deep-research
  feature plan). This is the living high-level roadmap with Current
  Focus / Mid-Term / Long-Term / Icebox / Recently Completed sections
  the wiki maintains.

Sidebar reorganized: Guides now leads with the install/setup pages
(uv-setup, claude-code-cli, client-configurators), then capability
(multi-instance, tool-groups, cli, cli-examples), then advanced
(custom-tools, remote-server-auth, roslyn), then troubleshooting last.

Verified: npm run build clean. One broken-anchor fix landed for the
em-dash heading "FAQ — Claude Code" which slugifies to faq--claude-code
(double dash).
Custom React landing page replaces the markdown-doc-as-homepage.
Refined CSS for a calmer, more spacious feel. Navbar gets icon
links for GitHub/Discord and a Reference + Releases quick-jump.

What lands:

- src/pages/index.js + 3 components (HomeHero, HomeStats, HomeFeatures):
  hero with eyebrow, large headline, install one-liner, dual CTA;
  4-cell stats row (43 tools, 25 resources, 12+ clients, Unity 2021.3+
  through 6.x); 6-card feature grid linking to the most important
  docs (tools, multi-instance, transports, tool-groups, docs-workflow,
  custom-tools).

- getting-started/index.md slug moved from / to /getting-started so
  the custom landing can claim the root. Title harmonized with
  sidebar label ("Overview"); body H1 + intro updated to match.

- docusaurus.config.js navbar:
  - Added Reference and Releases as left items (quick access to the
    two most-trafficked pages)
  - GitHub + Discord text labels replaced with icon links via
    .header-icon-link CSS class + inline SVG backgrounds. Dark-mode
    invert via CSS variable.

- src/css/custom.css:
  - 16px base, 1.7 line-height, generous heading spacing
  - Tighter heading letter-spacing (-0.012 to -0.022em)
  - Subtle code-block borders, no garish shadow
  - Cleaner tables (rounded, single border, no internal grid)
  - Sidebar font 0.92rem, calmer hover/active states
  - Navbar: no shadow, subtle bottom border, tighter height
  - --ifm-toc-border-color set transparent for cleaner right rail
  - Dark mode background tuned to near-black

Verified: npm run build clean. Smoke test: / returns custom hero,
/getting-started returns the doc, /guides/uv-setup renders new
wiki content, /guides/cursor correctly 404s.
- HomeHero: building_scene.gif rendered below the install block in a
  bordered, rounded frame with a one-line caption. lazy-loaded, sized
  1200x675 to avoid layout shift. Asset copied from docs/images/ into
  website/static/img/ so the docs site is self-contained.
- /reference/cli: new page documenting the mcp-for-unity CLI —
  invocation (uvx and uv run), how it talks to Unity over HTTP,
  global flags table, command-group → MCP-tool mapping (29 groups
  cross-linked to their generated tool reference pages), Click
  --help discovery, source pointers.
- /reference/manifest: new page documenting manifest.json — its
  relationship to package.json (UPM) and pyproject.toml (PyPI),
  per-field reference (top-level, server, tools), MCPB bundle
  generation path.
- sidebars.js: uncommented both reference items.

Verified: build clean. Smoke test: / renders gif, /reference/cli +
/reference/manifest both 200, gif fetch returns 2.2 MB.
Second iteration after user feedback. GitHub + Discord icons are now
visually prominent without dominating the navbar. Search verified
working in the production build (1.6 MB lunr index, /search page
returns 200, queries for 'manage_material' and 'roslyn' both hit).
…uidance

docs: clarify development setup and package-source checks
Problem: website/docs/releases.md and the README's "Recent Updates"
block had drifted badly. README claimed v9.6.3 was the latest; the
actual latest is v9.7.0 (and there are 60 releases on record going
back to v4.0.0).

Solution:
- tools/sync_release_notes.py: pulls every non-draft release from the
  GitHub Releases API and renders both files. Uses `gh api` when
  available (handles auth + TLS cleanly), falls back to urllib +
  certifi when not. Supports --check for CI drift detection.

- README.md: gets a sentinel-bracketed `<!-- recent-updates:start -->
  ... <!-- recent-updates:end -->` block the script regenerates
  surgically — never touches the surrounding content. Latest 5
  releases with tag, date, link.

- website/docs/releases.md: full 60-release history, grouped by minor
  version, each release body inside a collapsible `<details>` block.
  Now shows the real v9.7.0 → v4.0.0 span.

- .github/workflows/sync-releases.yml: triggers the sync on every
  release event (published/edited/unpublished/deleted), daily at
  11:00 UTC (catches out-of-band edits), and on workflow_dispatch.
  Commits directly to beta with [skip ci]. PRs run --check only.

- /contributing/docs page: new "Release notes sync" section
  documenting the do-not-edit contract for releases.md and the
  recent-updates block, plus the manual sync commands.

Verified: sync ran end-to-end via `gh api`, renders 60 releases into
1304 lines of releases.md + 5 entries in the README block. npm run
build passes.
- docusaurus.config.js: count *.Configurator.cs files in
  MCPForUnity/Editor/Clients/Configurators/ at build time, expose
  via siteConfig.customFields.supportedClientCount. No hand-maintained
  constant to forget — the homepage stats row stays accurate forever.
  Current count: 21.

- HomeStats: reads the count via useDocusaurusContext. Replaces the
  "12+" hardcode with the real number.

- HomeHero tagline + README intro + Overview doc intro: replace
  "Claude, Claude Code, Cursor, VS Code, Windsurf" with the more
  representative "Claude, Codex, VS Code, local LLMs, and more" —
  reflects the actual client lineup that matters today.

Verified live: stats row reads "21 MCP clients supported"; hero
tagline reads "Claude, Codex, VS Code, local LLMs, and more".
Reworks the homepage and shared chrome into a "terminal meets blueprint"
aesthetic — mono microcopy as a deliberate signal, hairline borders,
dot-grid backdrop, no rounded blobs.

Landing components (new + reworked):
- HomeHero: status-pill eyebrow (live OPERATIONAL · v9.7.0 with a
  pulsing green dot), confident "Run the Unity Editor with your AI
  assistant." headline with an indigo marker-highlight on
  "AI assistant", terminal-style install block with STABLE + BETA
  channels and per-channel Copy buttons, refined demo frame
- HomeStats: spec-sheet treatment (// SPEC at a glance) with mono
  numbers and labels in a hairline grid. 21 clients (dynamic count)
- HomeArchitecture (NEW): three-stage flow MCP client → Python server
  → Unity Editor with mono edge labels (`stdio · HTTP /mcp`,
  `WebSocket · /hub/plugin`) and a filled-vs-outlined legend
- HomeFeatures: numbered index cards (01 CONTROL, 02 ROUTING, …) with
  hairline borders only and mono kicker labels
- HomeCloser (NEW): closing CTA strip + uncollapsed research citation
  block with full bibtex
- CopyButton (NEW): reusable clipboard component with check-feedback,
  used by the install block

Asset pipeline:
- building_scene.gif (2.1 MB) → MP4 (274 KB) + WebM (290 KB), wrapped
  in <video autoplay loop muted playsInline> with format fallback
- logo-mark.svg + logo-mark-dark.svg: minimal "bridge" mark (filled
  node → line → outlined node), tight 40×16 viewBox so it fills the
  navbar height crisply at any DPI
- social-card.png: regenerated 1200×630 (52 KB) via headless Chrome
  from a Satoshi/JetBrains-Mono HTML template — corner crosshairs,
  status pill, headline, spec line, URL

Navbar polish (docusaurus.config.js + custom.css):
- GitHub + Discord become icon-only links via mask-image +
  background-color: currentColor (no filter-blur artifacts, theme-
  aware). Reference + Releases promoted to left items
- Day/night toggle + GitHub + Discord all share 40×40 box and 0.2rem
  margin so the right cluster sits on an even rhythm
- Search bar absolute-positioned to the centre of the navbar with
  refined ⌘K kbd pill hints (system font for crisp ⌘ glyph, 22px
  tall, 2px bottom border for Linear/Vercel-style physicality, fades
  on focus)

Theme contrast hardening (custom.css):
- Pinned --ifm-heading-color (was 'inherit') and --ifm-background-color
  (was '#0000' — transparent — in light mode). Buttons and link colors
  that resolved through these vars were rendering invisible
- Architecture filled stages softened from solid heading-black to
  emphasis-200 cards with hairline borders
- Cmd+K hint kbds switched from JetBrains Mono (fuzzy ⌘ glyph) to
  system font, with refined Linear-style chrome
- dot-grid backdrop helper on the hero + closer sections

Footer: dropped the Asset Store link (lived in the More column),
kept GitHub + PyPI.
Hand-written examples on five high-traffic tool pages (preserved across
regeneration by the generator) and a proper nested Tools sidebar so
groups are collapsible categories instead of a flat list.

Examples (in <!-- examples:start --><!-- examples:end --> blocks):
- manage_gameobject: create primitives, modify (move + reparent),
  delete by tag, duplicate, multi-instance routing
- manage_scene: load, paged get_hierarchy, save, create from template,
  additive multi-scene editing
- manage_material: create, assign to renderer, set_material_shader_property,
  tint via MaterialPropertyBlock (mode: property_block) for batching
- manage_script: REWRITTEN to match the tool's actual surface
  (create / read / delete only). The previous draft conflated it with
  script_apply_edits / validate_script — those examples moved to:
- script_apply_edits: replace_method, insert_method (with position
  anchor), delete_method, anchor_insert (regex anchor), multi-op
  atomic transaction
- batch_execute: 9-op spawn-three-colored-cubes payload, parallel/
  fail_fast semantics, batch-size limits

Generator fixes (tools/generate_docs_reference.py):
- Examples-preservation regex now requires markers at line boundaries
  (re.MULTILINE + ^/$ anchors). Previously the generator's own warning
  banner referenced the literal `<!-- examples:start --><!-- examples:end -->`
  strings and the lazy regex matched THOSE first — capturing empty
  content and overwriting real examples with the placeholder
- --check mode now reads existing examples from the committed location
  (passes `examples_source=TOOLS_OUT`) instead of the empty tempdir,
  so CI drift detection no longer false-positives every run
- Emits `_category_.json` per group dir + a sidebar_class_name on the
  catalog index — Docusaurus then renders Tools → group → tool as a
  proper nested tree, with the duplicate catalog-as-child entry
  CSS-hidden via .sidebar-hidden

Sidebar (sidebars.js):
- Reference > Tools is now a single category, link points to the
  catalog index, items autogenerate from website/docs/reference/tools/
  using the new `_category_.json` metadata for nesting

Verified: build clean, generator --check exits 0, examples survive
end-to-end regeneration round-trip.
Flattens the <details>/<summary> wrapper into a top-level "## Citation"
section with a one-line lead, the venue (SA Technical Communications
'25, ACM) as a DOI link, and the bibtex below. Same intent as the
homepage's HomeCloser citation block — make the paper findable without
a click and signal that this is a research-grade project.

Also re-indents the bibtex for readability (column-aligned fields).
…e license

- Badge: shorten label from "Docs · coplaydev.github.io/unity-mcp" to
  just "Docs · unity-mcp". Cleaner badge row, link unchanged.
- "Read the Docs" section: drop the redundant
  "Getting Started · Tool Reference · Architecture · Contributing"
  one-liner under the link — visitors hit the docs site and see the
  full sidebar there.
- Citation: expand from one paragraph + bibtex to a structured block
  with paper info (venue, DOI, ISBN), an APA-format plain-text citation,
  and a cleaned-up BibTeX key (wu2025mcpunity). Lower friction for
  non-LaTeX users.
- License: moved from mid-document to the very bottom, after Disclaimer.
  Standard placement for license attribution.
Citation: trimmed to bibtex only — the paper info paragraph and APA
plain-text citation were nice-to-have but added vertical noise. The
bibtex carries enough metadata for both code search and academic use.

Hosting move (Scriptwonder fork preview):
- docusaurus.config.js: url + organizationName flipped to Scriptwonder
- docs-deploy.yml: deploy on push to `docs/v2-wiki-refresh` OR `beta`
  (Setup Pages, Upload artifact, Deploy job conditions all updated).
  Lets the live preview at scriptwonder.github.io/unity-mcp update as
  we iterate, without waiting for an upstream maintainer to enable
  Pages on CoplayDev/unity-mcp.
- Hardcoded URLs in README.md, website/README.md, website/static/
  robots.txt swapped from coplaydev.github.io/unity-mcp to
  scriptwonder.github.io/unity-mcp via a one-shot sed.
- docs.md + website/README.md retain a one-line note about flipping
  back to coplaydev once upstream Pages is enabled.

After push, to make the preview actually serve:
- Settings → Pages → Source → "GitHub Actions"
  on https://github.com/Scriptwonder/unity-mcp/settings/pages
The deploy job in the next push will then provision Pages on first run.
Pages is now enabled on CoplayDev/unity-mcp, so the canonical preview
URL is back to https://coplaydev.github.io/unity-mcp/.

- docusaurus.config.js: url + organizationName back to CoplayDev
- docs-deploy.yml: deploy condition narrowed back to push-to-beta only
  (drops the temporary docs/v2-wiki-refresh trigger)
- README.md, website/README.md, website/static/robots.txt,
  website/docs/contributing/docs.md: hardcoded scriptwonder URLs swept
  back to coplaydev, and the temporary "Scriptwonder fork preview" /
  "flips back to coplaydev" prose removed

Next deploy of the live site happens when this lands on upstream/beta
(via PR merge) and triggers the existing workflow.
CodeRabbit + Copilot review fixes that don't touch the generated tool
reference. Generator change + regenerated pages come in a follow-up
commit.

docs:
- guides/uv-setup.md: Python requirement was wrongly 3.12+; the server
  pyproject declares >=3.10. Verify command + body updated to 3.10+.
  Homebrew tip retains 3.12 as a reasonable default.
- getting-started/index.md: drop "(coming soon)" placeholders for
  Your First Prompt and Choosing an MCP Client — both pages exist
  in this PR. Setup Wizard remains "coming soon" (not in this PR).
- .github/ISSUE_TEMPLATE/bug_report.yml: troubleshooting link pointed
  at /guides/cursor (deleted earlier in this branch); now points at
  /guides/troubleshooting which is where that content lives.

components:
- CopyButton: track setTimeout in a useRef, clear it on unmount and
  before scheduling a new one. Prevents React "setState on unmounted
  component" warnings and stops timer-stacking on rapid clicks.
- HomeArchitecture diagram <div>: now role="img" with a descriptive
  aria-label that explains the layer flow, so assistive tech actually
  announces the diagram instead of skipping it.

workflows (security):
- docs-deploy.yml, docs-generate.yml: add `persist-credentials: false`
  on actions/checkout — these jobs never push, so the token shouldn't
  linger in the checked-out worktree (zizmor `artipacked` warning).
- sync-releases.yml:
  - Workflow-level permissions narrowed to `contents: read`; the
    `sync` job opts into `contents: write` itself. `drift-check`
    stays read-only.
  - drift-check job: was gated on `pull_request` but the workflow had
    no pull_request trigger — unreachable code. Added a paths-scoped
    pull_request trigger so PRs touching the sync script or the synced
    docs run the check.
  - `sync` job retains `persist-credentials: true` (it pushes back).
  - drift-check checkout gets `persist-credentials: false`.

CodeRabbit comments NOT addressed in this PR and why:
- execute_menu_item 'exists' mode, script_apply_edits malformed JSON,
  find_gameobjects empty param descriptions: all live in the Python
  tool's source description string under Server/src/services/tools/.
  Fixing upstream is a separate code PR; the generator faithfully
  renders whatever source provides.
- React 18.3.1 / Docusaurus 3.10.1 bump: out of scope for this docs
  PR; the lockfile already permits the latest 18.x, and a Docusaurus
  minor bump is a separate dependency PR.
- robots.txt sitemap 404 check: will resolve as soon as Pages serves
  the site on the canonical URL. Not a real bug.
- sidebars.js duplicate roadmap: /architecture/roadmap is the 2026
  feature deep-research; /architecture/project-roadmap is the wiki
  living roadmap. Two distinct docs, intentional.
- scripting_ext group blurb: comes from the registry TOOL_GROUPS map;
  wording tweak not worth touching in a docs PR.
PR #1157 review (Copilot + CodeRabbit) flagged that several tool pages
had truncated frontmatter, e.g. manage_asset rendering as:
  description: "Performs asset operations (import, create, modify, delete, etc"

Root cause: the generator used `description.split(".")[0]` to derive the
frontmatter blurb. That cuts at the FIRST period — including periods
inside abbreviations and parenthesized lists ("etc.) in Unity."), so
the rendered description stopped mid-clause.

Fix: introduce `_first_sentence()` that splits on real sentence
boundaries — `.` / `!` / `?` followed by whitespace + capital, or a
paragraph break — and falls back to the whole string if no boundary
exists. Also caps absurdly long single-sentence descriptions at ~240
chars to keep frontmatter compact.

All three call sites that used the old split:
- frontmatter `description:` in render_tool_page
- group-index bullets in render_group_index
- catalog-index bullets in render_catalog_index

Regenerated all 43 tool pages + 9 group landings + catalog index +
resources catalog. Verified `--check` passes round-trip and full
website build is clean.

manage_asset now reads: "Performs asset operations (import, create,
modify, delete, etc.) in Unity."
PR #1157 review surfaced that the drift-check job was failing on
outsider PRs that touched README.md for unrelated reasons (citation
tweaks, link fixes). The path filter caught any README edit even when
the recent-updates block wasn't touched, and the failure couldn't be
fixed by the PR author since they didn't have push access to commit
a regen.

Real-world reasoning: release notes can only legitimately go stale
when a release event occurs. PRs cannot introduce drift the workflow
needs to "catch" — and a drift-check that an outsider can't fix is
hostile to contributions.

Changes:
- Drop the `pull_request` trigger entirely (was only there to feed the
  now-removed drift-check job).
- Drop the daily `schedule` cron. UI edits to release bodies are
  caught by the `release.edited` event already; falling back to a
  cron added mystery commits unattached to a release.
- Drop the `drift-check` job. Nothing left needs to gate on PRs.
- Keep `release.{published,edited,unpublished,deleted}` as the
  canonical trigger, and `workflow_dispatch` as the manual hatch.
- Updated /contributing/docs page to match, with an explicit
  paragraph on why PRs are NOT a trigger here.
@github-actions github-actions Bot merged commit 78ee541 into main May 24, 2026
@github-actions github-actions Bot deleted the release/v9.7.1 branch May 24, 2026 19:37
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.

4 participants