diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..33cbf6d49 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,122 @@ +name: Bug report +description: Something isn't working as expected +title: "[Bug]: " +labels: ["bug", "needs-triage"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to file a bug. The more specific you can be, the faster we can help. + + **Before filing:** + - Search [existing issues](https://github.com/CoplayDev/unity-mcp/issues?q=is%3Aissue) to avoid duplicates + - Check the [troubleshooting docs](https://coplaydev.github.io/unity-mcp/guides/troubleshooting) and [setup wiki](https://github.com/CoplayDev/unity-mcp/wiki) + + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Clear, concrete description. What did you expect? What did you get? + placeholder: When I run X, I expect Y, but I see Z. + validations: + required: true + + - type: textarea + id: reproduce + attributes: + label: Reproduction steps + description: Numbered steps. Include the exact prompt or command if relevant. + placeholder: | + 1. Open Window > MCP for Unity + 2. Click Start Server + 3. In Claude Desktop, prompt: "create a red cube" + 4. Observe error in console: ... + validations: + required: true + + - type: input + id: unity-version + attributes: + label: Unity version + placeholder: "6000.0.34f1, 2022.3.42f1, etc." + validations: + required: true + + - type: input + id: package-version + attributes: + label: MCP for Unity package version + description: Found under Window > Package Manager → MCP for Unity. + placeholder: "9.6.3" + validations: + required: true + + - type: input + id: server-version + attributes: + label: Python server version + description: Run `uv pip show mcpforunityserver` or check the bundled wheel. + placeholder: "9.6.3" + validations: + required: false + + - type: dropdown + id: client + attributes: + label: MCP client + options: + - Claude Desktop + - Claude Code + - Cursor + - VS Code (Copilot) + - Windsurf + - Cline + - GitHub Copilot CLI + - Codex + - Qwen Code + - Gemini CLI + - OpenClaw + - Other (specify in description) + validations: + required: true + + - type: dropdown + id: transport + attributes: + label: Transport + options: + - HTTP (default) + - stdio + - Don't know + validations: + required: true + + - type: dropdown + id: os + attributes: + label: OS + options: + - macOS + - Windows + - Linux + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Relevant logs / console output + description: Editor console, MCP for Unity log, client log. Strip secrets. + render: text + validations: + required: false + + - type: checkboxes + id: terms + attributes: + label: Checks + options: + - label: I searched existing issues and did not find a duplicate + required: true + - label: I included logs / steps to reproduce + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..95bbcb217 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,14 @@ +blank_issues_enabled: false +contact_links: + - name: Discord — chat with maintainers + url: https://discord.gg/y4p8KfzrN4 + about: Best for quick questions, troubleshooting, and design discussion. + - name: Documentation + url: https://coplaydev.github.io/unity-mcp/ + about: Getting Started, guides, tool reference, and architecture notes. + - name: Security vulnerability + url: https://github.com/CoplayDev/unity-mcp/security/advisories/new + about: Report privately via GitHub Security Advisories or email security@coplay.dev. Do NOT open a public issue. + - name: Discussion / design idea + url: https://github.com/CoplayDev/unity-mcp/discussions + about: Broad questions, design conversations, show-and-tell. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..630fada6d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,63 @@ +name: Feature request +description: Suggest a new tool, capability, or quality-of-life improvement +title: "[Feature]: " +labels: ["enhancement", "needs-triage"] +body: + - type: markdown + attributes: + value: | + Got an idea? Great. The more concrete you can be about *who* this helps and *what* they're trying to do, the easier it is to scope. + + For tool requests: please name the Unity API/system you'd be wrapping and what your MCP client would actually say. + + - type: textarea + id: problem + attributes: + label: What problem are you trying to solve? + description: Frame the user need first, not the implementation. + placeholder: | + When I'm prototyping with the LLM, I can't get it to build a NavMesh because there's no MCP tool for the AI navigation system. I have to flip back to the Editor manually. + validations: + required: true + + - type: textarea + id: proposal + attributes: + label: What would you like to see? + description: Be specific. New tool? New action on an existing tool? New resource? Workflow change? + placeholder: | + A new `manage_navigation` tool with actions: bake, clear, set_agent_radius, query_nearest_edge, ... + validations: + required: true + + - type: textarea + id: prior-art + attributes: + label: Prior art / how do you work around this today? + placeholder: I currently bake manually via Window > AI > Navigation, then ask the LLM to reason about it. + validations: + required: false + + - type: dropdown + id: scope + attributes: + label: Scope hint + options: + - New tool (substantial) + - New action on an existing tool + - New resource + - UX / editor window + - CLI improvement + - Documentation + - Other + validations: + required: true + + - type: checkboxes + id: contribute + attributes: + label: Would you be willing to help build this? + options: + - label: I can open a PR if a maintainer sketches the approach + - label: I can help test + - label: I can write the docs diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml new file mode 100644 index 000000000..2ee53f24f --- /dev/null +++ b/.github/workflows/docs-deploy.yml @@ -0,0 +1,92 @@ +name: Docs — Build & Deploy + +# Builds the Docusaurus site under /website and, on push to beta, deploys +# to GitHub Pages at https://coplaydev.github.io/unity-mcp/. +# +# PR runs only build (no deploy) as a preview-validation step. +# Re-deploys also fire when the Python tool/resource registry changes, +# so M3's auto-generated reference pages stay fresh. + +on: + push: + branches: [beta] + paths: + - website/** + - docs/** + - Server/src/services/tools/** + - Server/src/services/resources/** + - Server/src/services/registry/** + - .github/workflows/docs-deploy.yml + pull_request: + branches: [beta, main] + paths: + - website/** + - docs/** + - Server/src/services/tools/** + - Server/src/services/resources/** + - Server/src/services/registry/** + - .github/workflows/docs-deploy.yml + workflow_dispatch: {} + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + name: Build site + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Full history so Docusaurus's showLastUpdateTime / showLastUpdateAuthor + # can resolve real per-file commit metadata. Shallow clones make every + # page report the latest commit instead. + fetch-depth: 0 + # No push back from this workflow — the deploy uses the Pages + # OIDC token issued by actions/deploy-pages, not the repo token. + persist-credentials: false + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: website/package-lock.json + + - name: Install dependencies + working-directory: website + run: npm ci + + - name: Setup Pages + if: github.event_name == 'push' && github.ref == 'refs/heads/beta' + uses: actions/configure-pages@v5 + + - name: Build + working-directory: website + run: npm run build + + - name: Upload Pages artifact + if: github.event_name == 'push' && github.ref == 'refs/heads/beta' + uses: actions/upload-pages-artifact@v3 + with: + path: website/build + + deploy: + name: Deploy to GitHub Pages + needs: build + if: github.event_name == 'push' && github.ref == 'refs/heads/beta' + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/docs-generate.yml b/.github/workflows/docs-generate.yml new file mode 100644 index 000000000..5db34efb1 --- /dev/null +++ b/.github/workflows/docs-generate.yml @@ -0,0 +1,72 @@ +name: Docs — Reference Drift Check + +# Fails a PR if the committed /website/docs/reference/ output disagrees +# with what tools/generate_docs_reference.py would produce from the live +# Python tool/resource registry. Contributors should regenerate locally: +# +# cd Server && uv run python ../tools/generate_docs_reference.py +# +# or install the pre-commit hook to make this automatic: +# +# tools/install-hooks.sh + +on: + pull_request: + branches: [beta, main] + paths: + - Server/src/services/tools/** + - Server/src/services/resources/** + - Server/src/services/registry/** + - website/docs/reference/** + - tools/generate_docs_reference.py + - .github/workflows/docs-generate.yml + push: + branches: [beta] + paths: + - Server/src/services/tools/** + - Server/src/services/resources/** + - Server/src/services/registry/** + - website/docs/reference/** + - tools/generate_docs_reference.py + - .github/workflows/docs-generate.yml + workflow_dispatch: {} + +jobs: + check: + name: Check docs reference is fresh + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + version: latest + + - name: Set up Python + run: uv python install 3.10 + + - name: Sync Server deps + working-directory: Server + run: uv sync + + - name: Drift check + working-directory: Server + run: uv run python ../tools/generate_docs_reference.py --check + + - name: Tool-count sanity + run: | + set -euo pipefail + # Match the decorator at start-of-line (skips imports and docstring mentions). + decorator_count=$(grep -rhE "^@mcp_for_unity_tool\(" Server/src/services/tools/ | wc -l | tr -d ' ') + # md_count excludes group landing pages (index.md) and the catalog root. + md_count=$(find website/docs/reference/tools -name '*.md' -not -name 'index.md' | wc -l | tr -d ' ') + echo "decorator_count=$decorator_count, md_count=$md_count" + if [[ "$decorator_count" != "$md_count" ]]; then + echo "Mismatch: $decorator_count @mcp_for_unity_tool decorators vs $md_count reference pages." >&2 + echo "Run: cd Server && uv run python ../tools/generate_docs_reference.py" >&2 + exit 1 + fi diff --git a/.github/workflows/sync-releases.yml b/.github/workflows/sync-releases.yml new file mode 100644 index 000000000..8892af0b0 --- /dev/null +++ b/.github/workflows/sync-releases.yml @@ -0,0 +1,78 @@ +name: Docs — Sync Release Notes + +# Keeps website/docs/releases.md and the README's "Recent Updates" block +# in sync with the GitHub Releases API. Source of truth is GitHub Releases. +# +# Triggers (intentionally narrow): +# - release.published / edited / unpublished / deleted: the only time +# the synced files can legitimately go stale. Fires on every release +# event so the docs reflect the new version within ~30 seconds. +# - workflow_dispatch: manual escape hatch (re-run after a one-off +# GitHub UI edit to a release body, or to backfill after a downtime). +# +# Why no pull_request / schedule triggers: +# - PR-time drift-check would fail outsider PRs that touched README for +# unrelated reasons (e.g. typo fixes) and the contributor has no push +# access to fix it. The synced files are maintained by the release +# pipeline, not by PR authors — drift can't logically be introduced +# by a PR that the workflow couldn't already handle on release. +# - A daily cron would mask the source-of-truth (release events) and +# produce mystery commits unattached to a release. Better to let +# workflow_dispatch handle the rare out-of-band UI edit. +# +# Behavior: +# - Commits directly to `beta` with [skip ci] in the message — the +# change is mechanical (re-render from API output), pre-validated, +# and confined to two well-known files. + +on: + release: + types: [published, edited, unpublished, deleted] + workflow_dispatch: {} + +permissions: + contents: read + +concurrency: + group: docs-sync-releases + cancel-in-progress: false + +jobs: + sync: + name: Sync release notes + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout beta + uses: actions/checkout@v4 + with: + ref: beta + # Full history so the commit lands on a fresh ref tip. + fetch-depth: 0 + # `sync` needs to push back, so the token must persist here. + persist-credentials: true + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Sync release notes + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: python tools/sync_release_notes.py + + - name: Commit & push (if anything changed) + run: | + set -euo pipefail + if git diff --quiet -- website/docs/releases.md README.md; then + echo "No drift — release notes already up to date." + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add website/docs/releases.md README.md + git commit -m "docs: sync release notes from GitHub Releases [skip ci]" + git push origin beta diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9973d78aa --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,75 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in MCP for Unity a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes +- Focusing on what is best for the community as a whole + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information (physical or email address) without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Project maintainers are responsible for clarifying and enforcing these standards and will take appropriate and fair corrective action in response to any behavior they deem inappropriate, threatening, offensive, or harmful. + +Maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned with this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces — GitHub repository, Discord, official communications channels — and also when an individual is officially representing the community in public spaces. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the maintainers at **conduct@coplay.dev**. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Project maintainers will follow these guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact:** Use of inappropriate language or other behavior deemed unprofessional or unwelcome. + +**Consequence:** A private, written warning, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact:** A violation through a single incident or series of actions. + +**Consequence:** A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. + +### 3. Temporary Ban + +**Community Impact:** A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence:** A temporary ban from any sort of interaction or public communication with the community for a specified period of time. + +### 4. Permanent Ban + +**Community Impact:** Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence:** A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. + +[homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..6896c5cb3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,71 @@ +# Contributing to MCP for Unity + +Thanks for wanting to help! MCP for Unity is community-maintained and PRs of any size are welcome — bug fixes, new tools, docs improvements, tests. + +## Quick Start + +1. **Fork** this repo and **clone** your fork. +2. Branch off `beta` (not `main`): + ```bash + git checkout -b feat/your-idea upstream/beta + ``` +3. Install the dev environment (see [Dev Setup](https://coplaydev.github.io/unity-mcp/contributing/dev-setup)). +4. Make your change with tests. +5. Open a PR against `beta`. PRs against `main` will be redirected. + +## What We Look For + +- **Tests for new behavior.** Python tests live in `Server/tests/`; Unity EditMode tests live in `TestProjects/UnityMCPTests/Assets/Tests/`. +- **Domain symmetry.** New tools live in *both* `Server/src/services/tools/manage_.py` (Python MCP tool) and `MCPForUnity/Editor/Tools/Manage.cs` (C# implementation). See [Adding a New Tool](https://coplaydev.github.io/unity-mcp/contributing/dev-setup). +- **Minimal abstraction.** Three similar lines of code is better than a helper that's only used once. +- **Documentation as code.** Tool reference pages under `website/docs/reference/` are auto-generated — never hand-edit them outside the `` blocks. + +## Before You Push + +```bash +# Python tests +cd Server && uv run pytest tests/ -v + +# Unity multi-version compile check (matches CI) +tools/check-unity-versions.sh + +# Pre-commit hook for docs reference (one-time setup) +tools/install-hooks.sh +``` + +The pre-commit hook regenerates `website/docs/reference/` whenever you touch a tool/resource module — saves you a CI round trip. + +## Pull Request Checklist + +- [ ] Branched off `beta` +- [ ] New or updated tests +- [ ] Docs updated (the auto-gen handles the tool reference; narrative docs under `website/docs/` are hand-written) +- [ ] No commented-out code, no `// removed for X` markers, no `_unused` renames +- [ ] PR description explains the **why**, not just the **what** + +## Code Style + +- **Python:** type hints required; follow the patterns in existing `manage_*.py` files. +- **C#:** match existing namespace conventions under `MCPForUnity.Editor.*`; route Unity API differences through `MCPForUnity/Runtime/Helpers/Unity*Compat.cs` shims rather than `#if UNITY_*_OR_NEWER` blocks. +- **Markdown:** wrap at sensible widths; use sentence case in headings. + +## Areas That Need Help + +- Examples in tool reference pages (`website/docs/reference/tools/**/*.md` — add inside the `` blocks). +- Net-new guide content (multi-instance routing, tool groups, transport modes). +- Translations beyond Chinese. +- Cross-platform shell testing for the CLI. + +## Reporting Bugs / Requesting Features + +Use the issue templates under [`.github/ISSUE_TEMPLATE/`](.github/ISSUE_TEMPLATE/). For security concerns, see [SECURITY.md](SECURITY.md) — do **not** open a public issue. + +## Code of Conduct + +See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). Be excellent to each other. + +## Questions? + +- [GitHub Issues](https://github.com/CoplayDev/unity-mcp/issues) — bugs, features +- [Discord](https://discord.gg/y4p8KfzrN4) — chat with maintainers and other contributors +- [Discussions](https://github.com/CoplayDev/unity-mcp/discussions) — design ideas, broad questions diff --git a/README.md b/README.md index 5b2b72afb..28cc954b3 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,10 @@ | [English](README.md) | [简体中文](docs/i18n/README-zh.md) | |----------------------|---------------------------------| -#### Proudly sponsored and maintained by [Aura](https://www.tryaura.dev/) -- the AI assistant for Unreal & Unity. -##### And don't miss [Godot A](https://github.com/hi-godot/godot-ai)I 🤖, the new open source MCP/AI project from the makers of MCP for Unity! +#### Proudly sponsored and maintained by [Aura](https://www.tryaura.dev/) — the AI assistant for Unreal & Unity. +##### And don't miss [Godot AI](https://github.com/hi-godot/godot-ai), the new open source MCP/AI project from the makers of MCP for Unity. +[![Docs](https://img.shields.io/badge/Docs-unity--mcp-4f46e5)](https://coplaydev.github.io/unity-mcp/) [![Discord](https://img.shields.io/badge/discord-join-red.svg?logo=discord&logoColor=white)](https://discord.gg/y4p8KfzrN4) [![](https://img.shields.io/badge/Website-Visit-purple)](https://www.coplay.dev/?ref=unity-mcp) [![](https://img.shields.io/badge/Unity-000000?style=flat&logo=unity&logoColor=blue 'Unity')](https://unity.com/releases/editor/archive) @@ -13,277 +14,103 @@ [![](https://badge.mcpx.dev?status=on 'MCP Enabled')](https://modelcontextprotocol.io/introduction) [![](https://img.shields.io/badge/License-MIT-red.svg 'MIT License')](https://opensource.org/licenses/MIT) -**Create your Unity apps with LLMs!** MCP for Unity bridges AI assistants (Claude, Claude Code, Cursor, VS Code, etc.) with your Unity Editor via the [Model Context Protocol](https://modelcontextprotocol.io/introduction). Give your LLM the tools to manage assets, control scenes, edit scripts, and automate tasks. +**Create your Unity apps with LLMs.** MCP for Unity bridges AI assistants — Claude, Codex, VS Code, local LLMs, and more — with your Unity Editor via the [Model Context Protocol](https://modelcontextprotocol.io/introduction). Give your LLM the tools to manage assets, control scenes, edit scripts, run tests, and automate workflows. MCP for Unity building a scene -
-Recent Updates - -* **v9.6.3 (beta)** — New `manage_profiler` tool (14 actions): Profiler session control (start/stop/status/set areas), frame timing and counter reads, object memory queries, memory snapshots (take/list/compare via com.unity.memoryprofiler), and Frame Debugger (enable/disable/get events). Group: `profiling`. -* **v9.6.2** — New `manage_physics` tool (21 actions): physics settings, layer collision matrix, physics materials, joints (5 3D + 9 2D types), queries (raycast, raycast_all, linecast, shapecast, overlap), force application (AddForce/AddTorque/AddExplosionForce), rigidbody configuration, scene-wide validation, and edit-mode simulation. Full 3D and 2D support. -* **v9.6.1** — QoL extensions: `manage_editor` gains undo/redo actions. `manage_scene` gains multi-scene editing (additive load, close, set active, move GO between scenes), scene templates (3d_basic, 2d_basic, etc.), and scene validation with auto-repair. New `manage_build` tool: trigger player builds, switch platforms, configure player settings, manage build scenes and profiles (Unity 6+), run batch builds across multiple platforms, and async job tracking with polling. New `MaxPollSeconds` infrastructure for long-running tool operations. -* **v9.5.4** — New `unity_reflect` and `unity_docs` tools for API verification: inspect live C# APIs via reflection and fetch official Unity documentation (ScriptReference, Manual, package docs). New `manage_packages` tool: install, remove, search, and manage Unity packages and scoped registries. Includes input validation, dependency checks on removal, and git URL warnings. -* **v9.5.3** — New `manage_graphics` tool (33 actions): volume/post-processing, light baking, rendering stats, pipeline settings, URP renderer features. 3 new resources: `volumes`, `rendering_stats`, `renderer_features`. -* **v9.5.2** — New `manage_camera` tool with Cinemachine support (presets, priority, noise, blending, extensions), `cameras` resource, priority persistence fix via SerializedProperty. - -
-Older releases - -* **v9.4.8** — New editor UI, real-time tool toggling via `manage_tools`, skill sync window, multi-view screenshot, one-click Roslyn installer, Qwen Code & Gemini CLI clients, ProBuilder mesh editing via `manage_probuilder`. -* **v9.4.7** — Per-call Unity instance routing, macOS pyenv PATH fix, domain reload resilience for script tools. -* **v9.4.6** — New `manage_animation` tool, Cline client support, stale connection detection, tool state persistence across reloads. -* **v9.4.4** — Configurable `batch_execute` limits, tool filtering by session state, IPv6/IPv4 loopback fixes. - -
-
- --- -## Quick Start +## Read the Docs -### Prerequisites +### **→ [coplaydev.github.io/unity-mcp](https://coplaydev.github.io/unity-mcp/)** -* **Unity 2021.3 LTS+** — [Download Unity](https://unity.com/download) -* **Python 3.10+** and **uv** — [Install uv](https://docs.astral.sh/uv/getting-started/installation/) -* **An MCP Client** — [Claude Desktop](https://claude.ai/download) | [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | [Cursor](https://www.cursor.com/en/downloads) | [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview) | [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli) | [OpenClaw](https://openclaw.ai) - -### 1. Install the Unity Package +--- -In Unity: `Window > Package Manager > + > Add package from git URL...` +## Install -> [!TIP] -> ```text -> https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main -> ``` +In Unity: **Window → Package Manager → + → Add package from git URL**, paste: -**Want the latest beta?** Use the beta branch: ```text -https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#beta -``` - -
-Other install options (Asset Store, OpenUPM) - -**Unity Asset Store:** -1. Visit [MCP for Unity on the Asset Store](https://assetstore.unity.com/packages/tools/generative-ai/mcp-for-unity-ai-driven-development-329908) -2. Click `Add to My Assets`, then import via `Window > Package Manager` - -**OpenUPM:** -```bash -openupm add com.coplaydev.unity-mcp +https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main ``` -
- -### 2. Start the Server & Connect - -**First-run wizard (recommended):** After import, MCP for Unity opens a setup window automatically. -1. Confirm Python and uv are installed — the window guides you through both if missing. -2. Click **Done**. Once dependencies are green, you'll see a list of MCP clients detected on your machine. -3. Pick the clients you want to configure and click **Configure Selected**. Done. -**Manually (anytime):** `Window > MCP for Unity` opens the main panel. -- Click **Start Server** if it's not already running (launches HTTP server on `localhost:8080`). -- In the **Clients** tab, click **Configure All Detected Clients** to set up every client found on your machine in one shot, or pick a single client from the dropdown and click **Configure**. -- Look for 🟢 "Connected ✓". +Beta channel uses `#beta`. Asset Store and OpenUPM paths are documented in the [Install guide](https://coplaydev.github.io/unity-mcp/getting-started/install). -**Per-client gotchas:** Some clients (Cursor, Antigravity 2.0, Antigravity IDE, OpenClaw) still require enabling an MCP toggle or plugin in their own settings. The two Antigravity clients are listed separately because Antigravity 2.0 migrated its MCP config into `~/.gemini/config/` while Antigravity IDE still uses `~/.gemini/antigravity-ide/`; if you run both, configure each one. OpenClaw also needs the `openclaw-mcp-bridge` plugin enabled and follows the currently selected MCP for Unity transport (`HTTP` or `stdio`). Claude Desktop only supports stdio — MCP for Unity will silently configure it that way even if you've selected HTTP elsewhere. Claude Code, VS Code, Windsurf, Cline, and the various CLI clients auto-connect after configuration. +Then **Window → MCP for Unity → Configure All Detected Clients**. That's it — try a prompt: -**Updates handle themselves.** When you update the package, MCP for Unity rewrites the configs of every detected client on the next Editor open — no need to repeat the Configure step. +> Create a red, blue, and yellow cube in the current scene. -**That's it!** Try a prompt like: *"Create a red, blue and yellow cube"* or *"Build a simple player controller"* +Full walkthrough: [Your First Prompt](https://coplaydev.github.io/unity-mcp/getting-started/first-prompt). --- +
-Features & Tools - -### Key Features -* **Natural Language Control** — Instruct your LLM to perform Unity tasks -* **Powerful Tools** — Manage assets, scenes, materials, scripts, and editor functions -* **Automation** — Automate repetitive Unity workflows -* **Extensible** — Works with various MCP Clients - -### Available Tools -`apply_text_edits` • `batch_execute` • `create_script` • `debug_request_context` • `delete_script` • `execute_custom_tool` • `execute_menu_item` • `find_gameobjects` • `find_in_file` • `get_sha` • `get_test_job` • `manage_animation` • `manage_asset` • `manage_build` • `manage_camera` • `manage_components` • `manage_editor` • `manage_gameobject` • `manage_graphics` • `manage_material` • `manage_packages` • `manage_physics` • `manage_prefabs` • `manage_probuilder` • `manage_profiler` • `manage_scene` • `manage_script` • `manage_script_capabilities` • `manage_scriptable_object` • `manage_shader` • `manage_texture` • `manage_tools` • `manage_ui` • `manage_vfx` • `read_console` • `refresh_unity` • `run_tests` • `script_apply_edits` • `set_active_instance` • `unity_docs` • `unity_reflect` • `validate_script` - -### Available Resources -`cameras` • `custom_tools` • `renderer_features` • `rendering_stats` • `volumes` • `editor_active_tool` • `editor_prefab_stage` • `editor_selection` • `editor_state` • `editor_windows` • `gameobject` • `gameobject_api` • `gameobject_component` • `gameobject_components` • `get_tests` • `get_tests_for_mode` • `menu_items` • `prefab_api` • `prefab_hierarchy` • `prefab_info` • `project_info` • `project_layers` • `project_tags` • `tool_groups` • `unity_instances` - -**Performance Tip:** Use `batch_execute` for multiple operations — it's 10-100x faster than individual calls! -
- -
-Manual Configuration - -If auto-setup doesn't work, add this to your MCP client's config file: - -**HTTP (default — works with Cursor, Windsurf, Antigravity 2.0, Antigravity IDE, VS Code, Cline; Claude Desktop is stdio-only, see below):** -```json -{ - "mcpServers": { - "unityMCP": { - "url": "http://localhost:8080/mcp" - } - } -} -``` - -**VS Code:** -```json -{ - "servers": { - "unityMCP": { - "type": "http", - "url": "http://localhost:8080/mcp" - } - } -} -``` - -
-Stdio configuration (uvx) - -**macOS/Linux:** -```json -{ - "mcpServers": { - "unityMCP": { - "command": "uvx", - "args": ["--from", "mcpforunityserver", "mcp-for-unity", "--transport", "stdio"] - } - } -} -``` - -**Windows:** -```json -{ - "mcpServers": { - "unityMCP": { - "command": "C:/Users/YOUR_USERNAME/AppData/Local/Microsoft/WinGet/Links/uvx.exe", - "args": ["--from", "mcpforunityserver", "mcp-for-unity", "--transport", "stdio"] - } - } -} -``` -
-
- -
-Multiple Unity Instances - -MCP for Unity supports multiple Unity Editor instances. To target a specific one: - -1. Ask your LLM to check the `unity_instances` resource -2. Use `set_active_instance` with the `Name@hash` (e.g., `MyProject@abc123`) -3. All subsequent tools route to that instance -
- -
-Roslyn Script Validation (Advanced) - -For **Strict** validation that catches undefined namespaces, types, and methods: - -1. Install [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity) -2. `Window > NuGet Package Manager` → Install `Microsoft.CodeAnalysis` v5.0 -3. Also install `SQLitePCLRaw.core` and `SQLitePCLRaw.bundle_e_sqlite3` v3.0.2 -4. Add `USE_ROSLYN` to `Player Settings > Scripting Define Symbols` -5. Restart Unity - -
- One-click installer (recommended) - - Open `Window > MCP for Unity`, scroll to the **Runtime Code Execution (Roslyn)** section in the Scripts/Validation tab, and click **Install Roslyn DLLs**. This downloads the required NuGet packages and places the DLLs in `Assets/Plugins/Roslyn/` automatically. - - You can also run it from the menu: `Window > MCP For Unity > Install Roslyn DLLs`. -
- -
- Manual DLL installation (if the installer isn't available) - - 1. Download `Microsoft.CodeAnalysis.CSharp.dll` and dependencies from [NuGet](https://www.nuget.org/packages/Microsoft.CodeAnalysis.CSharp/) - 2. Place DLLs in `Assets/Plugins/Roslyn/` folder - 3. Ensure .NET compatibility settings are correct - 4. Add `USE_ROSLYN` to Scripting Define Symbols - 5. Restart Unity -
-
- -
-Troubleshooting +Recent Updates -* **Unity Bridge Not Connecting:** Check `Window > MCP for Unity` status, restart Unity -* **Server Not Starting:** Verify `uv --version` works, check the terminal for errors -* **Client Not Connecting:** Ensure the HTTP server is running and the URL matches your config +* **[v9.7.0](https://github.com/CoplayDev/unity-mcp/releases/tag/v9.7.0)** (2026-05-22) +* **[v9.6.8](https://github.com/CoplayDev/unity-mcp/releases/tag/v9.6.8)** (2026-04-27) +* **[v9.6.6](https://github.com/CoplayDev/unity-mcp/releases/tag/v9.6.6)** (2026-04-07) +* **[v9.6.5](https://github.com/CoplayDev/unity-mcp/releases/tag/v9.6.5)** (2026-04-03) +* **[v9.6.4](https://github.com/CoplayDev/unity-mcp/releases/tag/v9.6.4)** (2026-03-31) -**Detailed setup guides:** -* [Fix Unity MCP and Cursor, VSCode & Windsurf](https://github.com/CoplayDev/unity-mcp/wiki/1.-Fix-Unity-MCP-and-Cursor,-VSCode-&-Windsurf) — uv/Python installation, PATH issues -* [Fix Unity MCP and Claude Code](https://github.com/CoplayDev/unity-mcp/wiki/2.-Fix-Unity-MCP-and-Claude-Code) — Claude CLI installation -* [Common Setup Problems](https://github.com/CoplayDev/unity-mcp/wiki/3.-Common-Setup-Problems) — macOS dyld errors, FAQ +Full history: [Release Notes](https://coplaydev.github.io/unity-mcp/releases). -Still stuck? [Open an Issue](https://github.com/CoplayDev/unity-mcp/issues) or [Join Discord](https://discord.gg/y4p8KfzrN4)
+ -
-Contributing - -See [README-DEV.md](docs/development/README-DEV.md) for development setup. For custom tools, see [CUSTOM_TOOLS.md](docs/reference/CUSTOM_TOOLS.md). +--- -1. Fork → Create issue → Branch (`feature/your-idea`) → Make changes → PR -
+## Community -
-Telemetry & Privacy +- [Discord](https://discord.gg/y4p8KfzrN4) — chat with maintainers and other contributors +- [Issues](https://github.com/CoplayDev/unity-mcp/issues) — bugs and feature requests +- [Discussions](https://github.com/CoplayDev/unity-mcp/discussions) — design ideas and broader questions +- Security: see [SECURITY.md](SECURITY.md) for private reporting -Anonymous, privacy-focused telemetry (no code, no project names, no personal data). Opt out with `DISABLE_TELEMETRY=true`. See [TELEMETRY.md](docs/reference/TELEMETRY.md). -
+## Contributing -
-Security +See [CONTRIBUTING.md](CONTRIBUTING.md). Branch off `beta`, not `main`. The full dev setup, testing, and release process live in the [Contributing](https://coplaydev.github.io/unity-mcp/contributing/dev-setup) docs. -Network defaults are intentionally fail-closed: -* **HTTP Local** allows loopback-only hosts by default (`127.0.0.1`, `localhost`, `::1`). -* Bind-all interfaces (`0.0.0.0`, `::`) require explicit opt-in in **Advanced Settings** via **Allow LAN Bind (HTTP Local)**. -* **HTTP Remote** requires `https://` by default. -* Plaintext `http://` for remote endpoints requires explicit opt-in via **Allow Insecure Remote HTTP**. -
+## Advanced ---- - -**License:** MIT — See [LICENSE](LICENSE) | **Need help?** [Discord](https://discord.gg/y4p8KfzrN4) | [Issues](https://github.com/CoplayDev/unity-mcp/issues) - ---- +- **Multiple Unity instances** — [Multi-Instance Routing](https://coplaydev.github.io/unity-mcp/guides/multi-instance) +- **Tool groups (vfx / animation / ui / testing / etc.)** — [Tool Groups](https://coplaydev.github.io/unity-mcp/guides/tool-groups) +- **Roslyn script validation** — [Roslyn Validation](https://coplaydev.github.io/unity-mcp/guides/roslyn) +- **Remote-hosted server with auth** — [Remote Server Auth](https://coplaydev.github.io/unity-mcp/guides/remote-server-auth) ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=CoplayDev/unity-mcp&type=Date)](https://www.star-history.com/#CoplayDev/unity-mcp&Date) -
-Citation for Research -If you are working on research that is related to Unity-MCP, please cite us! +## Citation + +If MCP for Unity helped your research, please cite it. ```bibtex -@inproceedings{10.1145/3757376.3771417, -author = {Wu, Shutong and Barnett, Justin P.}, -title = {MCP-Unity: Protocol-Driven Framework for Interactive 3D Authoring}, -year = {2025}, -isbn = {9798400721366}, -publisher = {Association for Computing Machinery}, -address = {New York, NY, USA}, -url = {https://doi.org/10.1145/3757376.3771417}, -doi = {10.1145/3757376.3771417}, -series = {SA Technical Communications '25} +@inproceedings{wu2025mcpunity, + author = {Wu, Shutong and Barnett, Justin P.}, + title = {{MCP-Unity}: {Protocol-Driven} Framework for Interactive {3D} Authoring}, + year = {2025}, + isbn = {9798400721366}, + publisher = {Association for Computing Machinery}, + address = {New York, NY, USA}, + url = {https://doi.org/10.1145/3757376.3771417}, + doi = {10.1145/3757376.3771417}, + series = {SA Technical Communications '25} } ``` -
## Unity AI Tools by Aura Aura offers 2 AI tools for Unity: - **MCP for Unity** is available freely under the MIT license. -- **Aura for Unity** is a premium Unity/Unreal AI assistant that is built for game devs. +- **Aura for Unity** is a premium Unity/Unreal AI assistant built for game devs. ## Disclaimer This project is a free and open-source tool for the Unity Editor, and is not affiliated with Unity Technologies. + +--- + +**License:** MIT — see [LICENSE](LICENSE). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..67c252e67 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,51 @@ +# Security Policy + +## Reporting a Vulnerability + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, email **security@coplay.dev** with: + +- A clear description of the issue +- Steps to reproduce or a proof-of-concept +- The version of MCP for Unity affected (UPM package + Python server) +- Your OS, Unity Editor version, and MCP client +- Optional: a suggested fix + +We aim to acknowledge reports within **3 business days** and to share an initial assessment within **10 business days**. Critical fixes are released as patch versions on both `main` and the beta channel. + +## Supported Versions + +| Version | Supported | +|---------|-----------| +| latest (`main`) | Yes | +| latest beta (`beta`) | Yes | +| older releases | No — please upgrade | + +## Network Defaults (Safe by Default) + +MCP for Unity is intentionally fail-closed: + +- **HTTP Local** binds to loopback only by default (`127.0.0.1`, `localhost`, `::1`). LAN bind (`0.0.0.0`, `::`) requires explicit opt-in via **Allow LAN Bind (HTTP Local)** in Advanced Settings. +- **HTTP Remote** requires `https://` by default. Plaintext `http://` for remote endpoints requires explicit opt-in via **Allow Insecure Remote HTTP**. +- Remote-hosted mode requires API key authentication. See [Remote Server Auth](https://coplaydev.github.io/unity-mcp/guides/remote-server-auth). + +If you find a way to bypass any of these guards, that qualifies as a security vulnerability and warrants a private report. + +## What Counts as a Security Issue + +- Remote code execution via crafted MCP messages +- Auth bypass on remote-hosted server +- Filesystem read/write outside the intended Unity project root +- Network requests that escape the configured allow-list +- Credential or API-key leakage in logs, telemetry, or error responses + +## What Doesn't Count + +- Tool actions that intentionally modify the Unity project (that's the product) +- Issues that require an attacker to already have shell access to the host +- Vulnerabilities in third-party dependencies — please report those upstream first; we'll bump our pins after the upstream fix lands + +## Disclosure Timeline + +Once a fix is shipped, we publish a security advisory on the GitHub Security tab and credit the reporter (unless they prefer anonymity). diff --git a/docs/guides/CURSOR_HELP.md b/docs/guides/CURSOR_HELP.md deleted file mode 100644 index b1c11e408..000000000 --- a/docs/guides/CURSOR_HELP.md +++ /dev/null @@ -1,85 +0,0 @@ -### Cursor/VSCode/Windsurf: UV path issue on Windows (diagnosis and fix) - -#### The issue -- Some Windows machines have multiple `uv.exe` locations. Our auto-config sometimes picked a less stable path, causing the MCP client to fail to launch the MCP for Unity Server or for the path to be auto-rewritten on repaint/restart. - -#### Typical symptoms -- Cursor shows the MCP for Unity server but never connects or reports it “can’t start.” -- Your `%USERPROFILE%\\.cursor\\mcp.json` flips back to a different `command` path when Unity or the MCP for Unity window refreshes. - -#### Real-world example -- Wrong/fragile path (auto-picked): - - `C:\Users\mrken.local\bin\uv.exe` (malformed, not standard) - - `C:\Users\mrken\AppData\Local\Microsoft\WinGet\Packages\astral-sh.uv_Microsoft.Winget.Source_8wekyb3d8bbwe\uv.exe` -- Correct/stable path (works with Cursor): - - `C:\Users\mrken\AppData\Local\Microsoft\WinGet\Links\uv.exe` - -#### Quick fix (recommended) -1) In MCP for Unity: `Window > MCP for Unity` → select your MCP client (Cursor or Windsurf) -2) If you see “uv Not Found,” click “Choose `uv` Install Location” and browse to: - - `C:\Users\\AppData\Local\Microsoft\WinGet\Links\uv.exe` -3) If uv is already found but wrong, still click “Choose `uv` Install Location” and select the `Links\uv.exe` path above. This saves a persistent override. -4) Click “Auto Configure” (or re-open the client) and restart Cursor. - -This sets an override stored in the Editor (key: `MCPForUnity.UvPath`) so MCP for Unity won’t auto-rewrite the config back to a different `uv.exe` later. - -#### Verify the fix -- Confirm global Cursor config is at: `%USERPROFILE%\\.cursor\\mcp.json` -- You should see something like: - -```json -{ - "mcpServers": { - "unityMCP": { - "command": "C:\\Users\\YOU\\AppData\\Local\\Microsoft\\WinGet\\Links\\uvx.exe", - "args": [ - "--from", - "mcpforunityserver", - "mcp-for-unity", - "--transport", - "stdio" - ] - } - } -} -``` - -- Manually run the same command in PowerShell to confirm it launches: - -```powershell -"C:\Users\YOU\AppData\Local\Microsoft\WinGet\Links\uvx.exe" --from mcpforunityserver mcp-for-unity --transport stdio -``` - -If that runs without error, restart Cursor and it should connect. - -#### Why this happens -- On Windows, multiple `uv.exe` can exist (WinGet Packages path, a WinGet Links shim, Python Scripts, etc.). The Links shim is the most stable target for GUI apps to launch. -- Prior versions of the auto-config could pick the first found path and re-write config on refresh. Choosing a path via the MCP window pins a known‑good absolute path and prevents auto-rewrites. - -#### Extra notes -- Restart Cursor after changing `mcp.json`; it doesn’t always hot-reload that file. -- If you also have a project-scoped `.cursor\\mcp.json` in your Unity project folder, that file overrides the global one. - - -### Why pin the WinGet Links shim (and not the Packages path) - -- Windows often has multiple `uv.exe` installs and GUI clients (Cursor/Windsurf/VSCode) may launch with a reduced `PATH`. Using an absolute path is safer than `"command": "uv"`. -- WinGet publishes stable launch shims in these locations: - - User scope: `%LOCALAPPDATA%\Microsoft\WinGet\Links\uv.exe` - - Machine scope: `C:\Program Files\WinGet\Links\uv.exe` - These shims survive upgrades and are intended as the portable entrypoints. See the WinGet notes: [discussion](https://github.com/microsoft/winget-pkgs/discussions/184459) • [how to find installs](https://superuser.com/questions/1739292/how-to-know-where-winget-installed-a-program) -- The `Packages` root is where payloads live and can change across updates, so avoid pointing your config at it. - -Recommended practice - -- Prefer the WinGet Links shim paths above. If present, select one via “Choose `uv` Install Location”. -- If the unity window keeps rewriting to a different `uv.exe`, pick the Links shim again; MCP for Unity saves a pinned override and will stop auto-rewrites. -- If neither Links path exists, a reasonable fallback is `~/.local/bin/uv.exe` (uv tools bin) or a Scoop shim, but Links is preferred for stability. - -References - -- WinGet portable Links: [GitHub discussion](https://github.com/microsoft/winget-pkgs/discussions/184459) -- WinGet install locations: [Super User](https://superuser.com/questions/1739292/how-to-know-where-winget-installed-a-program) -- GUI client PATH caveats (Cursor): [Cursor community thread](https://forum.cursor.com/t/mcp-feature-client-closed-fix/54651?page=4) -- uv tools install location (`~/.local/bin`): [Astral docs](https://docs.astral.sh/uv/concepts/tools/) - diff --git a/tools/generate_docs_reference.py b/tools/generate_docs_reference.py new file mode 100644 index 000000000..dc94dc9a0 --- /dev/null +++ b/tools/generate_docs_reference.py @@ -0,0 +1,628 @@ +#!/usr/bin/env python3 +""" +Generate Docusaurus reference pages for MCP for Unity tools and resources. + +Single source of truth: the Python `@mcp_for_unity_tool` and +`@mcp_for_unity_resource` registries under Server/src/services/. The C# +attributes carry only Name/Group/Description; the Python decorator owns the +richest typing (Annotated[...] parameter docs) and is what the MCP client +actually sees over the wire. + +Outputs: + website/docs/reference/tools//.md — one per tool + website/docs/reference/tools//index.md — group landing + website/docs/reference/tools/index.md — catalog landing + website/docs/reference/resources/index.md — resources catalog + +Modes: + --write (default) regenerate files in place + --check re-emit to a temp dir and diff against committed files; + exits non-zero on drift (used by CI / pre-commit hook) + +Hand-authored example blocks between and + are preserved across regeneration. + +Run requirements: the Server/ Python dependencies must be importable, since +we load every tool module to trigger decorator registration. In CI: + cd Server && uv sync && cd .. && uv --project Server run python tools/generate_docs_reference.py --check +""" + +from __future__ import annotations + +import argparse +import filecmp +import importlib +import inspect +import json +import re +import shutil +import sys +import tempfile +import textwrap +import typing +from dataclasses import dataclass +from pathlib import Path +from types import GenericAlias +from typing import Annotated, Any, Literal, Union, get_args, get_origin + +REPO_ROOT = Path(__file__).resolve().parent.parent +SERVER_SRC = REPO_ROOT / "Server" / "src" +WEBSITE_DOCS = REPO_ROOT / "website" / "docs" +TOOLS_OUT = WEBSITE_DOCS / "reference" / "tools" +RESOURCES_OUT = WEBSITE_DOCS / "reference" / "resources" + +GENERATED_BANNER = ( + "> **Auto-generated** from the Python tool registry. Do not hand-edit " + "outside `` blocks — the " + "generator (`tools/generate_docs_reference.py`) will overwrite them." +) + +EXAMPLES_OPEN = "" +EXAMPLES_CLOSE = "" +EXAMPLES_PLACEHOLDER = ( + f"{EXAMPLES_OPEN}\n" + "*No examples yet. Add usage examples here — they will be preserved across regenerations.*\n" + f"{EXAMPLES_CLOSE}\n" +) + + +# --------------------------------------------------------------------------- +# Registry loading +# --------------------------------------------------------------------------- + + +def _ensure_server_on_path() -> None: + if str(SERVER_SRC) not in sys.path: + sys.path.insert(0, str(SERVER_SRC)) + + +def load_registries() -> tuple[list[dict[str, Any]], list[dict[str, Any]]]: + """Import every tool/resource module so the decorators fire, then return + the populated registries.""" + _ensure_server_on_path() + + from services.registry import ( # noqa: WPS433 (deferred import by design) + get_registered_tools, + get_registered_resources, + clear_tool_registry, + clear_resource_registry, + ) + from utils.module_discovery import discover_modules + + clear_tool_registry() + clear_resource_registry() + + tools_pkg = importlib.import_module("services.tools") + resources_pkg = importlib.import_module("services.resources") + + # Walk both directories and import every module — the @decorator + # side-effects populate the registries. + list(discover_modules(Path(tools_pkg.__file__).parent, tools_pkg.__name__)) + list(discover_modules(Path(resources_pkg.__file__).parent, resources_pkg.__name__)) + + return get_registered_tools(), get_registered_resources() + + +# --------------------------------------------------------------------------- +# Parameter introspection +# --------------------------------------------------------------------------- + + +@dataclass(frozen=True) +class ParamDoc: + name: str + type_str: str + required: bool + description: str | None + default: str | None + + +def _render_type(annotation: Any) -> str: + """Render a typing annotation as a short Markdown-safe string.""" + if annotation is inspect.Parameter.empty or annotation is None: + return "any" + + origin = get_origin(annotation) + + if origin is Annotated: + return _render_type(get_args(annotation)[0]) + + if origin in (Union, getattr(typing, "UnionType", Union)): + parts = [_render_type(a) for a in get_args(annotation) if a is not type(None)] + has_none = type(None) in get_args(annotation) or any( + part.endswith(" | None") or part == "None" for part in parts + ) + # Strip any inner "| None" — we'll add a single one at the end if needed. + parts = [p[: -len(" | None")] if p.endswith(" | None") else p for p in parts] + rendered = " | ".join(p for p in parts if p and p != "None") + return rendered + (" | None" if has_none else "") + + if origin is Literal: + literals = ", ".join(repr(a) for a in get_args(annotation)) + return f"Literal[{literals}]" + + if origin is list or annotation is list: + args = get_args(annotation) + inner = ", ".join(_render_type(a) for a in args) if args else "Any" + return f"list[{inner}]" + + if origin is dict or annotation is dict: + args = get_args(annotation) + inner = ", ".join(_render_type(a) for a in args) if args else "Any" + return f"dict[{inner}]" + + if origin is tuple or annotation is tuple: + args = get_args(annotation) + inner = ", ".join(_render_type(a) for a in args) if args else "Any" + return f"tuple[{inner}]" + + if isinstance(annotation, type): + return annotation.__name__ + + if isinstance(annotation, GenericAlias): # e.g. list[str] without origin + return str(annotation) + + return str(annotation).replace("typing.", "") + + +def _annotation_description(annotation: Any) -> str | None: + """Pull the human-readable string from an Annotated[...] parameter.""" + + def _walk(a: Any) -> str | None: + origin = get_origin(a) + if origin is Annotated: + for meta in get_args(a)[1:]: + if isinstance(meta, str): + return meta + # Recurse into the underlying type — e.g. Annotated[str, "..."] | None + return _walk(get_args(a)[0]) + if origin in (Union, getattr(typing, "UnionType", Union)): + for arg in get_args(a): + desc = _walk(arg) + if desc: + return desc + return None + + return _walk(annotation) + + +def _is_required(param: inspect.Parameter) -> bool: + return param.default is inspect.Parameter.empty + + +def _render_default(default: Any) -> str | None: + if default is inspect.Parameter.empty: + return None + if default is None: + return "None" + return repr(default) + + +def introspect_params(func: Any) -> list[ParamDoc]: + sig = inspect.signature(func) + try: + hints = typing.get_type_hints(func, include_extras=True) + except Exception: + hints = {} + + out: list[ParamDoc] = [] + for name, param in sig.parameters.items(): + if name in {"self", "cls", "ctx"}: + continue + annotation = hints.get(name, param.annotation) + out.append( + ParamDoc( + name=name, + type_str=_render_type(annotation), + required=_is_required(param), + description=_annotation_description(annotation), + default=_render_default(param.default), + ) + ) + return out + + +# --------------------------------------------------------------------------- +# Markdown rendering +# --------------------------------------------------------------------------- + + +_SENTENCE_BOUNDARY = re.compile(r"(?<=[.!?])\s+(?=[A-Z])|\n\s*\n") + + +def _first_sentence(description: str) -> str: + """Return the first sentence of a tool description, suitable for + frontmatter / catalog blurbs. + + The earlier implementation used `description.split(".")[0]` which + cut the string at the first period — including periods inside + abbreviations and parenthesized lists (e.g. `etc.) in Unity`), + producing truncated frontmatter like `"...modify, delete, etc"`. + + Split on a real sentence boundary instead: a `.`, `!`, or `?` + followed by whitespace + a capital letter (or a paragraph break). + Fall back to the entire string if no boundary is found, then + smart-truncate to keep frontmatter compact. + """ + text = (description or "").strip().replace('"', "'") + if not text: + return "" + first = _SENTENCE_BOUNDARY.split(text, maxsplit=1)[0].strip() + # Cap absurdly long single-sentence descriptions + if len(first) > 240: + first = first[:237].rstrip() + "…" + return first + + +def _escape_table_cell(s: str) -> str: + return s.replace("|", "\\|").replace("\n", " ") + + +def _read_existing_examples(path: Path) -> str: + """Return the existing examples block from a generated file, if any. + + Requires the start/end markers to sit on their own line so we don't + match the markers that appear inside the generator's own warning + banner (which references the literal marker strings).""" + if not path.exists(): + return EXAMPLES_PLACEHOLDER + text = path.read_text(encoding="utf-8") + match = re.search( + rf"^{re.escape(EXAMPLES_OPEN)}\s*\n(.*?)^{re.escape(EXAMPLES_CLOSE)}\s*$", + text, + re.DOTALL | re.MULTILINE, + ) + if not match: + return EXAMPLES_PLACEHOLDER + captured = match.group(1) + if not captured.strip(): + return EXAMPLES_PLACEHOLDER + return f"{EXAMPLES_OPEN}\n{captured.strip()}\n{EXAMPLES_CLOSE}\n" + + +def render_tool_page(tool: dict[str, Any], existing_examples: str) -> str: + name = tool["name"] + description = (tool.get("description") or "").strip() + group = tool.get("group") or "core" + func = tool["func"] + module = getattr(func, "__module__", "") + params = introspect_params(func) + + # Sidebar/title metadata + desc_for_meta = _first_sentence(description) or name + front_matter = textwrap.dedent( + f"""\ + --- + title: {name} + sidebar_label: {name} + description: "{desc_for_meta}" + --- + """ + ) + + if params: + rows = ["| Name | Type | Required | Description |", "|------|------|----------|-------------|"] + for p in params: + req = "yes" if p.required else "—" + desc = _escape_table_cell(p.description or "") + type_cell = _escape_table_cell(f"`{p.type_str}`") + rows.append(f"| `{p.name}` | {type_cell} | {req} | {desc} |") + params_section = "\n".join(rows) + else: + params_section = "_No parameters._" + + return ( + f"{front_matter}\n" + f"# `{name}`\n\n" + f"{GENERATED_BANNER}\n\n" + f"**Group:** `{group}`  ·  " + f"**Module:** `{module}`\n\n" + f"## Description\n\n" + f"{description or '_No description provided._'}\n\n" + f"## Parameters\n\n" + f"{params_section}\n\n" + f"## Returns\n\n" + f"A `dict` containing the Unity response. The exact shape depends on the action.\n\n" + f"## Examples\n\n" + f"{existing_examples}\n" + ) + + +def render_group_index(group: str, tools: list[dict[str, Any]], group_blurb: str) -> str: + front_matter = textwrap.dedent( + f"""\ + --- + title: "{group} tools" + sidebar_label: "{group}" + description: "MCP for Unity tools in the {group} group." + --- + """ + ) + + bullets = [] + for tool in sorted(tools, key=lambda t: t["name"]): + n = tool["name"] + d = _first_sentence(tool.get("description") or "") + bullets.append(f"- **[`{n}`](./{n}.md)** — {d}") + body = "\n".join(bullets) if bullets else "_No tools in this group._" + + return ( + f"{front_matter}\n" + f"# `{group}` tools\n\n" + f"{group_blurb}\n\n" + f"{body}\n" + ) + + +def render_catalog_index(tools_by_group: dict[str, list[dict[str, Any]]], + group_blurbs: dict[str, str]) -> str: + front_matter = textwrap.dedent( + """\ + --- + title: Tool reference + sidebar_label: Tools + sidebar_class_name: sidebar-hidden + slug: /reference/tools + description: Auto-generated catalog of every MCP for Unity tool, grouped by domain. + --- + """ + ) + + sections = [ + "# Tool reference\n", + GENERATED_BANNER + "\n", + "Every tool MCP for Unity exposes, generated directly from the Python " + "`@mcp_for_unity_tool` registry under `Server/src/services/tools/`.\n", + ] + + for group in sorted(tools_by_group): + tools = tools_by_group[group] + sections.append(f"## `{group}`   ({len(tools)} tool{'s' if len(tools) != 1 else ''})") + sections.append(group_blurbs.get(group, "")) + for tool in sorted(tools, key=lambda t: t["name"]): + n = tool["name"] + d = _first_sentence(tool.get("description") or "") + sections.append(f"- **[`{n}`](./{group}/{n}.md)** — {d}") + sections.append("") + + return front_matter + "\n" + "\n".join(sections) + "\n" + + +def render_resources_catalog(resources: list[dict[str, Any]]) -> str: + front_matter = textwrap.dedent( + """\ + --- + title: Resource reference + sidebar_label: Resources + slug: /reference/resources + description: Auto-generated catalog of every MCP for Unity resource. + --- + """ + ) + + head = ( + "# Resource reference\n\n" + f"{GENERATED_BANNER}\n\n" + "Resources are read-only state surfaces exposed to MCP clients. " + "Tools mutate; resources observe.\n\n" + ) + + items = [] + for res in sorted(resources, key=lambda r: r["name"]): + name = res["name"] + uri = res.get("uri", "") + desc = (res.get("description") or "").strip() or "_No description._" + func = res["func"] + params = introspect_params(func) + if params: + param_lines = ["", "**Parameters:**", ""] + for p in params: + req = "required" if p.required else "optional" + d = p.description or "" + param_lines.append(f"- `{p.name}` (`{p.type_str}`, {req}) — {d}") + param_block = "\n".join(param_lines) + else: + param_block = "" + + items.append( + f"## `{name}`\n\n" + f"**URI:** `{uri}`\n\n" + f"{desc}\n" + f"{param_block}\n" + ) + + return front_matter + "\n" + head + "\n".join(items) + "\n" + + +# --------------------------------------------------------------------------- +# File-writing +# --------------------------------------------------------------------------- + + +GROUP_BLURBS_FALLBACK = { + "core": "Essential scene, script, asset, and editor tools — always on by default.", + "docs": "Unity API reflection and documentation lookup.", + "vfx": "Visual effects — VFX Graph, shaders, procedural textures.", + "animation": "Animator control and AnimationClip creation.", + "ui": "UI Toolkit — UXML, USS, UIDocument.", + "scripting_ext": "ScriptableObject management.", + "testing": "Test runner and async test jobs.", + "probuilder": "ProBuilder 3D modeling — requires `com.unity.probuilder`.", + "profiling": "Unity Profiler session control, counters, memory snapshots, Frame Debugger.", +} + + +def _resolve_group_blurbs() -> dict[str, str]: + """Pull live blurbs from the registry, falling back to the local copy.""" + try: + from services.registry import TOOL_GROUPS # type: ignore + return {g: blurb for g, blurb in TOOL_GROUPS.items()} + except Exception: + return GROUP_BLURBS_FALLBACK + + +def _write(path: Path, content: str) -> bool: + """Write only if content differs. Return True if a write happened.""" + path.parent.mkdir(parents=True, exist_ok=True) + if path.exists() and path.read_text(encoding="utf-8") == content: + return False + path.write_text(content, encoding="utf-8") + return True + + +def generate( + tools_root: Path = TOOLS_OUT, + resources_root: Path = RESOURCES_OUT, + examples_source: Path | None = None, +) -> dict[str, int]: + """Generate reference pages. + + When `examples_source` is provided, hand-authored examples blocks are + read from there instead of from `tools_root`. `--check` uses this to + write into a tempdir while still preserving examples from the committed + canonical location. + """ + tools, resources = load_registries() + group_blurbs = _resolve_group_blurbs() + + # Group tools. + tools_by_group: dict[str, list[dict[str, Any]]] = {} + for t in tools: + g = t.get("group") or "core" + tools_by_group.setdefault(g, []).append(t) + + stats = {"tools": 0, "groups": 0, "resources": 0, "writes": 0} + examples_root = examples_source if examples_source is not None else tools_root + + # Per-tool pages + per-group landing + Docusaurus category metadata. + for group, group_tools in sorted(tools_by_group.items()): + group_dir = tools_root / group + examples_dir = examples_root / group + for tool in sorted(group_tools, key=lambda t: t["name"]): + page_path = group_dir / f"{tool['name']}.md" + examples_path = examples_dir / f"{tool['name']}.md" + existing_examples = _read_existing_examples(examples_path) + page_md = render_tool_page(tool, existing_examples) + if _write(page_path, page_md): + stats["writes"] += 1 + stats["tools"] += 1 + index_md = render_group_index(group, group_tools, group_blurbs.get(group, "")) + if _write(group_dir / "index.md", index_md): + stats["writes"] += 1 + # _category_.json tells the autogenerated sidebar to wrap this + # directory in a collapsible category. Without it, the group's + # tool pages render flat as siblings of the group index. + category_json = json.dumps( + { + "label": group, + "link": {"type": "doc", "id": f"reference/tools/{group}/index"}, + "collapsed": True, + }, + indent=2, + ) + "\n" + if _write(group_dir / "_category_.json", category_json): + stats["writes"] += 1 + stats["groups"] += 1 + + # Top-level catalog index. The sidebar's "Tools" parent category in + # sidebars.js is what links to this doc — no root `_category_.json` + # here, because that would compete with the parent's explicit link + # and end up listing the catalog as a duplicate "Tools" child. + catalog_md = render_catalog_index(tools_by_group, group_blurbs) + if _write(tools_root / "index.md", catalog_md): + stats["writes"] += 1 + root_cat = tools_root / "_category_.json" + if root_cat.exists(): + root_cat.unlink() + + # Resources catalog (single page). + resources_md = render_resources_catalog(resources) + if _write(resources_root / "index.md", resources_md): + stats["writes"] += 1 + stats["resources"] = len(resources) + + return stats + + +# --------------------------------------------------------------------------- +# CLI +# --------------------------------------------------------------------------- + + +def _copytree_into(src: Path, dst: Path) -> None: + if src.exists(): + shutil.copytree(src, dst, dirs_exist_ok=True) + + +def _diff_trees(a: Path, b: Path) -> list[str]: + diffs: list[str] = [] + + def _walk(rel: Path) -> None: + cmp = filecmp.dircmp(a / rel, b / rel) + for name in cmp.left_only: + diffs.append(f"committed-only: {rel / name}") + for name in cmp.right_only: + diffs.append(f"generated-only: {rel / name}") + for name in cmp.diff_files: + diffs.append(f"differs: {rel / name}") + for name in cmp.common_dirs: + _walk(rel / name) + + if a.exists() and b.exists(): + _walk(Path(".")) + elif b.exists(): + diffs.append(f"committed missing entirely: {a}") + return diffs + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--check", action="store_true", + help="Generate into a temp dir and diff against the committed reference. Non-zero exit on drift.") + args = parser.parse_args(argv) + + if args.check: + # Use a persistent dir under /tmp if MCP4U_KEEP_CHECK is set, so the + # user can diff committed vs generated by hand. + import os + keep = bool(os.environ.get("MCP4U_KEEP_CHECK")) + ctx = tempfile.TemporaryDirectory(prefix="mcp4u-docs-check-") if not keep else None + tmp = ctx.__enter__() if ctx else tempfile.mkdtemp(prefix="mcp4u-docs-check-keep-") + try: + tmp_root = Path(tmp) + tmp_tools = tmp_root / "tools" + tmp_resources = tmp_root / "resources" + # Read existing examples from the committed location so + # preservation is honored in --check too. + generate(tmp_tools, tmp_resources, examples_source=TOOLS_OUT) + if keep: + print(f"[--check] generated tree retained at {tmp_root}") + + diffs = [] + diffs.extend(_diff_trees(TOOLS_OUT, tmp_tools)) + diffs.extend(_diff_trees(RESOURCES_OUT, tmp_resources)) + + if diffs: + print("Generated reference is stale. Run:") + print(" python tools/generate_docs_reference.py") + print("then commit the changes. Details:") + for d in diffs: + print(f" - {d}") + return 1 + + print("Generated docs reference is up-to-date.") + return 0 + finally: + if ctx: + ctx.__exit__(None, None, None) + + stats = generate() + print( + f"Generated {stats['tools']} tool pages across {stats['groups']} groups " + f"({stats['writes']} file(s) written) + {stats['resources']} resource entries." + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/hooks/pre-commit b/tools/hooks/pre-commit new file mode 100755 index 000000000..6742672db --- /dev/null +++ b/tools/hooks/pre-commit @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# Pre-commit hook: regenerate the Docusaurus tool/resource reference when +# any tool/resource module is part of the commit. Installed by +# tools/install-hooks.sh; opt-in (devs without the hook see no behavior change). +# To bypass for a single commit: git commit --no-verify + +set -e + +REPO_ROOT="$(git rev-parse --show-toplevel)" +GENERATOR="${REPO_ROOT}/tools/generate_docs_reference.py" + +if [[ ! -f "$GENERATOR" ]]; then + echo "pre-commit: $GENERATOR missing; skipping docs regeneration." >&2 + exit 0 +fi + +relevant_paths='^Server/src/services/(tools|resources|registry)/' + +# Look at the staged change set only — exclude pure deletions. +staged=$(git diff --cached --name-only --diff-filter=ACMR) + +if ! grep -qE "$relevant_paths" <<<"$staged"; then + exit 0 +fi + +echo "pre-commit: tool/resource module changes detected — regenerating /website/docs/reference/" + +# Prefer uv if available (matches how the Server's deps are pinned). Fall back +# to system python — the generator handles its own sys.path setup. +if command -v uv >/dev/null 2>&1 && [[ -f "${REPO_ROOT}/Server/pyproject.toml" ]]; then + (cd "${REPO_ROOT}/Server" && uv run python "$GENERATOR") +else + python3 "$GENERATOR" +fi + +# Stage any reference files that changed so the commit captures them. +if ! git diff --quiet -- "website/docs/reference"; then + echo "pre-commit: staging regenerated reference pages." + git add website/docs/reference +fi + +exit 0 diff --git a/tools/sync_release_notes.py b/tools/sync_release_notes.py new file mode 100644 index 000000000..9173b88b8 --- /dev/null +++ b/tools/sync_release_notes.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python3 +""" +Sync release notes from GitHub Releases into: + - website/docs/releases.md (full history, grouped by minor) + - README.md "Recent Updates" (latest N releases between sentinel markers) + +Why a sync script: the previous releases.md was hand-maintained and went stale +(it claimed v9.6.3 was latest when v9.7.0 had shipped). GitHub Releases is the +single source of truth; this script makes it the only source. + +Usage: + python tools/sync_release_notes.py # write + verify + python tools/sync_release_notes.py --check # CI: fail if drift + GITHUB_TOKEN=xxx python tools/sync_release_notes.py # higher rate limit + +Local runs without a token use anonymous GitHub API (60 req/hr — plenty for one +sync since we only paginate the /releases endpoint). +""" + +from __future__ import annotations + +import argparse +import json +import os +import re +import shutil +import ssl +import subprocess +import sys +import textwrap +import urllib.error +import urllib.request +from collections import defaultdict +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent +RELEASES_MD = REPO_ROOT / "website" / "docs" / "releases.md" +README_MD = REPO_ROOT / "README.md" + +OWNER = "CoplayDev" +REPO = "unity-mcp" +API = f"https://api.github.com/repos/{OWNER}/{REPO}/releases" + +README_RECENT_COUNT = 5 + +README_MARKER_OPEN = "" +README_MARKER_CLOSE = "" + +RELEASES_HEADER = textwrap.dedent( + """\ + --- + id: releases + slug: /releases + title: Release Notes + sidebar_label: Releases + description: Full version-by-version change history for MCP for Unity. + --- + + # Release Notes + + Latest releases land in [`beta`](https://github.com/CoplayDev/unity-mcp/tree/beta) before promotion to [`main`](https://github.com/CoplayDev/unity-mcp/tree/main). Major breaking changes get a dedicated migration guide under [Migrations](/migrations/v5). + + For the canonical changelog with PR links, see [GitHub Releases](https://github.com/CoplayDev/unity-mcp/releases). + + > Auto-generated from the GitHub Releases API by `tools/sync_release_notes.py`. Do not hand-edit — changes will be overwritten on the next sync. + + """ +) + + +# --------------------------------------------------------------------------- +# Fetch +# --------------------------------------------------------------------------- + + +def _fetch_via_gh(path: str) -> list[dict] | None: + """Prefer `gh api` when available — handles auth + SSL cleanly across + macOS Python distributions that miss the system trust store.""" + if not shutil.which("gh"): + return None + try: + result = subprocess.run( + ["gh", "api", path, "--paginate"], + check=True, + capture_output=True, + text=True, + timeout=60, + ) + except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e: + print(f"gh api failed ({e}); falling back to urllib.", file=sys.stderr) + return None + # `gh api --paginate` concatenates JSON arrays as `][`. Split + parse. + text = result.stdout.strip() + if not text: + return [] + if "][" in text: + text = "[" + text.replace("][", ",") + "]" + # Now we may have [[..],[..]] — flatten. + nested = json.loads(text) + flat: list[dict] = [] + for chunk in nested: + flat.extend(chunk if isinstance(chunk, list) else [chunk]) + return flat + return json.loads(text) + + +def _fetch_via_urllib(url: str) -> list[dict]: + headers = { + "User-Agent": "mcp-for-unity-docs-sync", + "Accept": "application/vnd.github+json", + } + token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN") + if token: + headers["Authorization"] = f"Bearer {token}" + + ctx = ssl.create_default_context() + try: + import certifi # type: ignore + ctx = ssl.create_default_context(cafile=certifi.where()) + except ImportError: + pass + + req = urllib.request.Request(url, headers=headers) + with urllib.request.urlopen(req, timeout=30, context=ctx) as resp: + return json.loads(resp.read().decode("utf-8")) + + +def fetch_all_releases() -> list[dict]: + # Try `gh api` first. + via_gh = _fetch_via_gh(f"repos/{OWNER}/{REPO}/releases?per_page=100") + if via_gh is not None: + return [r for r in via_gh if not r.get("draft")] + + # Fallback: paginate urllib. + all_releases: list[dict] = [] + page = 1 + while True: + batch = _fetch_via_urllib(f"{API}?per_page=100&page={page}") + if not batch: + break + all_releases.extend(batch) + if len(batch) < 100: + break + page += 1 + return [r for r in all_releases if not r.get("draft")] + + +# --------------------------------------------------------------------------- +# Render +# --------------------------------------------------------------------------- + + +_VERSION_RE = re.compile(r"^v?(\d+)\.(\d+)\.(\d+)") + + +def _parse_version(tag: str) -> tuple[int, int, int] | None: + m = _VERSION_RE.match(tag.strip()) + if not m: + return None + return tuple(int(x) for x in m.groups()) # type: ignore[return-value] + + +def _minor_key(tag: str) -> str: + v = _parse_version(tag) + if not v: + return tag + return f"v{v[0]}.{v[1]} series" + + +def _normalize_body(body: str | None) -> str: + if not body: + return "_No release notes._" + # Trim trailing whitespace; collapse 3+ blank lines. + body = body.strip() + body = re.sub(r"\n{3,}", "\n\n", body) + return body + + +def _digest(body: str | None, max_chars: int = 280) -> str: + """Pull a one-line digest for the README block. Prefers the first non-empty + line that isn't a heading or list-of-PRs link.""" + if not body: + return "" + for raw in body.splitlines(): + line = raw.strip() + if not line: + continue + # Skip headings and bullet-of-PR lines. + if line.startswith(("#", ">", "**Full Changelog**")): + continue + if line.startswith(("*", "-")) and "github.com" in line and "pull/" in line: + continue + # Strip bullet prefixes for the digest. + line = re.sub(r"^[*-]\s+", "", line) + # Strip leading markdown emphasis. + line = re.sub(r"^\*\*[^*]+\*\*[:.\s—-]*", "", line) + if len(line) > max_chars: + line = line[: max_chars - 1].rstrip() + "…" + return line + return "" + + +def render_releases_md(releases: list[dict]) -> str: + out = [RELEASES_HEADER] + + grouped: dict[str, list[dict]] = defaultdict(list) + order: list[str] = [] + for r in releases: + key = _minor_key(r["tag_name"]) + if key not in grouped: + order.append(key) + grouped[key].append(r) + + for key in order: + out.append(f"## {key}\n") + for r in grouped[key]: + tag = r["tag_name"] + name = (r.get("name") or tag).strip() + date = (r.get("published_at") or "").split("T")[0] + prerelease = " (beta)" if r.get("prerelease") else "" + url = r.get("html_url") or f"https://github.com/{OWNER}/{REPO}/releases/tag/{tag}" + body = _normalize_body(r.get("body")) + + summary = name if name and name != tag else tag + out.append(f"### [{summary}{prerelease}]({url}) — {date}\n") + out.append(f"
\nShow release notes\n\n{body}\n\n
\n") + out.append("") # blank line between groups + + # Migration footer + out.append("## Migration guides\n") + out.append( + "Breaking changes from prior major versions live under [Migrations](/migrations/v5):\n" + ) + out.append("- [v5 — UnityMcpBridge → MCPForUnity](/migrations/v5)") + out.append("- [v6 — New Editor Window (UI Toolkit + service architecture)](/migrations/v6)") + out.append("- [v8 — HTTP and Stdio support](/migrations/v8)\n") + return "\n".join(out) + + +def render_readme_recent(releases: list[dict], n: int = README_RECENT_COUNT) -> str: + lines = [README_MARKER_OPEN] + lines.append("
") + lines.append("Recent Updates") + lines.append("") + for r in releases[:n]: + tag = r["tag_name"] + date = (r.get("published_at") or "").split("T")[0] + url = r.get("html_url") or f"https://github.com/{OWNER}/{REPO}/releases/tag/{tag}" + digest = _digest(r.get("body")) + suffix = f" — {digest}" if digest else "" + prerelease = " *(beta)*" if r.get("prerelease") else "" + lines.append(f"* **[{tag}{prerelease}]({url})** ({date}){suffix}") + lines.append("") + lines.append( + "Full history: [Release Notes](https://coplaydev.github.io/unity-mcp/releases)." + ) + lines.append("") + lines.append("
") + lines.append(README_MARKER_CLOSE) + return "\n".join(lines) + + +# --------------------------------------------------------------------------- +# Apply +# --------------------------------------------------------------------------- + + +def replace_marked_block(text: str, replacement: str) -> str: + pattern = re.compile( + re.escape(README_MARKER_OPEN) + r".*?" + re.escape(README_MARKER_CLOSE), + re.DOTALL, + ) + if pattern.search(text): + return pattern.sub(replacement, text) + # First-time insert: try to replace the legacy
Recent Updates + legacy = re.compile( + r"
\s*\s*Recent Updates\s*.*?
", + re.DOTALL, + ) + if legacy.search(text): + return legacy.sub(replacement, text) + # Otherwise append before the "## Community" header if present. + anchor = "## Community" + if anchor in text: + return text.replace(anchor, f"{replacement}\n\n{anchor}", 1) + return text + "\n\n" + replacement + "\n" + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--check", action="store_true", + help="Exit non-zero if files would change. Used by CI to detect drift.") + args = parser.parse_args(argv) + + try: + releases = fetch_all_releases() + except urllib.error.HTTPError as e: + print(f"GitHub API error: {e.code} {e.reason}", file=sys.stderr) + if e.code == 403: + print("Hint: set GITHUB_TOKEN to lift the anonymous rate limit.", file=sys.stderr) + return 2 + + if not releases: + print("No releases returned by GitHub API. Aborting to avoid blanking files.", file=sys.stderr) + return 2 + + new_releases = render_releases_md(releases) + new_readme_block = render_readme_recent(releases) + + existing_releases = RELEASES_MD.read_text(encoding="utf-8") if RELEASES_MD.exists() else "" + existing_readme = README_MD.read_text(encoding="utf-8") if README_MD.exists() else "" + new_readme = replace_marked_block(existing_readme, new_readme_block) + + releases_drift = existing_releases != new_releases + readme_drift = existing_readme != new_readme + + if args.check: + if releases_drift or readme_drift: + print("Release notes are stale. Run:") + print(" python tools/sync_release_notes.py") + print("then commit the changes.") + if releases_drift: + print(f" - drift in {RELEASES_MD.relative_to(REPO_ROOT)}") + if readme_drift: + print(f" - drift in {README_MD.relative_to(REPO_ROOT)}") + return 1 + print(f"Release notes are up-to-date ({len(releases)} releases).") + return 0 + + if releases_drift: + RELEASES_MD.write_text(new_releases, encoding="utf-8") + if readme_drift: + README_MD.write_text(new_readme, encoding="utf-8") + + print(f"Synced {len(releases)} releases.") + print(f" - {RELEASES_MD.relative_to(REPO_ROOT)}: {'updated' if releases_drift else 'unchanged'}") + print(f" - {README_MD.relative_to(REPO_ROOT)}: {'updated' if readme_drift else 'unchanged'}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 000000000..4bbd4fe65 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1,20 @@ +# Dependencies +/node_modules + +# Production build +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/website/README.md b/website/README.md new file mode 100644 index 000000000..76918dad8 --- /dev/null +++ b/website/README.md @@ -0,0 +1,51 @@ +# MCP for Unity — Documentation Site + +Docusaurus 3.x site for MCP for Unity. Deployed to https://coplaydev.github.io/unity-mcp/ by `.github/workflows/docs-deploy.yml` on every push to `beta` that touches `website/**`, `docs/**`, or the Python tool registry. + +## Local development + +```bash +cd website +npm install +npm run start # serves at http://localhost:3000/unity-mcp/ +``` + +Edits to Markdown under `docs/` hot-reload. + +## Build + +```bash +npm run build # outputs to website/build/ +npm run serve # serves the build for local verification +``` + +## Layout + +``` +website/ + docs/ Markdown content + getting-started/ Overview, install, setup wizard, first prompt + guides/ How-to content (migrated in M2) + reference/ Tool & resource reference (auto-generated in M3) + architecture/ System design notes + contributing/ Dev setup, testing, releases + migrations/ Version-upgrade guides + src/ + css/custom.css Theme overrides + static/ + img/ Logo, favicon, social card + docusaurus.config.js Site config — brand title/URL/social links live here + sidebars.js Navigation tree +``` + +## Brand-neutral URL policy + +URL slugs must NOT contain `mcp-for-unity` or `unity-mcp`. The brand name lives in `docusaurus.config.js` (`title`, `tagline`, navbar/footer copy). A future product rename should touch this file and content text — not URL paths. See the rename-proofing section of the plan. + +## Adding a redirect when renaming a slug + +Never rename a published slug without adding an entry to `plugin-client-redirects` in `docusaurus.config.js`. External backlinks must keep working. + +## Tool reference (M3+) + +Files under `docs/reference/tools/` and `docs/reference/resources/` are **generated** from the Python `@mcp_for_unity_tool` and `@mcp_for_unity_resource` registries by `tools/generate_docs_reference.py`. Do not hand-edit those files outside the `` blocks — the generator will overwrite them. diff --git a/docs/manage-physics-patch.md b/website/docs/architecture/manage-physics.md similarity index 100% rename from docs/manage-physics-patch.md rename to website/docs/architecture/manage-physics.md diff --git a/website/docs/architecture/project-roadmap.md b/website/docs/architecture/project-roadmap.md new file mode 100644 index 000000000..dad49420d --- /dev/null +++ b/website/docs/architecture/project-roadmap.md @@ -0,0 +1,82 @@ +--- +id: project-roadmap +slug: /architecture/project-roadmap +title: Project Roadmap +sidebar_label: Project Roadmap +description: Living document — goals, current focus, mid-term and long-term plans for MCP for Unity. Maintained alongside the GitHub wiki. +--- + +# Project Roadmap + +A living document outlining MCP for Unity's high-level goals, priorities, and planned features. It evolves with community feedback, technical discoveries, and shifting priorities. + +For the deep-research **2026 Feature Roadmap** (per-tool API coverage analysis), see [Feature Roadmap 2026](/architecture/roadmap). + +**Want to contribute or discuss?** See [How to Contribute or Provide Feedback](#how-to-contribute-or-provide-feedback). + +## Overall Vision & Goals + +The primary goal is to provide a robust, flexible, and easy-to-use bridge between the Unity Editor and external MCP clients (Claude Desktop, Cursor, and beyond). + +Key objectives: + +1. **Make onboarding effortless** — setting up the MCP server is a known pain point for the ecosystem and this project; we'll make it easier to get started. +2. **Improve speed & efficiency** — reduce latency and token usage for faster workflows. +3. **Expand integrations** — more MCP clients, better MCP server discovery, improved auth. +4. **Improve developer experience** — clean APIs, clearer docs, maintainable architecture. +5. **Align with real user needs** — prioritize community- and customer-driven improvements from feedback. + +## Current Focus + +Legend: **Feat** = feature, **Fix** = bug fix, **Imp** = improvement, **Doc** = docs, **Test** = tests, **Tech** = tech debt / refactor, **Arch** = architecture. + +- **Doc** — Documentation overhaul to improve clarity, onboarding, and discoverability +- **Imp** — Per-call instance routing — target specific Unity instances on any tool call ([#772](https://github.com/CoplayDev/unity-mcp/pull/772)) +- **Fix** — Code Coverage dependency guard for fresh installs ([#540](https://github.com/CoplayDev/unity-mcp/issues/540)) + +## Mid-Term Plans + +Items aimed for further out. Details and priorities are less defined. + +- **Feat** — Explore Runtime MCP Operation ([Discussion #781](https://github.com/CoplayDev/unity-mcp/discussions/781)) +- **Feat** — Explore adding GenAI plugins for 2D and 3D assets ([Discussion #778](https://github.com/CoplayDev/unity-mcp/discussions/778)) +- **Tech** — Re-evaluate script editing capabilities and consolidate + +## Long-Term Ideas & Future Directions + +Bigger ideas or major features further down the line (>6–9 months) or requiring significant research / design. + +- **Arch** — Dependency Injection to improve testability +- **Feat** — Add more play mode functionality — support MCP during runtime with custom tools would let LLMs interact with user-created games / experiences + +## Maybe / Icebox / Backlog + +Suggested or considered but not currently planned. May be revisited later. + +- Visual scripting integration (e.g., Bolt / PlayMaker) +- **Test** — Test coverage for Tools, networking, and ideally end-to-end +- **Imp** — Docker support for running the MCP server ([Discussion #776](https://github.com/CoplayDev/unity-mcp/discussions/776)) +- **Imp** — Tool search / tool filtering to reduce context ([Discussion #777](https://github.com/CoplayDev/unity-mcp/discussions/777)) + +## Recently Completed + +- **Feat** — Per-call `unity_instance` routing via tool arguments ([#772](https://github.com/CoplayDev/unity-mcp/pull/772)) — supersedes CLI flags approach +- **Feat** — HTTP Server Authentication ([#433](https://github.com/CoplayDev/unity-mcp/issues/433)) +- **Feat** — Flag to make custom tools available globally or by project ([#416](https://github.com/CoplayDev/unity-mcp/issues/416)) +- **Fix** — High resource costs when not in use ([#577](https://github.com/CoplayDev/unity-mcp/issues/577)) +- **Imp** — Use MCP for Unity via the CLI ([#544](https://github.com/CoplayDev/unity-mcp/pull/544)) +- **Imp** — OpenCode Support ([#498](https://github.com/CoplayDev/unity-mcp/pull/498)) + +For details on past releases, see [Release Notes](/releases) or the [GitHub Releases page](https://github.com/CoplayDev/unity-mcp/releases). + +## How to Contribute or Provide Feedback + +1. **Discuss ideas:** use [GitHub Discussions](https://github.com/CoplayDev/unity-mcp/discussions) to discuss roadmap items or propose new ones. +2. **Request features:** [open a new issue](https://github.com/CoplayDev/unity-mcp/issues/new) using the Feature Request template. **Check existing issues first.** +3. **Report bugs:** [open a bug report](https://github.com/CoplayDev/unity-mcp/issues/new). Provide clear steps to reproduce. +4. **Contribute code / docs:** see [CONTRIBUTING.md](https://github.com/CoplayDev/unity-mcp/blob/beta/CONTRIBUTING.md). Look for issues tagged `help wanted` or `good first issue`. Review open [Pull Requests](https://github.com/CoplayDev/unity-mcp/pulls). +5. **Comment on issues / PRs:** provide feedback directly on the issues and PRs linked above. + +## Disclaimer + +This roadmap is a high-level overview of potential future direction. It is not a commitment or guarantee. Priorities and timelines may change based on community feedback, resource availability, technical challenges, and strategic shifts. Refer to specific GitHub Issues and Milestones for the most granular, up-to-date status. diff --git a/website/docs/architecture/python-layers.md b/website/docs/architecture/python-layers.md new file mode 100644 index 000000000..0292db637 --- /dev/null +++ b/website/docs/architecture/python-layers.md @@ -0,0 +1,71 @@ +--- +id: python-layers +slug: /architecture/python-layers +title: Three-Layer Python Design +sidebar_label: Three-Layer Python Design +description: The Python server has three independent surfaces — MCP tools, CLI commands, and resources — that all funnel into the same C# Editor handlers. +--- + +# Three-Layer Python Design + +The Python server (`Server/src/`) exposes three distinct surfaces. They look similar but serve different consumers and are **not auto-generated from each other**. + +| Layer | Where | Framework | Consumer | Transport to Unity | +|---|---|---|---|---| +| **MCP Tools** | `Server/src/services/tools/` | FastMCP (`@mcp_for_unity_tool`) | AI assistants via MCP | WebSocket (`send_with_unity_instance`) | +| **CLI Commands** | `Server/src/cli/commands/` | Click (`@click.command`) | Developers in a terminal | HTTP (`run_command`) | +| **Resources** | `Server/src/services/resources/` | FastMCP (`@mcp_for_unity_resource`) | AI assistants, read-only | WebSocket | + +Both MCP tools and CLI commands eventually call the same C# `HandleCommand` methods inside `MCPForUnity/Editor/Tools/`. Resources are read-only — they observe state without mutating it. + +## Why three layers, not one + +Each surface has a different shape of consumer: + +- **MCP tools** need rich type annotations (`Annotated[Type, "description"]`) because they're handed to an LLM. The descriptions are the prompt the LLM reads. +- **CLI commands** need composable flags, shell-friendly defaults, and graceful error messages. Click gives those for free. +- **Resources** need to be cheap to call repeatedly because the LLM polls them. They use a lighter decorator and skip the routing middleware. + +Trying to autogenerate one layer from another erodes the ergonomics of all three. The cost is keeping the three in sync — which is mostly a discipline problem solved by domain symmetry. + +## Domain symmetry + +When you add a new domain (say, `manage_navigation`), you write **three** files: + +``` +Server/src/services/tools/manage_navigation.py # @mcp_for_unity_tool +Server/src/cli/commands/navigation.py # @click.command +MCPForUnity/Editor/Tools/ManageNavigation.cs # [McpForUnityTool] +``` + +The Python tool and CLI command both invoke the C# handler — they just take different paths to it. + +## Tool registration + +Tools are auto-discovered by walking `Server/src/services/tools/`. Each `.py` file with `@mcp_for_unity_tool`-decorated functions is imported at server startup; the decorator side-effects populate a global registry (`services.registry`). The registry is also what `tools/generate_docs_reference.py` reads to emit the [tool reference](/reference/tools). + +A tool's `group` parameter controls per-session visibility — see [Tool Groups](/guides/tool-groups). `group=None` means the tool is always visible (server meta-tools like `set_active_instance` and `manage_tools`). + +## Where the layers diverge from "just call the C# handler" + +- **MCP tools** add parameter normalization (camelCase → snake_case via `ParamNormalizerMiddleware`), telemetry, and per-session routing. +- **CLI commands** add `@handle_unity_errors` for terminal-friendly stack traces, and synchronous wrappers around the async core. +- **Resources** skip middleware entirely — they're meant to be hot-path. + +## Server entry point + +`Server/src/main.py` (~935 lines) is the orchestrator: + +1. Builds the FastMCP server +2. Calls `register_all_tools(mcp)` — auto-discovery +3. Calls `register_all_resources(mcp)` — same pattern, different decorator +4. Sets up the WebSocket hub for HTTP transport +5. Configures middleware (telemetry, normalization, instance routing) +6. Starts the transport (`http`/`stdio` from `core.config`) + +## Where to read more + +- Tool/CLI handler shape: `Server/src/services/tools/manage_material.py` is a canonical example +- Registry: `Server/src/services/registry/tool_registry.py` (~130 LOC, the single source the docs reference generator reads) +- Transport: `Server/src/transport/` — plugin hub (`plugin_hub.py`), websocket client, legacy stdio bridge +- C# side: `MCPForUnity/Editor/Tools/ManageMaterial.cs` is the C# half of `manage_material` diff --git a/docs/reference/REMOTE_SERVER_AUTH_ARCHITECTURE.md b/website/docs/architecture/remote-auth.md similarity index 100% rename from docs/reference/REMOTE_SERVER_AUTH_ARCHITECTURE.md rename to website/docs/architecture/remote-auth.md diff --git a/docs/feature-roadmap-2026.md b/website/docs/architecture/roadmap.md similarity index 100% rename from docs/feature-roadmap-2026.md rename to website/docs/architecture/roadmap.md diff --git a/docs/reference/TELEMETRY.md b/website/docs/architecture/telemetry.md similarity index 100% rename from docs/reference/TELEMETRY.md rename to website/docs/architecture/telemetry.md diff --git a/website/docs/architecture/transports.md b/website/docs/architecture/transports.md new file mode 100644 index 000000000..1b1abc2ed --- /dev/null +++ b/website/docs/architecture/transports.md @@ -0,0 +1,98 @@ +--- +id: transports +slug: /architecture/transports +title: Transport Modes +sidebar_label: Transport Modes +description: HTTP versus stdio — when to use each, what the trade-offs are, and how multi-agent isolation works. +--- + +# Transport Modes + +MCP for Unity supports two transports between the MCP client and the Python server. The choice affects multi-agent capability, configuration shape, and a few subtle behaviors around instance routing. + +## Quick decision + +| If you want… | Use | +|---|---| +| Multiple MCP clients sharing one Unity instance | **HTTP** | +| Multiple Unity instances driven from one client | either | +| Lowest setup friction | **stdio** (Claude Desktop default) | +| Remote-hosted server (cloud, Docker) | **HTTP** | +| Marketplace distribution that can't ship Python | **HTTP** (remote URL) | + +## HTTP (default) + +**Architecture:** one Python process, one shared WebSocket hub at `/hub/plugin`, multiple MCP clients can connect concurrently. Each client gets a `client_id` and session-keyed state. + +**Endpoint:** `http://localhost:8080/mcp` + +**MCP client config:** + +```json +{ + "mcpServers": { + "unityMCP": { "url": "http://localhost:8080/mcp" } + } +} +``` + +**What you gain:** +- Multi-agent: Claude Code and Cursor open at the same time, both seeing the same Unity Editor +- Session isolation: each client's active instance, tool-group visibility, and middleware state are independent +- Remote hosting: the server can run on a different machine or in a container + +**What you give up:** +- Port-number shorthand for `set_active_instance` (HTTP enforces `Name@hash`) +- A small amount of setup complexity if you bind to LAN — see [Security](https://github.com/CoplayDev/unity-mcp/blob/beta/SECURITY.md) + +## Stdio + +**Architecture:** the MCP client spawns a dedicated Python process via `stdio`, communicating over stdin/stdout. The Python process talks to Unity over a legacy TCP bridge. + +**MCP client config (macOS/Linux):** + +```json +{ + "mcpServers": { + "unityMCP": { + "command": "uvx", + "args": ["--from", "mcpforunityserver", "mcp-for-unity", "--transport", "stdio"] + } + } +} +``` + +**What you gain:** +- Lowest configuration friction; works without HTTP port allocation +- Port-number shorthand: `set_active_instance(instance="6401")` +- Claude Desktop only supports stdio — that's why MCP for Unity silently selects stdio when configuring Claude Desktop, even if you have HTTP picked elsewhere + +**What you give up:** +- Single-agent: a new MCP client connection replaces the previous one +- No native session isolation: switching the active Unity instance in one client affects what the next client sees +- Cannot host remotely + +## What "instance" means in each mode + +- **HTTP**: instance state is keyed by `client_id` in middleware. Two clients can hold different active instances concurrently against the same Unity Editor pool. +- **Stdio**: instance state is process-local. Since there's one Python process per client, isolation is implicit — but switching processes loses the old state. + +See [Multi-Instance Routing](/guides/multi-instance) for the routing API. + +## Switching transport + +In the Unity Editor: **Window → MCP for Unity → Settings**, pick `HTTP` or `stdio`, click **Configure All Detected Clients**. The configurator rewrites each client's MCP config to match. + +Claude Desktop is the exception — it's always written as stdio regardless of your selection, because it doesn't support HTTP. + +## Network security (HTTP only) + +By default, HTTP binds to loopback (`127.0.0.1` / `::1`). Binding to all interfaces (`0.0.0.0` / `::`) requires explicit opt-in: **Advanced Settings → Allow LAN Bind (HTTP Local)**. + +Remote endpoints require `https://`. To allow plaintext `http://` for a remote URL, opt in via **Allow Insecure Remote HTTP**. Both guards are fail-closed: if you don't flip the switch, the server refuses the unsafe configuration. + +## Where this is implemented + +- Python: `Server/src/transport/` (plugin hub, websocket transport, legacy stdio bridge) +- C#: `MCPForUnity/Editor/Services/` (transport clients, server management, stdio bridge host) +- v8 migration notes: [/migrations/v8](/migrations/v8) — the architectural story of HTTP arriving diff --git a/website/docs/architecture/unity-compat.md b/website/docs/architecture/unity-compat.md new file mode 100644 index 000000000..7dac2953c --- /dev/null +++ b/website/docs/architecture/unity-compat.md @@ -0,0 +1,65 @@ +--- +id: unity-compat +slug: /architecture/unity-compat +title: Unity API Compatibility Shims +sidebar_label: Unity Compat Shims +description: How MCP for Unity supports Unity 2021 LTS through 6.x and the CoreCLR 6.8 path without sprinkling version gates across every call site. +--- + +# Unity API Compatibility Shims + +MCP for Unity targets a wide Unity version range — **2021.3 LTS → Unity 6.x → CoreCLR 6.8**. Unity has renamed, deprecated, and threatened to remove a handful of APIs across that window. Rather than sprinkle `#if UNITY_*_OR_NEWER` at every call site, MCP for Unity routes the friction through a small set of **shims** under `MCPForUnity/Runtime/Helpers/`. + +## The catalog + +The canonical list lives in `MCPForUnity/Runtime/Helpers/UnityCompatShims.cs` (an intentionally empty marker class — its XML doc is the source of truth and ships inside the UPM package, so end-users can `F12` into it). + +| Shim | Wraps | Deprecated / Removed | +|---|---|---| +| `UnityFindObjectsCompat` | `Object.FindObjectsOfType` → `FindObjectsByType` | 2023.1 | +| `UnityObjectIdCompat` | `InstanceID` ↔ `EntityId` | 6000.3 → 6000.6 (CS0619) | +| `UnityPhysicsCompat` | `Physics{,2D}.autoSyncTransforms`, `autoSimulation` → `simulationMode` | 6000.0 / 2022.2 | +| `UnityAssembliesCompat` | `AppDomain.GetAssemblies` → `UnityEngine.Assemblies.CurrentAssemblies` | Unity 6.8 CoreCLR | + +## When to add a new shim + +One of these must be true: + +1. The API is marked `[Obsolete]` **and** the call site can't simply be deleted, **or** +2. Three or more call sites need version gating for the same API, **or** +3. A future Unity version has publicly announced rename or removal of the API. + +If only one or two call sites are affected and the rename isn't on the roadmap, a localized `#if UNITY_*_OR_NEWER` is fine. Don't pre-shim speculatively. + +## What does **not** belong in a shim + +- Hot-path engine APIs (`Transform.position`, `Vector3.*`, `GetComponent`) — version gating these is noise, and they don't move +- APIs Unity has not threatened to break (`Mathf`, `Quaternion`, most of `AssetDatabase`) — adding a shim implies maintenance forever +- Editor-internal undocumented APIs — those *should* break loudly so the package maintainers notice immediately + +## The pattern + +Two implementation styles, picked by what the SDK exposes: + +- **Static dispatch** (`#if UNITY_*_OR_NEWER`): use when the new API exists in the SDK you compile against. The shim picks the right call site at compile time, with no runtime cost. +- **Reflection with a cached `MethodInfo` / `PropertyInfo`**: use when the new API is in a version you don't yet target, or when the old API may eventually be removed (CS0619). One reflection lookup at static-init time, then plain delegate invocation forever after. + +In both cases, **fail-soft**: callers should treat a missing API as a no-op, never throw. This keeps the package compiling and behaving sensibly on every supported Unity version, including ones the maintainer hasn't tested yet. + +## Compile-checking across versions locally + +`tools/check-unity-versions.sh` runs a compile-only check across the same Unity versions CI runs. The matrix is in `tools/unity-versions.json`. + +```bash +tools/check-unity-versions.sh # compile-only across installed Unity Hub editors +tools/check-unity-versions.sh --full # full EditMode test run +``` + +The pre-push hook (installed via `tools/install-hooks.sh`) runs this automatically when your push touches `MCPForUnity/`, `TestProjects/`, or the version matrix. + +## Source pointers + +- Catalog + policy: `MCPForUnity/Runtime/Helpers/UnityCompatShims.cs` +- Individual shim files: same directory, named `Unity*Compat.cs` +- Unity 6.x deprecation list: Unity upgrade guides +- CoreCLR 6.8 path: [Unity discussion thread](https://discussions.unity.com/t/path-to-coreclr-2026-upgrade-guide/1714279) diff --git a/docs/development/README-DEV.md b/website/docs/contributing/dev-setup.md similarity index 99% rename from docs/development/README-DEV.md rename to website/docs/contributing/dev-setup.md index 54a02bf6e..5db9b3a23 100644 --- a/docs/development/README-DEV.md +++ b/website/docs/contributing/dev-setup.md @@ -1,6 +1,6 @@ # MCP for Unity - Developer Guide -| [English](README-DEV.md) | [简体中文](README-DEV-zh.md) | +| English | [简体中文](https://github.com/CoplayDev/unity-mcp/blob/beta/docs/development/README-DEV-zh.md) | |---------------------------|------------------------------| ## Contributing diff --git a/website/docs/contributing/docs.md b/website/docs/contributing/docs.md new file mode 100644 index 000000000..543122c49 --- /dev/null +++ b/website/docs/contributing/docs.md @@ -0,0 +1,151 @@ +--- +id: docs +slug: /contributing/docs +title: Docs Workflow +sidebar_label: Docs Workflow +description: How the documentation site is built, what's auto-generated, and how to ship a docs change. +--- + +# Docs Workflow + +The documentation site you're reading is built with **Docusaurus 3** and lives under `/website` in the same repo as the code. Every doc change goes through normal PRs. + +## What's hand-written vs. auto-generated + +| Section | Source | Authored by | +|---|---|---| +| Getting Started, Guides, Architecture, Contributing, Migrations | `website/docs/
/*.md` | hand-written | +| **Tool reference** (`/reference/tools/**`) | generated from `Server/src/services/tools/` | `tools/generate_docs_reference.py` | +| **Resource catalog** (`/reference/resources/`) | generated from `Server/src/services/resources/` | same generator | + +The generator owns everything inside the front-matter banner. The **examples block** between `` and `` is hand-written and **preserved across regenerations**. + +## Editing a hand-written page + +1. Find the file under `website/docs/`. +2. Edit the markdown. +3. Local preview: `cd website && npm run start` → http://localhost:3000/unity-mcp/ +4. Commit and PR against `beta`. + +CI runs `npm run build` on every PR via `.github/workflows/docs-deploy.yml`. The PR check fails if the build fails, so dead links and missing pages surface before merge. + +## Adding examples to a generated tool page + +Find the page at `website/docs/reference/tools//.md`. Look for: + +```html + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + +``` + +Replace the placeholder text with your example. **Don't move or rename the markers** — the generator uses them to know where your content is. + +Run the generator to verify your examples survive a regeneration round-trip: + +```bash +cd Server && uv run python ../tools/generate_docs_reference.py +git diff website/docs/reference/tools//.md +# Should show only your additions; the rest of the file is regenerated identically. +``` + +## Adding a new doc page + +1. Create the `.md` file under the appropriate `website/docs/
/`. Front-matter at minimum: + + ```yaml + --- + id: my-page + slug: /
/my-page + title: Page Title + sidebar_label: Short Label + description: One-line description (used in search and OG). + --- + ``` + +2. Add the page to `website/sidebars.js` under the right category. +3. Use **brand-neutral slugs** — never put `mcp-for-unity` or `unity-mcp` in a URL path. The product name lives in `docusaurus.config.js`. + +## When a slug must change + +URL changes break external links. Always add a redirect: + +```js +// website/docusaurus.config.js → plugins → @docusaurus/plugin-client-redirects +{ + redirects: [ + { from: '/old/slug', to: '/new/slug' }, + ], +} +``` + +## When tool/resource registries change + +The pre-commit hook (installed via `tools/install-hooks.sh`) auto-regenerates `website/docs/reference/` whenever you stage a change under `Server/src/services/{tools,resources,registry}/`. Without the hook: + +```bash +cd Server && uv run python ../tools/generate_docs_reference.py +git add website/docs/reference/ +``` + +CI (`.github/workflows/docs-generate.yml`) fails the PR if the committed reference is stale. + +## Release notes sync + +`website/docs/releases.md` and the README's "Recent Updates" block are **both** generated from the GitHub Releases API by `tools/sync_release_notes.py`. The script: + +- Uses `gh api` when available, falls back to `urllib` (with `certifi` if installed) otherwise. +- Renders the full release history into `releases.md`, grouped by minor version, with each release body in a collapsible `
` block. +- Replaces the block between `` and `` in the root `README.md` with the latest five releases. + +CI keeps both in sync automatically via `.github/workflows/sync-releases.yml`. Triggers are intentionally narrow so the workflow never blocks outsider PRs: + +| Trigger | What happens | +|---|---| +| `release.{published,edited,unpublished,deleted}` | Sync fires within ~30 seconds and commits directly to `beta` with `[skip ci]`. This is the canonical entry point — the only time the synced files can legitimately go stale. | +| `workflow_dispatch` | Manual escape hatch (re-run after a one-off UI edit, or to backfill). | + +**Not triggered on `pull_request`.** A drift check at PR time would fail outsider PRs that edit README for unrelated reasons (typo fix, citation tweak), and the contributor wouldn't have push access to regenerate. The synced files are maintained by the release pipeline, not by PR authors. + +To sync manually: + +```bash +python tools/sync_release_notes.py # write +python tools/sync_release_notes.py --check # exit non-zero on drift +``` + +Do not hand-edit `releases.md` or the `recent-updates` block in `README.md` — your change will be overwritten on the next sync. + +## Deploy + +The live site at `https://coplaydev.github.io/unity-mcp/` deploys automatically on push to `beta`. No manual step per change. + +### First-time setup (maintainers only) + +The first deploy requires GitHub Pages to be enabled for the repo: + +1. **Settings → Pages → Source** → choose **GitHub Actions** (not "Deploy from a branch"). +2. Push to `beta` (or run the `Docs — Build & Deploy` workflow via **Actions → Run workflow**). +3. After the deploy job succeeds, the URL appears under **Settings → Pages**. + +The workflow uses `actions/configure-pages@v5` + `actions/deploy-pages@v4`, so once Pages is set to "GitHub Actions" source, the deploy step provisions everything else automatically. + +### Custom domain + +When ready, add a `CNAME` file at `website/static/CNAME` containing the domain (e.g. `unitymcp.dev`), update `url` and `baseUrl` in `docusaurus.config.js`, and configure the DNS provider per [GitHub's custom-domain guide](https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site). + +## Markdown format + +Pages use **CommonMark** (Docusaurus `format: 'detect'` mode), not full MDX. That means `{...}` and `` in body text are literals — no JS-expression parsing. If you need React components, name the file `.mdx` instead of `.md`. + +## Translations + +Chinese versions of `README-DEV.md` and the overview live under `docs/i18n/` and `docs/development/README-DEV-zh.md`. Full Docusaurus i18n setup (with `locales: ['en', 'zh']`) is deferred until the English site is stable. + +## Search + +Local lunr search ships today via `@easyops-cn/docusaurus-search-local`. The Algolia DocSearch application is queued (free for OSS, 4–6 week approval); the swap-in is a config change when the time comes. + +## Typography + +The site uses **Satoshi** (Fontshare) for body and headings and **JetBrains Mono** (Google Fonts) for code. Both load via stylesheet links in `docusaurus.config.js`. Theme overrides live in `website/src/css/custom.css`. diff --git a/docs/guides/RELEASING.md b/website/docs/contributing/releases.md similarity index 100% rename from docs/guides/RELEASING.md rename to website/docs/contributing/releases.md diff --git a/website/docs/contributing/testing.md b/website/docs/contributing/testing.md new file mode 100644 index 000000000..d91416b55 --- /dev/null +++ b/website/docs/contributing/testing.md @@ -0,0 +1,94 @@ +--- +id: testing +slug: /contributing/testing +title: Testing +sidebar_label: Testing +description: How to run Python and Unity tests locally, what CI runs, and how to add new tests. +--- + +# Testing + +Three test suites cover MCP for Unity: Python unit tests, Unity EditMode/PlayMode tests, and a multi-version Unity compile matrix. CI runs all three; you should run the two relevant to your change locally before pushing. + +## Python tests + +Location: `Server/tests/` + +```bash +# All tests +cd Server && uv run pytest tests/ -v + +# Single file +cd Server && uv run pytest tests/test_manage_material.py -v + +# Single test by name pattern +cd Server && uv run pytest tests/ -k "test_create_material" -v +``` + +CI workflow: `.github/workflows/python-tests.yml`. Coverage is uploaded to Codecov on every run. + +### Adding a Python test + +For a new tool `manage_`, add `Server/tests/test_manage_.py`. Existing tests are the best template — most are integration-style: they spin up a fake Unity bridge, call the tool, and assert on the dispatched payload. + +## Unity tests + +Location: `TestProjects/UnityMCPTests/Assets/Tests/` + +- **EditMode** (60+ files): tool validation, parser edge cases, scene paging, domain reload resilience, batch execution, AI property matching, scriptable objects, animation, physics, gameobject lifecycle +- **PlayMode**: basic integration smoke tests + +To run locally, open `TestProjects/UnityMCPTests` in Unity, then **Window → General → Test Runner**. + +CI runs both modes across a multi-Unity matrix via `.github/workflows/unity-tests.yml`. + +### Adding a Unity test + +Mirror the C# tool you're adding. For `ManageNavigation.cs` in `MCPForUnity/Editor/Tools/`, create `TestProjects/UnityMCPTests/Assets/Tests/EditMode/Editor/ManageNavigationTests.cs`. Use the existing assembly definition (`MCPForUnityTests.Editor.asmdef`) so the suite picks it up automatically. + +## Multi-version compile matrix + +This is the most common pre-push surprise: code that builds on your Unity version fails on another supported version because of an API rename. The local matrix check prevents that. + +```bash +tools/check-unity-versions.sh # compile-only across installed Unity Hub editors +tools/check-unity-versions.sh --full # full EditMode test run on each version +``` + +The matrix is `tools/unity-versions.json`. The script discovers Unity installations via Unity Hub's standard locations on macOS, Windows, and Linux. + +When you touch anything in `MCPForUnity/Runtime/Helpers/Unity*Compat.cs` or any `#if UNITY_*_OR_NEWER` block, run this. The [Unity Compat Shims](/architecture/unity-compat) doc explains the policy. + +## Pre-push hook + +`tools/install-hooks.sh` installs a pre-push hook that runs `check-unity-versions.sh` in compile-only mode when your push touches Unity-relevant paths. One-time setup: + +```bash +tools/install-hooks.sh +``` + +To bypass for a single push: `git push --no-verify`. Use this when you're pushing docs-only or pure Python changes. + +## Pre-commit hook (docs reference) + +The same install script wires a pre-commit hook that regenerates `website/docs/reference/` whenever you stage a change under `Server/src/services/{tools,resources,registry}/`. CI fails if you skip this and the committed reference drifts — see `.github/workflows/docs-generate.yml`. + +## Stress / load testing + +Two scripts under `tools/`: + +- `stress_mcp.py` — concurrent MCP tool calls; surfaces middleware contention +- `stress_editor_state.py` — hammers the `editor_state` resource; surfaces serialization hotspots + +These are not part of CI; run them when you change transport, middleware, or hot-path serialization. + +## What CI actually runs on every PR + +| Workflow | Trigger | Duration | What it asserts | +|---|---|---|---| +| `python-tests.yml` | `Server/**` changes | ~2 min | `pytest` clean, coverage uploaded | +| `unity-tests.yml` | `MCPForUnity/**` / `TestProjects/**` changes | ~15 min × N versions | EditMode + PlayMode tests clean across the matrix | +| `docs-deploy.yml` | `website/**`, `docs/**`, tool/resource registry changes | ~1 min (build) | Docusaurus build succeeds; on push to `beta`, deploys to GitHub Pages | +| `docs-generate.yml` | same triggers as docs-deploy | ~1 min | Reference docs are not stale; decorator count matches MD count | + +Skip-equivalent: if the only files you changed are README, governance, or unrelated metadata, only the relevant subset of these fires. diff --git a/website/docs/getting-started/clients.md b/website/docs/getting-started/clients.md new file mode 100644 index 000000000..0be1ff516 --- /dev/null +++ b/website/docs/getting-started/clients.md @@ -0,0 +1,53 @@ +--- +id: clients +slug: /getting-started/clients +title: Choosing an MCP Client +sidebar_label: Choosing a Client +description: Capability matrix across every MCP client MCP for Unity auto-configures. +--- + +# Choosing an MCP Client + +MCP for Unity auto-configures every client the package detects on your machine. The differences below decide which one fits your workflow. + +## Capability matrix + +| Client | Transport | Auto-config | Streaming reasoning | Free tier | Notes | +|---|---|---|---|---|---| +| **Claude Desktop** | stdio only | yes | yes | yes (rate-limited) | Easiest setup. Stdio is silently chosen even if HTTP is selected globally. | +| **Claude Code** | HTTP | yes | yes | needs Anthropic plan | First-party. Strong with multi-tool workflows. | +| **Cursor** | HTTP | yes | yes | partial | Requires an MCP toggle in Cursor's own settings after auto-config. | +| **VS Code (Copilot)** | HTTP | yes | yes | with Copilot | Configures under `servers` (not `mcpServers`). | +| **Windsurf** | HTTP | yes | yes | yes | Auto-connects after config. | +| **Cline** | HTTP | yes | yes | yes | Auto-connects after config. | +| **GitHub Copilot CLI** | HTTP | yes | yes | with Copilot | Terminal-based agent. | +| **Codex** | HTTP | yes | yes | with OpenAI | Auto-connects. | +| **Qwen Code** | HTTP | yes | yes | yes | Auto-connects. | +| **Gemini CLI** | HTTP | yes | yes | yes | Auto-connects. | +| **OpenClaw** | HTTP / stdio | yes | yes | yes | Requires `openclaw-mcp-bridge` plugin enabled. Follows MCP for Unity's transport choice. | +| **Antigravity** | HTTP | yes | yes | varies | Requires an MCP toggle in Antigravity settings. | + +## How to pick + +- **You want it to just work**: Claude Desktop. Stdio means no port conflicts and no firewall prompts. +- **You're building a multi-agent or remote workflow**: anything HTTP. Multiple clients can share one Python server; see [Multi-Instance Routing](/guides/multi-instance). +- **You're already in your IDE**: Cursor, VS Code Copilot, or Cline — keeps you in flow. +- **You want a terminal**: Claude Code, Copilot CLI, Codex, Gemini CLI, or Qwen Code. + +## Manual configuration + +If auto-config doesn't run (offline machine, sandboxed install, etc.), copy the snippet under **Manual MCP client configuration** in [Install](./install) into your client's MCP config file. + +## Per-client toggle locations + +A few clients need an MCP toggle flipped on after the configurator writes their config. Find it here: + +- **Cursor** → Settings → MCP → enable the `unityMCP` server +- **Antigravity** → Settings → MCP servers → enable +- **OpenClaw** → enable the `openclaw-mcp-bridge` plugin + +Everything else just connects on next launch. + +## When you update the package + +Run **Window → MCP for Unity → Configure All Detected Clients** any time. It's safe to re-run — the configurator writes idempotently. diff --git a/website/docs/getting-started/first-prompt.md b/website/docs/getting-started/first-prompt.md new file mode 100644 index 000000000..ab4ea4e9b --- /dev/null +++ b/website/docs/getting-started/first-prompt.md @@ -0,0 +1,62 @@ +--- +id: first-prompt +slug: /getting-started/first-prompt +title: Your First Prompt +sidebar_label: Your First Prompt +description: End-to-end walkthrough — from typing a prompt to seeing the result in your Unity scene. +--- + +# Your First Prompt + +You've installed the package and connected a client. Here's what to actually say. + +## Prerequisites + +- [Install](./install) is complete +- The MCP for Unity status panel reads `Connected` +- Your scene is open in the Unity Editor (any scene will do — even an empty one) + +## The prompt + +In your MCP client (Claude Desktop, Cursor, etc.), say: + +> Create a red, blue, and yellow cube in the current scene, spaced one unit apart on the X axis. + +The assistant should: + +1. Call `manage_scene` (or `find_gameobjects`) to inspect the active scene +2. Call `manage_gameobject` three times to create cubes +3. Call `manage_material` to create or assign colored materials +4. Call `manage_components` to attach the material to each cube's MeshRenderer + +Total round trip is usually 5–15 seconds depending on your network and the client. + +## What you should see in Unity + +Three cubes appear in the **Hierarchy** panel. Switch to the Scene view to see them laid out. If the materials are correct, they'll render red, blue, and yellow. + +If the cubes appear but materials are missing (gray), your project may be using URP/HDRP — the LLM should detect this from `manage_graphics` but sometimes guesses Standard. Tell it explicitly: *"This project uses URP, please use the URP/Lit shader."* + +## Stretching it + +Try escalating prompts in the same session: + +> Add a directional light if there isn't one, and a perspective camera positioned at (0, 2, -5) looking at the cubes. + +> Write a C# script that makes the red cube oscillate up and down by 0.5 units, attach it to the red cube, and enter Play mode. + +> Run all tests in EditMode and report which ones fail. + +Each of these uses a different tool group — `core` for objects/scripts, `core` again for editor mode control, `testing` for test runs (you may need to activate the `testing` group first; see [Tool Groups](/guides/tool-groups)). + +## When something goes wrong + +- **"I couldn't find any Unity instance"** — the server isn't reachable. Check the status panel. +- **"Multiple Unity instances detected"** — you have more than one Editor open. See [Multi-Instance Routing](/guides/multi-instance). +- **Tool calls succeed but nothing happens in the scene** — your client may be in dry-run mode, or you might have hit an MCP visibility toggle for the relevant tool. Ask the assistant to call `manage_tools` action `list_groups`. + +## What to read next + +- [Choosing an MCP Client](./clients) — capability differences across clients +- [Tool Groups](/guides/tool-groups) — enabling vfx, animation, ui, testing, etc. +- [Tool reference](/reference/tools) — every available tool with parameters diff --git a/website/docs/getting-started/index.md b/website/docs/getting-started/index.md new file mode 100644 index 000000000..2db6581be --- /dev/null +++ b/website/docs/getting-started/index.md @@ -0,0 +1,39 @@ +--- +id: index +slug: /getting-started +title: Overview +sidebar_label: Overview +description: AI-driven game development for the Unity Editor via the Model Context Protocol. +--- + +# Overview + +MCP for Unity bridges AI assistants — Claude, Codex, VS Code, local LLMs, and more — with the Unity Editor via the [Model Context Protocol](https://modelcontextprotocol.io/introduction). Give your LLM the tools to manage assets, control scenes, edit scripts, run tests, and automate workflows. + +![MCP for Unity building a scene](https://raw.githubusercontent.com/CoplayDev/unity-mcp/beta/docs/images/building_scene.gif) + +## What you get + +- **40+ Unity Editor tools** exposed over MCP — `manage_scene`, `manage_script`, `manage_gameobject`, `manage_material`, `manage_physics`, `run_tests`, and more. +- **25+ read-only resources** for state introspection — `editor_state`, `gameobject_components`, `project_info`, `unity_instances`, etc. +- **Auto-configuration** for popular MCP clients — Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Cline, Codex, Qwen, Gemini CLI, Copilot CLI, OpenClaw. +- **Multi-instance support** — drive several Unity Editors from a single session via `set_active_instance`. +- **Two transports** — HTTP (multi-agent, default) and stdio (single-agent legacy). + +## When you'd use it + +- Prototype scenes and gameplay with natural language ("build a player controller with WASD and a double-jump"). +- Generate and refactor C# scripts with full project context and validation. +- Automate repetitive editor tasks — bulk asset processing, scene validation, regression testing. +- Build custom AI-driven editor tools on top of the MCP protocol. + +## Next steps + +- **[Install](./install.md)** — Add the Unity package, install the Python server, and connect your first MCP client. +- **[Your First Prompt](./first-prompt.md)** — End-to-end "build me a red cube" tutorial. +- **[Choosing an MCP Client](./clients.md)** — A capability matrix across all supported clients. +- **Setup Wizard** *(coming soon)* — Walk through the first-run experience. + +--- + +MIT licensed. Sponsored and maintained by [Aura](https://www.tryaura.dev/). Not affiliated with Unity Technologies. diff --git a/website/docs/getting-started/install.md b/website/docs/getting-started/install.md new file mode 100644 index 000000000..fa4159468 --- /dev/null +++ b/website/docs/getting-started/install.md @@ -0,0 +1,139 @@ +--- +id: install +slug: /getting-started/install +title: Install +sidebar_label: Install +description: Add MCP for Unity to your Unity project and connect an MCP client. +--- + +# Install + +Three install paths are supported. Pick one. **Git URL** is the fastest if you just want to try it. + +## Prerequisites + +- **Unity 2021.3 LTS or newer** — [Download Unity](https://unity.com/download) +- **Python 3.10+** with [`uv`](https://docs.astral.sh/uv/getting-started/installation/) — the setup wizard guides you through both if missing +- **An MCP client** — [Claude Desktop](https://claude.ai/download), [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Cursor](https://www.cursor.com/), [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview), [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli), [Windsurf](https://windsurf.com/), [Cline](https://cline.bot/), [OpenClaw](https://openclaw.ai/), and more + +## Option 1 — Git URL (fastest) + +In Unity, open **Window → Package Manager**, click the **`+`** button, choose **Add package from git URL...**, and paste: + +```text +https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main +``` + +For the latest beta features, use the `beta` branch: + +```text +https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#beta +``` + +## Option 2 — Unity Asset Store + +1. Visit [MCP for Unity on the Asset Store](https://assetstore.unity.com/packages/tools/generative-ai/mcp-for-unity-ai-driven-development-329908). +2. Click **Add to My Assets**. +3. Import via **Window → Package Manager → My Assets**. + +## Option 3 — OpenUPM + +```bash +openupm add com.coplaydev.unity-mcp +``` + +## Start the server and connect + +After import, MCP for Unity opens a **setup wizard** automatically. + +1. Confirm Python and `uv` are installed — the wizard guides you through both if missing. +2. Click **Done**. Once dependencies are green, a list of MCP clients detected on your machine appears. +3. Pick the clients you want to configure and click **Configure Selected**. + +You can return to this UI anytime via **Window → MCP for Unity** to start/stop the server, switch transport (HTTP vs stdio), or reconfigure clients. The status panel reads `Connected` when everything is wired up. + +### First prompt + +Try one of these in your MCP client: + +> Create a red, blue, and yellow cube in the current scene. + +> Build a simple player controller with WASD movement and a double-jump. + +> List every script in `Assets/Scripts` and tell me which ones reference `Rigidbody`. + +## Per-client notes + +- **Claude Desktop** only supports stdio. MCP for Unity will silently configure it that way even if you have HTTP selected elsewhere. +- **Cursor, Antigravity, OpenClaw** still require enabling an MCP toggle or plugin in their own settings after auto-configuration. +- **OpenClaw** also needs the `openclaw-mcp-bridge` plugin enabled and follows the currently selected MCP for Unity transport. +- **Claude Code, VS Code, Windsurf, Cline, and the CLI clients** auto-connect after configuration. + +Detailed per-client setup lives in the [MCP Client Configurators guide](/guides/client-configurators). + +## Manual MCP client configuration + +If auto-configuration doesn't work for your client, add this to your client's MCP config file: + +### HTTP (default — Cursor, Windsurf, Antigravity, VS Code, Cline, etc.) + +```json +{ + "mcpServers": { + "unityMCP": { + "url": "http://localhost:8080/mcp" + } + } +} +``` + +### VS Code + +```json +{ + "servers": { + "unityMCP": { + "type": "http", + "url": "http://localhost:8080/mcp" + } + } +} +``` + +### Stdio (Claude Desktop, or any client without HTTP) + +**macOS / Linux:** + +```json +{ + "mcpServers": { + "unityMCP": { + "command": "uvx", + "args": ["--from", "mcpforunityserver", "mcp-for-unity", "--transport", "stdio"] + } + } +} +``` + +**Windows:** + +```json +{ + "mcpServers": { + "unityMCP": { + "command": "C:/Users/YOUR_USERNAME/AppData/Local/Microsoft/WinGet/Links/uvx.exe", + "args": ["--from", "mcpforunityserver", "mcp-for-unity", "--transport", "stdio"] + } + } +} +``` + +## Troubleshooting + +- **Unity Bridge not connecting** — Open **Window → MCP for Unity** and check the status panel. Restart Unity if needed. +- **Server not starting** — Verify `uv --version` works in your terminal. Check the MCP for Unity log for errors. +- **Client not connecting** — Confirm the HTTP server is running on `localhost:8080` and the URL in your client config matches. + +For Cursor / VS Code / Windsurf and Claude Code troubleshooting, see the [GitHub Wiki](https://github.com/CoplayDev/unity-mcp/wiki) *(migrating into this site)*. + +Still stuck? [Open an issue](https://github.com/CoplayDev/unity-mcp/issues) or [join Discord](https://discord.gg/y4p8KfzrN4). diff --git a/website/docs/guides/claude-code-cli.md b/website/docs/guides/claude-code-cli.md new file mode 100644 index 000000000..64f02e015 --- /dev/null +++ b/website/docs/guides/claude-code-cli.md @@ -0,0 +1,72 @@ +--- +id: claude-code-cli +slug: /guides/claude-code-cli +title: Install or Repair Claude Code CLI +sidebar_label: Claude Code CLI +description: Install or repair the Claude Code CLI (claude) so MCP for Unity can launch it. +--- + +# Install or Repair Claude Code CLI + +You need the Claude Code CLI (`claude`) available on your system. + +:::caution Switching transport requires a restart +If you change from `http` to `stdio` (or vice versa) in the MCP for Unity window, **restart Claude Code** for it to pick up the change. +::: + +## Recommended (native installers) + +**macOS / Linux / WSL:** + +```bash +curl -fsSL https://claude.ai/install.sh | bash +claude doctor +``` + +**Windows PowerShell:** + +```powershell +irm https://claude.ai/install.ps1 | iex +claude doctor +``` + +## Alternative: npm via NVM (installs under `~/.nvm`) + +```bash +# Install / select a Node version +nvm install v21.7.1 +nvm use v21.7.1 + +# Install Claude Code CLI into this Node's global prefix +npm install -g @anthropic-ai/claude-code + +# Verify it's under NVM +which claude +claude --version +``` + +## Alternative: npm with system / Homebrew Node + +```bash +# If you don't have Node yet (macOS): +brew install node + +# Install Claude Code CLI globally +npm install -g @anthropic-ai/claude-code + +# Verify it's on PATH (typical: /opt/homebrew/bin/claude or /usr/local/bin/claude) +which claude +claude --version +``` + +## macOS PATH gotcha + +On macOS, Unity launched from Finder / Hub may not inherit your shell PATH. If `claude` isn't found: + +- **Either** launch Hub from Terminal (so PATH propagates), +- **or** use the MCP for Unity window's **"Choose Claude Install Location"** to set the absolute path. + +## Related troubleshooting + +- macOS dyld ICU library errors: see [Common Setup Problems → macOS Claude CLI dyld error](/guides/troubleshooting#macos-claude-cli-fails-to-start-dyld-icu-library-not-loaded) +- "Claude Not Found" in the Register button: see the FAQ in [Common Setup Problems](/guides/troubleshooting#faq--claude-code) diff --git a/docs/guides/CLI_EXAMPLE.md b/website/docs/guides/cli-examples.md similarity index 98% rename from docs/guides/CLI_EXAMPLE.md rename to website/docs/guides/cli-examples.md index 6034b5147..9872723fa 100644 --- a/docs/guides/CLI_EXAMPLE.md +++ b/website/docs/guides/cli-examples.md @@ -1,4 +1,10 @@ -## Unity MCP (CLI Mode) +--- +title: CLI Examples +sidebar_label: CLI Examples +description: Worked examples of using MCP for Unity in CLI mode. +--- + +# Unity MCP (CLI Mode) We use Unity MCP via **CLI commands** instead of MCP server connection. This avoids the reconnection issues that occur when Unity restarts. diff --git a/docs/guides/CLI_USAGE.md b/website/docs/guides/cli.md similarity index 100% rename from docs/guides/CLI_USAGE.md rename to website/docs/guides/cli.md diff --git a/docs/guides/MCP_CLIENT_CONFIGURATORS.md b/website/docs/guides/client-configurators.md similarity index 100% rename from docs/guides/MCP_CLIENT_CONFIGURATORS.md rename to website/docs/guides/client-configurators.md diff --git a/docs/reference/CUSTOM_TOOLS.md b/website/docs/guides/custom-tools.md similarity index 100% rename from docs/reference/CUSTOM_TOOLS.md rename to website/docs/guides/custom-tools.md diff --git a/website/docs/guides/multi-instance.md b/website/docs/guides/multi-instance.md new file mode 100644 index 000000000..f03b76091 --- /dev/null +++ b/website/docs/guides/multi-instance.md @@ -0,0 +1,82 @@ +--- +id: multi-instance +slug: /guides/multi-instance +title: Multi-Instance Routing +sidebar_label: Multi-Instance Routing +description: Drive several Unity Editors from a single MCP session with set_active_instance and per-call routing. +--- + +# Multi-Instance Routing + +You can have several Unity Editors open at once and aim a single MCP session at any of them. + +## When this comes up + +- You're refactoring a shared package and need to test the same change in two projects +- You're comparing behavior between Unity LTS and Unity 6 +- You have a runtime project + a tooling project both connected +- You're driving a CI fixture project alongside your day-to-day work + +## How instances are identified + +Each connected Unity Editor advertises a stable ID of the form `Name@hash`, where: + +- `Name` is the project's `productName` from Player Settings +- `hash` is a stable 8-character hash derived from the project path + +Example: `MyGame@a1b2c3d4`. + +You can also reference an instance by: + +- **Hash prefix** (e.g. `a1b` if it's unambiguous) +- **Port number** — stdio transport only + +## Discovering instances + +Read the resource: + +> `mcpforunity://instances` + +It returns the list of currently connected Editors with their `Name@hash`, project path, transport, and port. Most MCP clients expose this as the `unity_instances` resource. + +## Setting the active instance for the session + +``` +set_active_instance(instance="MyGame@a1b2c3d4") +``` + +Once set, **every subsequent tool call** in the session routes to that instance until you change it. This is the most common pattern: choose once, then prompt normally. + +You can also use: + +``` +set_active_instance(instance="a1b") # hash prefix +set_active_instance(instance="6401") # port number (stdio only) +``` + +## Routing a single call without changing the session default + +Pass `unity_instance` on the individual tool call: + +``` +manage_scene(action="get_hierarchy", unity_instance="MyGame@a1b2c3d4") +``` + +This is useful for comparing two projects in the same prompt — e.g., "Read the same script from both projects and tell me what differs." + +The server accepts the same value formats as `set_active_instance`: `Name@hash`, hash prefix, or (stdio) port number. + +## What happens with no active instance + +- **One Unity Editor connected** → it's used automatically. +- **Multiple Editors connected and no active set** → the server errors with the available instance list. Call `set_active_instance` and retry. + +## HTTP vs stdio differences + +- **HTTP**: instance state is keyed per-session by `client_id`, so two MCP clients can target different Editors at the same time on the same Python server. +- **Stdio**: port-number shorthand works because there's a separate Python process per client. HTTP shares one process and uses `Name@hash` exclusively. + +## Related reference + +- [`set_active_instance`](/reference/tools/core/set_active_instance) — full tool reference +- [`unity_instances` resource](/reference/resources) — discovery surface diff --git a/docs/guides/REMOTE_SERVER_AUTH.md b/website/docs/guides/remote-server-auth.md similarity index 100% rename from docs/guides/REMOTE_SERVER_AUTH.md rename to website/docs/guides/remote-server-auth.md diff --git a/website/docs/guides/roslyn.md b/website/docs/guides/roslyn.md new file mode 100644 index 000000000..3f27a1a6e --- /dev/null +++ b/website/docs/guides/roslyn.md @@ -0,0 +1,54 @@ +--- +id: roslyn +slug: /guides/roslyn +title: Roslyn Script Validation (Advanced) +sidebar_label: Roslyn Validation +description: Enable strict C# validation that catches undefined namespaces, types, and methods before the script reaches the Unity compiler. +--- + +# Roslyn Script Validation + +By default, MCP for Unity uses a fast structural validator for scripts the LLM generates. For **strict** validation that catches undefined namespaces, types, and methods at write time — without a full Unity compile — install the optional Roslyn DLLs. + +Most users don't need this. Enable it when: + +- You're letting the LLM write a lot of unsupervised C# and want stricter feedback loops +- You're seeing recurring compile errors that survive the structural validator +- You're building custom tools that depend on accurate symbol resolution + +## One-click installer (recommended) + +1. Open **Window → MCP for Unity**. +2. Scroll to the **Runtime Code Execution (Roslyn)** section in the Scripts / Validation tab. +3. Click **Install Roslyn DLLs**. + +The installer downloads the required NuGet packages, places the DLLs in `Assets/Plugins/Roslyn/`, and adds `USE_ROSLYN` to Scripting Define Symbols. + +You can also trigger it from the menu: **Window → MCP For Unity → Install Roslyn DLLs**. + +## Manual install (if the installer isn't available) + +1. Install [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity). +2. Open **Window → NuGet Package Manager**. +3. Install: + - `Microsoft.CodeAnalysis` v5.0 + - `SQLitePCLRaw.core` v3.0.2 + - `SQLitePCLRaw.bundle_e_sqlite3` v3.0.2 +4. Add `USE_ROSLYN` to **Player Settings → Scripting Define Symbols**. +5. Restart Unity. + +## Manual DLL install (no NuGetForUnity) + +1. Download `Microsoft.CodeAnalysis.CSharp.dll` and its dependencies from [NuGet.org](https://www.nuget.org/packages/Microsoft.CodeAnalysis.CSharp/). +2. Place DLLs in `Assets/Plugins/Roslyn/`. +3. Ensure .NET compatibility settings are correct for your Unity version. +4. Add `USE_ROSLYN` to Scripting Define Symbols. +5. Restart Unity. + +## Verifying it's active + +After restart, the MCP for Unity status panel shows **Roslyn: enabled** under the Scripts section. The `validate_script` tool now performs full semantic analysis rather than the structural pass. + +## Disabling + +Remove `USE_ROSLYN` from Scripting Define Symbols. The plugin falls back to structural validation; the DLLs can stay in `Assets/Plugins/Roslyn/` or be removed. diff --git a/website/docs/guides/tool-groups.md b/website/docs/guides/tool-groups.md new file mode 100644 index 000000000..def7fc164 --- /dev/null +++ b/website/docs/guides/tool-groups.md @@ -0,0 +1,80 @@ +--- +id: tool-groups +slug: /guides/tool-groups +title: Tool Groups and manage_tools +sidebar_label: Tool Groups +description: Per-session visibility for the 43 tools. Activate vfx, animation, ui, testing, etc. only when you need them. +--- + +# Tool Groups + +MCP for Unity ships 43 tools, but exposing all of them to the LLM at once balloons the prompt and dilutes routing decisions. So tools are sorted into **groups**, and only `core` is enabled by default. + +## The groups + +| Group | Default | Description | +|---|---|---| +| `core` | enabled | Essential scene, script, asset, and editor tools — always on. | +| `animation` | off | Animator control, AnimationClip creation. | +| `ui` | off | UI Toolkit — UXML, USS, UIDocument. | +| `vfx` | off | VFX Graph, shaders, procedural textures. | +| `scripting_ext` | off | ScriptableObject management. | +| `testing` | off | Test runner and async test jobs. | +| `probuilder` | off | ProBuilder 3D modeling. Requires `com.unity.probuilder` package. | +| `profiling` | off | Profiler session control, counters, memory snapshots, Frame Debugger. | +| `docs` | off | Unity API reflection and documentation lookup. | + +## Enabling a group + +Use the `manage_tools` meta-tool from your prompt: + +> Activate the `vfx` group so we can author shaders. + +The assistant calls: + +``` +manage_tools(action="activate", group="vfx") +``` + +After activation, the group's tools appear in the next tool listing and are usable for the remainder of the session. + +## Listing what's available + +``` +manage_tools(action="list_groups") +``` + +Returns every group with its current activation state and tool names. + +## Deactivating + +``` +manage_tools(action="deactivate", group="vfx") +``` + +Useful when a group's tools are confusing the assistant — e.g., `manage_shader` and `manage_material` both apply to materials in different ways. Disabling the one you're not using keeps the assistant focused. + +## Other actions + +- `sync` — refreshes visibility from the Unity Editor's per-tool toggle UI. Use after toggling tools in `Window > MCP for Unity > Tools`. +- `reset` — restores defaults (only `core` enabled). + +## Why this exists + +Three reasons: + +1. **Prompt economy**: each visible tool adds tokens to every assistant call. Hiding what you're not using is real money saved at scale. +2. **Routing clarity**: when the LLM picks between 43 tools versus 30, the wrong-tool rate drops measurably. +3. **Package hygiene**: tools in `probuilder` only work if `com.unity.probuilder` is installed; hiding them by default avoids confusing errors. + +## Server vs. session state + +- The Unity Editor maintains a per-tool **toggle UI** (`Window > MCP for Unity > Tools`) that controls server-side visibility. +- The `manage_tools` meta-tool controls **per-session** visibility — different MCP sessions can see different groups even against the same server. + +`sync` reconciles the two: it pulls the Editor's toggle states into the current session. + +## Related reference + +- [`manage_tools`](/reference/tools/core/manage_tools) — full tool reference +- [`tool_groups` resource](/reference/resources) — discoverable group catalog diff --git a/website/docs/guides/troubleshooting.md b/website/docs/guides/troubleshooting.md new file mode 100644 index 000000000..baedd4e7d --- /dev/null +++ b/website/docs/guides/troubleshooting.md @@ -0,0 +1,183 @@ +--- +id: troubleshooting +slug: /guides/troubleshooting +title: Common Setup Problems +sidebar_label: Troubleshooting / FAQ +description: Real-world fixes for the issues people actually hit — macOS dyld errors, WSL2 bridging, DLL version conflicts, and per-client FAQs. +--- + +# Common Setup Problems + +## macOS: Claude CLI fails to start (dyld ICU library not loaded) + +**Symptoms:** +- MCP for Unity error: *"Failed to start Claude CLI. dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.71.dylib …"* +- Running `claude` in Terminal fails with missing `libicui18n.xx.dylib`. + +**Cause:** +Homebrew Node (or the `claude` binary) was linked against an ICU version that's no longer installed; dyld can't find that dylib. + +**Fix options (pick one):** + +**Reinstall Homebrew Node** (relinks to current ICU), then reinstall CLI: + +```bash +brew update +brew reinstall node +npm uninstall -g @anthropic-ai/claude-code +npm install -g @anthropic-ai/claude-code +``` + +**Use NVM Node** (avoids Homebrew ICU churn): + +```bash +nvm install --lts +nvm use --lts +npm install -g @anthropic-ai/claude-code +# Unity MCP → Claude Code → Choose Claude Location → ~/.nvm/versions/node//bin/claude +``` + +**Use the native installer** (puts `claude` in a stable path): + +```bash +# macOS / Linux +curl -fsSL https://claude.ai/install.sh | bash +# Unity MCP → Claude Code → Choose Claude Location → /opt/homebrew/bin/claude or ~/.local/bin/claude +``` + +**After fixing:** in MCP for Unity (Claude Code section), click **"Choose Claude Location"** and select the working `claude` binary, then **Register** again. + +--- + +## WSL2: Connecting Claude Code (Linux) to Unity (Windows) + +If you're running Claude Code from WSL2 and Unity on Windows, the MCP server runs on the Windows side but Claude Code needs to reach it from WSL. Here's how to bridge the two. + +*Contributed by [@aollivier82](https://github.com/CoplayDev/unity-mcp/issues/712).* + +### 1. Install the Unity package + +In Unity Package Manager, add by git URL: + +```text +https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main +``` + +In the MCP for Unity settings, change the port to **8090** (or any free port — the default 8080 can conflict with other services like Tailscale). + +### 2. Install uv on Windows + +The MCP server requires `uv`. From an admin PowerShell: + +```powershell +irm https://astral.sh/uv/install.ps1 | iex +``` + +### 3. Set up port forwarding from WSL to Windows + +WSL2 runs in a separate network namespace, so you need to forward the MCP port. From an admin PowerShell: + +```powershell +netsh interface portproxy add v4tov4 listenport=8090 listenaddress=0.0.0.0 connectport=8090 connectaddress=127.0.0.1 +``` + +Then add a firewall rule to allow it: + +```powershell +New-NetFirewallRule -DisplayName "Unity MCP Server" -Direction Inbound -LocalPort 8090 -Protocol TCP -Action Allow +``` + +### 4. Find your WSL host IP + +From inside WSL: + +```bash +cat /etc/resolv.conf | grep nameserver | awk '{print $2}' +``` + +This prints the Windows host IP as seen from WSL (e.g. `172.21.48.1`). It's a private address that varies per machine. + +### 5. Add the MCP server to Claude Code + +From WSL, using the IP from step 4: + +```bash +claude mcp add --transport http UnityMCP http://:8090/mcp +``` + +For example: + +```bash +claude mcp add --transport http UnityMCP http://172.21.48.1:8090/mcp +``` + +Note: this uses **HTTP transport**, not stdio — since the server is running on the Windows side. + +### 6. Verify + +Start Unity, then start Claude Code. You should see `UnityMCP` listed as a connected MCP server. Test it by asking Claude to get your scene info. + +**Notes:** +- If you restart your machine, the WSL host IP may change. Re-run step 4 and update the MCP config if needed. +- The port proxy persists across reboots. To remove it later: `netsh interface portproxy delete v4tov4 listenport=8090 listenaddress=0.0.0.0` +- If the connection fails, make sure Unity is running and the MCP server is started (check the MCP for Unity panel). + +--- + +## DLL reference mismatch with Unity AI Assistant package + +If you're using **Unity 6.3+** alongside the **Unity AI Assistant** package, you may encounter `System.Collections.Immutable` version conflicts. + +*Reported by [@rkroska](https://github.com/CoplayDev/unity-mcp/issues/557).* + +**Symptoms:** +- Compilation errors referencing `System.Collections.Immutable` version mismatches +- Errors appear after installing MCP for Unity in a project that has the Unity AI Assistant package + +**Cause:** +Unity AI Assistant bundles `System.Collections.Immutable` v10, while MCP for Unity's CodeAnalysis dependency needs v9. Unity's built-in version may be v8. These conflict during assembly resolution. + +**Fix options:** + +- **Option A (recommended):** If you don't need Unity AI Assistant, remove it via Package Manager. Then install `System.Collections.Immutable` v9.0.0 as a DLL in `Assets/Plugins/`. +- **Option B:** If you need both packages, install `System.Collections.Immutable` v9.0.0 in `Assets/Plugins/` to satisfy MCP's dependency. The AI Assistant's v10 reference should be forward-compatible. + +**Note:** This is a Unity assembly resolution issue, not specific to MCP for Unity. Unity doesn't have a NuGet-style dependency resolver, so DLL version conflicts must be resolved manually. + +--- + +## "No Unity Instances Found" + +:::tip When in doubt, restart your client +Clients like Claude Code or JetBrains Rider can get confused if you switch transport modes mid-session. Restart the client so it picks up the new configuration. +::: + +If restarting doesn't fix it: +- Check the MCP for Unity status panel — does it say `Connected`? +- Open `mcpforunity://instances` in your client. If it returns an empty list, the Unity-side bridge isn't running. +- Try **Window → MCP for Unity → Restart Server**. + +--- + +## FAQ — Claude Code + +**Q: Unity can't find `claude` even though Terminal can.** +A: macOS apps launched from Finder / Hub don't inherit your shell PATH. In the MCP for Unity window, click **"Choose Claude Location"** and select the absolute path (e.g., `/opt/homebrew/bin/claude` or `~/.nvm/versions/node//bin/claude`). + +**Q: I installed via NVM; where is `claude`?** +A: Typically `~/.nvm/versions/node//bin/claude`. The MCP for Unity UI also scans NVM versions and you can browse to it via **"Choose Claude Location"**. + +**Q: The Register button says "Claude Not Found".** +A: Install the CLI or set the path. Click the orange **[HELP]** link in the MCP for Unity window for step-by-step install instructions, then choose the binary location. See also: [Install or Repair Claude Code CLI](/guides/claude-code-cli). + +## FAQ — VS Code + +**Q: When I first set up and start the MCP for Unity server in VS Code, I get a failed response that says `Canceled: Canceled`.** +A: Start a new chat — the bad chat didn't pick up the MCP server configuration. + +![Canceled error screenshot](https://github.com/user-attachments/assets/571e2aeb-c286-4235-ab2b-8285c0db3296) + +## FAQ — Cursor / Windsurf / VS Code (Windows uv path) + +**Q: My MCP client keeps failing to launch the server even though `uv` is installed.** +A: Some Windows machines have multiple `uv.exe` locations. Auto-config sometimes picks a less stable path, causing the launch to fail or auto-rewrite on every restart. Use **"Choose UV Install Location"** in the MCP for Unity window and pin the **WinGet Links shim** path (`%LOCALAPPDATA%\Microsoft\WinGet\Links\uv.exe`) — it's stable across uv upgrades. diff --git a/website/docs/guides/uv-setup.md b/website/docs/guides/uv-setup.md new file mode 100644 index 000000000..6ade2c990 --- /dev/null +++ b/website/docs/guides/uv-setup.md @@ -0,0 +1,110 @@ +--- +id: uv-setup +slug: /guides/uv-setup +title: Install or Repair uv + Python +sidebar_label: uv + Python Setup +description: Install or repair uv and Python — the runtime MCP for Unity needs to launch the Python server from Cursor, VS Code, Windsurf, Rider, and other uv-based clients. +--- + +# Install or Repair uv + Python + +The key to configuring MCP with **Cursor, VS Code, Windsurf, and Rider is [`uv`](https://docs.astral.sh/uv/)**. + +- `uv` is a fast Python package manager used to install and run the Unity MCP Server (`mcp-for-unity`). +- **How it's used:** your MCP client config points to `command: uvx` with args like `--from mcpforunityserver mcp-for-unity --transport stdio`. The client invokes `uvx` directly to launch the server. +- **Why it matters:** if `uv` isn't installed or on PATH, Cursor / Windsurf / VS Code can't start the server. The MCP for Unity window will show **"uv Not Found"** until fixed. +- **Detection / override:** the MCP for Unity window auto-detects `uv` in common locations and on PATH. If not found, use **"Choose UV Install Location"** to navigate to your `uv` binary and save the path. + +:::tip When in doubt, restart your client +Clients like Claude Code or JetBrains Rider can get confused if you switch from `http` to `stdio` (or vice versa). If they say **"No Unity Instances found"**, restart the client so it picks up the new configuration. +::: + +## Requirements + +You need **Python 3.10+** and the **`uv`** package manager. + +### Verify + +```bash +python3 --version # should be 3.10+ +uv --version # should print a version like "uv 0.x" +``` + +## Install Python + +**macOS:** + +```bash +# Option A: Official installer (recommended) +# Download from https://www.python.org/downloads/ + +# Option B: Homebrew (3.12 is the latest LTS as of writing; 3.10 also works) +brew install python@3.12 +``` + +**Windows:** + +```powershell +# Official installer (recommended) +# Download from https://www.python.org/downloads/windows/ +``` + +## Install uv + +**macOS / Linux / WSL:** + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +# or Homebrew on macOS +brew install uv +``` + +**Windows PowerShell:** + +```powershell +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" +# or +winget install --id=astral-sh.uv -e +``` + +## Common uv locations + +| OS | Path | +|---|---| +| **macOS** | `/opt/homebrew/bin/uv`, `/usr/local/bin/uv`, `~/.local/bin/uv` | +| **Linux** | `/usr/local/bin/uv`, `/usr/bin/uv`, `~/.local/bin/uv` | +| **Windows** | `%LOCALAPPDATA%/Programs/Python/Python3xx/Scripts/uv.exe` | + +## MCP for Unity window behavior + +- If `uv` isn't found, the status panel shows a red **"uv Not Found"** with a hint **"Make sure uv is installed! [CLICK]"**. +- Use **"Choose UV Install Location"** to browse to the `uv` binary. This saves the path and reconfigures automatically. +- On macOS, Unity launched from Finder may not inherit your PATH. Setting the `uv` location here is the easiest fix. + +## Notes and gotchas + +- **macOS GUI apps don't inherit your shell startup files.** PATH may differ from Terminal. Set `uv` via the MCP window to avoid PATH issues. +- **Windows vs WSL:** if you installed `uv` inside WSL only, Windows-native Unity can't see it. Install `uv` on Windows, or use the MCP window to point to a Windows `uv.exe`. +- **Custom locations:** if you installed `uv` somewhere non-standard, the picker path is stored in `UnityMCP.UvPath` and persists across sessions. + +## What the "Repair Python Env" button does + +- Deletes the server's `.venv` and `.python-version` (if present) +- Runs `uv sync` in the Unity MCP Server `src` directory to rebuild a clean environment +- Useful after Python upgrades or missing modules + +## Where the Unity MCP Server is installed + +| OS | Path | +|---|---| +| **macOS** | `~/Library/Application Support/UnityMCP/UnityMcpServer/src` (or `~/Library/AppSupport/UnityMCP/UnityMcpServer/src` via symlink) | +| **Windows** | `%USERPROFILE%/AppData/Local/UnityMCP/UnityMcpServer/src` | +| **Linux** | `~/.local/share/UnityMCP/UnityMcpServer/src` | + +## Manual repair / run + +```bash +cd +uv sync +uv run server.py +``` diff --git a/docs/migrations/v5_MIGRATION.md b/website/docs/migrations/v5.md similarity index 84% rename from docs/migrations/v5_MIGRATION.md rename to website/docs/migrations/v5.md index 63157889e..2942c05eb 100644 --- a/docs/migrations/v5_MIGRATION.md +++ b/website/docs/migrations/v5.md @@ -15,7 +15,7 @@ Version 5 introduces a new package structure. The package is now installed from 3. Find **MCP for Unity** in the list 4. Click the **Remove** button to uninstall the legacy package -![Uninstalling the legacy package](images/v5_01_uninstall.png) +![Uninstalling the legacy package](/img/v5_01_uninstall.png) ### Step 2: Install from the New Path @@ -24,18 +24,18 @@ Version 5 introduces a new package structure. The package is now installed from 3. Enter the following URL: `https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity` 4. Click **Add** to install the package -![Installing from the new MCPForUnity path](images/v5_02_install.png) +![Installing from the new MCPForUnity path](/img/v5_02_install.png) ### Step 3: Rebuild MCP Server After installing the new package, you need to rebuild the MCP server: 1. In Unity, go to **Window > MCP for Unity > Open MCP Window** -![Opening the MCP window](images/v5_03_open_mcp_window.png) +![Opening the MCP window](/img/v5_03_open_mcp_window.png) 2. Click the **Rebuild MCP Server** button -![Rebuilding the MCP server](images/v5_04_rebuild_mcp_server.png) +![Rebuilding the MCP server](/img/v5_04_rebuild_mcp_server.png) 3. You should see a success message confirming the rebuild -![Rebuild success](images/v5_05_rebuild_success.png) +![Rebuild success](/img/v5_05_rebuild_success.png) ## Verification diff --git a/docs/migrations/v6_NEW_UI_CHANGES.md b/website/docs/migrations/v6.md similarity index 98% rename from docs/migrations/v6_NEW_UI_CHANGES.md rename to website/docs/migrations/v6.md index aad77f023..b33ad19ec 100644 --- a/docs/migrations/v6_NEW_UI_CHANGES.md +++ b/website/docs/migrations/v6.md @@ -2,10 +2,10 @@ > **UI Toolkit-based window with service-oriented architecture** -![New MCP Editor Window Dark](./images/v6_new_ui_dark.png) +![New MCP Editor Window Dark](/img/v6_new_ui_dark.png) *Dark theme* -![New MCP Editor Window Light](./images/v6_new_ui_light.png) +![New MCP Editor Window Light](/img/v6_new_ui_light.png) *Light theme* --- @@ -56,7 +56,7 @@ The new MCP Editor Window is a complete rebuild using **UI Toolkit (UXML/USS)** - **Server Download Button** - Asset Store users can download the server from GitHub releases - **Dynamic UI** - Shows appropriate button based on installation type -![Asset Store Version](./images/v6_new_ui_asset_store_version.png) +![Asset Store Version](/img/v6_new_ui_asset_store_version.png) *Asset Store version showing the "Download & Install Server" button* --- diff --git a/docs/migrations/v8_NEW_NETWORKING_SETUP.md b/website/docs/migrations/v8.md similarity index 98% rename from docs/migrations/v8_NEW_NETWORKING_SETUP.md rename to website/docs/migrations/v8.md index 9e96cae62..8edaea54f 100644 --- a/docs/migrations/v8_NEW_NETWORKING_SETUP.md +++ b/website/docs/migrations/v8.md @@ -12,7 +12,7 @@ This project has 3 components: - MCP Server - Unity Editor plugin -![3 components of MCP for Unity](./images/networking-architecture.png) +![3 components of MCP for Unity](/img/networking-architecture.png) The MCP clients (e.g., Cursor, VS Code, Windsurf, Claude Code) are how users interact with our systems. They communicate with the MCP server by sending commands. The MCP commands communicates with our Unity plugin, which gives reports on the action it completed (for function tools) or gives it data (for resources). @@ -69,7 +69,7 @@ Let's discuss both technical and political reasons: - Do you want to run the MCP server on a dedicated server all your personal computers connect to? You can. - Do you want to run MCP server in the cloud and have various projects use it? You can. - HTTP opens up easier ways to communicate with the MCP server w/o using the MCP protocol - - For example, this version supports custom tools that only require C# code (see [CUSTOM_TOOLS.md](./CUSTOM_TOOLS.md) for more info). This was easy to implement because we added a special endpoint to handle tool registration + - For example, this version supports custom tools that only require C# code (see the [Custom Tools guide](/guides/custom-tools) for more info). This was easy to implement because we added a special endpoint to handle tool registration - Our MCP server can now be hosted by various MCP marketplaces, they typically require an HTTP server because they host it remotely. - We can distribute the plugin with a remote URL, so users would not need to install Python or `uv` installed to use MCP for Unity. - This is a contentious issue. Who should host the server, particularly for an open source, community centered project? For now, Coplay will host the server as it is the sponsor of this project. This remote URL would not be the default for users who install via Git or OpenUPM, but it will become the default for users who install via the Unity Asset Store, where we can't submit the plugin if it requires Python/`uv` to be installed. diff --git a/website/docs/reference/cli.md b/website/docs/reference/cli.md new file mode 100644 index 000000000..7bcc1af69 --- /dev/null +++ b/website/docs/reference/cli.md @@ -0,0 +1,96 @@ +--- +id: cli +slug: /reference/cli +title: CLI Reference +sidebar_label: CLI +description: The mcp-for-unity command-line interface — invocation, global flags, command groups, and how each maps to the equivalent MCP tool. +--- + +# CLI Reference + +The `mcp-for-unity` CLI is a developer-facing terminal for the same Unity automations the MCP tools expose. Both invoke the same C# `HandleCommand` methods on the Unity side — see [Three-Layer Python Design](/architecture/python-layers) for why both layers exist. + +## Invocation + +```bash +# Run via uvx (no install) +uvx --from mcpforunityserver mcp-for-unity [args] + +# Run from a Server checkout +cd Server && uv run mcp-for-unity [args] + +# Run via the dedicated CLI entry point (alias) +uvx --from mcpforunityserver unity-mcp [args] +``` + +## How it talks to Unity + +The CLI uses **HTTP** to the Python server (default `http://127.0.0.1:8080`), regardless of how your MCP clients are configured. The Python server in turn talks to the connected Unity Editor via WebSocket. MCP tools take a similar path via WebSocket directly; CLI commands take HTTP. + +## Global flags + +| Flag | Default | Meaning | +|---|---|---| +| `--host` | `127.0.0.1` | Python server host to connect to | +| `--port` | `8080` | Python server port | +| `--instance` | (auto) | Target Unity instance (`Name@hash`, hash prefix, or port number) | +| `--format` | `text` | Output format: `text` or `json` | +| `--verbose / -v` | off | Print full request/response payloads | +| `--version` | — | Print CLI version and exit | +| `--help` | — | Show command help | + +For multi-instance setups, see [Multi-Instance Routing](/guides/multi-instance). + +## Command groups + +The CLI mirrors the MCP tool catalog. Each command group wraps one or more `manage_*` tools. + +| Group | What it does | Equivalent MCP tool | +|---|---|---| +| `mcp-for-unity instance` | List instances, check connection, set active | [`set_active_instance`](/reference/tools/core/set_active_instance) | +| `mcp-for-unity scene` | Load/save/query/edit scenes | [`manage_scene`](/reference/tools/core/manage_scene) | +| `mcp-for-unity gameobject` | Create/transform/delete GameObjects | [`manage_gameobject`](/reference/tools/core/manage_gameobject) | +| `mcp-for-unity component` | Add/remove/configure components | [`manage_components`](/reference/tools/core/manage_components) | +| `mcp-for-unity script` | Create/read/modify C# scripts | [`manage_script`](/reference/tools/core/manage_script) | +| `mcp-for-unity asset` | Asset import/create/modify/search | [`manage_asset`](/reference/tools/core/manage_asset) | +| `mcp-for-unity material` | Material CRUD + shader props | [`manage_material`](/reference/tools/core/manage_material) | +| `mcp-for-unity prefab` | Prefab create/instantiate/unpack | [`manage_prefabs`](/reference/tools/core/manage_prefabs) | +| `mcp-for-unity texture` | Texture create + patterns/gradients | [`manage_texture`](/reference/tools/vfx/manage_texture) | +| `mcp-for-unity shader` | Shader CRUD | [`manage_shader`](/reference/tools/vfx/manage_shader) | +| `mcp-for-unity vfx` | VFX, particle systems, trails | [`manage_vfx`](/reference/tools/vfx/manage_vfx) | +| `mcp-for-unity camera` | Camera + Cinemachine presets | [`manage_camera`](/reference/tools/core/manage_camera) | +| `mcp-for-unity graphics` | Volumes, post-processing, light bake | [`manage_graphics`](/reference/tools/core/manage_graphics) | +| `mcp-for-unity lighting` | Lighting-specific operations | (subset of graphics) | +| `mcp-for-unity physics` | 3D + 2D physics, joints, queries | [`manage_physics`](/reference/tools/core/manage_physics) | +| `mcp-for-unity audio` | Audio operations | (subset of asset) | +| `mcp-for-unity animation` | Animator + AnimationClip | [`manage_animation`](/reference/tools/animation/manage_animation) | +| `mcp-for-unity ui` | UI Toolkit — UXML/USS/UIDocument | [`manage_ui`](/reference/tools/ui/manage_ui) | +| `mcp-for-unity build` | Player builds across platforms | [`manage_build`](/reference/tools/core/manage_build) | +| `mcp-for-unity editor` | Editor state, play mode, undo/redo | [`manage_editor`](/reference/tools/core/manage_editor) | +| `mcp-for-unity packages` | UPM install/remove/embed | [`manage_packages`](/reference/tools/core/manage_packages) | +| `mcp-for-unity probuilder` | ProBuilder meshes | [`manage_probuilder`](/reference/tools/probuilder/manage_probuilder) | +| `mcp-for-unity profiler` | Profiler session + counters + snapshots | [`manage_profiler`](/reference/tools/profiling/manage_profiler) | +| `mcp-for-unity code` | Execute arbitrary C# in the Editor | [`execute_code`](/reference/tools/scripting_ext/execute_code) | +| `mcp-for-unity batch` | Run multiple operations atomically | [`batch_execute`](/reference/tools/core/batch_execute) | +| `mcp-for-unity tool` | Activate/deactivate tool groups | [`manage_tools`](/reference/tools/core/manage_tools) | +| `mcp-for-unity reflect` | Inspect Unity APIs via reflection | [`unity_reflect`](/reference/tools/docs/unity_reflect) | +| `mcp-for-unity docs` | Fetch Unity docs (ScriptReference, Manual) | [`unity_docs`](/reference/tools/docs/unity_docs) | + +## Discovering subcommands and flags + +Every group supports `--help`: + +```bash +mcp-for-unity scene --help +mcp-for-unity scene load --help +``` + +The help text is the authoritative per-command reference — flags, choices, and defaults all live there because the CLI is built on Click and self-describes. + +## Examples + +See [CLI Examples](/guides/cli-examples) for end-to-end walkthroughs and the [CLI Usage Guide](/guides/cli) for narrative context (when to use the CLI vs an MCP client). + +## Source + +CLI command definitions: [`Server/src/cli/commands/`](https://github.com/CoplayDev/unity-mcp/tree/beta/Server/src/cli/commands). Entry point: [`Server/src/cli/main.py`](https://github.com/CoplayDev/unity-mcp/blob/beta/Server/src/cli/main.py). diff --git a/website/docs/reference/manifest.md b/website/docs/reference/manifest.md new file mode 100644 index 000000000..d032b1829 --- /dev/null +++ b/website/docs/reference/manifest.md @@ -0,0 +1,69 @@ +--- +id: manifest +slug: /reference/manifest +title: manifest.json Reference +sidebar_label: manifest.json +description: The repo-root manifest.json — what it describes, why it ships, and which fields are authoritative for the MCP marketplace bundle. +--- + +# `manifest.json` Reference + +The `manifest.json` at the repo root describes MCP for Unity as a package — independent of Unity's UPM `package.json` (which lives at `MCPForUnity/package.json`). It's used by MCP marketplaces and aggregators to surface the project's metadata, server invocation, and tool catalog. + +If you're adding a new MCP tool, update [the tool registry](/architecture/python-layers) and let CI's drift check fail any stale entry — the generator keeps the docs in sync. The `tools` block in `manifest.json` is a separate, hand-maintained surface (see Notes below). + +## Top-level fields + +| Field | Type | Description | +|---|---|---| +| `manifest_version` | string | Schema version for this manifest (currently `"0.3"`) | +| `name` | string | Display name shown by aggregators | +| `version` | string | Semver of the current release | +| `description` | string | One-line product description | +| `author.name` | string | Maintainer's display name | +| `author.url` | string | Maintainer's website | +| `repository.type` | string | `"git"` | +| `repository.url` | string | Canonical repo URL | +| `homepage` | string | Project homepage | +| `documentation` | string | Docs landing URL | +| `support` | string | Where to file issues | +| `icon` | string | Path to a square icon, relative to the manifest | + +## `server` + +Tells aggregators how to launch the Python server. + +```json +"server": { + "type": "python", + "entry_point": "Server/src/main.py", + "mcp_config": { + "command": "uvx", + "args": ["--from", "mcpforunityserver", "mcp-for-unity"], + "env": {} + } +} +``` + +- **`type`** — runtime family. Currently always `"python"`. +- **`entry_point`** — file an aggregator would point a Python interpreter at if it weren't using `uvx`. +- **`mcp_config.command`** — recommended launch command. `uvx` keeps the dependency tree managed without a global install. +- **`mcp_config.args`** — invocation arguments. Default transport is `http`; pass `--transport stdio` to switch. +- **`mcp_config.env`** — environment variables to set before launching (telemetry opt-outs, log levels, etc.). + +## `tools` + +A flat array of `{ name, description }` entries listing every MCP tool the server exposes. Aggregators use it for search and category surfaces without having to introspect the live registry. + +This list is hand-maintained for now. The authoritative count and metadata live in the Python tool registry — see the [Tool reference](/reference/tools) for the generated catalog with full parameter docs. + +## Notes + +- `manifest.json` is NOT the Unity UPM manifest. That's `MCPForUnity/package.json` (name: `com.coplaydev.unity-mcp`). +- The Python PyPI package metadata lives in `Server/pyproject.toml` (name: `mcpforunityserver`). +- All three — `manifest.json`, `package.json`, `pyproject.toml` — are independent surfaces with overlapping but non-identical fields. A rename touches all three. +- An MCPB bundle is produced from `manifest.json` via [`tools/generate_mcpb.py`](https://github.com/CoplayDev/unity-mcp/blob/beta/tools/generate_mcpb.py). + +## Where it ships + +The current `manifest.json` is at the repo root: [`manifest.json`](https://github.com/CoplayDev/unity-mcp/blob/beta/manifest.json). diff --git a/website/docs/reference/resources/index.md b/website/docs/reference/resources/index.md new file mode 100644 index 000000000..0c0ce75e2 --- /dev/null +++ b/website/docs/reference/resources/index.md @@ -0,0 +1,260 @@ +--- +title: Resource reference +sidebar_label: Resources +slug: /reference/resources +description: Auto-generated catalog of every MCP for Unity resource. +--- + +# Resource reference + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +Resources are read-only state surfaces exposed to MCP clients. Tools mutate; resources observe. + +## `cameras` + +**URI:** `mcpforunity://scene/cameras` + +List all cameras in the scene (Unity Camera + CinemachineCamera) with status. Includes Brain state, Cinemachine camera priorities, pipeline components, follow/lookAt targets, and Unity Camera info. + +URI: mcpforunity://scene/cameras + + +## `custom_tools` + +**URI:** `mcpforunity://custom-tools` + +Lists custom tools available for the active Unity project. + +URI: mcpforunity://custom-tools + + +## `editor_active_tool` + +**URI:** `mcpforunity://editor/active-tool` + +Currently active editor tool (Move, Rotate, Scale, etc.) and transform handle settings. + +URI: mcpforunity://editor/active-tool + + +## `editor_prefab_stage` + +**URI:** `mcpforunity://editor/prefab-stage` + +Current prefab editing context if a prefab is open in isolation mode. Returns isOpen=false if no prefab is being edited. + +URI: mcpforunity://editor/prefab-stage + + +## `editor_selection` + +**URI:** `mcpforunity://editor/selection` + +Detailed information about currently selected objects in the editor, including GameObjects, assets, and their properties. + +URI: mcpforunity://editor/selection + + +## `editor_state` + +**URI:** `mcpforunity://editor/state` + +Canonical editor readiness snapshot. Includes advice and server-computed staleness. + +URI: mcpforunity://editor/state + + +## `editor_windows` + +**URI:** `mcpforunity://editor/windows` + +All currently open editor windows with their titles, types, positions, and focus state. + +URI: mcpforunity://editor/windows + + +## `gameobject` + +**URI:** `mcpforunity://scene/gameobject/{instance_id}` + +Get detailed information about a single GameObject by instance ID. Returns name, tag, layer, active state, transform data, parent/children IDs, and component type list (no full component properties). + +URI: mcpforunity://scene/gameobject/{instance_id} + +**Parameters:** + +- `instance_id` (`str`, required) — + +## `gameobject_api` + +**URI:** `mcpforunity://scene/gameobject-api` + +Documentation for GameObject resources. Use find_gameobjects tool to get instance IDs, then access resources below. + +URI: mcpforunity://scene/gameobject-api + +**Parameters:** + +- `_ctx` (`Context`, required) — + +## `gameobject_component` + +**URI:** `mcpforunity://scene/gameobject/{instance_id}/component/{component_name}` + +Get a specific component on a GameObject by type name. Returns the fully serialized component with all properties. + +URI: mcpforunity://scene/gameobject/{instance_id}/component/{component_name} + +**Parameters:** + +- `instance_id` (`str`, required) — +- `component_name` (`str`, required) — + +## `gameobject_components` + +**URI:** `mcpforunity://scene/gameobject/{instance_id}/components` + +Get all components on a GameObject with full property serialization. Supports pagination with pageSize and cursor parameters. + +URI: mcpforunity://scene/gameobject/{instance_id}/components + +**Parameters:** + +- `instance_id` (`str`, required) — +- `page_size` (`int`, optional) — +- `cursor` (`int`, optional) — +- `include_properties` (`bool`, optional) — + +## `get_tests` + +**URI:** `mcpforunity://tests` + +Provides the first page of Unity tests (default 50 items). For filtering or pagination, use the run_tests tool instead. + +URI: mcpforunity://tests + + +## `get_tests_for_mode` + +**URI:** `mcpforunity://tests/{mode}` + +Provides the first page of tests for a specific mode (EditMode or PlayMode). For filtering or pagination, use the run_tests tool instead. + +URI: mcpforunity://tests/{mode} + +**Parameters:** + +- `mode` (`Literal['EditMode', 'PlayMode']`, required) — + +## `menu_items` + +**URI:** `mcpforunity://menu-items` + +Provides a list of all menu items. + +URI: mcpforunity://menu-items + + +## `prefab_api` + +**URI:** `mcpforunity://prefab-api` + +Documentation for Prefab resources. Use manage_asset action=search filterType=Prefab to find prefabs, then access resources below. + +URI: mcpforunity://prefab-api + +**Parameters:** + +- `_ctx` (`Context`, required) — + +## `prefab_hierarchy` + +**URI:** `mcpforunity://prefab/{encoded_path}/hierarchy` + +Get the full hierarchy of a prefab with nested prefab information. Returns all GameObjects with their components and nesting depth. + +URI: mcpforunity://prefab/{encoded_path}/hierarchy + +**Parameters:** + +- `encoded_path` (`str`, required) — + +## `prefab_info` + +**URI:** `mcpforunity://prefab/{encoded_path}` + +Get detailed information about a prefab asset by URL-encoded path. Returns prefab type, root object name, component types, child count, and variant info. + +URI: mcpforunity://prefab/{encoded_path} + +**Parameters:** + +- `encoded_path` (`str`, required) — + +## `project_info` + +**URI:** `mcpforunity://project/info` + +Static project information including root path, Unity version, and platform. This data rarely changes. + +URI: mcpforunity://project/info + + +## `project_layers` + +**URI:** `mcpforunity://project/layers` + +All layers defined in the project's TagManager with their indices (0-31). Read this before using add_layer or remove_layer tools. + +URI: mcpforunity://project/layers + + +## `project_tags` + +**URI:** `mcpforunity://project/tags` + +All tags defined in the project's TagManager. Read this before using add_tag or remove_tag tools. + +URI: mcpforunity://project/tags + + +## `renderer_features` + +**URI:** `mcpforunity://pipeline/renderer-features` + +Lists all URP renderer features on the active renderer with type, name, and active state. + + +## `rendering_stats` + +**URI:** `mcpforunity://rendering/stats` + +Snapshot of rendering performance statistics (draw calls, batches, triangles, frame time, etc.). + + +## `tool_groups` + +**URI:** `mcpforunity://tool-groups` + +Available tool groups and their tools. Use manage_tools to activate/deactivate groups per session. + +URI: mcpforunity://tool-groups + + +## `unity_instances` + +**URI:** `mcpforunity://instances` + +Lists all running Unity Editor instances with their details. + +URI: mcpforunity://instances + + +## `volumes` + +**URI:** `mcpforunity://scene/volumes` + +Lists all Volume components in the active scene with their profiles, effects, and settings. + + diff --git a/website/docs/reference/tools/animation/_category_.json b/website/docs/reference/tools/animation/_category_.json new file mode 100644 index 000000000..67e68df7b --- /dev/null +++ b/website/docs/reference/tools/animation/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "animation", + "link": { + "type": "doc", + "id": "reference/tools/animation/index" + }, + "collapsed": true +} diff --git a/website/docs/reference/tools/animation/index.md b/website/docs/reference/tools/animation/index.md new file mode 100644 index 000000000..f2a57be64 --- /dev/null +++ b/website/docs/reference/tools/animation/index.md @@ -0,0 +1,11 @@ +--- +title: "animation tools" +sidebar_label: "animation" +description: "MCP for Unity tools in the animation group." +--- + +# `animation` tools + +Animator control & AnimationClip creation + +- **[`manage_animation`](./manage_animation.md)** — Manage Unity animation: Animator control and AnimationClip creation. diff --git a/website/docs/reference/tools/animation/manage_animation.md b/website/docs/reference/tools/animation/manage_animation.md new file mode 100644 index 000000000..c73672500 --- /dev/null +++ b/website/docs/reference/tools/animation/manage_animation.md @@ -0,0 +1,37 @@ +--- +title: manage_animation +sidebar_label: manage_animation +description: "Manage Unity animation: Animator control and AnimationClip creation." +--- + +# `manage_animation` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `animation`  ·  **Module:** `services.tools.manage_animation` + +## Description + +Manage Unity animation: Animator control and AnimationClip creation. Action prefixes: animator_* (play, crossfade, set parameters, get info), controller_* (create AnimatorControllers, add states/transitions/parameters), clip_* (create clips, add keyframe curves, assign to GameObjects). Action-specific parameters go in `properties` (keys match ManageAnimation.cs). + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `str` | yes | Action to perform (prefix: animator_, controller_, clip_). | +| `target` | `str \| None` | — | Target GameObject (name/path/id). | +| `search_method` | `Literal['by_id', 'by_name', 'by_path', 'by_tag', 'by_layer'] \| None` | — | How to find the target GameObject. | +| `clip_path` | `str \| None` | — | Asset path for AnimationClip (e.g. 'Assets/Animations/Walk.anim'). | +| `controller_path` | `str \| None` | — | Asset path for AnimatorController (e.g. 'Assets/Animators/Player.controller'). | +| `properties` | `dict[str, Any] \| str \| None` | — | Action-specific parameters (dict or JSON string). | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/_category_.json b/website/docs/reference/tools/core/_category_.json new file mode 100644 index 000000000..c8f3d384b --- /dev/null +++ b/website/docs/reference/tools/core/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "core", + "link": { + "type": "doc", + "id": "reference/tools/core/index" + }, + "collapsed": true +} diff --git a/website/docs/reference/tools/core/apply_text_edits.md b/website/docs/reference/tools/core/apply_text_edits.md new file mode 100644 index 000000000..8363901b6 --- /dev/null +++ b/website/docs/reference/tools/core/apply_text_edits.md @@ -0,0 +1,47 @@ +--- +title: apply_text_edits +sidebar_label: apply_text_edits +description: "Apply small text edits to a C# script identified by URI." +--- + +# `apply_text_edits` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_script` + +## Description + +Apply small text edits to a C# script identified by URI. + IMPORTANT: This tool replaces EXACT character positions. Always verify content at target lines/columns BEFORE editing! + RECOMMENDED WORKFLOW: + 1. First call resources/read with start_line/line_count to verify exact content + 2. Count columns carefully (or use find_in_file to locate patterns) + 3. Apply your edit with precise coordinates + 4. Consider script_apply_edits with anchors for safer pattern-based replacements + Notes: + - For method/class operations, use script_apply_edits (safer, structured edits) + - For pattern-based replacements, consider anchor operations in script_apply_edits + - Lines, columns are 1-indexed + - Tabs count as 1 column + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `uri` | `str` | yes | URI of the script to edit under Assets/ directory, mcpforunity://path/Assets/... or file://... or Assets/... | +| `edits` | `list[dict[str, Any]]` | yes | List of edits to apply to the script, i.e. a list of {startLine,startCol,endLine,endCol,newText} (1-indexed!) | +| `precondition_sha256` | `str \| None` | — | Optional SHA256 of the script to edit, used to prevent concurrent edits | +| `strict` | `bool \| None` | — | Optional strict flag, used to enforce strict mode | +| `options` | `dict[str, Any] \| None` | — | Optional options, used to pass additional options to the script editor | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/batch_execute.md b/website/docs/reference/tools/core/batch_execute.md new file mode 100644 index 000000000..b4f22895e --- /dev/null +++ b/website/docs/reference/tools/core/batch_execute.md @@ -0,0 +1,100 @@ +--- +title: batch_execute +sidebar_label: batch_execute +description: "Executes multiple MCP commands in a single batch for dramatically better performance." +--- + +# `batch_execute` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.batch_execute` + +## Description + +Executes multiple MCP commands in a single batch for dramatically better performance. STRONGLY RECOMMENDED when creating/modifying multiple objects, adding components to multiple targets, or performing any repetitive operations. Reduces latency and token costs by 10-100x compared to sequential tool calls. The max commands per batch is configurable in the Unity MCP Tools window (default 25, hard max 100). Example: creating 5 cubes → use 1 batch_execute with 5 create commands instead of 5 separate calls. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `commands` | `list[dict[str, Any]]` | yes | List of commands with 'tool' and 'params' keys. | +| `parallel` | `bool \| None` | — | Attempt to run read-only commands in parallel | +| `fail_fast` | `bool \| None` | — | Stop processing after the first failure | +| `max_parallelism` | `int \| None` | — | Hint for the maximum number of parallel workers | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +### Why batch? + +A loop of 10 individual `manage_gameobject` calls pays 10 round trips to Unity. `batch_execute` pays one. For multi-object setup, batches are routinely **10–100× faster**. Use them whenever the next call doesn't need the previous call's return value. + +### Spawn three colored cubes in one round trip + +> Create a red, blue, and yellow cube at x = -1, 0, 1. + +```json +{ + "commands": [ + { "tool": "manage_gameobject", "params": { + "action": "create", "name": "RedCube", + "primitive_type": "Cube", "position": [-1, 0, 0] + }}, + { "tool": "manage_gameobject", "params": { + "action": "create", "name": "BlueCube", + "primitive_type": "Cube", "position": [0, 0, 0] + }}, + { "tool": "manage_gameobject", "params": { + "action": "create", "name": "YellowCube", + "primitive_type": "Cube", "position": [1, 0, 0] + }}, + { "tool": "manage_material", "params": { + "action": "create", "material_path": "Materials/Red.mat", + "shader": "Standard", "properties": { "_Color": [1, 0, 0, 1] } + }}, + { "tool": "manage_material", "params": { + "action": "create", "material_path": "Materials/Blue.mat", + "shader": "Standard", "properties": { "_Color": [0, 0, 1, 1] } + }}, + { "tool": "manage_material", "params": { + "action": "create", "material_path": "Materials/Yellow.mat", + "shader": "Standard", "properties": { "_Color": [1, 1, 0, 1] } + }}, + { "tool": "manage_material", "params": { + "action": "assign_material_to_renderer", "target": "RedCube", + "search_method": "by_name", "material_path": "Materials/Red.mat" + }}, + { "tool": "manage_material", "params": { + "action": "assign_material_to_renderer", "target": "BlueCube", + "search_method": "by_name", "material_path": "Materials/Blue.mat" + }}, + { "tool": "manage_material", "params": { + "action": "assign_material_to_renderer", "target": "YellowCube", + "search_method": "by_name", "material_path": "Materials/Yellow.mat" + }} + ] +} +``` + +### Mix tools freely + +A batch can mix any tools, as long as ordering inside the batch doesn't depend on a previous call's *return value*. If you need the response of step N to feed step N+1, split into two batches. + +### Stop on first failure vs continue + +Set `fail_fast: true` (default) to abort the rest on the first failed step. Pass `fail_fast: false` to attempt every operation and collect per-step results, useful for "best-effort cleanup" patterns. + +### Parallel reads + +Pass `parallel: true` to let the server run **read-only** commands concurrently. Mutating ops still serialize for safety. Tune with `max_parallelism`. + +### Limits + +Batch size is configurable in the Unity MCP Tools window (default 25, hard max 100). Past the limit, split into multiple batches — round-trip cost is still amortized. + + diff --git a/website/docs/reference/tools/core/create_script.md b/website/docs/reference/tools/core/create_script.md new file mode 100644 index 000000000..e39d0e8de --- /dev/null +++ b/website/docs/reference/tools/core/create_script.md @@ -0,0 +1,35 @@ +--- +title: create_script +sidebar_label: create_script +description: "Create a new C# script at the given project path." +--- + +# `create_script` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_script` + +## Description + +Create a new C# script at the given project path. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `path` | `str` | yes | Path under Assets/ to create the script at, e.g., 'Assets/Scripts/My.cs' | +| `contents` | `str` | yes | Contents of the script to create (plain text C# code). The server handles Base64 encoding. | +| `script_type` | `str \| None` | — | Script type (e.g., 'C#') | +| `namespace` | `str \| None` | — | Namespace for the script | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/debug_request_context.md b/website/docs/reference/tools/core/debug_request_context.md new file mode 100644 index 000000000..e517873bf --- /dev/null +++ b/website/docs/reference/tools/core/debug_request_context.md @@ -0,0 +1,30 @@ +--- +title: debug_request_context +sidebar_label: debug_request_context +description: "Return the current FastMCP request context details (client_id, session_id, and meta dump)." +--- + +# `debug_request_context` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.debug_request_context` + +## Description + +Return the current FastMCP request context details (client_id, session_id, and meta dump). + +## Parameters + +_No parameters._ + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/delete_script.md b/website/docs/reference/tools/core/delete_script.md new file mode 100644 index 000000000..868e9d464 --- /dev/null +++ b/website/docs/reference/tools/core/delete_script.md @@ -0,0 +1,32 @@ +--- +title: delete_script +sidebar_label: delete_script +description: "Delete a C# script by URI or Assets-relative path." +--- + +# `delete_script` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_script` + +## Description + +Delete a C# script by URI or Assets-relative path. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `uri` | `str` | yes | URI of the script to delete under Assets/ directory, mcpforunity://path/Assets/... or file://... or Assets/... | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/execute_custom_tool.md b/website/docs/reference/tools/core/execute_custom_tool.md new file mode 100644 index 000000000..70918ca40 --- /dev/null +++ b/website/docs/reference/tools/core/execute_custom_tool.md @@ -0,0 +1,33 @@ +--- +title: execute_custom_tool +sidebar_label: execute_custom_tool +description: "Execute a project-scoped custom tool registered by Unity." +--- + +# `execute_custom_tool` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.execute_custom_tool` + +## Description + +Execute a project-scoped custom tool registered by Unity. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `tool_name` | `str` | yes | | +| `parameters` | `dict[str, Any] \| None` | — | | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/execute_menu_item.md b/website/docs/reference/tools/core/execute_menu_item.md new file mode 100644 index 000000000..dad09b763 --- /dev/null +++ b/website/docs/reference/tools/core/execute_menu_item.md @@ -0,0 +1,32 @@ +--- +title: execute_menu_item +sidebar_label: execute_menu_item +description: "Execute a Unity menu item by path." +--- + +# `execute_menu_item` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.execute_menu_item` + +## Description + +Execute a Unity menu item by path. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `menu_path` | `str \| None` | — | Menu path for 'execute' or 'exists' (e.g., 'File/Save Project') | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/find_gameobjects.md b/website/docs/reference/tools/core/find_gameobjects.md new file mode 100644 index 000000000..df0a657e0 --- /dev/null +++ b/website/docs/reference/tools/core/find_gameobjects.md @@ -0,0 +1,36 @@ +--- +title: find_gameobjects +sidebar_label: find_gameobjects +description: "Search for GameObjects in the scene by name, tag, layer, component type, or path." +--- + +# `find_gameobjects` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.find_gameobjects` + +## Description + +Search for GameObjects in the scene by name, tag, layer, component type, or path. Returns instance IDs only (paginated). Then use mcpforunity://scene/gameobject/{id} resource for full data, or mcpforunity://scene/gameobject/{id}/components for component details. For CRUD operations (create/modify/delete), use manage_gameobject instead. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `search_term` | `str` | yes | | +| `search_method` | `Literal['by_name', 'by_tag', 'by_layer', 'by_component', 'by_path', 'by_id']` | — | | +| `include_inactive` | `bool \| str \| None` | — | | +| `page_size` | `int \| str \| None` | — | | +| `cursor` | `int \| str \| None` | — | | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/find_in_file.md b/website/docs/reference/tools/core/find_in_file.md new file mode 100644 index 000000000..282cce1dd --- /dev/null +++ b/website/docs/reference/tools/core/find_in_file.md @@ -0,0 +1,36 @@ +--- +title: find_in_file +sidebar_label: find_in_file +description: "Searches a file with a regex pattern and returns line numbers and excerpts." +--- + +# `find_in_file` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.find_in_file` + +## Description + +Searches a file with a regex pattern and returns line numbers and excerpts. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `uri` | `str` | yes | The resource URI to search under Assets/ or file path form supported by read_resource | +| `pattern` | `str` | yes | The regex pattern to search for | +| `project_root` | `str \| None` | — | Optional project root path | +| `max_results` | `int` | — | Cap results to avoid huge payloads | +| `ignore_case` | `bool \| str \| None` | — | Case insensitive search | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/get_sha.md b/website/docs/reference/tools/core/get_sha.md new file mode 100644 index 000000000..951e07fc3 --- /dev/null +++ b/website/docs/reference/tools/core/get_sha.md @@ -0,0 +1,32 @@ +--- +title: get_sha +sidebar_label: get_sha +description: "Get SHA256 and basic metadata for a Unity C# script without returning file contents." +--- + +# `get_sha` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_script` + +## Description + +Get SHA256 and basic metadata for a Unity C# script without returning file contents. Requires uri (script path under Assets/ or mcpforunity://path/Assets/... or file://...). + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `uri` | `str` | yes | URI of the script to edit under Assets/ directory, mcpforunity://path/Assets/... or file://... or Assets/... | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/index.md b/website/docs/reference/tools/core/index.md new file mode 100644 index 000000000..f0075dee8 --- /dev/null +++ b/website/docs/reference/tools/core/index.md @@ -0,0 +1,40 @@ +--- +title: "core tools" +sidebar_label: "core" +description: "MCP for Unity tools in the core group." +--- + +# `core` tools + +Essential scene, script, asset & editor tools (always on by default) + +- **[`apply_text_edits`](./apply_text_edits.md)** — Apply small text edits to a C# script identified by URI. +- **[`batch_execute`](./batch_execute.md)** — Executes multiple MCP commands in a single batch for dramatically better performance. +- **[`create_script`](./create_script.md)** — Create a new C# script at the given project path. +- **[`debug_request_context`](./debug_request_context.md)** — Return the current FastMCP request context details (client_id, session_id, and meta dump). +- **[`delete_script`](./delete_script.md)** — Delete a C# script by URI or Assets-relative path. +- **[`execute_custom_tool`](./execute_custom_tool.md)** — Execute a project-scoped custom tool registered by Unity. +- **[`execute_menu_item`](./execute_menu_item.md)** — Execute a Unity menu item by path. +- **[`find_gameobjects`](./find_gameobjects.md)** — Search for GameObjects in the scene by name, tag, layer, component type, or path. +- **[`find_in_file`](./find_in_file.md)** — Searches a file with a regex pattern and returns line numbers and excerpts. +- **[`get_sha`](./get_sha.md)** — Get SHA256 and basic metadata for a Unity C# script without returning file contents. +- **[`manage_asset`](./manage_asset.md)** — Performs asset operations (import, create, modify, delete, etc.) in Unity. +- **[`manage_build`](./manage_build.md)** — Manage Unity player builds — trigger builds, switch platforms, configure settings, manage build scenes and profiles, run batch builds across platforms. +- **[`manage_camera`](./manage_camera.md)** — Manage cameras (Unity Camera + Cinemachine). +- **[`manage_components`](./manage_components.md)** — Add, remove, or set properties on components attached to GameObjects. +- **[`manage_editor`](./manage_editor.md)** — Controls and queries the Unity editor's state and settings. +- **[`manage_gameobject`](./manage_gameobject.md)** — Performs CRUD operations on GameObjects. +- **[`manage_graphics`](./manage_graphics.md)** — Manage rendering graphics: volumes, post-processing, light baking, rendering stats, pipeline settings, and URP renderer features. +- **[`manage_material`](./manage_material.md)** — Manages Unity materials (set properties, colors, shaders, etc). +- **[`manage_packages`](./manage_packages.md)** — Manage Unity packages: query, install, remove, embed, and configure registries. +- **[`manage_physics`](./manage_physics.md)** — Manage physics settings, collision matrix, materials, joints, queries, and validation. +- **[`manage_prefabs`](./manage_prefabs.md)** — Manages Unity Prefab assets. +- **[`manage_scene`](./manage_scene.md)** — Performs CRUD operations on Unity scenes. +- **[`manage_script`](./manage_script.md)** — Compatibility router for legacy script operations. +- **[`manage_script_capabilities`](./manage_script_capabilities.md)** — Get manage_script capabilities (supported ops, limits, and guards). +- **[`manage_tools`](./manage_tools.md)** — Manage which tool groups are visible in this session. +- **[`read_console`](./read_console.md)** — Gets messages from or clears the Unity Editor console. +- **[`refresh_unity`](./refresh_unity.md)** — Request a Unity asset database refresh and optionally a script compilation. +- **[`script_apply_edits`](./script_apply_edits.md)** — Structured C# edits (methods/classes) with safer boundaries - prefer this over raw text. +- **[`set_active_instance`](./set_active_instance.md)** — Set the active Unity instance for this client/session. +- **[`validate_script`](./validate_script.md)** — Validate a C# script and return diagnostics. diff --git a/website/docs/reference/tools/core/manage_asset.md b/website/docs/reference/tools/core/manage_asset.md new file mode 100644 index 000000000..ad1485f3f --- /dev/null +++ b/website/docs/reference/tools/core/manage_asset.md @@ -0,0 +1,44 @@ +--- +title: manage_asset +sidebar_label: manage_asset +description: "Performs asset operations (import, create, modify, delete, etc.) in Unity." +--- + +# `manage_asset` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_asset` + +## Description + +Performs asset operations (import, create, modify, delete, etc.) in Unity. + +Tip (payload safety): for `action="search"`, prefer paging (`page_size`, `page_number`) and keep `generate_preview=false` (previews can add large base64 blobs). + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['import', 'create', 'modify', 'delete', 'duplicate', 'move', 'rename', 'search', 'get_info', 'create_folder', 'get_components']` | yes | Perform CRUD operations on assets. | +| `path` | `str` | yes | Asset path (e.g., 'Materials/MyMaterial.mat') or search scope (e.g., 'Assets'). | +| `asset_type` | `str \| None` | — | Asset type (e.g., 'Material', 'Folder') - required for 'create'. Note: For ScriptableObjects, use manage_scriptable_object. | +| `properties` | `dict[str, Any] \| str \| None` | — | Dictionary of properties for 'create'/'modify'. Keys are property names, values are property values. | +| `destination` | `str \| None` | — | Target path for 'duplicate'/'move'. | +| `generate_preview` | `bool` | — | Generate a preview/thumbnail for the asset when supported. Warning: previews may include large base64 payloads; keep false unless needed. | +| `search_pattern` | `str \| None` | — | Search pattern (e.g., '*.prefab' or AssetDatabase filters like 't:MonoScript'). Recommended: put queries like 't:MonoScript' here and set path='Assets'. | +| `filter_type` | `str \| None` | — | Filter type for search | +| `filter_date_after` | `str \| None` | — | Date after which to filter | +| `page_size` | `int \| float \| str \| None` | — | Page size for pagination. Recommended: 25 (smaller for LLM-friendly responses). | +| `page_number` | `int \| float \| str \| None` | — | Page number for pagination (1-based). | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/manage_build.md b/website/docs/reference/tools/core/manage_build.md new file mode 100644 index 000000000..97506a980 --- /dev/null +++ b/website/docs/reference/tools/core/manage_build.md @@ -0,0 +1,47 @@ +--- +title: manage_build +sidebar_label: manage_build +description: "Manage Unity player builds — trigger builds, switch platforms, configure settings, manage build scenes and profiles, run batch builds across platforms." +--- + +# `manage_build` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_build` + +## Description + +Manage Unity player builds — trigger builds, switch platforms, configure settings, manage build scenes and profiles, run batch builds across platforms. Actions: build, status, platform, settings, scenes, profiles, batch, cancel. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `str` | yes | Action: build, status, platform, settings, scenes, profiles, batch, cancel | +| `target` | `str \| None` | — | Build target: windows64, osx, linux64, android, ios, webgl, uwp, tvos, visionos | +| `output_path` | `str \| None` | — | Output path for the build | +| `scenes` | `str \| None` | — | JSON array of scene paths, or comma-separated paths | +| `development` | `str \| None` | — | Development build (true/false) | +| `options` | `str \| None` | — | JSON array of BuildOptions: clean_build, auto_run, deep_profiling, compress_lz4, strict_mode, detailed_report | +| `subtarget` | `str \| None` | — | Build subtarget: player or server | +| `scripting_backend` | `str \| None` | — | Scripting backend: mono or il2cpp (persistent change) | +| `profile` | `str \| None` | — | Build Profile asset path (Unity 6+ only) | +| `property` | `str \| None` | — | Settings property: product_name, company_name, version, bundle_id, scripting_backend, defines, architecture | +| `value` | `str \| None` | — | Value to set for the property (omit to read) | +| `activate` | `str \| None` | — | Activate a build profile (true/false) | +| `targets` | `str \| None` | — | JSON array of targets for batch build | +| `profiles` | `str \| None` | — | JSON array of profile paths for batch build (Unity 6+) | +| `output_dir` | `str \| None` | — | Base output directory for batch builds | +| `job_id` | `str \| None` | — | Job ID for status/cancel | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/manage_camera.md b/website/docs/reference/tools/core/manage_camera.md new file mode 100644 index 000000000..b66a557c9 --- /dev/null +++ b/website/docs/reference/tools/core/manage_camera.md @@ -0,0 +1,80 @@ +--- +title: manage_camera +sidebar_label: manage_camera +description: "Manage cameras (Unity Camera + Cinemachine)." +--- + +# `manage_camera` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_camera` + +## Description + +Manage cameras (Unity Camera + Cinemachine). Works without Cinemachine using basic Camera; unlocks presets, pipelines, and blending when Cinemachine is installed. Use ping to check Cinemachine availability. + +SETUP: +- ping: Check if Cinemachine is available +- ensure_brain: Ensure CinemachineBrain exists on main camera +- get_brain_status: Get Brain state (active camera, blend, etc.) + +CAMERA CREATION: +- create_camera: Create camera with preset (third_person, freelook, follow, dolly, static, top_down, side_scroller). Falls back to basic Camera without Cinemachine. + +CAMERA CONFIGURATION: +- set_target: Set Follow and/or LookAt targets on a camera +- set_priority: Set camera priority for Brain selection +- set_lens: Configure lens (fieldOfView, nearClipPlane, farClipPlane, orthographicSize, dutch) +- set_body: Configure Body component (bodyType to swap, plus component properties) +- set_aim: Configure Aim component (aimType to swap, plus component properties) +- set_noise: Configure Noise component (amplitudeGain, frequencyGain) + +EXTENSIONS: +- add_extension: Add extension (extensionType: CinemachineConfiner2D, CinemachineDeoccluder, CinemachineImpulseListener, CinemachineFollowZoom, CinemachineRecomposer, etc.) +- remove_extension: Remove extension by type + +CAMERA CONTROL: +- set_blend: Configure default blend (style: Cut/EaseInOut/Linear/etc., duration) +- force_camera: Override Brain to use specific camera +- release_override: Release camera override +- list_cameras: List all cameras with status + +CAPTURE: +- screenshot: Capture a screenshot. By default (no camera specified) uses ScreenCapture API, which captures all render layers including Screen Space - Overlay UI canvases. Specifying a camera uses direct camera rendering, which EXCLUDES Screen Space - Overlay canvases (use only when you need a specific viewpoint without UI). Supports include_image=true for inline base64 PNG, batch='surround' for 6-angle contact sheet, batch='orbit' for configurable grid, view_target/view_position for positioned capture, and capture_source='scene_view' to capture the active Unity Scene View viewport. +- screenshot_multiview: Shorthand for screenshot with batch='surround' and include_image=true. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `str` | yes | The camera action to perform. | +| `target` | `str \| None` | — | Target camera (name, path, or instance ID). | +| `search_method` | `Literal['by_id', 'by_name', 'by_path'] \| None` | — | How to find target. | +| `properties` | `dict[str, Any] \| str \| None` | — | Action-specific parameters (dict or JSON string). | +| `screenshot_file_name` | `str \| None` | — | Screenshot file name (optional). Defaults to timestamp. | +| `screenshot_super_size` | `int \| str \| None` | — | Screenshot supersize multiplier (integer >= 1). | +| `camera` | `str \| None` | — | Camera to capture from (name, path, or instance ID). Omit to use ScreenCapture API (captures all layers including Screen Space Overlay UI). Specify only when you need a particular camera viewpoint; note that Screen Space - Overlay canvases will NOT appear in camera-rendered captures. | +| `include_image` | `bool \| str \| None` | — | If true, return screenshot as inline base64 PNG. Default false. | +| `max_resolution` | `int \| str \| None` | — | Max resolution (longest edge px) for inline image. Default 640. | +| `capture_source` | `Literal['game_view', 'scene_view'] \| None` | — | Screenshot source. 'game_view' (default) captures the game/camera path; 'scene_view' captures the active Unity Scene View viewport. | +| `batch` | `str \| None` | — | Batch capture mode: 'surround' (6 angles) or 'orbit' (configurable grid). | +| `view_target` | `str \| int \| list[float] \| None` | — | Target to focus on. GameObject name/path/ID or [x,y,z]. For game_view: aims camera at target. For scene_view: frames the Scene View on the target. | +| `view_position` | `list[float] \| str \| None` | — | World position [x,y,z] to place camera for positioned capture. | +| `view_rotation` | `list[float] \| str \| None` | — | Euler rotation [x,y,z] for camera. Overrides view_target if both provided. | +| `orbit_angles` | `int \| str \| None` | — | Number of azimuth samples for batch='orbit' (default 8, max 36). | +| `orbit_elevations` | `list[float] \| str \| None` | — | Elevation angles in degrees for batch='orbit' (default [0, 30, -15]). | +| `orbit_distance` | `float \| str \| None` | — | Camera distance from target for batch='orbit' (default auto). | +| `orbit_fov` | `float \| str \| None` | — | Camera FOV in degrees for batch='orbit' (default 60). | +| `output_folder` | `str \| None` | — | Optional folder for screenshot output. Project-relative (e.g. 'Assets/Screenshots' or 'Captures') or absolute path inside the project. Overrides the user's Editor preference. If omitted, falls back to the Editor preference, then to the built-in default (Assets/Screenshots). | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/manage_components.md b/website/docs/reference/tools/core/manage_components.md new file mode 100644 index 000000000..4f10789c6 --- /dev/null +++ b/website/docs/reference/tools/core/manage_components.md @@ -0,0 +1,39 @@ +--- +title: manage_components +sidebar_label: manage_components +description: "Add, remove, or set properties on components attached to GameObjects." +--- + +# `manage_components` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_components` + +## Description + +Add, remove, or set properties on components attached to GameObjects. Actions: add, remove, set_property. Requires target (instance ID or name) and component_type. For READING component data, use the mcpforunity://scene/gameobject/{id}/components resource or mcpforunity://scene/gameobject/{id}/component/{name} for a single component. For creating/deleting GameObjects themselves, use manage_gameobject instead. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['add', 'remove', 'set_property']` | yes | Action to perform: add (add component), remove (remove component), set_property (set component property) | +| `target` | `str \| int` | yes | Target GameObject - instance ID (preferred) or name/path | +| `component_type` | `str` | yes | Component type name (e.g., 'Rigidbody', 'BoxCollider', 'MyScript') | +| `search_method` | `Literal['by_id', 'by_name', 'by_path'] \| None` | — | How to find the target GameObject | +| `property` | `str \| None` | — | Property name to set (for set_property action) | +| `value` | `str \| int \| float \| bool \| dict[Any] \| list[Any] \| None` | — | Value to set (for set_property action). For object references: instance ID (int), asset path (string), or {"guid": "..."} / {"path": "..."}. For Sprite sub-assets: {"guid": "...", "spriteName": ""} or {"guid": "...", "fileID": }. Single-sprite textures auto-resolve. | +| `properties` | `dict[str, Any] \| str \| None` | — | Dictionary of property names to values. Example: {"mass": 5.0, "useGravity": false} | +| `component_index` | `int \| None` | — | Zero-based index to select which component when multiple of the same type exist. Use the components resource to discover indices. If omitted, targets the first instance. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/manage_editor.md b/website/docs/reference/tools/core/manage_editor.md new file mode 100644 index 000000000..61e308760 --- /dev/null +++ b/website/docs/reference/tools/core/manage_editor.md @@ -0,0 +1,35 @@ +--- +title: manage_editor +sidebar_label: manage_editor +description: "Controls and queries the Unity editor's state and settings." +--- + +# `manage_editor` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_editor` + +## Description + +Controls and queries the Unity editor's state and settings. Read-only actions: telemetry_status, telemetry_ping. Modifying actions: play, pause, stop, set_active_tool, add_tag, remove_tag, add_layer, remove_layer, deploy_package, restore_package, undo, redo. For prefab editing (open/save/close prefab stage), use manage_prefabs. deploy_package copies the configured MCPForUnity source folder into the project's installed package location (triggers recompile, no confirmation dialog). restore_package reverts to the pre-deployment backup. undo/redo perform Unity editor undo/redo and return the affected group name. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['telemetry_status', 'telemetry_ping', 'play', 'pause', 'stop', 'set_active_tool', 'add_tag', 'remove_tag', 'add_layer', 'remove_layer', 'deploy_package', 'restore_package', 'undo', 'redo']` | yes | Get and update the Unity Editor state. deploy_package copies the configured MCPForUnity source into the project's package location (triggers recompile). restore_package reverts the last deployment from backup. undo/redo perform editor undo/redo. For prefab editing (open/save/close prefab stage), use manage_prefabs. | +| `tool_name` | `str \| None` | — | Tool name when setting active tool | +| `tag_name` | `str \| None` | — | Tag name when adding and removing tags | +| `layer_name` | `str \| None` | — | Layer name when adding and removing layers | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/manage_gameobject.md b/website/docs/reference/tools/core/manage_gameobject.md new file mode 100644 index 000000000..db00ac02e --- /dev/null +++ b/website/docs/reference/tools/core/manage_gameobject.md @@ -0,0 +1,126 @@ +--- +title: manage_gameobject +sidebar_label: manage_gameobject +description: "Performs CRUD operations on GameObjects." +--- + +# `manage_gameobject` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_gameobject` + +## Description + +Performs CRUD operations on GameObjects. Actions: create, modify, delete, duplicate, move_relative, look_at. NOT for searching — use the find_gameobjects tool to search by name/tag/layer/component/path. NOT for component management — use the manage_components tool (add/remove/set_property) or mcpforunity://scene/gameobject/{id}/components resource (read). + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['create', 'modify', 'delete', 'duplicate', 'move_relative', 'look_at'] \| None` | — | Action to perform on GameObject. | +| `target` | `str \| None` | — | GameObject identifier by name, path, or instance ID for modify/delete/duplicate actions | +| `search_method` | `Literal['by_id', 'by_name', 'by_path', 'by_tag', 'by_layer', 'by_component'] \| None` | — | How to resolve 'target'. If omitted, Unity infers: instance ID -> by_id, path (contains '/') -> by_path, otherwise by_name. | +| `name` | `str \| None` | — | GameObject name for 'create' (initial name) and 'modify' (rename) actions. | +| `tag` | `str \| None` | — | Tag name - used for both 'create' (initial tag) and 'modify' (change tag) | +| `parent` | `str \| None` | — | Parent GameObject reference - used for both 'create' (initial parent) and 'modify' (change parent) | +| `position` | `list[float] \| dict[str, float] \| str \| None` | — | Position as [x, y, z] array, {x, y, z} object, or JSON string | +| `rotation` | `list[float] \| dict[str, float] \| str \| None` | — | Rotation as [x, y, z] euler angles array, {x, y, z} object, or JSON string | +| `scale` | `list[float] \| dict[str, float] \| str \| None` | — | Scale as [x, y, z] array, {x, y, z} object, or JSON string | +| `components_to_add` | `list[str] \| str \| None` | — | List of component names to add during 'create' or 'modify' | +| `primitive_type` | `str \| None` | — | Primitive type for 'create' action | +| `save_as_prefab` | `bool \| str \| None` | — | If True, saves the created GameObject as a prefab (accepts true/false or 'true'/'false') | +| `prefab_path` | `str \| None` | — | Path for prefab creation | +| `prefab_folder` | `str \| None` | — | Folder for prefab creation | +| `set_active` | `bool \| str \| None` | — | If True, sets the GameObject active (accepts true/false or 'true'/'false') | +| `layer` | `str \| None` | — | Layer name | +| `is_static` | `bool \| str \| None` | — | Set the GameObject's static flag. true = all StaticEditorFlags, false = none (accepts true/false or 'true'/'false') | +| `components_to_remove` | `list[str] \| str \| None` | — | List of component names to remove | +| `component_properties` | `dict[str, dict[str, Any]] \| str \| None` | — | Dictionary of component names to their properties to set. For example: `{"MyScript": {"otherObject": {"find": "Player", "method": "by_name"}}}` assigns GameObject `{"MyScript": {"playerHealth": {"find": "Player", "component": "HealthComponent"}}}` assigns Component Example set nested property: - Access shared material: `{"MeshRenderer": {"sharedMaterial.color": [1, 0, 0, 1]}}` | +| `new_name` | `str \| None` | — | New name for the duplicated object (default: SourceName_Copy) | +| `offset` | `list[float] \| str \| None` | — | Offset from original/reference position as [x, y, z] array (list or JSON string) | +| `reference_object` | `str \| None` | — | Reference object for relative movement (required for move_relative) | +| `direction` | `Literal['left', 'right', 'up', 'down', 'forward', 'back', 'front', 'backward', 'behind'] \| None` | — | Direction for relative movement (e.g., 'right', 'up', 'forward') | +| `distance` | `float \| None` | — | Distance to move in the specified direction (default: 1.0) | +| `world_space` | `bool \| str \| None` | — | If True (default), use world space directions; if False, use reference object's local directions | +| `look_at_target` | `list[float] \| str \| None` | — | World position [x,y,z] or GameObject name/path/ID to look at (for look_at action). | +| `look_at_up` | `list[float] \| str \| None` | — | Optional up vector [x,y,z] for look_at. Defaults to [0,1,0]. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +### Create a red cube at the world origin + +> Create a cube called `RedCube` at (0, 0, 0). + +```json +{ + "action": "create", + "name": "RedCube", + "primitive_type": "Cube", + "position": [0, 0, 0] +} +``` + +Pair with [`manage_material`](./manage_material) to make it actually red. + +### Find a GameObject by name and move it + +> Move the `Player` 5 units up. + +```json +{ + "action": "modify", + "target": "Player", + "search_method": "by_name", + "position": [0, 5, 0] +} +``` + +`search_method: by_name` matches the first GameObject whose name equals `Player`. Use `by_path` for `Parent/Child/Leaf` lookups or `by_id` for instance IDs. + +### Parent one GameObject under another + +> Make `Sword` a child of `Player/RightHand`. + +```json +{ + "action": "modify", + "target": "Sword", + "search_method": "by_name", + "parent": "Player/RightHand" +} +``` + +### Delete every GameObject tagged `Cleanup` + +> Delete all objects tagged `Cleanup` in the current scene. + +```json +{ + "action": "delete", + "target": "Cleanup", + "search_method": "by_tag" +} +``` + +### Multi-instance routing + +> In the `Editor2` instance, duplicate `MainCamera`. + +```json +{ + "action": "duplicate", + "target": "MainCamera", + "search_method": "by_name", + "unity_instance": "Editor2" +} +``` + +See [Multi-Instance Routing](/guides/multi-instance) for the full routing model. + + diff --git a/website/docs/reference/tools/core/manage_graphics.md b/website/docs/reference/tools/core/manage_graphics.md new file mode 100644 index 000000000..7ac2814ee --- /dev/null +++ b/website/docs/reference/tools/core/manage_graphics.md @@ -0,0 +1,101 @@ +--- +title: manage_graphics +sidebar_label: manage_graphics +description: "Manage rendering graphics: volumes, post-processing, light baking, rendering stats, pipeline settings, and URP renderer features." +--- + +# `manage_graphics` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_graphics` + +## Description + +Manage rendering graphics: volumes, post-processing, light baking, rendering stats, pipeline settings, and URP renderer features. Use ping to check pipeline and available features. + +VOLUME (require URP/HDRP): +- volume_create, volume_add_effect, volume_set_effect, volume_remove_effect +- volume_get_info, volume_set_properties, volume_list_effects, volume_create_profile + +BAKE (Edit mode only): +- bake_start, bake_cancel, bake_status, bake_clear, bake_reflection_probe +- bake_get_settings, bake_set_settings +- bake_create_light_probe_group, bake_create_reflection_probe, bake_set_probe_positions + +STATS: +- stats_get: Rendering counters (draw calls, batches, triangles, etc.) +- stats_list_counters, stats_set_scene_debug, stats_get_memory + +PIPELINE: +- pipeline_get_info, pipeline_set_quality, pipeline_get_settings, pipeline_set_settings + +FEATURES (URP only): +- feature_list, feature_add, feature_remove, feature_configure, feature_toggle, feature_reorder + +SKYBOX / ENVIRONMENT: +- skybox_get: Read all environment settings (material, ambient, fog, reflection, sun) +- skybox_set_material: Set skybox material by asset path +- skybox_set_properties: Set properties on current skybox material (tint, exposure, rotation) +- skybox_set_ambient: Set ambient lighting mode and colors +- skybox_set_fog: Enable/configure fog (mode, color, density, start/end distance) +- skybox_set_reflection: Set environment reflection settings +- skybox_set_sun: Set the sun source light + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `str` | yes | The graphics action to perform. | +| `target` | `str \| None` | — | Target object name or instance ID. | +| `effect` | `str \| None` | — | Effect type name (e.g., 'Bloom', 'Vignette'). | +| `parameters` | `dict[str, Any] \| None` | — | Dict of parameter values. | +| `properties` | `dict[str, Any] \| None` | — | Dict of properties to set. | +| `settings` | `dict[str, Any] \| None` | — | Dict of settings (bake/pipeline). | +| `name` | `str \| None` | — | Name for created objects. | +| `is_global` | `bool \| None` | — | Whether Volume is global (default true). | +| `weight` | `float \| None` | — | Volume weight (0-1). | +| `priority` | `float \| None` | — | Volume priority. | +| `profile_path` | `str \| None` | — | Asset path for VolumeProfile. | +| `effects` | `list[dict[str, Any]] \| None` | — | Effect definitions for volume_create. | +| `path` | `str \| None` | — | Asset path for volume_create_profile. | +| `level` | `str \| None` | — | Quality level name or index. | +| `position` | `list[float] \| None` | — | Position [x,y,z]. | +| `grid_size` | `list[int] \| None` | — | Probe grid size [x,y,z]. | +| `spacing` | `float \| None` | — | Probe grid spacing. | +| `size` | `list[float] \| None` | — | Probe/volume size [x,y,z]. | +| `resolution` | `int \| None` | — | Probe resolution. | +| `mode` | `str \| None` | — | Probe mode or debug mode. | +| `hdr` | `bool \| None` | — | HDR for reflection probes. | +| `box_projection` | `bool \| None` | — | Box projection for reflection probes. | +| `positions` | `list[list[float]] \| None` | — | Probe positions array. | +| `index` | `int \| None` | — | Feature index. | +| `active` | `bool \| None` | — | Feature active state. | +| `order` | `list[int] \| None` | — | Feature reorder indices. | +| `async_bake` | `bool \| None` | — | Async bake (default true). | +| `feature_type` | `str \| None` | — | Renderer feature type name. | +| `material` | `str \| None` | — | Material asset path for feature. | +| `color` | `list[float] \| None` | — | Color [r,g,b,a] for ambient/fog. | +| `intensity` | `float \| None` | — | Intensity value (ambient/reflection). | +| `ambient_mode` | `str \| None` | — | Ambient mode: Skybox, Trilight, Flat, Custom. | +| `equator_color` | `list[float] \| None` | — | Equator color [r,g,b,a] (Trilight mode). | +| `ground_color` | `list[float] \| None` | — | Ground color [r,g,b,a] (Trilight mode). | +| `fog_enabled` | `bool \| None` | — | Enable or disable fog. | +| `fog_mode` | `str \| None` | — | Fog mode: Linear, Exponential, ExponentialSquared. | +| `fog_color` | `list[float] \| None` | — | Fog color [r,g,b,a]. | +| `fog_density` | `float \| None` | — | Fog density (Exponential modes). | +| `fog_start` | `float \| None` | — | Fog start distance (Linear mode). | +| `fog_end` | `float \| None` | — | Fog end distance (Linear mode). | +| `bounces` | `int \| None` | — | Reflection bounces. | +| `reflection_mode` | `str \| None` | — | Default reflection mode: Skybox, Custom. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/manage_material.md b/website/docs/reference/tools/core/manage_material.md new file mode 100644 index 000000000..11b843936 --- /dev/null +++ b/website/docs/reference/tools/core/manage_material.md @@ -0,0 +1,101 @@ +--- +title: manage_material +sidebar_label: manage_material +description: "Manages Unity materials (set properties, colors, shaders, etc)." +--- + +# `manage_material` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_material` + +## Description + +Manages Unity materials (set properties, colors, shaders, etc). Read-only actions: ping, get_material_info. Modifying actions: create, set_material_shader_property, set_material_color, assign_material_to_renderer, set_renderer_color. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['ping', 'create', 'set_material_shader_property', 'set_material_color', 'assign_material_to_renderer', 'set_renderer_color', 'get_material_info']` | yes | Action to perform. | +| `material_path` | `str \| None` | — | Path to material asset (Assets/...) | +| `property` | `str \| None` | — | Shader property name (e.g., _BaseColor, _MainTex) | +| `shader` | `str \| None` | — | Shader name (default: Standard) | +| `properties` | `dict[str, Any] \| str \| None` | — | Initial properties to set as {name: value} dict. | +| `value` | `list \| float \| int \| str \| bool \| None` | — | Value to set (color array, float, texture path/instruction) | +| `color` | `list[float] \| dict[str, float] \| str \| None` | — | Color as [r, g, b] or [r, g, b, a] array, {r, g, b, a} object, or JSON string. | +| `target` | `str \| None` | — | Target GameObject (name, path, or find instruction) | +| `search_method` | `Literal['by_id', 'by_name', 'by_path', 'by_tag', 'by_layer', 'by_component'] \| None` | — | Search method for target | +| `slot` | `int \| None` | — | Material slot index (0-based) | +| `mode` | `Literal['shared', 'instance', 'property_block', 'create_unique'] \| None` | — | Assignment/modification mode; behavior when omitted is action-specific on the Unity side. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +### Create a red material from scratch + +> Create `Assets/Materials/Red.mat` using the Standard shader, base color red. + +```json +{ + "action": "create", + "material_path": "Materials/Red.mat", + "shader": "Standard", + "properties": { "_Color": [1, 0, 0, 1] } +} +``` + +For URP, use `"shader": "Universal Render Pipeline/Lit"` and property `_BaseColor`. + +### Assign an existing material to a GameObject + +> Apply `Assets/Materials/Red.mat` to the `RedCube`. + +```json +{ + "action": "assign_material_to_renderer", + "target": "RedCube", + "search_method": "by_name", + "material_path": "Materials/Red.mat", + "slot": 0, + "mode": "shared" +} +``` + +`mode: shared` reuses the asset. `mode: instance` clones it per-renderer (use sparingly — costs draw call batching). + +### Change just one shader property + +> Set `_Metallic` on `Materials/Red.mat` to 0.8. + +```json +{ + "action": "set_material_shader_property", + "material_path": "Materials/Red.mat", + "property": "_Metallic", + "value": 0.8 +} +``` + +### Tint a renderer without touching the shared material + +> Tint the cube's MeshRenderer blue using a MaterialPropertyBlock. + +```json +{ + "action": "set_renderer_color", + "target": "RedCube", + "search_method": "by_name", + "color": [0, 0, 1, 1], + "mode": "property_block" +} +``` + +`property_block` mode avoids creating a per-instance material clone, preserving batching. + + diff --git a/website/docs/reference/tools/core/manage_packages.md b/website/docs/reference/tools/core/manage_packages.md new file mode 100644 index 000000000..446d40c7b --- /dev/null +++ b/website/docs/reference/tools/core/manage_packages.md @@ -0,0 +1,59 @@ +--- +title: manage_packages +sidebar_label: manage_packages +description: "Manage Unity packages: query, install, remove, embed, and configure registries." +--- + +# `manage_packages` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_packages` + +## Description + +Manage Unity packages: query, install, remove, embed, and configure registries. + +QUERY (read-only): +- list_packages: List all installed packages +- search_packages: Search Unity registry by keyword +- get_package_info: Get details about a specific installed package +- ping: Check package manager availability +- status: Poll async job status (job_id required for list/search; optional for add/remove/embed) + +INSTALL/REMOVE: +- add_package: Install a package (name, name@version, git URL, or file: path) +- remove_package: Remove a package (checks dependents; use force=true to override) + +REGISTRIES: +- list_registries: List all scoped registries +- add_registry: Add a scoped registry (e.g., OpenUPM) +- remove_registry: Remove a scoped registry + +UTILITY: +- embed_package: Copy package to local Packages/ for editing +- resolve_packages: Force re-resolution of all packages + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `str` | yes | The package action to perform. | +| `package` | `str \| None` | — | Package identifier (name, name@version, git URL, or file: path). | +| `force` | `bool \| None` | — | Force removal even if other packages depend on it. | +| `query` | `str \| None` | — | Search query for search_packages. | +| `job_id` | `str \| None` | — | Job ID for polling status. | +| `name` | `str \| None` | — | Registry name for add_registry/remove_registry. | +| `url` | `str \| None` | — | Registry URL for add_registry. | +| `scopes` | `list[str] \| None` | — | Registry scopes for add_registry. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/manage_physics.md b/website/docs/reference/tools/core/manage_physics.md new file mode 100644 index 000000000..8dd05af20 --- /dev/null +++ b/website/docs/reference/tools/core/manage_physics.md @@ -0,0 +1,94 @@ +--- +title: manage_physics +sidebar_label: manage_physics +description: "Manage physics settings, collision matrix, materials, joints, queries, and validation." +--- + +# `manage_physics` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_physics` + +## Description + +Manage physics settings, collision matrix, materials, joints, queries, and validation. + +SETTINGS: ping, get_settings, set_settings +COLLISION MATRIX: get_collision_matrix, set_collision_matrix +MATERIALS: create_physics_material, configure_physics_material, assign_physics_material +JOINTS: add_joint, configure_joint, remove_joint +QUERIES: raycast, raycast_all, linecast, shapecast, overlap +FORCES: apply_force +RIGIDBODY: get_rigidbody, configure_rigidbody +VALIDATION: validate +SIMULATION: simulate_step + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['ping', 'get_settings', 'set_settings', 'get_collision_matrix', 'set_collision_matrix', 'create_physics_material', 'configure_physics_material', 'assign_physics_material', 'add_joint', 'configure_joint', 'remove_joint', 'raycast', 'raycast_all', 'linecast', 'shapecast', 'overlap', 'validate', 'simulate_step', 'apply_force', 'get_rigidbody', 'configure_rigidbody']` | yes | The physics action to perform. | +| `dimension` | `str \| None` | — | Physics dimension: '3d' (default) or '2d'. | +| `settings` | `dict[str, Any] \| None` | — | Key-value settings for set_settings. | +| `layer_a` | `str \| None` | — | Layer name or index for collision matrix. | +| `layer_b` | `str \| None` | — | Layer name or index for collision matrix. | +| `collide` | `bool \| None` | — | Whether layers should collide (set_collision_matrix). | +| `name` | `str \| None` | — | Name for new physics material. | +| `path` | `str \| None` | — | Asset path for materials. | +| `dynamic_friction` | `float \| None` | — | Dynamic friction (0-1). | +| `static_friction` | `float \| None` | — | Static friction (0-1). | +| `bounciness` | `float \| None` | — | Bounciness (0-1). | +| `friction` | `float \| None` | — | Friction for 2D materials. | +| `friction_combine` | `str \| None` | — | Friction combine mode: Average, Minimum, Multiply, Maximum. | +| `bounce_combine` | `str \| None` | — | Bounce combine mode: Average, Minimum, Multiply, Maximum. | +| `material_path` | `str \| None` | — | Path to physics material asset for assign. | +| `target` | `str \| None` | — | Target GameObject name or instance ID. | +| `collider_type` | `str \| None` | — | Specific collider type to target. | +| `search_method` | `str \| None` | — | Search method for target resolution. | +| `joint_type` | `str \| None` | — | Joint type: fixed, hinge, spring, character, configurable (3D); distance, fixed, friction, hinge, relative, slider, spring, target, wheel (2D). | +| `connected_body` | `str \| None` | — | Connected body target for joints. | +| `motor` | `dict[str, Any] \| None` | — | Motor config: {targetVelocity, force, freeSpin}. | +| `limits` | `dict[str, Any] \| None` | — | Limits config: {min, max, bounciness}. | +| `spring` | `dict[str, Any] \| None` | — | Spring config: {spring, damper, targetPosition}. | +| `drive` | `dict[str, Any] \| None` | — | Drive config for ConfigurableJoint. | +| `properties` | `dict[str, Any] \| None` | — | Direct property dict for joints or materials. | +| `origin` | `list[float] \| None` | — | Ray origin [x,y,z] or [x,y]. | +| `direction` | `list[float] \| None` | — | Ray direction [x,y,z] or [x,y]. | +| `max_distance` | `float \| None` | — | Max raycast distance. | +| `layer_mask` | `str \| None` | — | Layer mask for queries (name or int). | +| `query_trigger_interaction` | `str \| None` | — | Trigger interaction: UseGlobal, Ignore, Collide. | +| `shape` | `str \| None` | — | Overlap shape: sphere, box, capsule (3D); circle, box, capsule (2D). | +| `position` | `list[float] \| None` | — | Overlap position [x,y,z] or [x,y]. | +| `size` | `Any \| None` | — | Overlap size: float (radius) or [x,y,z] (half-extents). | +| `start` | `list[float] \| None` | — | Linecast start point [x,y,z] or [x,y]. | +| `end` | `list[float] \| None` | — | Linecast end point [x,y,z] or [x,y]. | +| `point1` | `list[float] \| None` | — | Capsule shapecast point1 [x,y,z]. | +| `point2` | `list[float] \| None` | — | Capsule shapecast point2 [x,y,z]. | +| `height` | `float \| None` | — | Capsule height for shapecast. | +| `capsule_direction` | `int \| None` | — | Capsule direction: 0=X, 1=Y (default), 2=Z. | +| `angle` | `float \| None` | — | Rotation angle for 2D shape casts. | +| `force` | `list[float] \| None` | — | Force vector [x,y,z] or [x,y] for apply_force. | +| `force_mode` | `str \| None` | — | Force mode: Force, Impulse, Acceleration, VelocityChange (3D); Force, Impulse (2D). | +| `force_type` | `str \| None` | — | Force type: 'normal' (default) or 'explosion' (3D only). | +| `torque` | `list[float] \| None` | — | Torque vector [x,y,z] (3D) or [z] (2D). | +| `explosion_position` | `list[float] \| None` | — | Explosion center [x,y,z]. | +| `explosion_radius` | `float \| None` | — | Explosion radius. | +| `explosion_force` | `float \| None` | — | Explosion force magnitude. | +| `upwards_modifier` | `float \| None` | — | Explosion upwards modifier. | +| `steps` | `int \| None` | — | Number of simulation steps (max 100). | +| `step_size` | `float \| None` | — | Step size in seconds. | +| `page_size` | `int \| None` | — | Page size for validate results (default 50). | +| `cursor` | `int \| None` | — | Cursor offset for validate pagination. | +| `component_index` | `int \| None` | — | Zero-based index to select which component when multiple of the same type exist (e.g., multiple HingeJoints or BoxColliders). If omitted, targets the first instance. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/manage_prefabs.md b/website/docs/reference/tools/core/manage_prefabs.md new file mode 100644 index 000000000..99566e866 --- /dev/null +++ b/website/docs/reference/tools/core/manage_prefabs.md @@ -0,0 +1,50 @@ +--- +title: manage_prefabs +sidebar_label: manage_prefabs +description: "Manages Unity Prefab assets." +--- + +# `manage_prefabs` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_prefabs` + +## Description + +Manages Unity Prefab assets. Actions: get_info, get_hierarchy, create_from_gameobject, modify_contents, open_prefab_stage, save_prefab_stage, close_prefab_stage. Two approaches to prefab editing: (1) Headless: use modify_contents for automated/scripted edits without opening the prefab in the editor. (2) Interactive: use open_prefab_stage to open a prefab, then manage_gameobject/manage_components to edit objects inside the prefab stage, then save_prefab_stage to save and close_prefab_stage to return to the main scene. Use create_child parameter with modify_contents to add child GameObjects or nested prefab instances to a prefab (single object or array for batch creation in one save). Example: create_child=[{"name": "Child1", "primitive_type": "Sphere", "position": [1,0,0]}, {"name": "Nested", "source_prefab_path": "Assets/Prefabs/Bullet.prefab", "position": [0,2,0]}]. Use delete_child parameter to remove child GameObjects from the prefab (single name/path or array of paths for batch deletion. Example: delete_child=["Child1", "Child2/Grandchild"]). Use component_properties with modify_contents to set serialized fields on existing components (e.g. component_properties={"Rigidbody": {"mass": 5.0}, "MyScript": {"health": 100}}). Supports object references via {"guid": "..."}, {"path": "Assets/..."}, or {"instanceID": 123}. Use manage_asset action=search filterType=Prefab to list prefabs. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['create_from_gameobject', 'get_info', 'get_hierarchy', 'modify_contents', 'open_prefab_stage', 'save_prefab_stage', 'close_prefab_stage']` | yes | Prefab operation to perform. | +| `prefab_path` | `str \| None` | — | Prefab asset path (e.g., Assets/Prefabs/MyPrefab.prefab). | +| `target` | `str \| None` | — | Target GameObject: scene object for create_from_gameobject, or object within prefab for modify_contents (name or path like 'Parent/Child'). | +| `allow_overwrite` | `bool \| None` | — | Allow replacing existing prefab. | +| `search_inactive` | `bool \| None` | — | Include inactive GameObjects in search. | +| `unlink_if_instance` | `bool \| None` | — | Unlink from existing prefab before creating new one. | +| `position` | `list[float] \| dict[str, float] \| str \| None` | — | New local position [x, y, z] or {x, y, z} for modify_contents. | +| `rotation` | `list[float] \| dict[str, float] \| str \| None` | — | New local rotation (euler angles) [x, y, z] or {x, y, z} for modify_contents. | +| `scale` | `list[float] \| dict[str, float] \| str \| None` | — | New local scale [x, y, z] or {x, y, z} for modify_contents. | +| `name` | `str \| None` | — | New name for the target object in modify_contents. | +| `tag` | `str \| None` | — | New tag for the target object in modify_contents. | +| `layer` | `str \| None` | — | New layer name for the target object in modify_contents. | +| `set_active` | `bool \| None` | — | Set active state of target object in modify_contents. | +| `parent` | `str \| None` | — | New parent object name/path within prefab for modify_contents. | +| `components_to_add` | `list[str] \| None` | — | Component types to add in modify_contents. | +| `components_to_remove` | `list[str] \| None` | — | Component types to remove in modify_contents. | +| `create_child` | `dict[str, Any] \| list[dict[str, Any]] \| None` | — | Create child GameObject(s) in the prefab. Single object or array of objects, each with: name (required), parent (optional, defaults to target), source_prefab_path (optional: asset path to instantiate as nested prefab, e.g. 'Assets/Prefabs/Bullet.prefab'), primitive_type (optional: Cube, Sphere, Capsule, Cylinder, Plane, Quad), position, rotation, scale, components_to_add, tag, layer, set_active. source_prefab_path and primitive_type are mutually exclusive. | +| `delete_child` | `str \| list[str] \| None` | — | Child name(s) or path(s) to remove from the prefab. Supports single string or array for batch deletion (e.g. 'Child1' or ['Child1', 'Child1/Grandchild']). | +| `component_properties` | `dict[str, dict[str, Any]] \| None` | — | Set properties on existing components in modify_contents. Keys are component type names, values are dicts of property name to value. Example: {"Rigidbody": {"mass": 5.0}, "MyScript": {"health": 100}}. Supports object references via {"guid": "..."}, {"path": "Assets/..."}, or {"instanceID": 123}. For Sprite sub-assets: {"guid": "...", "spriteName": ""}. Single-sprite textures auto-resolve. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/manage_scene.md b/website/docs/reference/tools/core/manage_scene.md new file mode 100644 index 000000000..8e571028c --- /dev/null +++ b/website/docs/reference/tools/core/manage_scene.md @@ -0,0 +1,110 @@ +--- +title: manage_scene +sidebar_label: manage_scene +description: "Performs CRUD operations on Unity scenes." +--- + +# `manage_scene` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_scene` + +## Description + +Performs CRUD operations on Unity scenes. Read-only actions: get_hierarchy, get_active, get_build_settings, get_loaded_scenes, scene_view_frame. Modifying actions: create (with optional template), load (with optional additive flag), save, close_scene, set_active_scene, move_to_scene, validate (with optional auto_repair). For build settings management (add/remove/enable scenes), use manage_build(action='scenes'). For screenshots, use manage_camera (screenshot, screenshot_multiview actions). + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['create', 'load', 'save', 'get_hierarchy', 'get_active', 'get_build_settings', 'scene_view_frame', 'close_scene', 'set_active_scene', 'get_loaded_scenes', 'move_to_scene', 'validate']` | yes | Perform CRUD operations on Unity scenes and control the Scene View camera. | +| `name` | `str \| None` | — | Scene name. | +| `path` | `str \| None` | — | Scene path. | +| `build_index` | `int \| str \| None` | — | Unity build index (quote as string, e.g., '0'). | +| `scene_view_target` | `str \| int \| None` | — | GameObject reference for scene_view_frame (name, path, or instance ID). | +| `parent` | `str \| int \| None` | — | Optional parent GameObject reference (name/path/instanceID) to list direct children. | +| `page_size` | `int \| str \| None` | — | Page size for get_hierarchy paging. | +| `cursor` | `int \| str \| None` | — | Opaque cursor for paging (offset). | +| `max_nodes` | `int \| str \| None` | — | Hard cap on returned nodes per request (safety). | +| `max_depth` | `int \| str \| None` | — | Accepted for forward-compatibility; current paging returns a single level. | +| `max_children_per_node` | `int \| str \| None` | — | Child paging hint (safety). | +| `include_transform` | `bool \| str \| None` | — | If true, include local transform in node summaries. | +| `scene_name` | `str \| None` | — | Scene name for multi-scene operations. | +| `scene_path` | `str \| None` | — | Full scene path (e.g. 'Assets/Scenes/Level2.unity'). | +| `target` | `str \| int \| None` | — | GameObject reference (name, path, or instanceID) for move_to_scene. | +| `remove_scene` | `bool \| str \| None` | — | For close_scene: true to fully remove, false to just unload. | +| `additive` | `bool \| str \| None` | — | For load: true to open scene additively (keeps current scene). | +| `template` | `str \| None` | — | For create: scene template ('empty', 'default', '3d_basic', '2d_basic'). Omit for empty scene. | +| `auto_repair` | `bool \| str \| None` | — | For validate: true to auto-fix missing scripts (undoable). | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +### Load a scene from `Assets/Scenes/` + +> Open `Assets/Scenes/MainMenu.unity`. + +```json +{ + "action": "load", + "path": "Scenes/MainMenu.unity" +} +``` + +Paths are relative to `Assets/`. Forward slashes only. + +### Get the scene hierarchy (paged) + +> List every GameObject in the active scene. + +```json +{ + "action": "get_hierarchy", + "page_size": 100 +} +``` + +Returns up to `page_size` entries plus a `next_cursor` for the remainder. Always page large hierarchies. + +### Save the active scene + +> Save the active scene under its existing path. + +```json +{ "action": "save" } +``` + +### Create a scene from a template + +> Make a new 3D scene called `Lab`. + +```json +{ + "action": "create", + "path": "Scenes/Lab.unity", + "template": "3d_basic" +} +``` + +Other templates: `2d_basic`, `default`, `empty`. + +### Additive multi-scene editing + +> Load `Scenes/Boss.unity` additively while keeping the current scene open. + +```json +{ + "action": "load", + "path": "Scenes/Boss.unity", + "additive": true +} +``` + +Use `set_active_scene`, `close_scene`, and `move_to_scene` to compose multi-scene setups. + + diff --git a/website/docs/reference/tools/core/manage_script.md b/website/docs/reference/tools/core/manage_script.md new file mode 100644 index 000000000..e5c0ab852 --- /dev/null +++ b/website/docs/reference/tools/core/manage_script.md @@ -0,0 +1,89 @@ +--- +title: manage_script +sidebar_label: manage_script +description: "Compatibility router for legacy script operations." +--- + +# `manage_script` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_script` + +## Description + +Compatibility router for legacy script operations. Prefer apply_text_edits (ranges) or script_apply_edits (structured) for edits. Read-only action: read. Modifying actions: create, delete. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['create', 'read', 'delete']` | yes | Perform CRUD operations on C# scripts. | +| `name` | `str` | yes | Script name (no .cs extension) | +| `path` | `str` | yes | Asset path (default: 'Assets/') | +| `contents` | `str \| None` | — | Contents of the script to create | +| `script_type` | `str \| None` | — | Script type (e.g., 'C#') | +| `namespace` | `str \| None` | — | Namespace for the script | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +:::note Use the right tool for the job +`manage_script` only handles whole-file lifecycle: **create**, **read**, **delete**. For editing existing scripts, reach for: +- **[`script_apply_edits`](./script_apply_edits)** — structured edits (replace method, insert method, anchor-based insert/replace) with balanced-brace guards. Use this for most code changes. +- **[`apply_text_edits`](./apply_text_edits)** — raw line/column text edits with optional SHA precondition. Use for surgical text patches. +- **[`validate_script`](./validate_script)** — Roslyn-based validation (structural or full semantic). +- **[`read_console`](./read_console)** — fetch compile diagnostics after any change. +::: + +### Create a new script + +> Create `Assets/Scripts/PlayerController.cs` with a starter MonoBehaviour. + +```json +{ + "action": "create", + "name": "PlayerController", + "path": "Scripts/", + "namespace": "MyGame", + "contents": "using UnityEngine;\n\nnamespace MyGame {\n public class PlayerController : MonoBehaviour {\n void Update() { }\n }\n}\n" +} +``` + +`path` is relative to `Assets/` and must end in `/`. Omit `contents` to write a minimal stub. + +### Read a script's full contents + +> Show me `Assets/Scripts/PlayerController.cs`. + +```json +{ + "action": "read", + "name": "PlayerController", + "path": "Scripts/" +} +``` + +Returns the full file. For just a SHA (to detect drift between reads and writes), use [`get_sha`](./get_sha) instead — it's cheaper. + +### Delete a script + +> Remove `Assets/Scripts/PlayerController.cs`. + +```json +{ + "action": "delete", + "name": "PlayerController", + "path": "Scripts/" +} +``` + +### After every create / delete + +Unity needs a domain reload to compile the new file (or notice the old one is gone). Poll the `editor_state` resource's `isCompiling` field until it flips back to `false`, then run [`read_console`](./read_console) to catch any compile errors before relying on the new types. + + diff --git a/website/docs/reference/tools/core/manage_script_capabilities.md b/website/docs/reference/tools/core/manage_script_capabilities.md new file mode 100644 index 000000000..3c174a3dd --- /dev/null +++ b/website/docs/reference/tools/core/manage_script_capabilities.md @@ -0,0 +1,35 @@ +--- +title: manage_script_capabilities +sidebar_label: manage_script_capabilities +description: "Get manage_script capabilities (supported ops, limits, and guards)." +--- + +# `manage_script_capabilities` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_script` + +## Description + +Get manage_script capabilities (supported ops, limits, and guards). + Returns: + - ops: list of supported structured ops + - text_ops: list of supported text ops + - max_edit_payload_bytes: server edit payload cap + - guards: header/using guard enabled flag + +## Parameters + +_No parameters._ + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/manage_tools.md b/website/docs/reference/tools/core/manage_tools.md new file mode 100644 index 000000000..79b8aa5ad --- /dev/null +++ b/website/docs/reference/tools/core/manage_tools.md @@ -0,0 +1,33 @@ +--- +title: manage_tools +sidebar_label: manage_tools +description: "Manage which tool groups are visible in this session." +--- + +# `manage_tools` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_tools` + +## Description + +Manage which tool groups are visible in this session. Actions: list_groups (show all groups and their status), activate (enable a group), deactivate (disable a group), sync (refresh visibility from Unity Editor's toggle states), reset (restore defaults). Activating a group makes its tools appear; deactivating hides them. Use sync after toggling tools in the Unity Editor GUI. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['list_groups', 'activate', 'deactivate', 'sync', 'reset']` | yes | Action to perform. | +| `group` | `str \| None` | — | Group name (required for activate / deactivate). Valid groups: animation, core, docs, probuilder, profiling, scripting_ext, testing, ui, vfx | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/read_console.md b/website/docs/reference/tools/core/read_console.md new file mode 100644 index 000000000..a380721a9 --- /dev/null +++ b/website/docs/reference/tools/core/read_console.md @@ -0,0 +1,39 @@ +--- +title: read_console +sidebar_label: read_console +description: "Gets messages from or clears the Unity Editor console." +--- + +# `read_console` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.read_console` + +## Description + +Gets messages from or clears the Unity Editor console. Defaults to 10 most recent entries. Use page_size/cursor for paging. Note: For maximum client compatibility, pass count as a quoted string (e.g., '5'). The 'get' action is read-only; 'clear' modifies ephemeral UI state (not project data). + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['get', 'clear'] \| None` | — | Get or clear the Unity Editor console. Defaults to 'get' if omitted. | +| `types` | `list[Literal['error', 'warning', 'log', 'all']] \| str \| None` | — | Message types to get (accepts list or JSON string) | +| `count` | `int \| str \| None` | — | Max messages to return in non-paging mode (accepts int or string, e.g., 5 or '5'). Ignored when paging with page_size/cursor. | +| `filter_text` | `str \| None` | — | Text filter for messages | +| `page_size` | `int \| str \| None` | — | Page size for paginated console reads. Defaults to 50 when omitted. | +| `cursor` | `int \| str \| None` | — | Opaque cursor for paging (0-based offset). Defaults to 0. | +| `format` | `Literal['plain', 'detailed', 'json'] \| None` | — | Output format | +| `include_stacktrace` | `bool \| str \| None` | — | Include stack traces in output (accepts true/false or 'true'/'false') | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/refresh_unity.md b/website/docs/reference/tools/core/refresh_unity.md new file mode 100644 index 000000000..e898712b0 --- /dev/null +++ b/website/docs/reference/tools/core/refresh_unity.md @@ -0,0 +1,35 @@ +--- +title: refresh_unity +sidebar_label: refresh_unity +description: "Request a Unity asset database refresh and optionally a script compilation." +--- + +# `refresh_unity` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.refresh_unity` + +## Description + +Request a Unity asset database refresh and optionally a script compilation. Can optionally wait for readiness. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `mode` | `Literal['if_dirty', 'force']` | — | Refresh mode | +| `scope` | `Literal['assets', 'scripts', 'all']` | — | Refresh scope | +| `compile` | `Literal['none', 'request']` | — | Whether to request compilation | +| `wait_for_ready` | `bool` | — | If true, wait until editor_state.advice.ready_for_tools is true | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/script_apply_edits.md b/website/docs/reference/tools/core/script_apply_edits.md new file mode 100644 index 000000000..d6440540e --- /dev/null +++ b/website/docs/reference/tools/core/script_apply_edits.md @@ -0,0 +1,186 @@ +--- +title: script_apply_edits +sidebar_label: script_apply_edits +description: "Structured C# edits (methods/classes) with safer boundaries - prefer this over raw text." +--- + +# `script_apply_edits` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.script_apply_edits` + +## Description + +Structured C# edits (methods/classes) with safer boundaries - prefer this over raw text. + Best practices: + - Prefer anchor_* ops for pattern-based insert/replace near stable markers + - Use replace_method/delete_method for whole-method changes (keeps signatures balanced) + - Avoid whole-file regex deletes; validators will guard unbalanced braces + - For tail insertions, prefer anchor/regex_replace on final brace (class closing) + - Pass options.validate='standard' for structural checks; 'basic' for interior-only edits + Canonical fields (use these exact keys): + - op: replace_method | insert_method | delete_method | anchor_insert | anchor_delete | anchor_replace + - className: string (defaults to 'name' if omitted on method/class ops) + - methodName: string (required for replace_method, delete_method) + - replacement: string (required for replace_method, insert_method) + - position: start | end | after | before (insert_method only) + - afterMethodName / beforeMethodName: string (required when position='after'/'before') + - anchor: regex string (for anchor_* ops) + - text: string (for anchor_insert/anchor_replace) + Examples: + 1) Replace a method: + { + "name": "SmartReach", + "path": "Assets/Scripts/Interaction", + "edits": [ + { + "op": "replace_method", + "className": "SmartReach", + "methodName": "HasTarget", + "replacement": "public bool HasTarget(){ return currentTarget!=null; }" + } + ], + "options": {"validate": "standard", "refresh": "immediate"} + } + "2) Insert a method after another: + { + "name": "SmartReach", + "path": "Assets/Scripts/Interaction", + "edits": [ + { + "op": "insert_method", + "className": "SmartReach", + "replacement": "public void PrintSeries(){ Debug.Log(seriesName); }", + "position": "after", + "afterMethodName": "GetCurrentTarget" + } + ], + } + ] + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `name` | `str` | yes | Name of the script to edit | +| `path` | `str` | yes | Path to the script to edit under Assets/ directory | +| `edits` | `list[dict[str, Any]] \| str` | yes | List of edits to apply to the script (JSON list or stringified JSON) | +| `options` | `dict[str, Any] \| None` | — | Options for the script edit | +| `script_type` | `str` | — | Type of the script to edit | +| `namespace` | `str \| None` | — | Namespace of the script to edit | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +:::tip +Prefer this over [`apply_text_edits`](./apply_text_edits) for method-level changes. Structured ops keep braces balanced and survive incidental whitespace drift. Use `apply_text_edits` only when you need surgical line/column patching. +::: + +### Replace a single method + +> In `Assets/Scripts/PlayerController.cs`, make `HasTarget` return `currentTarget != null`. + +```json +{ + "name": "PlayerController", + "path": "Scripts/", + "edits": [ + { + "op": "replace_method", + "className": "PlayerController", + "methodName": "HasTarget", + "replacement": "public bool HasTarget() { return currentTarget != null; }" + } + ], + "options": { "validate": "standard", "refresh": "immediate" } +} +``` + +`path` ends with `/`. `validate: 'standard'` runs Roslyn structural checks before the write commits; use `'basic'` for cheap interior-only checks when you're touching a method body and trust the signature. + +### Insert a new method at the end of a class + +> Add a `Reset()` method after `Update` in `PlayerController`. + +```json +{ + "name": "PlayerController", + "path": "Scripts/", + "edits": [ + { + "op": "insert_method", + "className": "PlayerController", + "methodName": "Update", + "position": "after", + "replacement": "void Reset() { currentTarget = null; }" + } + ] +} +``` + +`position`: `start | end | before | after`. With `before`/`after`, `methodName` is the anchor; with `start`/`end`, it's the position within the class body. + +### Delete a method + +> Remove `PlayerController.LegacyTick`. + +```json +{ + "name": "PlayerController", + "path": "Scripts/", + "edits": [ + { "op": "delete_method", "className": "PlayerController", "methodName": "LegacyTick" } + ] +} +``` + +### Anchor-based insert (around a regex marker) + +> Add a `Debug.Log` right after the line containing `// --- input ---`. + +```json +{ + "name": "PlayerController", + "path": "Scripts/", + "edits": [ + { + "op": "anchor_insert", + "anchor": "//\\s*---\\s*input\\s*---", + "position": "after", + "replacement": " Debug.Log(\"input frame\");" + } + ] +} +``` + +Anchor ops are great for adding instrumentation near stable comment markers without locking into exact line numbers. The anchor is a regex; escape literal characters. + +### Apply several edits atomically + +> Replace two methods AND remove a third — all in one transaction. If validation fails on any, nothing is written. + +```json +{ + "name": "PlayerController", + "path": "Scripts/", + "edits": [ + { "op": "replace_method", "methodName": "Awake", "replacement": "void Awake() { Init(); }" }, + { "op": "replace_method", "methodName": "Update", "replacement": "void Update() { Tick(); }" }, + { "op": "delete_method", "methodName": "OnDestroyOld" } + ], + "options": { "validate": "standard" } +} +``` + +`className` defaults to `name` when omitted on method ops, so for single-class files you can skip it. + +### After every edit + +Poll `editor_state.isCompiling` until it flips back to `false`, then run [`read_console`](./read_console) to catch any compile errors before relying on the new types. + + diff --git a/website/docs/reference/tools/core/set_active_instance.md b/website/docs/reference/tools/core/set_active_instance.md new file mode 100644 index 000000000..b3d4815a0 --- /dev/null +++ b/website/docs/reference/tools/core/set_active_instance.md @@ -0,0 +1,32 @@ +--- +title: set_active_instance +sidebar_label: set_active_instance +description: "Set the active Unity instance for this client/session." +--- + +# `set_active_instance` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.set_active_instance` + +## Description + +Set the active Unity instance for this client/session. Accepts Name@hash, hash prefix, or port number (stdio only). + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `instance` | `str` | yes | Target instance (Name@hash, hash prefix, or port number in stdio mode) | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/core/validate_script.md b/website/docs/reference/tools/core/validate_script.md new file mode 100644 index 000000000..23b0d5e34 --- /dev/null +++ b/website/docs/reference/tools/core/validate_script.md @@ -0,0 +1,34 @@ +--- +title: validate_script +sidebar_label: validate_script +description: "Validate a C# script and return diagnostics." +--- + +# `validate_script` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `core`  ·  **Module:** `services.tools.manage_script` + +## Description + +Validate a C# script and return diagnostics. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `uri` | `str` | yes | URI of the script to validate under Assets/ directory, mcpforunity://path/Assets/... or file://... or Assets/... | +| `level` | `Literal['basic', 'standard']` | — | Validation level | +| `include_diagnostics` | `bool` | — | Include full diagnostics and summary | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/docs/_category_.json b/website/docs/reference/tools/docs/_category_.json new file mode 100644 index 000000000..92543d5be --- /dev/null +++ b/website/docs/reference/tools/docs/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "docs", + "link": { + "type": "doc", + "id": "reference/tools/docs/index" + }, + "collapsed": true +} diff --git a/website/docs/reference/tools/docs/index.md b/website/docs/reference/tools/docs/index.md new file mode 100644 index 000000000..b9cda82ba --- /dev/null +++ b/website/docs/reference/tools/docs/index.md @@ -0,0 +1,12 @@ +--- +title: "docs tools" +sidebar_label: "docs" +description: "MCP for Unity tools in the docs group." +--- + +# `docs` tools + +Unity API reflection and documentation lookup + +- **[`unity_docs`](./unity_docs.md)** — Fetch official Unity documentation from docs.unity3d.com. +- **[`unity_reflect`](./unity_reflect.md)** — Inspect Unity's live C# API via reflection. diff --git a/website/docs/reference/tools/docs/unity_docs.md b/website/docs/reference/tools/docs/unity_docs.md new file mode 100644 index 000000000..0d7632d86 --- /dev/null +++ b/website/docs/reference/tools/docs/unity_docs.md @@ -0,0 +1,47 @@ +--- +title: unity_docs +sidebar_label: unity_docs +description: "Fetch official Unity documentation from docs.unity3d.com." +--- + +# `unity_docs` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `docs`  ·  **Module:** `services.tools.unity_docs` + +## Description + +Fetch official Unity documentation from docs.unity3d.com. Returns descriptions, parameter details, code examples, and caveats. Use after unity_reflect confirms a type exists, to get usage patterns, gotchas, and code examples before writing implementation code. + +Actions: +- get_doc: Fetch ScriptReference docs for a class or member. Requires class_name. Optional member_name, version. +- get_manual: Fetch a Unity Manual page. Requires slug (e.g., 'execution-order', 'urp/urp-introduction'). Optional version. +- get_package_doc: Fetch package documentation. Requires package, page, pkg_version (e.g., package='com.unity.render-pipelines.universal', page='2d-index', pkg_version='17.0'). +- lookup: Search all doc sources in parallel (ScriptReference + Manual + package docs). Requires query or queries (comma-separated). Supports batch: queries='Physics.Raycast,NavMeshAgent,Light2D' searches all in one call. Optional package + pkg_version to also search package docs. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `str` | yes | The documentation action to perform. | +| `class_name` | `str \| None` | — | Unity class name (e.g. 'Physics', 'Transform'). | +| `member_name` | `str \| None` | — | Method or property name to look up. | +| `version` | `str \| None` | — | Unity version (e.g. '6000.0.38f1'). Auto-extracted. | +| `slug` | `str \| None` | — | Manual page slug (e.g., 'execution-order'). | +| `package` | `str \| None` | — | Package name (e.g., 'com.unity.render-pipelines.universal'). | +| `page` | `str \| None` | — | Package doc page (e.g., 'index', '2d-index'). | +| `pkg_version` | `str \| None` | — | Package version major.minor (e.g., '17.0'). | +| `query` | `str \| None` | — | Single search query for lookup (class name, topic, or slug). | +| `queries` | `str \| None` | — | Comma-separated search queries for batch lookup (e.g., 'Physics.Raycast,NavMeshAgent,Light2D'). | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/docs/unity_reflect.md b/website/docs/reference/tools/docs/unity_reflect.md new file mode 100644 index 000000000..5c6a4f236 --- /dev/null +++ b/website/docs/reference/tools/docs/unity_reflect.md @@ -0,0 +1,41 @@ +--- +title: unity_reflect +sidebar_label: unity_reflect +description: "Inspect Unity's live C# API via reflection." +--- + +# `unity_reflect` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `docs`  ·  **Module:** `services.tools.unity_reflect` + +## Description + +Inspect Unity's live C# API via reflection. Use this to verify that classes, methods, and properties exist before writing C# code — training data may be wrong or outdated. + +Actions: +- get_type: Member summary (names only) for a class. Requires class_name. +- get_member: Full signature detail for one member. Requires class_name + member_name. +- search: Type name search across loaded assemblies. Requires query. Optional scope. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `str` | yes | The reflection action to perform. | +| `class_name` | `str \| None` | — | Fully qualified or simple C# class name. | +| `member_name` | `str \| None` | — | Method, property, or field name to inspect. | +| `query` | `str \| None` | — | Search query for type name search. | +| `scope` | `str \| None` | — | Assembly scope for search: unity, packages, project, all. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/index.md b/website/docs/reference/tools/index.md new file mode 100644 index 000000000..b72fb3036 --- /dev/null +++ b/website/docs/reference/tools/index.md @@ -0,0 +1,84 @@ +--- +title: Tool reference +sidebar_label: Tools +sidebar_class_name: sidebar-hidden +slug: /reference/tools +description: Auto-generated catalog of every MCP for Unity tool, grouped by domain. +--- + +# Tool reference + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +Every tool MCP for Unity exposes, generated directly from the Python `@mcp_for_unity_tool` registry under `Server/src/services/tools/`. + +## `animation`   (1 tool) +Animator control & AnimationClip creation +- **[`manage_animation`](./animation/manage_animation.md)** — Manage Unity animation: Animator control and AnimationClip creation. + +## `core`   (30 tools) +Essential scene, script, asset & editor tools (always on by default) +- **[`apply_text_edits`](./core/apply_text_edits.md)** — Apply small text edits to a C# script identified by URI. +- **[`batch_execute`](./core/batch_execute.md)** — Executes multiple MCP commands in a single batch for dramatically better performance. +- **[`create_script`](./core/create_script.md)** — Create a new C# script at the given project path. +- **[`debug_request_context`](./core/debug_request_context.md)** — Return the current FastMCP request context details (client_id, session_id, and meta dump). +- **[`delete_script`](./core/delete_script.md)** — Delete a C# script by URI or Assets-relative path. +- **[`execute_custom_tool`](./core/execute_custom_tool.md)** — Execute a project-scoped custom tool registered by Unity. +- **[`execute_menu_item`](./core/execute_menu_item.md)** — Execute a Unity menu item by path. +- **[`find_gameobjects`](./core/find_gameobjects.md)** — Search for GameObjects in the scene by name, tag, layer, component type, or path. +- **[`find_in_file`](./core/find_in_file.md)** — Searches a file with a regex pattern and returns line numbers and excerpts. +- **[`get_sha`](./core/get_sha.md)** — Get SHA256 and basic metadata for a Unity C# script without returning file contents. +- **[`manage_asset`](./core/manage_asset.md)** — Performs asset operations (import, create, modify, delete, etc.) in Unity. +- **[`manage_build`](./core/manage_build.md)** — Manage Unity player builds — trigger builds, switch platforms, configure settings, manage build scenes and profiles, run batch builds across platforms. +- **[`manage_camera`](./core/manage_camera.md)** — Manage cameras (Unity Camera + Cinemachine). +- **[`manage_components`](./core/manage_components.md)** — Add, remove, or set properties on components attached to GameObjects. +- **[`manage_editor`](./core/manage_editor.md)** — Controls and queries the Unity editor's state and settings. +- **[`manage_gameobject`](./core/manage_gameobject.md)** — Performs CRUD operations on GameObjects. +- **[`manage_graphics`](./core/manage_graphics.md)** — Manage rendering graphics: volumes, post-processing, light baking, rendering stats, pipeline settings, and URP renderer features. +- **[`manage_material`](./core/manage_material.md)** — Manages Unity materials (set properties, colors, shaders, etc). +- **[`manage_packages`](./core/manage_packages.md)** — Manage Unity packages: query, install, remove, embed, and configure registries. +- **[`manage_physics`](./core/manage_physics.md)** — Manage physics settings, collision matrix, materials, joints, queries, and validation. +- **[`manage_prefabs`](./core/manage_prefabs.md)** — Manages Unity Prefab assets. +- **[`manage_scene`](./core/manage_scene.md)** — Performs CRUD operations on Unity scenes. +- **[`manage_script`](./core/manage_script.md)** — Compatibility router for legacy script operations. +- **[`manage_script_capabilities`](./core/manage_script_capabilities.md)** — Get manage_script capabilities (supported ops, limits, and guards). +- **[`manage_tools`](./core/manage_tools.md)** — Manage which tool groups are visible in this session. +- **[`read_console`](./core/read_console.md)** — Gets messages from or clears the Unity Editor console. +- **[`refresh_unity`](./core/refresh_unity.md)** — Request a Unity asset database refresh and optionally a script compilation. +- **[`script_apply_edits`](./core/script_apply_edits.md)** — Structured C# edits (methods/classes) with safer boundaries - prefer this over raw text. +- **[`set_active_instance`](./core/set_active_instance.md)** — Set the active Unity instance for this client/session. +- **[`validate_script`](./core/validate_script.md)** — Validate a C# script and return diagnostics. + +## `docs`   (2 tools) +Unity API reflection and documentation lookup +- **[`unity_docs`](./docs/unity_docs.md)** — Fetch official Unity documentation from docs.unity3d.com. +- **[`unity_reflect`](./docs/unity_reflect.md)** — Inspect Unity's live C# API via reflection. + +## `probuilder`   (1 tool) +ProBuilder 3D modeling – requires com.unity.probuilder package +- **[`manage_probuilder`](./probuilder/manage_probuilder.md)** — Manage ProBuilder meshes for in-editor 3D modeling. + +## `profiling`   (1 tool) +Unity Profiler session control, counters, memory snapshots & Frame Debugger +- **[`manage_profiler`](./profiling/manage_profiler.md)** — Unity Profiler session control, counter reads, memory snapshots, and Frame Debugger. + +## `scripting_ext`   (2 tools) +ScriptableObject management +- **[`execute_code`](./scripting_ext/execute_code.md)** — Execute arbitrary C# code inside the Unity Editor. +- **[`manage_scriptable_object`](./scripting_ext/manage_scriptable_object.md)** — Creates and modifies ScriptableObject assets using Unity SerializedObject property paths. + +## `testing`   (2 tools) +Test runner & async test jobs +- **[`get_test_job`](./testing/get_test_job.md)** — Polls an async Unity test job by job_id. +- **[`run_tests`](./testing/run_tests.md)** — Starts a Unity test run asynchronously and returns a job_id immediately. + +## `ui`   (1 tool) +UI Toolkit (UXML, USS, UIDocument) +- **[`manage_ui`](./ui/manage_ui.md)** — Manages Unity UI Toolkit elements (UXML documents, USS stylesheets, UIDocument components). + +## `vfx`   (3 tools) +Visual effects – VFX Graph, shaders, procedural textures +- **[`manage_shader`](./vfx/manage_shader.md)** — Manages shader scripts in Unity (create, read, update, delete). +- **[`manage_texture`](./vfx/manage_texture.md)** — Procedural texture generation for Unity. +- **[`manage_vfx`](./vfx/manage_vfx.md)** — Manage Unity VFX components (ParticleSystem, VisualEffect, LineRenderer, TrailRenderer). + diff --git a/website/docs/reference/tools/probuilder/_category_.json b/website/docs/reference/tools/probuilder/_category_.json new file mode 100644 index 000000000..f1f6e880a --- /dev/null +++ b/website/docs/reference/tools/probuilder/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "probuilder", + "link": { + "type": "doc", + "id": "reference/tools/probuilder/index" + }, + "collapsed": true +} diff --git a/website/docs/reference/tools/probuilder/index.md b/website/docs/reference/tools/probuilder/index.md new file mode 100644 index 000000000..1abd00023 --- /dev/null +++ b/website/docs/reference/tools/probuilder/index.md @@ -0,0 +1,11 @@ +--- +title: "probuilder tools" +sidebar_label: "probuilder" +description: "MCP for Unity tools in the probuilder group." +--- + +# `probuilder` tools + +ProBuilder 3D modeling – requires com.unity.probuilder package + +- **[`manage_probuilder`](./manage_probuilder.md)** — Manage ProBuilder meshes for in-editor 3D modeling. diff --git a/website/docs/reference/tools/probuilder/manage_probuilder.md b/website/docs/reference/tools/probuilder/manage_probuilder.md new file mode 100644 index 000000000..d3df5d4dc --- /dev/null +++ b/website/docs/reference/tools/probuilder/manage_probuilder.md @@ -0,0 +1,88 @@ +--- +title: manage_probuilder +sidebar_label: manage_probuilder +description: "Manage ProBuilder meshes for in-editor 3D modeling." +--- + +# `manage_probuilder` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `probuilder`  ·  **Module:** `services.tools.manage_probuilder` + +## Description + +Manage ProBuilder meshes for in-editor 3D modeling. Requires com.unity.probuilder package. + +SHAPE CREATION: +- create_shape: Create a ProBuilder primitive (shape_type: Cube/Cylinder/Sphere/Plane/Cone/Torus/Pipe/Arch/Stair/CurvedStair/Door/Prism). Shape-specific params in properties (size, radius, height, depth, width, segments, rows, columns, innerRadius, outerRadius, etc.). +- create_poly_shape: Create mesh from 2D polygon footprint (points: [[x,y,z],...], extrudeHeight, flipNormals). + +MESH EDITING: +- extrude_faces: Extrude faces outward (faceIndices, distance, method: FaceNormal/VertexNormal/IndividualFaces). +- extrude_edges: Extrude edges (edgeIndices or edges [{a,b},...], distance, asGroup). +- bevel_edges: Bevel edges (edgeIndices or edges [{a,b},...], amount 0-1). +- subdivide: Subdivide faces (faceIndices optional, all if omitted). +- delete_faces: Delete faces (faceIndices). +- bridge_edges: Bridge two open edges (edgeA, edgeB as {a,b} pairs, allowNonManifold). +- connect_elements: Connect edges or faces (edgeIndices/edges or faceIndices). +- detach_faces: Detach faces (faceIndices, deleteSourceFaces: bool). +- flip_normals: Flip face normals (faceIndices). +- merge_faces: Merge faces into one (faceIndices). +- combine_meshes: Combine multiple ProBuilder objects (targets: list of GameObjects). +- merge_objects: Merge objects into one ProBuilder mesh (targets list, auto-converts). +- duplicate_and_flip: Create double-sided geometry (faceIndices). +- create_polygon: Connect existing vertices into a new face (vertexIndices, unordered). + +VERTEX OPERATIONS: +- merge_vertices: Collapse vertices to single point (vertexIndices, collapseToFirst). +- weld_vertices: Weld vertices within proximity radius (vertexIndices, radius). +- split_vertices: Split shared vertices (vertexIndices). +- move_vertices: Translate vertices (vertexIndices, offset [x,y,z]). +- insert_vertex: Insert vertex on edge ({a,b}) or face (faceIndex) at point [x,y,z]. +- append_vertices_to_edge: Insert evenly-spaced points on edges (edgeIndices/edges, count). + +SELECTION: +- select_faces: Select faces by criteria (direction: up/down/forward/back/left/right, tolerance, growFrom, growAngle, floodFrom, floodAngle, loopFrom, ring). Returns faceIndices array for use with other actions. + +UV & MATERIALS: +- set_face_material: Assign material to faces (faceIndices optional — all faces when omitted, materialPath). +- set_face_color: Set vertex color on faces (faceIndices optional — all faces when omitted, color [r,g,b,a]). +- set_face_uvs: Set UV auto-unwrap params (faceIndices optional — all faces when omitted, scale, offset, rotation, flipU, flipV). + +QUERY: +- get_mesh_info: Get ProBuilder mesh details. Use include parameter to control detail level: 'summary' (default: counts, bounds, materials), 'faces' (+ face normals/centers/directions), 'edges' (+ edge vertex pairs), 'all' (everything). Each face includes direction ('top','bottom','front','back','left','right') for semantic selection. +- convert_to_probuilder: Convert a standard Unity mesh into ProBuilder for editing. + +SMOOTHING: +- set_smoothing: Set smoothing group on faces (faceIndices, smoothingGroup: 0=hard, 1+=smooth). +- auto_smooth: Auto-assign smoothing groups by angle (angleThreshold: default 30). + +MESH UTILITIES: +- center_pivot: Move pivot point to mesh bounds center. +- set_pivot: Set pivot to arbitrary world position (position [x,y,z]). +- freeze_transform: Bake position/rotation/scale into vertex data, reset transform. +- validate_mesh: Check mesh health (degenerate triangles, unused vertices). Read-only. +- repair_mesh: Auto-fix degenerate triangles and unused vertices. + +WORKFLOW TIP: Call get_mesh_info with include='faces' to see face normals and directions before editing. Each face shows its direction ('top','bottom','front','back','left','right') so you can pick the right indices for operations like extrude_faces or delete_faces. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `str` | yes | Action to perform. | +| `target` | `str \| None` | — | Target GameObject (name/path/id). | +| `search_method` | `Literal['by_id', 'by_name', 'by_path', 'by_tag', 'by_layer'] \| None` | — | How to find the target GameObject. | +| `properties` | `dict[str, Any] \| str \| None` | — | Action-specific parameters (dict or JSON string). | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/profiling/_category_.json b/website/docs/reference/tools/profiling/_category_.json new file mode 100644 index 000000000..2760297b1 --- /dev/null +++ b/website/docs/reference/tools/profiling/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "profiling", + "link": { + "type": "doc", + "id": "reference/tools/profiling/index" + }, + "collapsed": true +} diff --git a/website/docs/reference/tools/profiling/index.md b/website/docs/reference/tools/profiling/index.md new file mode 100644 index 000000000..055dae2f8 --- /dev/null +++ b/website/docs/reference/tools/profiling/index.md @@ -0,0 +1,11 @@ +--- +title: "profiling tools" +sidebar_label: "profiling" +description: "MCP for Unity tools in the profiling group." +--- + +# `profiling` tools + +Unity Profiler session control, counters, memory snapshots & Frame Debugger + +- **[`manage_profiler`](./manage_profiler.md)** — Unity Profiler session control, counter reads, memory snapshots, and Frame Debugger. diff --git a/website/docs/reference/tools/profiling/manage_profiler.md b/website/docs/reference/tools/profiling/manage_profiler.md new file mode 100644 index 000000000..50305f25f --- /dev/null +++ b/website/docs/reference/tools/profiling/manage_profiler.md @@ -0,0 +1,65 @@ +--- +title: manage_profiler +sidebar_label: manage_profiler +description: "Unity Profiler session control, counter reads, memory snapshots, and Frame Debugger." +--- + +# `manage_profiler` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `profiling`  ·  **Module:** `services.tools.manage_profiler` + +## Description + +Unity Profiler session control, counter reads, memory snapshots, and Frame Debugger. + +SESSION: +- profiler_start: Enable profiler, optionally record to .raw file (log_file, enable_callstacks) +- profiler_stop: Disable profiler, stop recording +- profiler_status: Get enabled state, active areas, recording path +- profiler_set_areas: Toggle ProfilerAreas on/off (areas dict) + +COUNTERS: +- get_frame_timing: FrameTimingManager data (12 fields, synchronous) +- get_counters: Generic counter read by category + optional counter names (async, 1-frame wait) +- get_object_memory: Memory size of a specific object by path + +MEMORY SNAPSHOT (requires com.unity.memoryprofiler): +- memory_take_snapshot: Capture memory snapshot to file +- memory_list_snapshots: List available .snap files +- memory_compare_snapshots: Compare two snapshot files + +FRAME DEBUGGER: +- frame_debugger_enable: Turn on Frame Debugger, report event count +- frame_debugger_disable: Turn off Frame Debugger +- frame_debugger_get_events: Get draw call events (paged, best-effort via reflection) + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `str` | yes | The profiler action to perform. | +| `category` | `str \| None` | — | Profiler category name for get_counters (e.g. Render, Scripts, Memory, Physics). | +| `counters` | `list[str] \| None` | — | Specific counter names for get_counters. Omit to read all in category. | +| `object_path` | `str \| None` | — | Scene hierarchy or asset path for get_object_memory. | +| `log_file` | `str \| None` | — | Path to .raw file for profiler_start recording. | +| `enable_callstacks` | `bool \| None` | — | Enable allocation callstacks for profiler_start. | +| `areas` | `dict[str, bool] \| None` | — | Dict of area name to bool for profiler_set_areas. | +| `snapshot_path` | `str \| None` | — | Output path for memory_take_snapshot. | +| `search_path` | `str \| None` | — | Search directory for memory_list_snapshots. | +| `snapshot_a` | `str \| None` | — | First snapshot path for memory_compare_snapshots. | +| `snapshot_b` | `str \| None` | — | Second snapshot path for memory_compare_snapshots. | +| `page_size` | `int \| None` | — | Page size for frame_debugger_get_events (default 50). | +| `cursor` | `int \| None` | — | Cursor offset for frame_debugger_get_events. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/scripting_ext/_category_.json b/website/docs/reference/tools/scripting_ext/_category_.json new file mode 100644 index 000000000..4e06525ea --- /dev/null +++ b/website/docs/reference/tools/scripting_ext/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "scripting_ext", + "link": { + "type": "doc", + "id": "reference/tools/scripting_ext/index" + }, + "collapsed": true +} diff --git a/website/docs/reference/tools/scripting_ext/execute_code.md b/website/docs/reference/tools/scripting_ext/execute_code.md new file mode 100644 index 000000000..ddf399882 --- /dev/null +++ b/website/docs/reference/tools/scripting_ext/execute_code.md @@ -0,0 +1,37 @@ +--- +title: execute_code +sidebar_label: execute_code +description: "Execute arbitrary C# code inside the Unity Editor." +--- + +# `execute_code` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `scripting_ext`  ·  **Module:** `services.tools.execute_code` + +## Description + +Execute arbitrary C# code inside the Unity Editor. The code runs as a method body with access to UnityEngine and UnityEditor namespaces. Use 'return' to send data back. Compiled in-memory — no script files created. Actions: execute (run code), get_history (list past executions), replay (re-run a history entry), clear_history. NOTE: safety_checks blocks known dangerous patterns but is not a full sandbox. Compiler options: 'auto' (Roslyn if available, else CodeDom), 'roslyn' (C# 12+, requires Microsoft.CodeAnalysis), 'codedom' (C# 6 only). + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['execute', 'get_history', 'replay', 'clear_history']` | yes | Action to perform. | +| `code` | `str \| None` | — | C# code to execute (for 'execute' action). Must be a valid method body. Access UnityEngine and UnityEditor namespaces. Use 'return' to send data back. | +| `safety_checks` | `bool` | — | Enable basic blocked-pattern checks (File.Delete, Process.Start, infinite loops, etc). Not a full sandbox — advanced bypass is possible. Default: true. | +| `index` | `int \| None` | — | History entry index to replay (for 'replay' action). | +| `limit` | `int` | — | Number of history entries to return (for 'get_history' action, 1-50). Default: 10. | +| `compiler` | `Literal['auto', 'roslyn', 'codedom']` | — | Compiler backend for 'execute' action. 'auto' uses Roslyn if Microsoft.CodeAnalysis is installed, else falls back to CodeDom. 'roslyn' forces Roslyn (C# 12+). 'codedom' forces legacy CSharpCodeProvider (C# 6). Default: auto. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/scripting_ext/index.md b/website/docs/reference/tools/scripting_ext/index.md new file mode 100644 index 000000000..c2a093d02 --- /dev/null +++ b/website/docs/reference/tools/scripting_ext/index.md @@ -0,0 +1,12 @@ +--- +title: "scripting_ext tools" +sidebar_label: "scripting_ext" +description: "MCP for Unity tools in the scripting_ext group." +--- + +# `scripting_ext` tools + +ScriptableObject management + +- **[`execute_code`](./execute_code.md)** — Execute arbitrary C# code inside the Unity Editor. +- **[`manage_scriptable_object`](./manage_scriptable_object.md)** — Creates and modifies ScriptableObject assets using Unity SerializedObject property paths. diff --git a/website/docs/reference/tools/scripting_ext/manage_scriptable_object.md b/website/docs/reference/tools/scripting_ext/manage_scriptable_object.md new file mode 100644 index 000000000..2bdcf91d9 --- /dev/null +++ b/website/docs/reference/tools/scripting_ext/manage_scriptable_object.md @@ -0,0 +1,39 @@ +--- +title: manage_scriptable_object +sidebar_label: manage_scriptable_object +description: "Creates and modifies ScriptableObject assets using Unity SerializedObject property paths." +--- + +# `manage_scriptable_object` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `scripting_ext`  ·  **Module:** `services.tools.manage_scriptable_object` + +## Description + +Creates and modifies ScriptableObject assets using Unity SerializedObject property paths. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `action` | `Literal['create', 'modify']` | yes | Action to perform: create or modify. | +| `type_name` | `str \| None` | — | Namespace-qualified ScriptableObject type name (for create). | +| `folder_path` | `str \| None` | — | Target folder under Assets/... (for create). | +| `asset_name` | `str \| None` | — | Asset file name without extension (for create). | +| `overwrite` | `bool \| str \| None` | — | If true, overwrite existing asset at same path (for create). | +| `target` | `dict[str, Any] \| str \| None` | — | Target asset reference {guid\|path} (for modify). | +| `patches` | `list[dict[str, Any]] \| str \| None` | — | Patch list (or JSON string) to apply. For object references: use {"ref": {"guid": "..."}} or {"value": {"guid": "..."}}. For Sprite sub-assets: include "spriteName" in the ref/value object. Single-sprite textures auto-resolve from guid/path alone. | +| `dry_run` | `bool \| str \| None` | — | If true, validate patches without applying (modify only). | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/testing/_category_.json b/website/docs/reference/tools/testing/_category_.json new file mode 100644 index 000000000..c98d3c5b0 --- /dev/null +++ b/website/docs/reference/tools/testing/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "testing", + "link": { + "type": "doc", + "id": "reference/tools/testing/index" + }, + "collapsed": true +} diff --git a/website/docs/reference/tools/testing/get_test_job.md b/website/docs/reference/tools/testing/get_test_job.md new file mode 100644 index 000000000..d16fdfaa4 --- /dev/null +++ b/website/docs/reference/tools/testing/get_test_job.md @@ -0,0 +1,35 @@ +--- +title: get_test_job +sidebar_label: get_test_job +description: "Polls an async Unity test job by job_id." +--- + +# `get_test_job` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `testing`  ·  **Module:** `services.tools.run_tests` + +## Description + +Polls an async Unity test job by job_id. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `job_id` | `str` | yes | Job id returned by run_tests | +| `include_failed_tests` | `bool` | — | Include details for failed/skipped tests only (default: false) | +| `include_details` | `bool` | — | Include details for all tests (default: false) | +| `wait_timeout` | `int \| None` | — | If set, wait up to this many seconds for tests to complete before returning. Reduces polling frequency and avoids client-side loop detection. Recommended: 30-60 seconds. Returns immediately if tests complete sooner. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/testing/index.md b/website/docs/reference/tools/testing/index.md new file mode 100644 index 000000000..4396e5e95 --- /dev/null +++ b/website/docs/reference/tools/testing/index.md @@ -0,0 +1,12 @@ +--- +title: "testing tools" +sidebar_label: "testing" +description: "MCP for Unity tools in the testing group." +--- + +# `testing` tools + +Test runner & async test jobs + +- **[`get_test_job`](./get_test_job.md)** — Polls an async Unity test job by job_id. +- **[`run_tests`](./run_tests.md)** — Starts a Unity test run asynchronously and returns a job_id immediately. diff --git a/website/docs/reference/tools/testing/run_tests.md b/website/docs/reference/tools/testing/run_tests.md new file mode 100644 index 000000000..07e90da52 --- /dev/null +++ b/website/docs/reference/tools/testing/run_tests.md @@ -0,0 +1,39 @@ +--- +title: run_tests +sidebar_label: run_tests +description: "Starts a Unity test run asynchronously and returns a job_id immediately." +--- + +# `run_tests` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `testing`  ·  **Module:** `services.tools.run_tests` + +## Description + +Starts a Unity test run asynchronously and returns a job_id immediately. Poll with get_test_job for progress. + +## Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `mode` | `Literal['EditMode', 'PlayMode']` | — | Unity test mode to run | +| `test_names` | `list[str] \| str \| None` | — | Full names of specific tests to run | +| `group_names` | `list[str] \| str \| None` | — | Same as test_names, except it allows for Regex | +| `category_names` | `list[str] \| str \| None` | — | NUnit category names to filter by | +| `assembly_names` | `list[str] \| str \| None` | — | Assembly names to filter tests by | +| `include_failed_tests` | `bool` | — | Include details for failed/skipped tests only (default: false) | +| `include_details` | `bool` | — | Include details for all tests (default: false) | +| `init_timeout` | `int \| None` | — | Initialization timeout in milliseconds. PlayMode tests may need longer due to domain reload (default: 15000). Recommended: 120000 for PlayMode. | + +## Returns + +A `dict` containing the Unity response. The exact shape depends on the action. + +## Examples + + +*No examples yet. Add usage examples here — they will be preserved across regenerations.* + + diff --git a/website/docs/reference/tools/ui/_category_.json b/website/docs/reference/tools/ui/_category_.json new file mode 100644 index 000000000..b73a0f1ce --- /dev/null +++ b/website/docs/reference/tools/ui/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "ui", + "link": { + "type": "doc", + "id": "reference/tools/ui/index" + }, + "collapsed": true +} diff --git a/website/docs/reference/tools/ui/index.md b/website/docs/reference/tools/ui/index.md new file mode 100644 index 000000000..d172ee806 --- /dev/null +++ b/website/docs/reference/tools/ui/index.md @@ -0,0 +1,11 @@ +--- +title: "ui tools" +sidebar_label: "ui" +description: "MCP for Unity tools in the ui group." +--- + +# `ui` tools + +UI Toolkit (UXML, USS, UIDocument) + +- **[`manage_ui`](./manage_ui.md)** — Manages Unity UI Toolkit elements (UXML documents, USS stylesheets, UIDocument components). diff --git a/website/docs/reference/tools/ui/manage_ui.md b/website/docs/reference/tools/ui/manage_ui.md new file mode 100644 index 000000000..18454e841 --- /dev/null +++ b/website/docs/reference/tools/ui/manage_ui.md @@ -0,0 +1,80 @@ +--- +title: manage_ui +sidebar_label: manage_ui +description: "Manages Unity UI Toolkit elements (UXML documents, USS stylesheets, UIDocument components)." +--- + +# `manage_ui` + +> **Auto-generated** from the Python tool registry. Do not hand-edit outside `` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them. + +**Group:** `ui`  ·  **Module:** `services.tools.manage_ui` + +## Description + +Manages Unity UI Toolkit elements (UXML documents, USS stylesheets, UIDocument components). Read-only actions: ping, read, get_visual_tree, list. Modifying actions: create, update, delete, attach_ui_document, detach_ui_document, create_panel_settings, update_panel_settings, modify_visual_element. +Visual actions: render_ui (captures UI panel to a PNG screenshot for self-evaluation). +Structural actions: link_stylesheet (adds a Style src reference to a UXML file). + +UI Toolkit workflow: +1. Use list to discover existing UI assets +2. Create a UXML file (structure, like HTML) +3. Create a USS file (styling, like CSS) +4. Link stylesheet to UXML via link_stylesheet +5. Attach UIDocument to a GameObject with the UXML source +6. Use get_visual_tree to inspect the result +7. Use modify_visual_element to change text, classes, or inline styles on live elements +8. Use render_ui to capture a visual preview for self-evaluation + - In play mode: first call queues a WaitForEndOfFrame screen capture and returns pending=true; + call render_ui a second time to retrieve the saved PNG (hasContent will be true). + - In editor mode: assigns a RenderTexture to PanelSettings (best-effort; may stay blank). +9. Use detach_ui_document to remove UIDocument from a GameObject +10. Use delete to remove .uxml/.uss files + +Important: Always use (with the ui: namespace prefix) in UXML, not bare