chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:49:17 +08:00
commit 7243d5823b
2201 changed files with 257291 additions and 0 deletions
@@ -0,0 +1,57 @@
---
description: How MCP for Unity tracks adoption with cookieless, aggregate-only analytics — a public PyPI downloads badge plus a private, maintainer-only dashboard.
---
# External analytics
## What is tracked and why
MCP for Unity tracks adoption with several aggregate signals, ordered from most to least honest about *real users*:
- **In-product DAU / WAU** — the true active-user count, deduplicated per anonymous install UUID by the in-product telemetry (`Server/src/core/telemetry.py`). Surfacing it on this dashboard needs a read API on the Coplay telemetry backend.
- **Unique repo cloners / viewers (14-day)** — from the GitHub repository traffic API; a strong proxy for developers actually pulling the code. Only collaborators can read it (needs a token), so it is private by nature.
- **GitHub stars / forks** — real accounts that starred or forked; public, an interest (not usage) signal.
- **PyPI installs** — daily/weekly/monthly download counts for `mcpforunityserver` from the public [pypistats.org](https://pypistats.org/packages/mcpforunityserver) API. **Heavily inflated** by CI, mirrors, `uvx` re-fetches, and Docker rebuilds — an install-event *reach* number, not a user count. A downloads badge appears in the README.
- **Docs traffic** — aggregate pageview totals from [GoatCounter](https://www.goatcounter.com/) when provisioned.
All sources are **cookieless, store no personal data, and expose only aggregates**. The DAU/WAU source is the [in-product telemetry](./telemetry) that runs inside the Unity Editor and is controlled by the user from the MCP for Unity settings window.
## What is public vs private
- **Public:** the PyPI **downloads badge** in the README (download counts are public on PyPI regardless of what we do).
- **Private (maintainer-only):** the unified install + docs-traffic **dashboard**. It is posted to the GitHub Actions run summary, which only repo collaborators can see. There is **no public stats page and no stats file published to the site**.
## Privacy stance
- No cookies, no fingerprinting, no user IDs.
- No PII is transmitted or stored.
- GoatCounter is a privacy-first analytics service; its [privacy policy](https://www.goatcounter.com/help/privacy) commits to not selling data. The GoatCounter dashboard should be kept **private** so traffic numbers stay maintainer-only.
- The maintainer summary contains only counts and a timestamp.
## How data flows
1. A GitHub Actions workflow (`.github/workflows/stats.yml`) runs daily at 06:00 UTC, and on demand via **Run workflow**.
2. `website/scripts/fetch-stats.mjs` fetches PyPI recent-download counts and, when GoatCounter secrets are present, the total pageview count.
3. The script renders a Markdown table that the workflow appends to `$GITHUB_STEP_SUMMARY`.
4. Collaborators read the numbers on the **Actions → Adoption stats** run page. Nothing is committed to the repo or published to the docs site.
## Maintainer provisioning
Stars, forks, and PyPI numbers work out of the box. The two highest-signal rows need setup:
**Unique repo cloners / viewers (GitHub traffic):**
1. Create a fine-grained PAT scoped to `CoplayDev/unity-mcp` with **Repository permissions → Administration: read** (the traffic API requires it; the default `GITHUB_TOKEN` returns 401/403).
2. Add it as the repository **secret** `STATS_GITHUB_TOKEN`.
**In-product DAU / WAU (the true active-user count):**
- The data is already collected by `Server/src/core/telemetry.py` (deduplicated per anonymous install UUID) and POSTed to the Coplay telemetry backend. Surfacing it here needs a **read / aggregate API** on that backend plus a token — back-end work owned by Coplay. Once available, add a `COPLAY_STATS_TOKEN` secret and a fetch in `fetch-stats.mjs`.
**Docs traffic (GoatCounter):**
1. Create a free [goatcounter.com](https://www.goatcounter.com/) site (e.g. code `mcp-for-unity`); keep its dashboard **private**.
2. Generate an API token with read access to stats.
3. Add secrets `GOATCOUNTER_TOKEN` (token) and `GOATCOUNTER_SITE` (site code), and an **Actions variable** `GOATCOUNTER_CODE` (same site code) so the docs build injects the cookieless beacon — collection happens on the public site, the numbers stay private.
Then run **Actions → Adoption stats → Run workflow**. The `stats` workflow needs only `contents: read` — it posts to the run summary and never commits.
+110
View File
@@ -0,0 +1,110 @@
# manage_physics — Complete Feature Patch
A new `manage_physics` MCP tool that gives AI assistants full control over Unity's 3D and 2D physics systems. **21 actions** across 9 categories, with C# Editor implementation, Python MCP service, CLI commands, and tests.
## Actions by Category
### Settings
| Action | Description |
|--------|-------------|
| `ping` | Health check — returns gravity, solver settings, simulation mode |
| `get_settings` | Read physics project settings (3D or 2D) |
| `set_settings` | Write physics project settings (gravity, solver iterations, thresholds, etc.) |
### Collision Matrix
| Action | Description |
|--------|-------------|
| `get_collision_matrix` | Read per-layer collision matrix |
| `set_collision_matrix` | Enable/disable collision between layer pairs |
### Materials
| Action | Description |
|--------|-------------|
| `create_physics_material` | Create PhysicMaterial (3D) or PhysicsMaterial2D assets with friction/bounciness/combine modes |
| `configure_physics_material` | Update properties on an existing physics material asset |
| `assign_physics_material` | Assign a physics material to a GameObject's collider |
### Joints
| Action | Description |
|--------|-------------|
| `add_joint` | Add a joint (hinge, spring, fixed, configurable, etc.) with optional connected body |
| `configure_joint` | Configure motor, limits, spring, drive, and direct properties on an existing joint |
| `remove_joint` | Remove joint(s) from a GameObject by type or all |
### Queries
| Action | Description |
|--------|-------------|
| `raycast` | Single-hit raycast from origin along direction |
| `raycast_all` | Multi-hit raycast returning all intersections |
| `linecast` | Check if anything intersects the line between two points |
| `shapecast` | Cast a shape (sphere, box, capsule) along a direction |
| `overlap` | Find all colliders within a shape (sphere, box, capsule) at a position |
### Forces
| Action | Description |
|--------|-------------|
| `apply_force` | Apply force, torque (or both), force-at-position, or explosion force to Rigidbodies. Supports all ForceModes for 3D and 2D |
### Rigidbody
| Action | Description |
|--------|-------------|
| `get_rigidbody` | Read full Rigidbody state: mass, velocity, position, rotation, damping, constraints, sleep state, centerOfMass |
| `configure_rigidbody` | Set Rigidbody properties (mass, damping, gravity, kinematic, interpolation, collision detection, constraints) |
### Validation
| Action | Description |
|--------|-------------|
| `validate` | Scan scene (or a single target) for physics issues. Paginated results (`page_size`/`cursor`/`next_cursor`) with per-category summary. 7 check categories: non-convex mesh, missing rigidbody, non-uniform scale, fast object with discrete detection, missing physics material, collision matrix, mixed 2D/3D. Smart warning levels — static colliders without Rigidbodies are downgraded to `[Info]` unless the object has an Animator |
### Simulation
| Action | Description |
|--------|-------------|
| `simulate_step` | Step physics simulation in Edit mode (1100 steps). Returns positions, velocities, and angular velocities of active Rigidbodies after stepping. Optional `target` to filter to a specific object |
## Architecture
### C# — 10 files in `MCPForUnity/Editor/Tools/Physics/`
| File | Purpose |
|------|---------|
| `ManagePhysics.cs` | Action dispatcher with `[McpForUnityTool]` registration |
| `PhysicsSettingsOps.cs` | ping, get_settings, set_settings |
| `CollisionMatrixOps.cs` | get_collision_matrix, set_collision_matrix |
| `PhysicsMaterialOps.cs` | create, configure, assign physics materials |
| `JointOps.cs` | add_joint, configure_joint, remove_joint |
| `PhysicsQueryOps.cs` | raycast, raycast_all, linecast, shapecast, overlap |
| `PhysicsForceOps.cs` | apply_force (normal, explosion, torque) |
| `PhysicsRigidbodyOps.cs` | get_rigidbody, configure_rigidbody |
| `PhysicsValidationOps.cs` | validate with pagination and smart warnings |
| `PhysicsSimulationOps.cs` | simulate_step with state reporting |
### Python — 3 files
| File | Purpose |
|------|---------|
| `Server/src/services/tools/manage_physics.py` | MCP tool definition with 21-action Literal type, forwards all params to Unity |
| `Server/src/cli/commands/physics.py` | Full CLI with commands for every action category |
| `Server/tests/test_manage_physics.py` | 19 unit tests covering action forwarding and validation |
### Unity Tests
| File | Purpose |
|------|---------|
| `TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManagePhysicsTests.cs` | 973-line EditMode test suite |
## Key Design Decisions
- **Modular ops classes**: Each physics domain (settings, materials, joints, queries, forces, etc.) gets its own C# class rather than one monolithic handler
- **Auto-dimension detection**: All actions auto-detect 2D vs 3D based on Rigidbody/Rigidbody2D component presence, with optional `dimension` override
- **Unity version compatibility**: Uses `#if UNITY_6000_0_OR_NEWER` for renamed APIs (drag → linearDamping, angularDrag → angularDamping)
- **Pagination on validate**: Large scenes can produce hundreds of warnings — paginated by default (50 per page) with a summary that always shows category counts regardless of page
- **Smart warning levels**: "Collider without Rigidbody" only escalates to a warning if the object has an Animator (suggesting runtime movement); otherwise downgraded to `[Info]`
- **Enriched responses**: Force/explosion actions echo back all applied values. Simulation returns Rigidbody states. Validation returns category breakdowns
## Stats
- **Net change**: +5,985 / 2,965 lines
- **New C# files**: 10 (+ 10 .meta)
- **New Python files**: 3
- **Actions**: 21
- **Tests**: 19 Python + EditMode C# suite
@@ -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 (>69 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.
@@ -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`
+363
View File
@@ -0,0 +1,363 @@
# Remote Server Auth: Architecture
This document describes the internal design of the API key authentication system used when the MCP for Unity server runs in remote-hosted mode. It is intended for contributors and maintainers.
## Overview
```
MCP Client MCP Server External Auth
(Cursor, etc.) (Python) Service
| | |
| X-API-Key: abc123 | |
| POST /mcp (tool call) | |
|-------------------------->| |
| | |
| UnityInstanceMiddleware.on_call_tool |
| | |
| _resolve_user_id() |
| | |
| | POST /validate |
| | {"api_key": "abc123"} |
| |------------------------------>|
| | |
| | {"valid":true, |
| | "user_id":"user-42"} |
| |<------------------------------|
| | |
| Cache result (TTL) |
| | |
| ctx.set_state("user_id", "user-42") |
| ctx.set_state("unity_instance", "Proj@hash") |
| | |
| PluginHub.send_command_for_instance |
| (user_id scoped session lookup) |
| | |
| Tool result | |
|<--------------------------| |
Unity Plugin MCP Server External Auth
(C# WebSocket) (Python) Service
| | |
| WS /hub/plugin | |
| X-API-Key: abc123 | |
|-------------------------->| |
| | |
| PluginHub.on_connect |
| | POST /validate |
| |------------------------------>|
| | {"valid":true, ...} |
| |<------------------------------|
| | |
| accept() | |
| websocket.state.user_id = "user-42" |
|<--------------------------| |
| | |
| {"type":"register", ...} | |
|-------------------------->| |
| | |
| PluginRegistry.register( |
| ..., user_id="user-42") |
| _user_hash_to_session[("user-42","hash")] = sid |
| | |
| {"type":"registered"} | |
|<--------------------------| |
```
## Components
### ApiKeyService
**File:** `Server/src/services/api_key_service.py`
Singleton service that validates API keys against an external HTTP endpoint.
- **Singleton access:** `ApiKeyService.get_instance()` / `ApiKeyService.is_initialized()`
- **Initialization:** Constructed in `create_mcp_server()` when `config.http_remote_hosted` and `config.api_key_validation_url` are both set.
- **Validation:** `async validate(api_key) -> ValidationResult`
- **Caching:** In-memory dict keyed by raw API key. Entries store `(valid, user_id, metadata, expires_at)`.
- **Retry:** 1 retry with 100ms backoff on timeouts and connection errors.
- **Fail-closed:** Any unrecoverable error returns `ValidationResult(valid=False)`.
### PluginHub (WebSocket Auth Gate)
**File:** `Server/src/transport/plugin_hub.py`
The `on_connect` method validates the API key from the WebSocket handshake headers before accepting the connection.
- Reads `X-API-Key` from `websocket.headers`
- Validates via `ApiKeyService.validate()`
- Stores `user_id` and `api_key_metadata` on `websocket.state` for use during registration
- Rejects with close codes: `4401` (missing), `4403` (invalid), `1013` (service unavailable)
The `_handle_register` method reads `websocket.state.user_id` and passes it to `PluginRegistry.register()`.
The `get_sessions(user_id=None)` and `_resolve_session_id(unity_instance, user_id=None)` methods accept an optional `user_id` to scope session queries in remote-hosted mode.
### PluginRegistry (Dual-Index Session Storage)
**File:** `Server/src/transport/plugin_registry.py`
In-memory registry of connected Unity plugin sessions. Maintains two parallel index maps:
| Index | Key | Used In |
|-------|-----|---------|
| `_hash_to_session` | `project_hash -> session_id` | Local mode |
| `_user_hash_to_session` | `(user_id, project_hash) -> session_id` | Remote-hosted mode |
Both indexes are updated during `register()` and cleaned up during `unregister()`.
Key methods:
- `register(session_id, project_name, project_hash, unity_version, user_id=None)` - Registers a session and updates the appropriate index. If an existing session claims the same key, it is evicted.
- `get_session_id_by_hash(project_hash)` - Local-mode lookup.
- `get_session_id_by_hash(project_hash, user_id)` - Remote-mode lookup.
- `list_sessions(user_id=None)` - Returns sessions filtered by user. Raises `ValueError` if `user_id` is `None` while `config.http_remote_hosted` is `True`, preventing accidental cross-user leaks.
### UnityInstanceMiddleware
**File:** `Server/src/transport/unity_instance_middleware.py`
FastMCP middleware that intercepts all tool and resource calls to inject the active Unity instance and user identity into the request-scoped context.
Entry points:
- `on_call_tool(context, call_next)` - Intercepts tool calls.
- `on_read_resource(context, call_next)` - Intercepts resource reads.
Both delegate to `_inject_unity_instance(context)`, which:
1. Calls `_resolve_user_id()` to extract the user identity from the HTTP request.
2. If remote-hosted mode is active and no `user_id` is resolved, raises `RuntimeError` (surfaces as MCP error).
3. Sets `ctx.set_state("user_id", user_id)`.
4. Looks up or auto-selects the active Unity instance.
5. Sets `ctx.set_state("unity_instance", active_instance)`.
### _resolve_user_id_from_request
**File:** `Server/src/transport/unity_transport.py`
Extracts the `user_id` from the current HTTP request's `X-API-Key` header.
```
_resolve_user_id_from_request()
-> if not config.http_remote_hosted: return None
-> if not ApiKeyService.is_initialized(): return None
-> get_http_headers() from FastMCP dependencies
-> extract "x-api-key" header
-> ApiKeyService.validate(api_key)
-> return result.user_id if valid, else None
```
The middleware calls this indirectly through `_resolve_user_id()`, which adds an early return when not in remote-hosted mode (avoiding the import of FastMCP internals in local mode).
## Request Lifecycle
A complete authenticated MCP tool call follows this path:
1. **HTTP request arrives** at `/mcp` with `X-API-Key: <key>` header.
2. **FastMCP dispatches** the MCP tool call through its middleware chain.
3. **`UnityInstanceMiddleware.on_call_tool`** is invoked.
4. **`_inject_unity_instance`** runs:
- Calls `_resolve_user_id()`, which calls `_resolve_user_id_from_request()`.
- The request function imports `get_http_headers` from FastMCP and reads the `x-api-key` header.
- `ApiKeyService.validate()` checks the cache or calls the external auth endpoint.
- If valid, `user_id` is returned. If invalid or missing, `None` is returned.
- In remote-hosted mode, `None` causes a `RuntimeError`.
5. **`user_id` stored in context** via `ctx.set_state("user_id", user_id)`.
6. **Session key derived** by `get_session_key(ctx)`:
- Priority: `client_id` (if available) > `user:{user_id}` > `"global"`.
- The `user:{user_id}` fallback ensures session isolation when MCP transports don't provide stable client IDs.
7. **Active Unity instance looked up** from `_active_by_key` dict using the session key. If none is set, `_maybe_autoselect_instance` is called (but returns `None` in remote-hosted mode).
8. **Instance injected** via `ctx.set_state("unity_instance", active_instance)`.
9. **Tool executes**, reading the instance from `ctx.get_state("unity_instance")`.
10. **Command routed** through `PluginHub.send_command_for_instance(unity_instance, ..., user_id=user_id)`, which resolves the session using `PluginRegistry.get_session_id_by_hash(project_hash, user_id)`.
## WebSocket Auth Flow
When a Unity plugin connects via WebSocket:
```
Plugin -> WS /hub/plugin (with X-API-Key header)
|
v
PluginHub.on_connect()
|
+-- config.http_remote_hosted && ApiKeyService.is_initialized()?
| |
| +-- No -> accept() (local mode, no auth needed)
| |
| +-- Yes -> read X-API-Key from headers
| |
| +-- No key -> close(4401, "API key required")
| |
| +-- ApiKeyService.validate(key)
| |
| +-- valid=True -> websocket.state.user_id = user_id
| | accept()
| |
| +-- valid=False, "unavailable" in error
| | -> close(1013, "Try again later")
| |
| +-- valid=False -> close(4403, "Invalid API key")
```
After acceptance, when the plugin sends a `register` message, `_handle_register` reads `websocket.state.user_id` and passes it to `PluginRegistry.register()`.
## Session Registry Design
### Local Mode
```
project_hash -> session_id
"abc123" -> "uuid-1"
"def456" -> "uuid-2"
```
A single `_hash_to_session` dict. Any user can see any session. `list_sessions(user_id=None)` returns all sessions.
### Remote-Hosted Mode
```
(user_id, project_hash) -> session_id
("user-A", "abc123") -> "uuid-1"
("user-B", "abc123") -> "uuid-3" (same project, different user)
("user-A", "def456") -> "uuid-2"
```
A separate `_user_hash_to_session` dict with composite keys. Two users working on cloned repos (same `project_hash`) get independent sessions.
### Reconnect Handling
When a Unity editor reconnects (e.g., after domain reload), `register()` detects the existing mapping for the same key and evicts the old session before inserting the new one. This ensures the latest WebSocket connection always wins.
### list_sessions Guard
`list_sessions(user_id=None)` raises `ValueError` when `config.http_remote_hosted` is `True`. This prevents code paths from accidentally listing all users' sessions. Every call site in remote-hosted mode must pass an explicit `user_id`.
## Caching Strategy
`ApiKeyService` maintains an in-memory cache:
```python
# api_key -> (valid, user_id, metadata, expires_at)
_cache: dict[str, tuple[bool, str | None, dict | None, float]]
```
### What Gets Cached
| Response | Cached? | Rationale |
|----------|---------|-----------|
| 200 + `valid: true` | Yes | Definitive valid result |
| 200 + `valid: false` | Yes | Definitive invalid result |
| 401 status | Yes | Definitive rejection |
| 5xx status | No | Transient; retry on next request |
| Timeout | No | Transient; retry on next request |
| Connection error | No | Transient; retry on next request |
| Unexpected exception | No | Transient; retry on next request |
Non-cacheable results use `ValidationResult(cacheable=False)`.
### Cache Lifecycle
- **TTL:** Configurable via `--api-key-cache-ttl` (default: 300 seconds).
- **Expiry:** Checked on read. Expired entries are deleted and re-validated.
- **Invalidation:** `invalidate_cache(api_key)` removes a single key. `clear_cache()` removes all.
- **Concurrency:** Protected by `asyncio.Lock`.
### Revocation Latency
A revoked key continues to work for up to `cache_ttl` seconds. Lower the TTL for faster revocation at the cost of more validation requests.
## Fail-Closed Behaviour
The system fails closed at every boundary:
| Component | Failure | Behaviour |
|-----------|---------|-----------|
| `ApiKeyService._validate_external` | Timeout after retries | `valid=False, cacheable=False` |
| `ApiKeyService._validate_external` | Connection error after retries | `valid=False, cacheable=False` |
| `ApiKeyService._validate_external` | 5xx status | `valid=False, cacheable=False` |
| `ApiKeyService._validate_external` | Unexpected exception | `valid=False, cacheable=False` |
| `PluginHub.on_connect` | Auth service unavailable | Close `1013` (retry hint) |
| `UnityInstanceMiddleware._inject_unity_instance` | No user_id in remote-hosted mode | `RuntimeError` |
API keys are never logged in full. Keys longer than 8 characters are redacted to `xxxx...yyyy` in log messages.
## Session Key Derivation
`UnityInstanceMiddleware.get_session_key(ctx)` determines which dict key to use for storing/retrieving the active Unity instance per session:
```
1. client_id (string, non-empty) -> return client_id
2. ctx.get_state("user_id") -> return "user:{user_id}"
3. fallback -> return "global"
```
- **`client_id`:** Stable per MCP client connection. Preferred when available.
- **`user:{user_id}`:** Used in remote-hosted mode when the MCP transport doesn't provide a stable client ID. Ensures different users don't share instance selections.
- **`"global"`:** Local-dev fallback for single-user scenarios. Unreachable in remote-hosted mode because the auth enforcement raises `RuntimeError` before this point if no `user_id` is available.
## Disabled Features in Remote-Hosted Mode
| Feature | Local Mode | Remote-Hosted Mode | Reason |
|---------|-----------|-------------------|--------|
| Auto-select sole instance | Enabled | Disabled | Implicit behaviour is dangerous with multiple users |
| CLI REST routes | Enabled | Disabled | No auth layer on these endpoints |
| `list_sessions(user_id=None)` | Returns all | Raises `ValueError` | Prevents accidental cross-user session leaks |
## Configuration Flow
```
CLI args / env vars
|
v
main.py: parser.parse_args()
|
+-- config.http_remote_hosted = args or env
+-- config.api_key_validation_url = args or env
+-- config.api_key_login_url = args or env
+-- config.api_key_cache_ttl = args or env (float)
+-- config.api_key_service_token_header = args or env
+-- config.api_key_service_token = args or env
|
+-- Validate: remote-hosted requires validation URL
| (exits with code 1 if missing)
|
v
create_mcp_server()
|
+-- get_unity_instance_middleware() -> registers middleware
|
+-- if remote-hosted + validation URL:
| ApiKeyService(
| validation_url, cache_ttl,
| service_token_header, service_token
| )
|
+-- WebSocketRoute("/hub/plugin", PluginHub)
|
+-- if not remote-hosted:
register CLI routes (/api/command, /api/instances, /api/custom-tools)
```
## Key Files
| File | Role |
|------|------|
| `Server/src/core/config.py` | `ServerConfig` dataclass with auth fields |
| `Server/src/main.py` | CLI argument parsing, startup validation, service initialization |
| `Server/src/services/api_key_service.py` | API key validation singleton with caching and retry |
| `Server/src/transport/plugin_hub.py` | WebSocket auth gate, user-scoped session queries |
| `Server/src/transport/plugin_registry.py` | Dual-index session storage (local + user-scoped) |
| `Server/src/transport/unity_instance_middleware.py` | Per-request user_id and instance injection |
| `Server/src/transport/unity_transport.py` | `_resolve_user_id_from_request` helper |
+307
View File
@@ -0,0 +1,307 @@
# Unity MCP Feature Roadmap 2026
## Research Summary
Six parallel research agents investigated 12+ domains across Unity's API surface. Every domain was assessed for: API stability, implementation complexity, developer value, dead ends, and dependencies.
### Current Tool Coverage (19 tools)
Animation, Asset, Audio, Camera, Components, Editor, GameObjects, Graphics, Lighting, Material, Prefabs, ProBuilder, Scene, Script, ScriptableObject, Shader, Texture, UI, VFX
---
## Prioritized Implementation Plan
### Tier 1: Foundation (Unblocks Everything Else)
#### 1. `manage_packages` — Package Management
| Dimension | Assessment |
|-----------|-----------|
| **Value** | Very High |
| **Complexity** | Medium |
| **Actions** | ~14 |
| **Dependencies** | None (core Unity) |
| **Audience** | 100% of users |
**Why first**: Directly unblocks XR, Addressables, Input System, and any workflow requiring optional packages. Currently the #1 gap — AI can detect missing packages but cannot install them.
**Key APIs**: `PackageManager.Client.Add/Remove/List/Search/Embed` (all public, async). Scoped registries via `manifest.json` editing. Assembly definitions as JSON files.
**Actions**: `add_package`, `remove_package`, `add_and_remove`, `list_packages`, `search_packages`, `get_package_info`, `embed_package`, `resolve_packages`, `list_registries`, `add_registry`, `remove_registry`, `list_assemblies`, `create_asmdef`, `ping`
**Challenge**: Domain reload after install/remove kills state. Solution: `PendingResponse` + `McpJobStateStore` (existing patterns).
#### 2. QoL: Extend Existing Tools
| Dimension | Assessment |
|-----------|-----------|
| **Value** | High |
| **Complexity** | Low |
| **Effort** | 1-2 days each |
**2a. Multi-scene editing** (extend `manage_scene`):
- `open_additive`, `close_scene`, `set_active_scene`, `get_loaded_scenes`, `save_setup`, `restore_setup`
- `add_to_build`, `remove_from_build`, `set_build_enabled`
**2b. Scene validation** (extend `manage_scene` or new resource):
- `validate` — detect missing scripts, broken prefab references, null references
- `repair` — auto-fix missing scripts
- Uses `GameObjectUtility.GetMonoBehavioursWithMissingScriptCount()`, `PrefabUtility.GetPrefabInstanceStatus()`
**2c. Undo/Redo** (extend `manage_editor`):
- `undo`, `redo``Undo.PerformUndo()` / `Undo.PerformRedo()`
**2d. Scene templates** (extend `manage_scene`):
- `create_from_template` — presets: `3d_basic`, `3d_urp`, `2d_basic`, `empty`
---
### Tier 2: Core Game Systems (High Value, Low-Medium Complexity)
#### 3. `manage_physics` — Physics System
| Dimension | Assessment |
|-----------|-----------|
| **Value** | High |
| **Complexity** | Low-Medium |
| **Actions** | ~18 |
| **Dependencies** | None (core Unity) |
| **Audience** | ~90% of games |
**Why**: Almost every game uses physics. Existing `manage_components` can add Rigidbody/Collider but lacks global settings, collision matrix, raycasting, and simulation.
**Key APIs**: All public and stable since Unity 5+. `Physics.*` static class, all component properties, `PhysicsMaterial` asset creation.
**Actions by category**:
- Rigidbody: `add_rigidbody`, `configure_rigidbody`
- Colliders: `add_collider`, `configure_collider`, `fit_collider`
- Materials: `create_physics_material`, `configure_physics_material`
- Joints: `add_joint`, `configure_joint`, `remove_joint`
- Global: `get_settings`, `set_settings`, `get_collision_matrix`, `set_collision_matrix`
- Simulation: `simulate_step`, `sync_transforms`
- Queries: `raycast`, `overlap_sphere`
**Dead ends**: Physics callbacks don't fire in editor simulation. Can't simulate individual objects. Physics debug viz is internal.
#### 4. `manage_input` — Input System
| Dimension | Assessment |
|-----------|-----------|
| **Value** | High |
| **Complexity** | Medium-Low |
| **Actions** | ~18 |
| **Dependencies** | `com.unity.inputsystem` (must install) |
| **Audience** | ~95% of games |
**Why**: Every game needs input. Tedious manual setup. Perfect for presets ("set up FPS controls with gamepad support").
**Key APIs**: `InputActionSetupExtensions` — clean fluent API. `InputActionAsset` is a ScriptableObject serialized as JSON. All public.
**Actions**: `create_input_actions`, `get_input_actions_info`, `add_action_map`, `remove_action_map`, `add_action`, `remove_action`, `set_action_properties`, `add_binding`, `add_composite_binding`, `remove_binding`, `add_control_scheme`, `remove_control_scheme`, `setup_player_input`, `create_preset` (fps, third_person, platformer, vehicle, ui), `ping`
**Dead ends**: InputSettings modification is fragile. Active input handler switching requires restart. Generated C# wrapper class toggling is fragile.
#### 5. `manage_navigation` — NavMesh & AI Navigation
| Dimension | Assessment |
|-----------|-----------|
| **Value** | High |
| **Complexity** | Low-Medium |
| **Actions** | ~22 |
| **Dependencies** | None (core) + `com.unity.ai.navigation` (optional) |
| **Audience** | ~70% of 3D games |
**Why**: Navigation is fundamental. NavMesh baking is a pain point for beginners. Enables complete AI character workflow.
**Key APIs**: Core `NavMesh.*` static methods are built-in (no package). `NavMeshSurface`/`NavMeshLink`/`NavMeshModifier` from AI Navigation package (optional).
**Actions**: `navmesh_bake`, `navmesh_clear`, `navmesh_sample_position`, `navmesh_calculate_path`, `navmesh_raycast`, `agent_add`, `agent_configure`, `agent_set_destination`, `obstacle_add`, `obstacle_configure`, `surface_add`, `surface_configure`, `link_add`, `link_configure`, `modifier_add`, `modifier_volume_add`, `ping`, etc.
**Resource**: `mcpforunity://scene/navigation`
**Dead ends**: Can't create new NavMesh area types programmatically. No visual NavMesh debugging API.
---
### Tier 3: Content Creation (High Value, Medium Complexity)
#### 6. `manage_terrain` — Terrain System
| Dimension | Assessment |
|-----------|-----------|
| **Value** | High |
| **Complexity** | Medium |
| **Actions** | ~24 |
| **Dependencies** | None (core Unity) |
| **Audience** | ~40% of 3D games |
**Why**: Enables prompt-driven terrain generation. "Create mountainous terrain with snow above 80% height" becomes possible. Procedural generation (Perlin, height/slope-based painting) is the killer feature.
**Key APIs**: `TerrainData.SetHeights/GetHeights`, `SetAlphamaps`, `SetHoles`, tree/detail placement. All public.
**Actions**: `create_terrain`, `get_info`, `get_heights`, `set_heights`, `generate_heights` (Perlin, ridged, fbm), `flatten`, `smooth_heights`, `add_layer`, `paint_layer`, `paint_layer_by_height`, `paint_layer_by_slope`, `set_tree_prototypes`, `add_trees`, `scatter_trees`, `set_detail_prototypes`, `scatter_details`, `set_holes`, `set_neighbors`, `set_settings`, `ping`
**Critical design**: Heightmap operations must be region-based (never full map). Procedural generation runs C#-side. Large data stays server-side.
#### 7. `manage_timeline` — Timeline System
| Dimension | Assessment |
|-----------|-----------|
| **Value** | High |
| **Complexity** | Medium |
| **Actions** | ~25 |
| **Dependencies** | `com.unity.timeline` (included by default) |
| **Audience** | ~35% of games |
**Why**: Unlocks programmatic cutscene/sequence construction — a unique AI workflow. "Create a 10-second cutscene where the camera pans, the door opens at 2s, and music fades in at 5s."
**Key APIs**: `TimelineAsset.CreateTrack<T>()`, `TrackAsset.CreateClip<T>()`, `PlayableDirector.SetGenericBinding()`, `SignalAsset/Emitter/Receiver`. All public, remarkably complete.
**Actions**: `create_timeline`, `get_timeline_info`, `add_track`, `remove_track`, `add_clip`, `set_clip_properties`, `move_clip`, `setup_director`, `set_binding`, `get_bindings`, `set_director_properties`, `create_signal`, `add_signal_emitter`, `setup_signal_receiver`, `add_group`, `ping`
**Synergies**: `manage_animation` (clips), `manage_camera` (Cinemachine bindings), `manage_scene`.
#### 8. `manage_netcode` — Networking / Multiplayer
| Dimension | Assessment |
|-----------|-----------|
| **Value** | High |
| **Complexity** | Medium |
| **Actions** | ~20 |
| **Dependencies** | `com.unity.netcode.gameobjects` |
| **Audience** | ~64% of developers |
**Why**: Largest untapped audience. Zero competition in MCP space. Networking setup is error-prone and boilerplate-heavy.
**Key APIs**: `NetworkManager`, `NetworkObject`, `NetworkTransform`, `NetworkAnimator`, `NetworkRigidbody` — all standard MonoBehaviours. `NetworkPrefabsList` — ScriptableObject.
**Actions**: `setup_create_manager`, `setup_configure_manager`, `prefab_create_list`, `prefab_register`, `prefab_make_network`, `component_add_network_object`, `component_add_network_transform`, `component_add_network_animator`, `component_add_network_rigidbody`, `codegen_network_behaviour`, `codegen_player_controller`, `validate`, `list_network_objects`, `ping`
**Unique value**: Code generation for `NetworkBehaviour` scripts with RPCs, `NetworkVariable<T>` declarations. The `validate` action catches common misconfigurations before runtime.
---
### Tier 4: Build & Deploy (Very High Value, Higher Complexity)
#### 9. `manage_build` — Build Pipeline
| Dimension | Assessment |
|-----------|-----------|
| **Value** | Very High |
| **Complexity** | Medium-High |
| **Actions** | ~15 |
| **Dependencies** | None (Addressables optional) |
**Why**: Essential for CI/CD workflows, platform management, and project configuration.
**Actions**: `build_player`, `build_status`, `switch_platform`, `get_platform`, `get_player_settings`, `set_player_settings`, `get_define_symbols`, `set_define_symbols`, `get_build_scenes`, `set_build_scenes`, `get_build_profile`, `set_build_profile`, `list_build_profiles`, `ping`
**Challenge**: `BuildPipeline.BuildPlayer` is synchronous and blocks the editor thread. Non-blocking actions (PlayerSettings, define symbols) are straightforward. Build triggering needs `EditorApplication.delayCall` + poll-based status.
#### 10. `manage_addressables` — Addressable Assets
| Dimension | Assessment |
|-----------|-----------|
| **Value** | High |
| **Complexity** | Medium |
| **Actions** | ~23 |
| **Dependencies** | `com.unity.addressables` |
**Why**: Unity's recommended asset management for any project needing dynamic loading, DLC, or reduced build sizes.
**Actions**: `group_create`, `group_remove`, `group_list`, `entry_add`, `entry_remove`, `entry_move`, `entry_set_address`, `entry_find`, `label_add`, `label_remove`, `label_list`, `label_set`, `profile_list`, `profile_get`, `profile_set`, `profile_set_active`, `build_content`, `build_update`, `build_clean`, `get_settings`, `set_settings`, `ping`
**Resources**: `mcpforunity://addressables/groups`, `mcpforunity://addressables/settings`
---
### Tier 5: Specialized Domains (Medium-High Value, Higher Complexity)
#### 11. `manage_xr` — XR / VR / AR
| Dimension | Assessment |
|-----------|-----------|
| **Value** | Medium-High |
| **Complexity** | HIGH |
| **Actions** | ~25 |
| **Dependencies** | 3-6 packages |
| **Audience** | ~18% of developers |
**Why**: XR setup is notoriously painful. Meta has 10 tools but only covers Meta-specific SDK — cross-platform XRI, AR Foundation, and project-level setup are our opportunity.
**Recommendation**: Target XRI 3.0+ only. Focus on project setup + XR Origin creation first. Defer AR Foundation to later phase. Requires `manage_packages` first.
#### 12. `manage_tilemap` — 2D Tilemap (split from broader 2D)
| Dimension | Assessment |
|-----------|-----------|
| **Value** | Medium-High |
| **Complexity** | Medium |
| **Actions** | ~15 |
| **Dependencies** | None (core) + optional extras |
**Why**: Tilemap is the highest-value subset of 2D tooling. AI-assisted tilemap population is a strong use case.
**Actions**: `create`, `set_tile`, `set_tiles`, `fill_region`, `clear`, `get_info`, `swap_tile`, `add_collider`, `tile_create`, `tile_create_rule`, `ping`
#### 13. `manage_optimization` — Scene Optimization
| Dimension | Assessment |
|-----------|-----------|
| **Value** | Medium |
| **Complexity** | Medium |
| **Actions** | ~10 |
| **Dependencies** | None (core Unity) |
**Actions**: `set_static_flags`, `get_static_flags`, `set_static_flags_recursive`, `occlusion_bake`, `occlusion_cancel`, `occlusion_status`, `occlusion_clear`, `configure_lod`, `get_lod_info`, `auto_lod`
---
## Master Priority Matrix
| # | Tool | Value | Complexity | Deps | Actions | Audience |
|---|------|-------|-----------|------|---------|----------|
| 1 | `manage_packages` | Very High | Medium | 0 | 14 | 100% |
| 2 | QoL extensions | High | Low | 0 | ~15 | 100% |
| 3 | `manage_physics` | High | Low-Med | 0 | 18 | 90% |
| 4 | `manage_input` | High | Med-Low | 1 | 18 | 95% |
| 5 | `manage_navigation` | High | Low-Med | 0-1 | 22 | 70% |
| 6 | `manage_terrain` | High | Medium | 0 | 24 | 40% |
| 7 | `manage_timeline` | High | Medium | 1 | 25 | 35% |
| 8 | `manage_netcode` | High | Medium | 1-2 | 20 | 64% |
| 9 | `manage_build` | Very High | Med-High | 0 | 15 | 100% |
| 10 | `manage_addressables` | High | Medium | 1 | 23 | 30% |
| 11 | `manage_xr` | Med-High | HIGH | 3-6 | 25 | 18% |
| 12 | `manage_tilemap` | Med-High | Medium | 0-2 | 15 | 25% |
| 13 | `manage_optimization` | Medium | Medium | 0 | 10 | 50% |
## Confirmed Dead Ends (Do Not Implement)
| Feature | Reason |
|---------|--------|
| Shader Graph node creation | Internal API, no public editor scripting |
| VFX Graph node editing | Internal visual graph API |
| Terrain brush stroke simulation | UI-based painting system, no programmatic API |
| XR runtime testing | Requires headset or Play mode |
| Multiplayer session testing | Requires multiple Play mode instances |
| Physics callbacks in editor sim | Unity blocks for safety |
| Tile Palette editing | No public API |
| 2D Animation bone rigging | Deep, undocumented editor API |
| Unity Cloud Build | Separate REST API, not Editor scripting |
| Frame Debugger window | Internal editor utility |
| Custom NavMesh area creation | Hard-coded to 32 slots, no creation API |
## Dependencies Graph
```
manage_packages (Tier 1)
|
+---> manage_input (requires com.unity.inputsystem)
+---> manage_netcode (requires com.unity.netcode.gameobjects)
+---> manage_addressables (requires com.unity.addressables)
+---> manage_xr (requires 3-6 packages)
+---> manage_timeline (usually pre-installed)
+---> manage_navigation (optional com.unity.ai.navigation)
No package dependency:
manage_physics, manage_terrain, manage_build,
manage_optimization, QoL extensions, manage_tilemap (core)
```
## Estimated Total Scope
- **13 new tools/extensions** across 5 tiers
- **~250+ new actions** total
- **~5 new resources**
- Zero internal/private API hacks needed — all public, stable Unity APIs
---
*Generated 2026-03-08 by 6 parallel research agents analyzing Unity 6 APIs, documentation, forums, and source references.*
+172
View File
@@ -0,0 +1,172 @@
# MCP for Unity Telemetry
MCP for Unity includes privacy-focused, anonymous telemetry to help us improve the product. This document explains what data is collected, how to opt out, and our privacy practices.
## 🔒 Privacy First
- **Anonymous**: We use randomly generated UUIDs - no personal information
- **Non-blocking**: Telemetry never interferes with your Unity workflow
- **Easy opt-out**: Simple environment variable or Unity Editor setting
- **Transparent**: All collected data types are documented here
## 📊 What We Collect
### Usage Analytics
- **Tool Usage**: Which MCP tools you use (manage_script, manage_scene, etc.)
- **Performance**: Execution times and success/failure rates
- **System Info**: Unity version, platform (Windows/Mac/Linux), MCP version
- **Milestones**: First-time usage events (first script creation, first tool use, etc.)
### Technical Diagnostics
- **Connection Events**: Bridge startup/connection success/failures
- **Error Reports**: Anonymized error messages (truncated to 200 chars)
- **Server Health**: Startup time, connection latency
### What We **DON'T** Collect
- ❌ Your code or script contents
- ❌ Project names, file names, or paths
- ❌ Personal information or identifiers
- ❌ Sensitive project data
- ❌ IP addresses (beyond what's needed for HTTP requests)
## 🚫 How to Opt Out
### Method 1: Environment Variable (Recommended)
Set any of these environment variables to `true`:
```bash
# Disable all telemetry
export DISABLE_TELEMETRY=true
# MCP for Unity specific
export UNITY_MCP_DISABLE_TELEMETRY=true
# MCP protocol wide
export MCP_DISABLE_TELEMETRY=true
```
### Method 2: Unity Editor (Coming Soon)
In Unity Editor: `Window > MCP for Unity > Settings > Disable Telemetry`
### Method 3: Manual Config
Add to your MCP client config:
```json
{
"env": {
"DISABLE_TELEMETRY": "true"
}
}
```
## 🔧 Technical Implementation
### Architecture
- **Python Server**: Core telemetry collection and transmission
- **Unity Bridge**: Local event collection from Unity Editor
- **Anonymous UUIDs**: Generated per-installation for aggregate analytics
- **Thread-safe**: Non-blocking background transmission
- **Fail-safe**: Errors never interrupt your workflow
### Data Storage
Telemetry data is stored locally in:
- **Windows**: `%APPDATA%\UnityMCP\`
- **macOS**: `~/Library/Application Support/UnityMCP/`
- **Linux**: `~/.local/share/UnityMCP/`
Files created:
- `customer_uuid.txt`: Anonymous identifier
- `milestones.json`: One-time events tracker
### Data Transmission
- **Endpoint**: `https://api-prod.coplay.dev/telemetry/events`
- **Method**: HTTPS POST with JSON payload
- **Retry**: Background thread with graceful failure
- **Timeout**: 10 second timeout, no retries on failure
## 📈 How We Use This Data
### Product Improvement
- **Feature Usage**: Understand which tools are most/least used
- **Performance**: Identify slow operations to optimize
- **Reliability**: Track error rates and connection issues
- **Compatibility**: Ensure Unity version compatibility
### Development Priorities
- **Roadmap**: Focus development on most-used features
- **Bug Fixes**: Prioritize fixes based on error frequency
- **Platform Support**: Allocate resources based on platform usage
- **Documentation**: Improve docs for commonly problematic areas
### What We Don't Do
- ❌ Sell data to third parties
- ❌ Use data for advertising/marketing
- ❌ Track individual developers
- ❌ Store sensitive project information
## 🛠️ For Developers
### Custom Telemetry Events
```python
core.telemetry import record_telemetry, RecordType
record_telemetry(RecordType.USAGE, {
"custom_event": "my_feature_used",
"metadata": "optional_data"
})
```
### Telemetry Status Check
```python
core.telemetry import is_telemetry_enabled
if is_telemetry_enabled():
print("Telemetry is active")
else:
print("Telemetry is disabled")
```
## 📋 Data Retention Policy
- **Aggregated Data**: Retained indefinitely for product insights
- **Raw Events**: Automatically purged after 90 days
- **Personal Data**: None collected, so none to purge
- **Opt-out**: Immediate - no data sent after opting out
## 🤝 Contact & Transparency
- **Questions**: [Discord Community](https://discord.gg/y4p8KfzrN4)
- **Issues**: [GitHub Issues](https://github.com/CoplayDev/unity-mcp/issues)
- **Privacy Concerns**: Create a GitHub issue with "Privacy" label
- **Source Code**: All telemetry code is open source in this repository
## 📊 Example Telemetry Event
Here's what a typical telemetry event looks like:
```json
{
"record": "tool_execution",
"timestamp": 1704067200,
"customer_uuid": "550e8400-e29b-41d4-a716-446655440000",
"session_id": "abc123-def456-ghi789",
"version": "3.0.2",
"platform": "posix",
"data": {
"tool_name": "manage_script",
"success": true,
"duration_ms": 42.5
}
}
```
Notice:
- ✅ Anonymous UUID (randomly generated)
- ✅ Tool performance metrics
- ✅ Success/failure tracking
- ❌ No code content
- ❌ No project information
- ❌ No personal data
---
*MCP for Unity Telemetry is designed to respect your privacy while helping us build a better tool. Thank you for helping improve MCP for Unity!*
+98
View File
@@ -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
+65
View File
@@ -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<T>`) — 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)
+349
View File
@@ -0,0 +1,349 @@
# MCP for Unity - Developer Guide
| English | [简体中文](https://github.com/CoplayDev/unity-mcp/blob/beta/docs/development/README-DEV-zh.md) |
|---------------------------|------------------------------|
## Contributing
**Branch off `beta`** to create PRs. The `main` branch is reserved for stable releases.
Before proposing major new features, please reach out to discuss - someone may already be working on it or it may have been considered previously. Open an issue or discussion to coordinate.
Keep PRs focused. A small fix with a clear repro and the exact Unity/package versions is much easier to review than a broad cleanup bundled with behavior changes.
For bug fixes, include:
- Unity version(s) tested
- package source used (`#beta`, `#main`, tag, fork branch, or `file:`)
- resolved Git commit from `Packages/packages-lock.json` when the package source is a Git URL
- commands/tests run locally
Avoid mixing release/version bumps with feature or bug-fix PRs. The release workflows handle package and server version updates.
## Repository Map
- `MCPForUnity/` - the Unity package: Editor UI, C# tool handlers, resources, compatibility shims, package metadata.
- `Server/` - the Python MCP server, CLI, FastMCP tool/resource registry, transports, and server-side tests.
- `TestProjects/UnityMCPTests/` - Unity project used for EditMode/PlayMode tests. Its manifest points at `file:../../../MCPForUnity`.
- `docs/` - user, contributor, release, migration, and reference documentation.
- `tools/` - release/build helpers, documentation update prompt, stress tools, and publishing scripts.
- `CustomTools/` - examples and support code for project-defined custom tools.
## Local Development Setup
### 0. Prepare the Python Server
For server work, use the same setup path as CI:
```bash
cd Server
uv sync
uv pip install -e ".[dev]"
uv run pytest tests/ -v --tb=short
```
Most Python unit tests do not need Unity running. Integration tests that talk to the Editor require a Unity instance with the bridge connected.
### 1. Point Unity to Your Local Server
For the fastest iteration when working on the Python server:
1. Open Unity and go to **Window > MCP for Unity**
2. Open **Settings > Advanced Settings**
3. Set **Server Source Override** to your local `Server/` directory path
4. Enable **Dev Mode (Force fresh server install)** - this adds `--refresh` to uvx commands so your changes are picked up on every server start
### 2. Switch Package Sources
You may want to use the `mcp_source.py` script to quickly switch your Unity project between different MCP package sources [allows you to quickly point your personal project to your local or remote unity-mcp repo, or the live upstream (Coplay) versions of the unity-mcp package]:
```bash
python mcp_source.py
```
Options:
1. **Upstream main** - stable release (CoplayDev/unity-mcp)
2. **Upstream beta** - development branch (CoplayDev/unity-mcp#beta)
3. **Remote branch** - your fork's current branch
4. **Local workspace** - file: URL to your local MCPForUnity folder
After switching, open Package Manager in Unity and Refresh to re-resolve packages.
When testing Unity package changes, prefer **Local workspace**. Do not patch `Library/PackageCache/` directly; Unity may overwrite it on the next resolve.
`#beta` and `#main` are moving branch names. When debugging a package-source issue, check `Packages/packages-lock.json` as well as `Packages/manifest.json`; the lock file tells you the commit Unity actually resolved.
Example Git package lock entry:
```json
"com.coplaydev.unity-mcp": {
"version": "https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#beta",
"source": "git",
"hash": "<resolved-git-commit>"
}
```
## Adding or Changing Tools and Resources
Built-in Unity tools usually have two sides:
- a C# handler under `MCPForUnity/Editor/Tools/`
- a Python-facing tool under `Server/src/services/tools/`
Resources follow the same split:
- C# resources under `MCPForUnity/Editor/Resources/`
- Python resources under `Server/src/services/resources/`
Use `[McpForUnityTool]` / `[McpForUnityResource]` on the Unity side and `@mcp_for_unity_tool` / `@mcp_for_unity_resource` on the server side. If the tool is long-running, use the existing `PendingResponse` / polling patterns instead of blocking the bridge.
Current server tool groups are:
- `core`
- `docs`
- `vfx`
- `animation`
- `ui`
- `scripting_ext`
- `testing`
- `probuilder`
- `profiling`
Tools with `group=None` are server meta-tools and are always visible. The default enabled group is `core`; other groups can be enabled through the Tools tab or `manage_tools`.
When adding, removing, or renaming tools/resources, update the public docs and client metadata. Start with `tools/UPDATE_DOCS_PROMPT.md`, then review the changes manually.
## Tool Selection & the Meta-Tool
MCP for Unity organizes tools into **groups**. You can selectively enable or disable tools to control which capabilities are exposed to AI clients — reducing context window usage and focusing the AI on relevant tools.
### Using the Tools Tab in the Editor
Open **Window > MCP for Unity** and switch to the **Tools** tab. Each tool group is displayed as a collapsible foldout with:
- **Per-tool toggles** — click individual tool toggles to enable or disable them.
- **Group checkbox** — a checkbox embedded directly in each group's foldout header (next to the group title) enables or disables all tools in that group at once without expanding or collapsing the foldout.
- **Enable All / Disable All** — global buttons to toggle all tools.
- **Rescan** — re-discovers tools from assemblies (useful after adding new `[McpForUnityTool]` classes).
- **Reconfigure Clients** — re-registers tools with the server and reconfigures all detected MCP clients in one click, applying your changes without navigating back to the Clients tab.
### How Changes Propagate
Tool visibility changes work differently depending on the transport mode:
**HTTP mode** (recommended):
1. Toggling a tool calls `ReregisterToolsAsync()`, which sends the updated enabled tool list to the Python server over WebSocket.
2. The server updates its internal tool visibility via `mcp.enable()`/`mcp.disable()` per group.
3. The server sends a `tools/list_changed` MCP notification to all connected client sessions.
4. Already-connected clients (Claude Desktop, VS Code, etc.) automatically receive the updated tool list.
**Stdio mode**:
1. Toggles are persisted locally but cannot be pushed to the server (no WebSocket connection).
2. The server starts with all groups enabled. After changing toggles, ask the AI to run `manage_tools` with `action='sync'` — this pulls the current tool states from Unity and syncs server visibility.
3. Alternatively, restart the server to pick up changes.
### The `manage_tools` Meta-Tool
The server exposes a built-in `manage_tools` tool (always visible, not group-gated) that AIs can call directly:
| Action | Description |
|--------|-------------|
| `list_groups` | Lists all tool groups with their tools and enable/disable status |
| `activate` | Enables a tool group by name (e.g., `group="vfx"`) |
| `deactivate` | Disables a tool group by name |
| `sync` | Pulls current tool states from Unity and syncs server visibility (essential for stdio mode) |
| `reset` | Restores default tool visibility |
### When You Need to Reconfigure
After toggling tools on/off, MCP clients need to learn about the changes:
- **HTTP mode**: Changes propagate automatically via `tools/list_changed`. Most clients pick this up immediately. If a client doesn't, click **Reconfigure Clients** on the Tools tab, or go to Clients tab and click Configure.
- **Stdio mode**: The server process needs to be told about changes. Either ask the AI to call `manage_tools(action='sync')`, or restart the MCP session. Click **Reconfigure Clients** to re-register all clients with updated config.
## Running Tests
All major new features (and some minor ones) must include test coverage. It's so easy to get LLMs to write tests, ya gotta do it!
### Python Tests
Located in `Server/tests/`:
```bash
cd Server
uv run pytest tests/ -v
```
Useful narrower runs:
```bash
uv run pytest tests/test_manage_camera.py -v
uv run pytest tests/integration/test_run_tests_async.py -v
uv run pytest tests/ -v --tb=short
```
### Unity C# Tests
Located in `TestProjects/UnityMCPTests/Assets/Tests/`.
The test project consumes the local Unity package from this repo. Use it for package import/compile checks before opening a PR that touches `MCPForUnity/Runtime/`, `MCPForUnity/Editor/`, or package metadata.
**Using the CLI** (requires Unity running with MCP bridge connected):
```bash
cd Server
# Run EditMode tests (default)
uv run python -m cli.main editor tests
# Run PlayMode tests
uv run python -m cli.main editor tests --mode PlayMode
# Run async and poll for results (useful for long test runs)
uv run python -m cli.main editor tests --async
uv run python -m cli.main editor poll-test <job_id> --wait 60
# Show only failed tests
uv run python -m cli.main editor tests --failed-only
```
**Using MCP tools directly** (from any MCP client):
```
run_tests(mode="EditMode")
run_tests(mode="PlayMode", init_timeout=120000) # PlayMode may need longer init due to domain reload
get_test_job(job_id="<id>", wait_timeout=60)
```
### Local headless test harness
`python tools/local_harness.py` boots a headless Editor and runs the smoke + EditMode + PlayMode legs over the bridge — the same entrypoint CI uses. See [Testing → Local headless test harness](./testing.md#local-headless-test-harness) for the flags and exit-code contract.
### Code Coverage
```bash
cd Server
uv run pytest tests/ --cov --cov-report=html
open htmlcov/index.html
```
## Compatibility Notes
The Unity package currently declares Unity `2021.3` as its minimum version in `MCPForUnity/package.json`. Code that uses Unity API conditionals (`UNITY_2022_3_OR_NEWER`, `UNITY_2023_1_OR_NEWER`, `UNITY_6000_*`) should be tested against the affected editor line, not just the oldest supported version.
For compatibility PRs, note the exact editor versions you tested in the PR body. If a Git package URL is involved, include the resolved `packages-lock.json` hash.
## Troubleshooting During Development
- **Unity still loads an old Git package**: close Unity, check `Packages/packages-lock.json`, then refresh Package Manager. If needed, remove only the stale `Library/PackageCache/com.coplaydev.unity-mcp@<hash>` folder while Unity is closed.
- **Unity opens in Safe Mode after changing package source**: the package failed to compile before MCP can start. Fix the compile errors first; the MCP server cannot recover from package compile failures.
- **Server changes are not picked up**: make sure **Server Source Override** points to your local `Server/` directory and **Dev Mode (Force fresh server install)** is enabled.
- **Stdio tool visibility looks stale**: call `manage_tools(action="sync")` or restart the MCP session. HTTP mode can push `tools/list_changed` notifications automatically.
- **Multiple Unity editors are open**: use `mcpforunity://instances` and `set_active_instance` to confirm which project the server is targeting.
## Unity-version CI matrix
CI exercises the package across multiple Unity versions to catch breaks in `#if UNITY_*_OR_NEWER` branches. The matrix is configured in `tools/unity-versions.json` and consumed by `.github/workflows/unity-tests.yml`.
**Every PR gets a unity-tests status check on open** (mirrors `python-tests.yml`). For same-repo PRs the default Unity 6 leg actually runs; for fork PRs the workflow appears but skips with a "missing license secrets" notice until a maintainer applies `safe-to-test` (existing secret-safety gate). The full 4-version matrix is opt-in via the `full-matrix` label.
**When the full matrix runs (all 4 versions in parallel):**
- Push to `beta` (the release gate).
- `workflow_call` from `beta-release.yml` / `release.yml`.
- Manual `workflow_dispatch` from the Actions tab.
- Any PR (in-repo or fork) labeled with **`full-matrix`** — apply when your change touches compat shims, conditional compilation, or anything else version-sensitive. Triggers a full-matrix run on the next `pull_request` or `pull_request_target` event. Cost is ~6-8 min wall clock vs ~3 min for the default leg.
Fork PRs still need `safe-to-test` as the base gate (so secrets are exposed against reviewed-only fork code); `full-matrix` is layered on top for fork-PR full-matrix runs.
**Default (single leg)** — every other path runs only against `defaultVersion` from `tools/unity-versions.json` (currently Unity 6.0 LTS, `6000.0.75f1`). The `floor` role (`2021.3.45f2`) still identifies the package minimum and runs as part of the full matrix; it's no longer the default-leg version.
## Local Unity-version parity check
The same `tools/unity-versions.json` drives a local script so you can reproduce CI behavior before pushing.
The script has two runners. Use whichever fits your setup:
| Runner | When to use | Cost |
|---|---|---|
| **Local Unity Hub** (default) | You already have one or more matrix versions installed via Unity Hub. Fastest. | Disk: each editor is 3-6 GB. |
| **GameCI Docker** (`--docker`) | You don't want to install every editor locally. Same containers CI uses. | One-time pull is 5-15 GB per version. On Apple Silicon, expect ~5-10× slowdown from amd64 emulation. |
### Local Unity Hub mode
```bash
# Compile-only check across every locally-installed Unity in the matrix (~30-60s warm per version).
tools/check-unity-versions.sh
# Full EditMode test run — matches what CI runs end-to-end.
tools/check-unity-versions.sh --full
# Filter to one version family.
tools/check-unity-versions.sh --only 6000.0
```
Windows uses the PowerShell companion:
```powershell
pwsh .\tools\check-unity-versions.ps1
pwsh .\tools\check-unity-versions.ps1 -Full
pwsh .\tools\check-unity-versions.ps1 -Only 6000.0
```
Versions not installed via Unity Hub are skipped — the script never forces you to install every editor in the matrix. Install the versions you most care about (typically the floor `2021.3.45f2` and your daily-driver Unity 6) and CI / Docker mode cover the rest.
### GameCI Docker mode (no Unity Hub install required)
```bash
tools/check-unity-versions.sh --docker # all matrix versions, compile-only
tools/check-unity-versions.sh --docker --full # full EditMode run
tools/check-unity-versions.sh --docker --only 2022.3 # one version family
```
```powershell
pwsh .\tools\check-unity-versions.ps1 -Docker
pwsh .\tools\check-unity-versions.ps1 -Docker -Full
```
**One-time setup: get a Unity license**
GameCI containers still need an activated Unity license. Free Personal activations work fine and are tied to the machine, not the editor version — so a single `.ulf` covers every version in the matrix.
```bash
# 1. Generate the request file (.alf) — outputs Unity_v<version>.alf in the current directory.
docker run --rm -v "$PWD":/work unityci/editor:ubuntu-2021.3.45f2-base-3 \
/opt/unity/Editor/Unity -batchmode -nographics -quit \
-createManualActivationFile -logFile /dev/stdout
# 2. Upload Unity_v<version>.alf at https://license.unity3d.com/manual
# Choose Personal license → save the resulting .ulf file.
# 3. Export the .ulf contents (add to ~/.zshrc or ~/.bashrc to persist):
export UNITY_LICENSE="$(cat /path/to/Unity_v<version>.ulf)"
# 4. Run the check.
tools/check-unity-versions.sh --docker
```
PowerShell equivalent for step 3: `$env:UNITY_LICENSE = Get-Content C:\path\to\Unity_v<version>.ulf -Raw`.
The same `UNITY_LICENSE` secret is what `.github/workflows/unity-tests.yml` uses in CI — once you have it, your local Docker runs and CI behave identically.
**Coverage gap on Apple Silicon Macs**: GameCI publishes only `linux/amd64` images. Docker Desktop runs them under Rosetta/QEMU at ~5-10× the native amd64 speed. A compile that takes 30s on Intel takes 3-5 min on M-series. Still faster than installing four Unity editors, but plan for it.
**Opt-in pre-push hook**
```bash
tools/install-hooks.sh # installs .git/hooks/pre-push (idempotent)
tools/install-hooks.sh --uninstall # removes our hooks
```
Once installed, `git push` runs the compile-only check first when the push touches `MCPForUnity/Editor/**`, `MCPForUnity/Runtime/**`, `TestProjects/UnityMCPTests/**`, `tools/unity-versions.json`, or `.github/workflows/unity-tests.yml`. Pushes that touch only docs, Server/, or unrelated files skip the check.
To bypass for a single push: `git push --no-verify`.
**Bumping the matrix**
Edit `tools/unity-versions.json` and update CI + local scripts both in one commit. The file is the single source of truth.
+151
View File
@@ -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/<section>/*.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 `<!-- examples:start -->` and `<!-- examples:end -->` 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/<group>/<tool-name>.md`. Look for:
```html
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
```
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/<group>/<tool-name>.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/<section>/`. Front-matter at minimum:
```yaml
---
id: my-page
slug: /<section>/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 `<details>` block.
- Replaces the block between `<!-- recent-updates:start -->` and `<!-- recent-updates:end -->` 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 `<tag>` 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, 46 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`.
+111
View File
@@ -0,0 +1,111 @@
# Releasing (Maintainers)
This repo uses a two-branch flow to keep `main` stable for users:
- `beta`: integration branch where feature PRs land
- `main`: stable branch that should match the latest release tag
## Release checklist
### 1) Promote `beta` to `main` via PR
- Create a PR with:
- base: `main`
- compare: `beta`
- Ensure required CI checks are green.
- Merge the PR.
Release note quality depends on how you merge:
- Squash-merging feature PRs into `beta` is OK.
- Avoid squash-merging the `beta -> main` promotion PR. Prefer a merge commit (or rebase merge) so GitHub can produce better auto-generated release notes.
### 2) Run the Release workflow (manual)
- Go to **GitHub → Actions → Release**
- Click **Run workflow**
- Select:
- `patch`, `minor`, or `major`
- Run it on branch: `main`
What the workflow does:
1. Creates a temporary `release/vX.Y.Z` branch with the version bump commit
2. Opens a PR from that branch into `main`
3. Auto-merges the PR (or waits for required checks, then merges)
4. Creates an annotated tag `vX.Y.Z` on the merged commit
5. Creates a GitHub Release for the tag
6. Publishes artifacts (Docker / PyPI / MCPB)
7. Opens a PR to merge `main` back into `beta` (so `beta` gets the bump)
8. Auto-merges the sync PR
9. Cleans up the temporary release branch
### 3) Verify release outputs
- Confirm a new tag exists: `vX.Y.Z`
- Confirm a GitHub Release exists for the tag
- Confirm artifacts:
- Docker image published with version `X.Y.Z`
- PyPI package published (if configured)
- `unity-mcp-X.Y.Z.mcpb` attached to the GitHub Release
## Required repo settings
### Branch protection (Rulesets)
The release workflow uses PRs instead of direct pushes, so it works with strict branch protection. No bypass actors are required.
Recommended ruleset for `main`:
- Require PR before merging
- Allowed merge methods: `merge`, `rebase` (no squash for promotion PRs)
- Required approvals: `0` (so automated PRs can merge without human review)
- Optionally require status checks
Recommended ruleset for `beta`:
- Require PR before merging
- Allowed merge methods: `squash` (for feature PRs)
- Required approvals: `0` (so the sync PR can auto-merge)
### Enable auto-merge (required)
The workflow uses `gh pr merge --auto` to automatically merge PRs once checks pass.
To enable:
1. Go to **Settings → General**
2. Scroll to **Pull Requests**
3. Check **Allow auto-merge**
Without this setting, the workflow will fall back to direct merge attempts, which may fail if branch protection requires checks.
## Failure modes and recovery
### Tag already exists
The workflow fails if the computed tag already exists. Pick a different bump type or investigate why a tag already exists for that version.
### Bump PR fails to merge
If the version bump PR cannot be merged (e.g., required checks fail):
- The workflow will fail before creating a tag.
- Fix the issue, then either:
- Manually merge the PR and create the tag/release, or
- Close the PR, delete the `release/vX.Y.Z` branch, and re-run the workflow.
### Sync PR (`main -> beta`) fails
If the sync PR has merge conflicts:
- The workflow will fail after the release is published (artifacts are already out).
- Manually resolve conflicts in the sync PR and merge it.
### Leftover release branch
If the workflow fails mid-run, a `release/vX.Y.Z` branch may remain. Delete it manually before re-running:
```bash
git push origin --delete release/vX.Y.Z
```
+116
View File
@@ -0,0 +1,116 @@
---
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_<domain>`, add `Server/tests/test_manage_<domain>.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`.
### Local headless test harness
One command boots a headless Hub-licensed Editor against `TestProjects/UnityMCPTests` and runs the smoke + EditMode + PlayMode legs over the bridge, then tears down:
```bash
python tools/local_harness.py
```
This is the same entrypoint CI uses — `.github/workflows/e2e-bridge.yml` collapses its boot/wait/discover/run-smoke shell into this invocation.
Key flags:
- `--legs smoke,editmode,playmode` — subset of legs to run.
- `--project-path TestProjects/UnityMCPTests` — Unity project to boot (repo-relative or absolute).
- `--reuse` — attach to an already-resident bridge instead of booting one.
- `--keep-alive` — leave the Editor running after the legs (no teardown).
- `--no-warmup` — skip the warm-up import phase.
Exit-code contract: `0` all blocking legs passed, `1` a blocking-leg regression, `2` bridge unreachable / setup failure, `3` project does not compile, `4` no Unity license / Hub seat, `5` Editor binary/version not found.
It needs a Hub-activated Editor locally (no ULF/serial); none of the CI license staging applies.
### 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.
+53
View File
@@ -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.
@@ -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 515 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
+39
View File
@@ -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.
+139
View File
@@ -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).
+72
View File
@@ -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)
+252
View File
@@ -0,0 +1,252 @@
---
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.
### Why CLI Instead of MCP Connection?
- MCP connection breaks when Unity restarts
- `/mcp reconnect` requires human intervention
- CLI works directly via HTTP to the MCP server - no persistent connection needed
- Claude can call CLI commands autonomously without reconnection issues
### Installation
```bash
cd Server # In unity-mcp repo
pip install -e .
# Or with uv:
uv pip install -e .
```
### Global Options
| Option | Description | Default | Env Variable |
|--------|-------------|---------|--------------|
| `-h, --host` | Server host | 127.0.0.1 | `UNITY_MCP_HOST` |
| `-p, --port` | Server port | 8080 | `UNITY_MCP_HTTP_PORT` |
| `-t, --timeout` | Timeout seconds | 30 | `UNITY_MCP_TIMEOUT` |
| `-f, --format` | Output: text, json, table | text | `UNITY_MCP_FORMAT` |
| `-i, --instance` | Target Unity instance | - | `UNITY_MCP_INSTANCE` |
### Core CLI Commands
**Status & Connection**
```bash
unity-mcp status # Check server + Unity connection
```
**Instance Management**
```bash
unity-mcp instance list # List connected Unity instances
unity-mcp instance set "ProjectName@abc" # Set active instance
unity-mcp instance current # Show current instance
```
**Editor Control**
```bash
unity-mcp editor play|pause|stop # Control play mode
unity-mcp editor console [--clear] # Get/clear console logs
unity-mcp editor refresh [--compile] # Refresh assets
unity-mcp editor menu "Edit/Project Settings..." # Execute menu item
unity-mcp editor add-tag "TagName" # Add tag
unity-mcp editor add-layer "LayerName" # Add layer
unity-mcp editor tests --mode PlayMode [--async]
unity-mcp editor poll-test <job_id> [--wait 60] [--details]
unity-mcp --instance "MyProject@abc123" editor play # Target a specific instance
```
**Custom Tools**
```bash
unity-mcp tool list
unity-mcp custom_tool list
unity-mcp editor custom-tool "bake_lightmaps"
unity-mcp editor custom-tool "capture_screenshot" --params '{"filename":"shot_01","width":1920,"height":1080}'
```
**Scene Operations**
```bash
unity-mcp scene hierarchy [--limit 20] [--depth 3]
unity-mcp scene active
unity-mcp scene load "Assets/Scenes/Main.unity"
unity-mcp scene save
unity-mcp --format json scene hierarchy
```
**Screenshots** (via `camera` command):
```bash
unity-mcp camera screenshot --file-name "capture"
unity-mcp camera screenshot --camera-ref "MainCam" --include-image --max-resolution 512
unity-mcp camera screenshot --batch surround --max-resolution 256
unity-mcp camera screenshot --batch orbit --view-target "Player"
unity-mcp camera screenshot --capture-source scene_view --view-target "Canvas" --include-image
unity-mcp camera screenshot-multiview --view-target "Player" --max-resolution 480
```
**GameObject Operations**
```bash
unity-mcp gameobject find "Name" [--method by_tag|by_name|by_layer|by_component]
unity-mcp gameobject create "Name" [--primitive Cube] [--position X Y Z]
unity-mcp gameobject modify "Name" [--position X Y Z] [--rotation X Y Z]
unity-mcp gameobject delete "Name" [--force]
unity-mcp gameobject duplicate "Name"
```
**Component Operations**
```bash
unity-mcp component add "GameObject" ComponentType
unity-mcp component remove "GameObject" ComponentType
unity-mcp component set "GameObject" Component property value
```
**Script Operations**
```bash
unity-mcp script create "ScriptName" --path "Assets/Scripts"
unity-mcp script read "Assets/Scripts/File.cs"
unity-mcp script delete "Assets/Scripts/File.cs" [--force]
unity-mcp code search "pattern" "path/to/file.cs" [--max-results 20]
```
**Asset Operations**
```bash
unity-mcp asset search --pattern "*.mat" --path "Assets/Materials"
unity-mcp asset info "Assets/Materials/File.mat"
unity-mcp asset mkdir "Assets/NewFolder"
unity-mcp asset move "Old/Path" "New/Path"
```
**Prefab Operations**
```bash
unity-mcp prefab open "Assets/Prefabs/File.prefab"
unity-mcp prefab save
unity-mcp prefab close
unity-mcp prefab create "GameObject" --path "Assets/Prefabs"
unity-mcp prefab modify "Assets/Prefabs/File.prefab" --delete-child Child1
unity-mcp prefab modify "Assets/Prefabs/File.prefab" --target Weapon --position "0,1,2"
unity-mcp prefab modify "Assets/Prefabs/File.prefab" --set-property "Rigidbody.mass=5"
```
**Material Operations**
```bash
unity-mcp material create "Assets/Materials/File.mat"
unity-mcp material set-color "File.mat" R G B
unity-mcp material assign "File.mat" "GameObject"
```
**Shader Operations**
```bash
unity-mcp shader create "Name" --path "Assets/Shaders"
unity-mcp shader read "Assets/Shaders/Custom.shader"
unity-mcp shader update "Assets/Shaders/Custom.shader" --file local.shader
unity-mcp shader delete "Assets/Shaders/File.shader" [--force]
```
**VFX Operations**
```bash
unity-mcp vfx particle info|play|stop|pause|restart|clear "Name"
unity-mcp vfx line info "Name"
unity-mcp vfx line create-line "Name" --start X Y Z --end X Y Z
unity-mcp vfx line create-circle "Name" --radius N
unity-mcp vfx trail info|set-time|clear "Name" [time]
```
**Camera Operations**
```bash
unity-mcp camera ping # Check Cinemachine
unity-mcp camera list # List all cameras
unity-mcp camera create --name "Cam" --preset follow --follow "Player"
unity-mcp camera set-target "Cam" --follow "Player" --look-at "Enemy"
unity-mcp camera set-lens "Cam" --fov 60 --near 0.1
unity-mcp camera set-priority "Cam" --priority 15
unity-mcp camera set-body "Cam" --body-type "CinemachineFollow"
unity-mcp camera set-aim "Cam" --aim-type "CinemachineRotationComposer"
unity-mcp camera set-noise "Cam" --amplitude 1.5 --frequency 0.5
unity-mcp camera ensure-brain --blend-style "EaseInOut" --blend-duration 1.5
unity-mcp camera force "Cam" # Force Brain to use camera
unity-mcp camera release # Release override
```
**Graphics Operations**
```bash
# Volumes
unity-mcp graphics volume-create --name "PostFX" --global
unity-mcp graphics volume-add-effect --target "PostFX" --effect "Bloom"
unity-mcp graphics volume-set-effect --target "PostFX" --effect "Bloom" -p intensity 1.5
unity-mcp graphics volume-info --target "PostFX"
# Pipeline
unity-mcp graphics pipeline-info
unity-mcp graphics pipeline-set-quality --level "High"
# Baking
unity-mcp graphics bake-start [--sync]
unity-mcp graphics bake-status
unity-mcp graphics bake-create-probes --spacing 5
# Stats
unity-mcp graphics stats
unity-mcp graphics stats-memory
# URP Features
unity-mcp graphics feature-list
unity-mcp graphics feature-add --type "ScreenSpaceAmbientOcclusion"
# Skybox
unity-mcp graphics skybox-info
unity-mcp graphics skybox-set-fog --enable --mode ExponentialSquared --density 0.02
unity-mcp graphics skybox-set-sun --target "DirectionalLight"
```
**Package Operations**
```bash
unity-mcp packages list # List installed
unity-mcp packages search "cinemachine" # Search registry
unity-mcp packages info "com.unity.cinemachine" # Details
unity-mcp packages add "com.unity.cinemachine" # Install
unity-mcp packages add "com.unity.cinemachine@4.1.1" # Specific version
unity-mcp packages remove "com.unity.cinemachine" [--force]
unity-mcp packages embed "com.unity.cinemachine" # Local editing
unity-mcp packages resolve # Re-resolve
unity-mcp packages list-registries
unity-mcp packages add-registry "Name" --url URL -s "com.example"
```
**Texture Operations**
```bash
unity-mcp texture create "Assets/Textures/Red.png" --color "1,0,0,1"
unity-mcp texture create "Assets/Textures/Check.png" --pattern checkerboard --width 256 --height 256
unity-mcp texture sprite "Assets/Sprites/Player.png" --width 32 --height 32 --ppu 16
unity-mcp texture modify "Assets/Textures/Img.png" --set-pixels '{"x":0,"y":0,"width":16,"height":16,"color":[1,0,0,1]}'
unity-mcp texture delete "Assets/Textures/Old.png" [--force]
```
**Lighting & UI**
```bash
unity-mcp lighting create "Name" --type Point|Spot [--intensity N] [--position X Y Z]
unity-mcp ui create-canvas "Name"
unity-mcp ui create-text "Name" --parent "Canvas" --text "Content"
unity-mcp ui create-button "Name" --parent "Canvas" --text "Label"
```
**Batch Operations**
```bash
unity-mcp batch run commands.json [--parallel] [--fail-fast]
unity-mcp batch inline '[{"tool": "manage_scene", "params": {...}}]'
unity-mcp batch template > commands.json
```
**Raw Access (Any Tool)**
```bash
unity-mcp raw tool_name 'JSON_params'
unity-mcp raw manage_scene '{"action":"get_active"}'
unity-mcp raw manage_camera '{"action":"screenshot","include_image":true}'
unity-mcp raw manage_graphics '{"action":"volume_get_info","target":"PostProcessing"}'
unity-mcp raw manage_packages '{"action":"list_packages"}'
```
### Note on MCP Server
The MCP HTTP server still needs to be running for CLI to work. Here is an example to run the server manually on Mac:
```bash
/opt/homebrew/bin/uvx --no-cache --refresh --from /XXX/unity-mcp/Server mcp-for-unity --transport http --http-url http://localhost:8080
```
+560
View File
@@ -0,0 +1,560 @@
# Unity MCP CLI Usage Guide
The Unity MCP CLI provides command-line access to control the Unity Editor through the Model Context Protocol. It currently only supports local HTTP.
Note: Some tools are still experimental and might fail under some circumstances. Please submit an issue to help us make it better.
## Installation
```bash
cd Server
pip install -e .
# Or with uv:
uv pip install -e .
```
## Quick Start
```bash
# Check connection
unity-mcp status
# List Unity instances
unity-mcp instance list
# Get scene hierarchy
unity-mcp scene hierarchy
# Find a GameObject
unity-mcp gameobject find "Player"
```
## Global Options
| Option | Env Variable | Description |
|--------|--------------|-------------|
| `-h, --host` | `UNITY_MCP_HOST` | Server host (default: 127.0.0.1) |
| `-p, --port` | `UNITY_MCP_HTTP_PORT` | Server port (default: 8080) |
| `-t, --timeout` | `UNITY_MCP_TIMEOUT` | Timeout in seconds (default: 30) |
| `-f, --format` | `UNITY_MCP_FORMAT` | Output format: text, json, table |
| `-i, --instance` | `UNITY_MCP_INSTANCE` | Target Unity instance |
## Command Reference
### Instance Management
```bash
# List connected Unity instances
unity-mcp instance list
# Set active instance
unity-mcp instance set "ProjectName@abc123"
# Show current instance
unity-mcp instance current
```
### Scene Operations
```bash
# Get scene hierarchy
unity-mcp scene hierarchy
unity-mcp scene hierarchy --limit 20 --depth 3
# Get active scene info
unity-mcp scene active
# Load/save scenes
unity-mcp scene load "Assets/Scenes/Main.unity"
unity-mcp scene save
# Screenshots (use camera command)
unity-mcp camera screenshot
unity-mcp camera screenshot --file-name "level_preview"
unity-mcp camera screenshot --camera-ref "SecondCamera" --include-image
unity-mcp camera screenshot --batch surround --max-resolution 256
unity-mcp camera screenshot --batch orbit --view-target "Player"
unity-mcp camera screenshot --capture-source scene_view --view-target "Canvas" --include-image
unity-mcp camera screenshot-multiview --view-target "Player" --max-resolution 480
```
### GameObject Operations
```bash
# Find GameObjects
unity-mcp gameobject find "Player"
unity-mcp gameobject find "Enemy" --method by_tag
# Create GameObjects
unity-mcp gameobject create "NewCube" --primitive Cube
unity-mcp gameobject create "Empty" --position 0 5 0
# Modify GameObjects
unity-mcp gameobject modify "Cube" --position 1 2 3 --rotation 0 45 0
# Delete/duplicate
unity-mcp gameobject delete "OldObject" --force
unity-mcp gameobject duplicate "Template"
```
### Component Operations
```bash
# Add component
unity-mcp component add "Player" Rigidbody
# Remove component
unity-mcp component remove "Player" Rigidbody
# Set property
unity-mcp component set "Player" Rigidbody mass 10
```
### Script Operations
```bash
# Create script
unity-mcp script create "PlayerController" --path "Assets/Scripts"
# Read script
unity-mcp script read "Assets/Scripts/Player.cs"
# Delete script
unity-mcp script delete "Assets/Scripts/Old.cs" --force
```
### Code Search
```bash
# Search with regex
unity-mcp code search "class.*Player" "Assets/Scripts/Player.cs"
unity-mcp code search "TODO|FIXME" "Assets/Scripts/Utils.cs"
unity-mcp code search "void Update" "Assets/Scripts/Game.cs" --max-results 20
```
### Shader Operations
```bash
# Create shader
unity-mcp shader create "MyShader" --path "Assets/Shaders"
# Read shader
unity-mcp shader read "Assets/Shaders/Custom.shader"
# Update from file
unity-mcp shader update "Assets/Shaders/Custom.shader" --file local.shader
# Delete shader
unity-mcp shader delete "Assets/Shaders/Old.shader" --force
```
### Editor Controls
```bash
# Play mode
unity-mcp editor play
unity-mcp editor pause
unity-mcp editor stop
# Refresh assets
unity-mcp editor refresh
unity-mcp editor refresh --compile
# Console
unity-mcp editor console
unity-mcp editor console --clear
# Tags and layers
unity-mcp editor add-tag "Enemy"
unity-mcp editor add-layer "Projectiles"
# Menu items
unity-mcp editor menu "Edit/Project Settings..."
# Custom tools
unity-mcp editor custom-tool "MyBuildTool"
unity-mcp editor custom-tool "Deploy" --params '{"target": "Android"}'
# List custom tools for the active Unity project
unity-mcp tool list
unity-mcp custom_tool list
```
#### Screenshot Parameters
| Option | Type | Description |
|--------|------|-------------|
| `--filename, -f` | string | Output filename (default: timestamp-based) |
| `--supersize, -s` | int | Resolution multiplier 14 for file-saved screenshots |
| `--camera-ref` | string | Camera name/path/ID (default: Camera.main) |
| `--include-image` | flag | Return base64 PNG inline in the response |
| `--max-resolution, -r` | int | Max longest-edge pixels (default 640) |
| `--batch, -b` | string | `surround` (6 angles) or `orbit` (configurable grid) |
| `--capture-source` | string | `game_view` (default) or `scene_view` (editor viewport) |
| `--view-target` | string | Target to focus on: GO name/path/ID, or `x,y,z`. Aims camera (game_view) or frames viewport (scene_view) |
| `--view-position` | string | Camera position as `x,y,z` (positioned screenshot, game_view only) |
| `--view-rotation` | string | Camera euler rotation as `x,y,z` (positioned screenshot, game_view only) |
| `--orbit-angles` | int | Number of azimuth steps around target (default 8) |
| `--orbit-elevations` | string | Vertical angles as JSON array, e.g. `[0,30,-15]` (default `[0, 30, -15]`) |
| `--orbit-distance` | float | Camera distance from target in world units (auto-fit if omitted) |
| `--orbit-fov` | float | Camera FOV in degrees (default 60) |
| `--output-dir, -o` | string | Save directory (default: Unity project's `Assets/Screenshots/`) |
### Testing
```bash
# Run tests synchronously
unity-mcp editor tests --mode EditMode
# Run tests asynchronously
unity-mcp editor tests --mode PlayMode --async
# Poll test job
unity-mcp editor poll-test <job_id>
unity-mcp editor poll-test <job_id> --wait 60 --details
```
### Material Operations
```bash
# Create material
unity-mcp material create "Assets/Materials/Red.mat"
# Set color
unity-mcp material set-color "Assets/Materials/Red.mat" 1 0 0
# Assign to object
unity-mcp material assign "Assets/Materials/Red.mat" "Cube"
```
### VFX Operations
Note: VFX Graph tooling is tested against com.unity.visualeffectgraph 12.1.13. Install VFX Graph and use URP/HDRP (set the Render Pipeline Asset) to avoid Unity warnings; other versions may be unsupported.
```bash
# Particle systems
unity-mcp vfx particle info "Fire"
unity-mcp vfx particle play "Fire" --with-children
unity-mcp vfx particle stop "Fire"
# Line renderers
unity-mcp vfx line info "LaserBeam"
unity-mcp vfx line create-line "Line" --start 0 0 0 --end 10 5 0
unity-mcp vfx line create-circle "Circle" --radius 5
# Trail renderers
unity-mcp vfx trail info "PlayerTrail"
unity-mcp vfx trail set-time "Trail" 2.0
# Raw VFX actions (access all 60+ actions)
unity-mcp vfx raw particle_set_main "Fire" --params '{"duration": 5}'
```
### ProBuilder Operations
Note: Requires com.unity.probuilder package installed in your Unity project.
```bash
# Create shapes
unity-mcp probuilder create-shape Cube
unity-mcp probuilder create-shape Torus --name "MyTorus" --params '{"rows": 16, "columns": 16}'
unity-mcp probuilder create-shape Stair --position 0 0 5 --params '{"steps": 10}'
# Create from polygon footprint
unity-mcp probuilder create-poly --points "[[0,0,0],[5,0,0],[5,0,5],[0,0,5]]" --height 3
# Get mesh info
unity-mcp probuilder info "MyCube"
# Raw ProBuilder actions
unity-mcp probuilder raw extrude_faces "MyCube" --params '{"faceIndices": [0], "distance": 1.0}'
unity-mcp probuilder raw bevel_edges "MyCube" --params '{"edgeIndices": [0,1], "amount": 0.2}'
unity-mcp probuilder raw set_face_material "MyCube" --params '{"faceIndices": [0], "materialPath": "Assets/Materials/Red.mat"}'
```
### Batch Operations
```bash
# Execute from JSON file
unity-mcp batch run commands.json
unity-mcp batch run commands.json --parallel --fail-fast
# Execute inline JSON
unity-mcp batch inline '[{"tool": "manage_scene", "params": {"action": "get_active"}}]'
# Generate template
unity-mcp batch template > my_commands.json
```
### Prefab Operations
```bash
# Open prefab for editing
unity-mcp prefab open "Assets/Prefabs/Player.prefab"
# Save and close
unity-mcp prefab save
unity-mcp prefab close
# Create from GameObject
unity-mcp prefab create "Player" --path "Assets/Prefabs"
# Modify prefab contents (headless, no UI)
unity-mcp prefab modify "Assets/Prefabs/Player.prefab" --target Weapon --position "0,1,2"
unity-mcp prefab modify "Assets/Prefabs/Player.prefab" --delete-child Child1 --delete-child "Turret/Barrel"
unity-mcp prefab modify "Assets/Prefabs/Player.prefab" --set-property "Rigidbody.mass=5"
unity-mcp prefab modify "Assets/Prefabs/Player.prefab" --add-component BoxCollider
unity-mcp prefab modify "Assets/Prefabs/Player.prefab" --create-child '{"name":"Spawn","primitive_type":"Sphere"}'
```
### Asset Operations
```bash
# Search assets
unity-mcp asset search --pattern "*.mat" --path "Assets/Materials"
# Get asset info
unity-mcp asset info "Assets/Materials/Red.mat"
# Create folder
unity-mcp asset mkdir "Assets/NewFolder"
# Move/rename
unity-mcp asset move "Assets/Old.mat" "Assets/Materials/"
```
### Animation Operations
```bash
# Play animation state
unity-mcp animation play "Player" "Run"
# Set animator parameter
unity-mcp animation set-parameter "Player" Speed 1.5
unity-mcp animation set-parameter "Player" IsRunning true
```
### Audio Operations
```bash
# Play audio
unity-mcp audio play "AudioPlayer"
# Stop audio
unity-mcp audio stop "AudioPlayer"
# Set volume
unity-mcp audio volume "AudioPlayer" 0.5
```
### Lighting Operations
```bash
# Create light
unity-mcp lighting create "NewLight" --type Point --position 0 5 0
unity-mcp lighting create "Spotlight" --type Spot --intensity 2
```
### UI Operations
```bash
# Create canvas
unity-mcp ui create-canvas "MainCanvas"
# Create text
unity-mcp ui create-text "Title" --parent "MainCanvas" --text "Hello World"
# Create button
unity-mcp ui create-button "StartBtn" --parent "MainCanvas" --text "Start"
# Create image
unity-mcp ui create-image "Background" --parent "MainCanvas"
```
### Camera Operations
```bash
unity-mcp camera ping # Check Cinemachine availability
unity-mcp camera list # List all cameras
unity-mcp camera create --name "Cam" --preset follow --follow "Player"
unity-mcp camera set-target "Cam" --follow "Player" --look-at "Enemy"
unity-mcp camera set-lens "Cam" --fov 60 --near 0.1 --far 1000
unity-mcp camera set-priority "Cam" --priority 15
unity-mcp camera set-body "Cam" --body-type "CinemachineFollow"
unity-mcp camera set-aim "Cam" --aim-type "CinemachineRotationComposer"
unity-mcp camera set-noise "Cam" --amplitude 1.5 --frequency 0.5
unity-mcp camera add-extension "Cam" CinemachineConfiner3D
unity-mcp camera ensure-brain --blend-style "EaseInOut" --blend-duration 1.5
unity-mcp camera brain-status
unity-mcp camera force "Cam" # Force Brain to use camera
unity-mcp camera release # Release override
unity-mcp camera screenshot --file-name "capture" --super-size 2
unity-mcp camera screenshot --batch orbit --view-target "Player" --max-resolution 256
unity-mcp camera screenshot --capture-source scene_view --view-target "Canvas" --include-image
unity-mcp camera screenshot-multiview --view-target "Player" --max-resolution 480
```
### Graphics Operations
```bash
# Volumes
unity-mcp graphics volume-create --name "PostFX" --global
unity-mcp graphics volume-add-effect --target "PostFX" --effect "Bloom"
unity-mcp graphics volume-set-effect --target "PostFX" --effect "Bloom" -p intensity 1.5
unity-mcp graphics volume-info --target "PostFX"
unity-mcp graphics volume-list-effects
# Render Pipeline
unity-mcp graphics pipeline-info
unity-mcp graphics pipeline-set-quality --level "High"
unity-mcp graphics pipeline-set-settings -s renderScale 1.5
# Light Baking
unity-mcp graphics bake-start [--sync]
unity-mcp graphics bake-status
unity-mcp graphics bake-cancel
unity-mcp graphics bake-settings
unity-mcp graphics bake-create-probes --spacing 5
unity-mcp graphics bake-create-reflection --resolution 512
# Stats & Debug
unity-mcp graphics stats
unity-mcp graphics stats-memory
unity-mcp graphics stats-debug-mode --mode "Wireframe"
# URP Renderer Features
unity-mcp graphics feature-list
unity-mcp graphics feature-add --type "ScreenSpaceAmbientOcclusion"
unity-mcp graphics feature-configure --name "SSAO" -p Intensity 1.5
unity-mcp graphics feature-toggle --name "SSAO" --active|--inactive
# Skybox & Environment
unity-mcp graphics skybox-info
unity-mcp graphics skybox-set-material --material "Assets/Materials/Sky.mat"
unity-mcp graphics skybox-set-ambient --mode Flat --color "0.2,0.2,0.3"
unity-mcp graphics skybox-set-fog --enable --mode ExponentialSquared --density 0.02
unity-mcp graphics skybox-set-reflection --intensity 1.0 --bounces 2
unity-mcp graphics skybox-set-sun --target "DirectionalLight"
```
### Package Operations
```bash
unity-mcp packages ping # Check package manager
unity-mcp packages list # List installed packages
unity-mcp packages search "cinemachine" # Search registry
unity-mcp packages info "com.unity.cinemachine" # Package details
unity-mcp packages add "com.unity.cinemachine" # Install package
unity-mcp packages add "com.unity.cinemachine@4.1.1" # Specific version
unity-mcp packages remove "com.unity.cinemachine" [--force]
unity-mcp packages embed "com.unity.cinemachine" # Embed for local editing
unity-mcp packages resolve # Force re-resolution
unity-mcp packages status <job_id> # Check async op
unity-mcp packages list-registries
unity-mcp packages add-registry "Name" --url URL -s "com.example"
unity-mcp packages remove-registry "Name"
```
### Texture Operations
```bash
unity-mcp texture create "Assets/Textures/Red.png" --color "1,0,0,1"
unity-mcp texture create "Assets/Textures/Check.png" --pattern checkerboard --width 256 --height 256
unity-mcp texture create "Assets/Textures/Img.png" --image-path "/path/to/source.png"
unity-mcp texture sprite "Assets/Sprites/Player.png" --width 32 --height 32 --ppu 16
unity-mcp texture modify "Assets/Textures/Img.png" --set-pixels '{"x":0,"y":0,"width":16,"height":16,"color":[1,0,0,1]}'
unity-mcp texture delete "Assets/Textures/Old.png" [--force]
# Patterns: checkerboard, stripes, stripes_h, stripes_v, stripes_diag, dots, grid, brick
```
### Raw Commands
For any MCP tool not covered by dedicated commands:
```bash
unity-mcp raw manage_scene '{"action": "get_hierarchy", "max_nodes": 100}'
unity-mcp raw read_console '{"count": 20}'
unity-mcp raw manage_camera '{"action": "screenshot", "include_image": true}'
unity-mcp raw manage_graphics '{"action": "volume_get_info", "target": "PostProcessing"}'
unity-mcp raw manage_packages '{"action": "list_packages"}'
```
---
## Complete Command Reference
| Group | Subcommands |
|-------|-------------|
| `instance` | `list`, `set`, `current` |
| `scene` | `hierarchy`, `active`, `load`, `save`, `create`, `build-settings` |
| `code` | `read`, `search` |
| `gameobject` | `find`, `create`, `modify`, `delete`, `duplicate`, `move` |
| `component` | `add`, `remove`, `set`, `modify` |
| `script` | `create`, `read`, `delete`, `edit`, `validate` |
| `shader` | `create`, `read`, `update`, `delete` |
| `editor` | `play`, `pause`, `stop`, `refresh`, `console`, `menu`, `tool`, `add-tag`, `remove-tag`, `add-layer`, `remove-layer`, `tests`, `poll-test`, `custom-tool` |
| `asset` | `search`, `info`, `create`, `delete`, `duplicate`, `move`, `rename`, `import`, `mkdir` |
| `prefab` | `open`, `close`, `save`, `create`, `modify` |
| `material` | `info`, `create`, `set-color`, `set-property`, `assign`, `set-renderer-color` |
| `camera` | `ping`, `list`, `create`, `set-target`, `set-lens`, `set-priority`, `set-body`, `set-aim`, `set-noise`, `add-extension`, `remove-extension`, `ensure-brain`, `brain-status`, `set-blend`, `force`, `release`, `screenshot`, `screenshot-multiview` |
| `graphics` | `ping`, `volume-create`, `volume-add-effect`, `volume-set-effect`, `volume-remove-effect`, `volume-info`, `volume-set-properties`, `volume-list-effects`, `volume-create-profile`, `pipeline-info`, `pipeline-settings`, `pipeline-set-quality`, `pipeline-set-settings`, `bake-start`, `bake-cancel`, `bake-status`, `bake-clear`, `bake-settings`, `bake-set-settings`, `bake-reflection-probe`, `bake-create-probes`, `bake-create-reflection`, `stats`, `stats-memory`, `stats-debug-mode`, `feature-list`, `feature-add`, `feature-remove`, `feature-configure`, `feature-reorder`, `feature-toggle`, `skybox-info`, `skybox-set-material`, `skybox-set-properties`, `skybox-set-ambient`, `skybox-set-fog`, `skybox-set-reflection`, `skybox-set-sun` |
| `packages` | `ping`, `list`, `search`, `info`, `add`, `remove`, `embed`, `resolve`, `status`, `list-registries`, `add-registry`, `remove-registry` |
| `texture` | `create`, `sprite`, `modify`, `delete` |
| `vfx particle` | `info`, `play`, `stop`, `pause`, `restart`, `clear` |
| `vfx line` | `info`, `set-positions`, `create-line`, `create-circle`, `clear` |
| `vfx trail` | `info`, `set-time`, `clear` |
| `vfx` | `raw` (access all 60+ actions) |
| `probuilder` | `create-shape`, `create-poly`, `info`, `raw` (access all 35+ actions) |
| `batch` | `run`, `inline`, `template` |
| `animation` | `play`, `set-parameter` |
| `audio` | `play`, `stop`, `volume` |
| `lighting` | `create` |
| `tool` | `list` |
| `custom_tool` | `list` |
| `ui` | `create-canvas`, `create-text`, `create-button`, `create-image` |
---
## Output Formats
```bash
# Text (default) - human readable
unity-mcp scene hierarchy
# JSON - for scripting
unity-mcp --format json scene hierarchy
# Table - structured display
unity-mcp --format table instance list
```
## Environment Variables
Set defaults via environment:
```bash
export UNITY_MCP_HOST=192.168.1.100
export UNITY_MCP_HTTP_PORT=8080
export UNITY_MCP_FORMAT=json
export UNITY_MCP_INSTANCE=MyProject@abc123
```
## Troubleshooting
### Connection Issues
```bash
# Check server status
unity-mcp status
# Verify Unity is running with MCP plugin
# Check Unity console for MCP connection messages
```
### Common Errors
| Error | Solution |
|-------|----------|
| Cannot connect to server | Ensure Unity MCP server is running |
| Unknown command type | Unity plugin may not support this tool |
| Timeout | Increase timeout with `-t 60` |
+300
View File
@@ -0,0 +1,300 @@
# MCP Client Configurators
This guide explains how MCP client configurators work in this repo and how to add a new one.
It covers:
- **Typical JSON-file clients** (Cursor, VSCode GitHub Copilot, VSCode Insiders, GitHub Copilot CLI, Windsurf, Kiro, Trae, Antigravity 2.0, Antigravity IDE, etc.).
- **Special clients** like **Claude CLI**, **Codex**, and **OpenClaw** that require custom logic.
- **How to add a new configurator class** so it shows up automatically in the MCP for Unity window.
## Quick example: JSON-file configurator
For most clients you just need a small class like this:
```csharp
using System;
using System.Collections.Generic;
using System.IO;
using MCPForUnity.Editor.Models;
namespace MCPForUnity.Editor.Clients.Configurators
{
public class MyClientConfigurator : JsonFileMcpConfigurator
{
public MyClientConfigurator() : base(new McpClient
{
name = "My Client",
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".myclient", "mcp.json"),
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".myclient", "mcp.json"),
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".myclient", "mcp.json"),
})
{ }
public override IList<string> GetInstallationSteps() => new List<string>
{
"Open My Client and go to MCP settings",
"Open or create the mcp.json file at the path above",
"Click Configure in MCP for Unity (or paste the manual JSON snippet)",
"Restart My Client"
};
}
}
```
---
## How the configurator system works
At a high level:
- **`IMcpClientConfigurator`** (`MCPForUnity/Editor/Clients/IMcpClientConfigurator.cs`)
- Contract for all MCP client configurators.
- Handles status detection, auto-configure, manual snippet, and installation steps.
- **Base classes** (`MCPForUnity/Editor/Clients/McpClientConfiguratorBase.cs`)
- **`McpClientConfiguratorBase`**
- Common properties and helpers.
- **`JsonFileMcpConfigurator`**
- For JSON-based config files (most clients).
- Implements `CheckStatus`, `Configure`, and `GetManualSnippet` using `ConfigJsonBuilder`.
- **`CodexMcpConfigurator`**
- For Codex-style TOML config files.
- **`ClaudeCliMcpConfigurator`**
- For CLI-driven clients like Claude Code (register/unregister via CLI, not JSON files).
- **`McpClient` model** (`MCPForUnity/Editor/Models/McpClient.cs`)
- Holds the per-client configuration:
- `name`
- `windowsConfigPath`, `macConfigPath`, `linuxConfigPath`
- Status and several **JSON-config flags** (used by `JsonFileMcpConfigurator`):
- `IsVsCodeLayout` VS Code-style layout (`servers` root, `type` field, etc.).
- `SupportsHttpTransport` whether the client supports HTTP transport.
- `EnsureEnvObject` ensure an `env` object exists.
- `StripEnvWhenNotRequired` remove `env` when not needed.
- `HttpUrlProperty` which property holds the HTTP URL (e.g. `"url"` vs `"serverUrl"`).
- `DefaultUnityFields` key/value pairs like `{ "disabled": false }` applied when missing.
- **Auto-discovery** (`McpClientRegistry`)
- `McpClientRegistry.All` uses `TypeCache.GetTypesDerivedFrom<IMcpClientConfigurator>()` to find configurators.
- A configurator appears automatically if:
- It is a **public, non-abstract class**.
- It has a **public parameterless constructor**.
- No extra registration list is required.
---
## Typical JSON-file clients
Most MCP clients use a JSON config file that defines one or more MCP servers. Examples:
- **Cursor** `JsonFileMcpConfigurator` (global `~/.cursor/mcp.json`).
- **VSCode GitHub Copilot** `JsonFileMcpConfigurator` with `IsVsCodeLayout = true`.
- **VSCode Insiders GitHub Copilot** `JsonFileMcpConfigurator` with `IsVsCodeLayout = true` and Insider-specific `Code - Insiders/User/mcp.json` paths.
- **GitHub Copilot CLI** `JsonFileMcpConfigurator` with standard HTTP transport.
- **Windsurf** `JsonFileMcpConfigurator` with Windsurf-specific flags (`HttpUrlProperty = "serverUrl"`, `DefaultUnityFields["disabled"] = false`, etc.).
- **Kiro**, **Trae**, **Antigravity 2.0** (`~/.gemini/config/mcp_config.json` after the 2.x migration), **Antigravity IDE** (separate `~/.gemini/antigravity-ide/mcp_config.json` — the IDE build did not migrate) JSON configs with project-specific paths and flags.
All of these follow the same pattern:
1. **Subclass `JsonFileMcpConfigurator`.**
2. **Provide a `McpClient` instance** in the constructor with:
- A user-friendly `name`.
- OS-specific config paths.
- Any JSON behavior flags as needed.
3. **Override `GetInstallationSteps`** to describe how users open or edit the config.
4. Rely on **base implementations** for:
- `CheckStatus` reads and validates the JSON config; can auto-rewrite to match Unity MCP.
- `Configure` writes/rewrites the config file.
- `GetManualSnippet` builds a JSON snippet using `ConfigJsonBuilder`.
### JSON behavior controlled by `McpClient`
`JsonFileMcpConfigurator` relies on the fields on `McpClient`:
- **HTTP vs stdio**
- `SupportsHttpTransport` + `EditorPrefs.UseHttpTransport` decide whether to configure
- `url` / `serverUrl` (HTTP), or
- `command` + `args` (stdio with `uvx`).
- **URL property name**
- `HttpUrlProperty` (default `"url"`) selects which JSON property to use for HTTP urls.
- Example: Windsurf and the two Antigravity clients use `"serverUrl"`.
- **VS Code layout**
- `IsVsCodeLayout = true` switches config structure to a VS Code compatible layout.
- **Env object and default fields**
- `EnsureEnvObject` / `StripEnvWhenNotRequired` control an `env` block.
- `DefaultUnityFields` adds client-specific fields if they are missing (e.g. `disabled: false`).
All of this logic is centralized in **`ConfigJsonBuilder`**, so most JSON-based clients **do not need to override** `GetManualSnippet`.
---
## Special clients
Some clients cannot be handled by the generic JSON configurator alone.
### Codex (TOML-based)
- Uses **`CodexMcpConfigurator`**.
- Reads and writes a **TOML** config (usually `~/.codex/config.toml`).
- Uses `CodexConfigHelper` to:
- Parse the existing TOML.
- Check for a matching Unity MCP server configuration.
- Write/patch the Codex server block.
- The `CodexConfigurator` class:
- Only needs to supply a `McpClient` with TOML config paths.
- Inherits the Codex-specific status and configure behavior from `CodexMcpConfigurator`.
### Claude Code (CLI-based)
- Uses **`ClaudeCliMcpConfigurator`**.
- Configuration is stored **internally by the Claude CLI**, not in a JSON file.
- `CheckStatus` and `Configure` are implemented in the base class using `claude mcp ...` commands:
- `CheckStatus` calls `claude mcp list` to detect if `UnityMCP` is registered.
- `Configure` toggles register/unregister via `claude mcp add/remove UnityMCP`.
- The `ClaudeCodeConfigurator` class:
- Only needs a `McpClient` with a `name`.
- Overrides `GetInstallationSteps` with CLI-specific instructions.
### Claude Desktop (JSON with restrictions)
- Uses **`JsonFileMcpConfigurator`**, but only supports **stdio transport**.
- `ClaudeDesktopConfigurator`:
- Sets `SupportsHttpTransport = false` in `McpClient`.
- Declares `SupportedTransports => StdioOnly`. `ClientConfigurationService` reads `SupportedTransports` and, via `ConfigureWithTransportCoercion` / `CoerceTransportFor`, temporarily coerces the transport pref to stdio before calling `Configure()` — so users with HTTP toggled globally still get a working stdio entry written without a thrown error. The coercion applies to any configurator whose `SupportedTransports` excludes the user's current transport; Claude Desktop is just the only one declaring stdio-only today.
### OpenClaw (plugin-based)
- Uses a custom configurator (`OpenClawConfigurator`) because OpenClaw MCP is plugin-driven.
- Config file path is `~/.openclaw/openclaw.json`.
- Unity MCP is configured through `plugins.entries.openclaw-mcp-bridge.config.servers.unityMCP`.
- When Unity MCP is set to HTTP, the bridge expects the MCP JSON-RPC endpoint URL (`http://127.0.0.1:<port>/mcp`), not just the HTTP base URL.
- When Unity MCP is set to stdio, the configurator writes a `uvx ... mcp-for-unity --transport stdio` subprocess entry.
- The bridge exposes a single proxy tool such as `unityMCP__call`, which then forwards to Unity MCP tool names.
- OpenClaw support follows the currently selected MCP for Unity transport (via `openclaw-mcp-bridge`).
---
## Adding a new MCP client (typical JSON case)
This is the most common scenario: your MCP client uses a JSON file to configure servers.
### 1. Choose the base class
- Use **`JsonFileMcpConfigurator`** if your client reads a JSON config file.
- Consider **`CodexMcpConfigurator`** only if you are integrating a TOML-based client like Codex.
- Consider **`ClaudeCliMcpConfigurator`** only if your client exposes a CLI command to manage MCP servers.
### 2. Create the configurator class
Create a new file under:
```text
MCPForUnity/Editor/Clients/Configurators
```
Name it something like:
```text
MyClientConfigurator.cs
```
Inside, follow the existing pattern (e.g. `CursorConfigurator`, `WindsurfConfigurator`, `KiroConfigurator`):
- **Namespace** must be:
- `MCPForUnity.Editor.Clients.Configurators`
- **Class**:
- `public class MyClientConfigurator : JsonFileMcpConfigurator`
- **Constructor**:
- Public, **parameterless**, and call `base(new McpClient { ... })`.
- Set at least:
- `name = "My Client"`
- `windowsConfigPath = ...`
- `macConfigPath = ...`
- `linuxConfigPath = ...`
- Optionally set flags:
- `IsVsCodeLayout = true` for VS Code-style config.
- `HttpUrlProperty = "serverUrl"` if your client expects `serverUrl`.
- `EnsureEnvObject` / `StripEnvWhenNotRequired` based on env handling.
- `DefaultUnityFields = { { "disabled", false }, ... }` for client-specific defaults.
Because the constructor is parameterless and public, **`McpClientRegistry` will auto-discover this configurator** with no extra registration.
### 3. Add installation steps
Override `GetInstallationSteps` to tell users how to configure the client:
- Where to find or create the JSON config file.
- Which menu path opens the MCP settings.
- Whether they should rely on the **Configure** button or copy-paste the manual JSON.
Look at `CursorConfigurator`, `VSCodeConfigurator`, `VSCodeInsidersConfigurator`, `KiroConfigurator`, `TraeConfigurator`, `AntigravityConfigurator`, or `AntigravityIdeConfigurator` for phrasing.
### 4. Rely on the base JSON logic
Unless your client has very unusual behavior, you typically **do not need to override**:
- `CheckStatus`
- `Configure`
- `GetManualSnippet`
The base `JsonFileMcpConfigurator`:
- Detects missing or mismatched config.
- Optionally rewrites config to match Unity MCP.
- Builds a JSON snippet with **correct HTTP vs stdio settings**, using `ConfigJsonBuilder`.
Only override these methods if your client has constraints that cannot be expressed via `McpClient` flags.
### 5. Verify in Unity
After adding your configurator class:
1. Open Unity and the **MCP for Unity** window.
2. Your client should appear in the list, sorted by display name (`McpClient.name`).
3. Use **Check Status** to verify:
- Missing config files show as `Not Configured`.
- Existing files with matching server settings show as `Configured`.
4. Click **Configure** to auto-write the config file.
5. Restart your MCP client and confirm it connects to Unity.
---
## Adding a custom (non-JSON) client
If your MCP client doesnt store configuration as a JSON file, you likely need a custom base class.
### Codex-style TOML client
- Subclass **`CodexMcpConfigurator`**.
- Provide TOML paths via `McpClient` (similar to `CodexConfigurator`).
- Override `GetInstallationSteps` to describe how to open/edit the TOML.
The Codex-specific status and configure logic is already implemented in the base class.
### CLI-managed client (Claude-style)
- Subclass **`ClaudeCliMcpConfigurator`**.
- Provide a `McpClient` with a `name`.
- Override `GetInstallationSteps` with the CLI flow.
The base class:
- Locates the CLI binary using `MCPServiceLocator.Paths`.
- Uses `ExecPath.TryRun` to call `mcp list`, `mcp add`, and `mcp remove`.
- Implements `Configure` as a toggle between register and unregister.
Use this only if the client exposes an official CLI for managing MCP servers.
---
## Summary
- **For most MCP clients**, you only need to:
- Create a `JsonFileMcpConfigurator` subclass in `Editor/Clients/Configurators`.
- Provide a `McpClient` with paths and flags.
- Override `GetInstallationSteps`.
- **Special cases** like Codex (TOML) and Claude Code (CLI) have dedicated base classes.
- **No manual registration** is needed: `McpClientRegistry` auto-discovers all configurators with a public parameterless constructor.
Following these patterns keeps all MCP client integrations consistent and lets users configure everything from the MCP for Unity window with minimal friction.
+310
View File
@@ -0,0 +1,310 @@
# Adding Custom Tools to MCP for Unity
MCP for Unity makes it easy to extend your AI assistant with custom capabilities. Using C# attributes and reflection, the system automatically discovers and registers your tools—no manual configuration needed.
This guide will walk you through creating your own tools, from simple synchronous operations to complex long-running tasks that survive Unity's domain reloads.
---
# Quick Start Guide
Let's get you up and running with your first custom tool.
## Step 1: Create Your Tool Handler
First, create a C# file in any `Editor/` folder within your Unity project. **The Editor folder is crucial**—we scan Editor assemblies for tools, so placing your code elsewhere means it won't be discovered.
Each tool is a static class with two key ingredients:
1. The `[McpForUnityTool]` attribute that tells the system "Hey, I'm a tool!"
2. A `HandleCommand(JObject)` method that does the actual work
You can also define a nested `Parameters` class with `[ToolParameter]` attributes. This gives your AI assistant helpful descriptions and lets it know which parameters are required.
```csharp
using Newtonsoft.Json.Linq;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Tools;
namespace MyProject.Editor.CustomTools
{
[McpForUnityTool("my_custom_tool")]
public static class MyCustomTool
{
public class Parameters
{
[ToolParameter("Value to process")]
public string param1 { get; set; }
[ToolParameter("Optional integer payload", Required = false)]
public int? param2 { get; set; }
}
public static object HandleCommand(JObject @params)
{
var parameters = @params.ToObject<Parameters>();
if (string.IsNullOrEmpty(parameters.param1))
{
return new ErrorResponse("param1 is required");
}
DoSomethingAmazing(parameters.param1, parameters.param2);
return new SuccessResponse("Custom tool executed successfully!", new
{
parameters.param1,
parameters.param2
});
}
private static void DoSomethingAmazing(string param1, int? param2)
{
// Your implementation
}
}
}
```
## Step 2: Refresh Your MCP Client
Once you've created your tool, you'll need to let your AI assistant know about it. While the MCP server can dynamically register new tools, not all clients pick up these changes automatically.
**The easiest approach:** Disconnect and reconnect to the MCP server in your client. This forces a fresh tool discovery.
**If that doesn't work:** Some clients (like Windsurf) may need you to remove and reconfigure the MCP for Unity server entirely. It's a bit more work, but it guarantees your new tools will appear.
## Step 3: List and Call Your Tool from the CLI
If you want to use the CLI directly, list custom tools for the active Unity project:
```bash
unity-mcp tool list
unity-mcp custom_tool list
```
Then call your tool by name:
```bash
unity-mcp editor custom-tool "my_custom_tool"
unity-mcp editor custom-tool "my_custom_tool" --params '{"param1":"value"}'
```
## Complete Example: Screenshot Tool
### C# Handler (`Assets/Editor/ScreenShots/CaptureScreenshotTool.cs`)
```csharp
using System.IO;
using Newtonsoft.Json.Linq;
using UnityEngine;
using MCPForUnity.Editor.Tools;
using MCPForUnity.Editor.Helpers;
namespace MyProject.Editor.CustomTools
{
[McpForUnityTool(
name: "capture_screenshot",
Description = "Capture screenshots in Unity, saving them as PNGs"
)]
public static class CaptureScreenshotTool
{
// Define parameters as a nested class for clarity
public class Parameters
{
[ToolParameter("Screenshot filename without extension, e.g., screenshot_01")]
public string filename { get; set; }
[ToolParameter("Width of the screenshot in pixels", Required = false)]
public int? width { get; set; }
[ToolParameter("Height of the screenshot in pixels", Required = false)]
public int? height { get; set; }
}
public static object HandleCommand(JObject @params)
{
// Parse parameters
var parameters = @params.ToObject<Parameters>();
if (string.IsNullOrEmpty(parameters.filename))
{
return new ErrorResponse("filename is required");
}
try
{
int width = parameters.width ?? Screen.width;
int height = parameters.height ?? Screen.height;
string absolutePath = Path.Combine(Application.dataPath, "Screenshots",
parameters.filename + ".png");
Directory.CreateDirectory(Path.GetDirectoryName(absolutePath));
// Find camera
Camera camera = Camera.main ?? Object.FindFirstObjectByType<Camera>();
if (camera == null)
{
return new ErrorResponse("No camera found in the scene");
}
// Capture screenshot
RenderTexture rt = new RenderTexture(width, height, 24);
camera.targetTexture = rt;
camera.Render();
RenderTexture.active = rt;
Texture2D screenshot = new Texture2D(width, height, TextureFormat.RGB24, false);
screenshot.ReadPixels(new Rect(0, 0, width, height), 0, 0);
screenshot.Apply();
// Cleanup
camera.targetTexture = null;
RenderTexture.active = null;
Object.DestroyImmediate(rt);
// Save
byte[] bytes = screenshot.EncodeToPNG();
File.WriteAllBytes(absolutePath, bytes);
Object.DestroyImmediate(screenshot);
return new SuccessResponse($"Screenshot saved to {absolutePath}", new
{
path = absolutePath,
width = width,
height = height
});
}
catch (System.Exception ex)
{
return new ErrorResponse($"Failed to capture screenshot: {ex.Message}");
}
}
}
}
```
## Long-Running (Polled) Tools
Some operations—like running tests, baking lightmaps, or building players—take time and might even trigger Unity domain reloads. For these cases, you'll want a **polled tool**.
Here's how it works: Your tool starts the work and returns a "pending" signal. Behind the scenes, the Python middleware automatically polls Unity for updates until the job completes (or times out after 10 minutes).
### Setting Up Polling
Mark your tool with `RequiresPolling = true` and specify a `PollAction` (typically `"status"`):
```csharp
[McpForUnityTool(RequiresPolling = true, PollAction = "status")]
```
### The Three Key Ingredients
1. **Start the work:** Return `new PendingResponse("message", pollIntervalSeconds)` to acknowledge the job has started. The poll interval tells the server how long to wait between checks.
2. **Implement the poll action:** Create a method (like `Status`) that checks progress and returns `_mcp_status` of `pending`, `complete`, or `error`. **Important:** The middleware calls your `PollAction` string exactly as written—no automatic case conversion—so make sure your `HandleCommand` recognizes it.
3. **Persist your state:** Use `McpJobStateStore` to save progress to the `Library/` folder. This ensures your tool remembers what it was doing even after a domain reload wipes memory.
### Complete Example
```csharp
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Tools;
[McpForUnityTool(
"bake_lightmaps",
Description = "Simulated async lightmap bake with polling",
RequiresPolling = true,
PollAction = "status"
)]
public static class BakeLightmaps
{
private const string ToolName = "bake_lightmaps";
private const float SimulatedDurationSeconds = 5f;
private static bool s_isRunning;
private static double s_lastUpdateTime;
private class State
{
public string lastStatus { get; set; }
public float progress { get; set; }
}
public static object HandleCommand(JObject @params)
{
if (s_isRunning)
{
var existing = McpJobStateStore.LoadState<State>(ToolName) ?? new State { lastStatus = "in_progress", progress = 0f };
return new PendingResponse("Bake already running", 0.5, existing);
}
var state = new State { lastStatus = "in_progress", progress = 0f };
McpJobStateStore.SaveState(ToolName, state);
s_isRunning = true;
s_lastUpdateTime = EditorApplication.timeSinceStartup;
EditorApplication.update += UpdateBake;
return new PendingResponse("Starting lightmap bake", 0.5, new { state.lastStatus, state.progress });
}
public static object Status(JObject _)
{
var state = McpJobStateStore.LoadState<State>(ToolName) ?? new State { lastStatus = "unknown", progress = 0f };
if (state.lastStatus == "completed")
{
return new { _mcp_status = "complete", message = "Bake finished", data = state };
}
if (state.lastStatus == "error")
{
return new { _mcp_status = "error", error = "Bake failed", data = state };
}
return new PendingResponse($"Baking... {state.progress:P0}", 0.5, state);
}
private static void UpdateBake()
{
if (!s_isRunning)
{
EditorApplication.update -= UpdateBake;
return;
}
var now = EditorApplication.timeSinceStartup;
var delta = now - s_lastUpdateTime;
s_lastUpdateTime = now;
var state = McpJobStateStore.LoadState<State>(ToolName) ?? new State { lastStatus = "in_progress", progress = 0f };
state.progress = Mathf.Clamp01(state.progress + (float)(delta / SimulatedDurationSeconds));
if (state.progress >= 1f)
{
state.lastStatus = "completed";
s_isRunning = false;
EditorApplication.update -= UpdateBake;
}
else
{
state.lastStatus = "in_progress";
}
McpJobStateStore.SaveState(ToolName, state);
}
}
```
### How the Polling Protocol Works
- **`_mcp_status: "pending"`** tells the middleware to keep checking back.
- **`_mcp_poll_interval`** (in seconds) controls how long to wait between polls. The server clamps this between 0.1 and 5 seconds to balance responsiveness with performance.
- **Null or empty responses** are treated as "still working" and trigger another poll.
- **Timeout protection:** After 10 minutes, the server gives up and returns a timeout error along with the last response it received.
- **Action routing:** The initial call uses whatever action your tool expects (often implicit). Subsequent polls use your exact `PollAction` string—no automatic snake_case or camelCase conversion—so make sure your `HandleCommand` switch statement handles it correctly.
+82
View File
@@ -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
+261
View File
@@ -0,0 +1,261 @@
# Remote Server API Key Authentication
When running the MCP for Unity server as a shared remote service, API key authentication ensures that only authorized users can access the server and that each user's Unity sessions are isolated from one another.
This guide covers how to configure, deploy, and use the feature.
## Prerequisites
### External Auth Service
You need an external HTTP endpoint that validates API keys. The server delegates all key validation to this endpoint rather than managing keys itself.
The endpoint must:
- Accept `POST` requests with a JSON body: `{"api_key": "<key>"}`
- Return a JSON response indicating validity and the associated user identity
- Be reachable from the MCP server over the network
See [Validation Contract](#validation-contract) for the full request/response specification.
### Transport Mode
API key authentication is only available when running with HTTP transport (`--transport http`). It has no effect in stdio mode.
## Server Configuration
### CLI Arguments
| Argument | Environment Variable | Default | Description |
| -------- | -------------------- | ------- | ----------- |
| `--http-remote-hosted` | `UNITY_MCP_HTTP_REMOTE_HOSTED` | `false` | Enable remote-hosted mode. Requires API key auth. |
| `--api-key-validation-url URL` | `UNITY_MCP_API_KEY_VALIDATION_URL` | None | External endpoint to validate API keys (required). |
| `--api-key-login-url URL` | `UNITY_MCP_API_KEY_LOGIN_URL` | None | URL where users can obtain or manage API keys. |
| `--api-key-cache-ttl SECONDS` | `UNITY_MCP_API_KEY_CACHE_TTL` | `300` | How long validated keys are cached (seconds). |
| `--api-key-service-token-header HEADER` | `UNITY_MCP_API_KEY_SERVICE_TOKEN_HEADER` | None | Header name for server-to-auth-service authentication. |
| `--api-key-service-token TOKEN` | `UNITY_MCP_API_KEY_SERVICE_TOKEN` | None | Token value sent to the auth service for server authentication. |
Environment variables take effect when the corresponding CLI argument is not provided. For boolean flags, set the env var to `true`, `1`, or `yes`.
### Startup Validation
The server validates its configuration at startup:
- If `--http-remote-hosted` is set but `--api-key-validation-url` is not provided (and the env var is also unset), the server logs an error and exits with code 1.
### Example
```bash
python -m src.main \
--transport http \
--http-host 0.0.0.0 \
--http-port 8080 \
--http-remote-hosted \
--api-key-validation-url https://auth.example.com/api/validate-key \
--api-key-login-url https://app.example.com/api-keys \
--api-key-cache-ttl 120
```
Or using environment variables:
```bash
export UNITY_MCP_TRANSPORT=http
export UNITY_MCP_HTTP_HOST=0.0.0.0
export UNITY_MCP_HTTP_PORT=8080
export UNITY_MCP_HTTP_REMOTE_HOSTED=true
export UNITY_MCP_API_KEY_VALIDATION_URL=https://auth.example.com/api/validate-key
export UNITY_MCP_API_KEY_LOGIN_URL=https://app.example.com/api-keys
python -m src.main
```
### Service Token (Optional)
If your auth service requires the MCP server to authenticate itself (server-to-server auth), configure a service token:
```bash
--api-key-service-token-header X-Service-Token \
--api-key-service-token "your-server-secret"
```
This adds the specified header to every validation request sent to the auth endpoint.
We strongly recommend using this feature because it ensures that the entity requesting validation is the MCP server itself, not an imposter.
## Unity Plugin Setup
When connecting to a remote-hosted server, Unity users need to provide their API key:
1. Open the MCP for Unity window in the Unity Editor.
2. Select HTTP Remote as the connection mode.
3. Enter the API key in the API Key field. The key is stored in `EditorPrefs` (per-machine, not source-controlled).
4. Click **Get API Key** to open the login URL in a browser if you need a new key. This fetches the URL from the server's `/api/auth/login-url` endpoint.
The API key is a one-time entry per machine. It persists across Unity sessions until explicitly cleared.
## MCP Client Configuration
When an API key is configured, the Unity plugin's MCP client configurators automatically include the `X-API-Key` header in generated configuration files.
Example generated config for **Cursor** (`~/.cursor/mcp.json`):
```json
{
"mcpServers": {
"mcp-for-unity": {
"url": "http://remote-server:8080/mcp",
"headers": {
"X-API-Key": "<your-api-key>"
}
}
}
}
```
Example for **Claude Code** (CLI):
```bash
claude mcp add --transport http mcp-for-unity http://remote-server:8080/mcp \
--header "X-API-Key: <your-api-key>"
```
Similar header injection works for VS Code, Windsurf, Cline, and other supported MCP clients.
## Behaviour Changes in Remote-Hosted Mode
Enabling `--http-remote-hosted` changes several server behaviours compared to the default local mode:
### Authentication Enforcement
All MCP tool and resource calls require a valid API key. The `X-API-Key` header must be present on every HTTP request to the `/mcp` endpoint. If the key is missing or invalid, the middleware raises a `RuntimeError` that surfaces as an MCP error response.
### WebSocket Auth Gate
Unity plugins connecting via WebSocket (`/hub/plugin`) are validated during the handshake:
| Scenario | WebSocket Close Code | Reason |
| -------- | -------------------- | ------ |
| No API key header | `4401` | API key required |
| Invalid API key | `4403` | Invalid API key |
| Auth service unavailable | `1013` | Try again later |
| Valid API key | Connection accepted | user_id stored in connection state |
### Session Isolation
Each user can only see and interact with their own Unity instances. When User A calls `set_active_instance` or lists instances, they only see Unity editors that connected with User A's API key. User B's sessions are invisible to User A.
### Auto-Select Disabled
In local mode, the server automatically selects the sole connected Unity instance. In remote-hosted mode, this auto-selection is disabled. Users must explicitly call `set_active_instance` with a `Name@hash` from the `mcpforunity://instances` resource.
### CLI Routes Disabled
The following REST endpoints are disabled in remote-hosted mode to prevent unauthenticated access:
- `POST /api/command`
- `GET /api/instances`
- `GET /api/custom-tools`
### Endpoints Always Available
These endpoints remain accessible regardless of auth:
| Endpoint | Method | Purpose |
| -------- | ------ | ------- |
| `/health` | GET | Health check for load balancers and monitoring |
| `/api/auth/login-url` | GET | Returns the login URL for API key management |
## Validation Contract
### Request
```http
POST <api-key-validation-url>
Content-Type: application/json
{
"api_key": "<the-api-key>"
}
```
If a service token is configured, an additional header is sent:
```http
<service-token-header>: <service-token-value>
```
### Response (Valid Key)
```json
{
"valid": true,
"user_id": "user-abc-123",
"metadata": {}
}
```
- `valid` (bool, required): Must be `true`.
- `user_id` (string, required): Stable identifier for the user. Used for session isolation.
- `metadata` (object, optional): Arbitrary metadata stored alongside the validation result.
### Response (Invalid Key)
```json
{
"valid": false,
"error": "API key expired"
}
```
- `valid` (bool, required): Must be `false`.
- `error` (string, optional): Human-readable reason.
### Response (HTTP 401)
A `401` status code is also treated as an invalid key (no body parsing required).
### Timeouts and Retries
- Request timeout: 5 seconds
- Retries: 1 (with 100ms backoff)
- Failure mode: deny by default (treated as invalid on any error)
Transient failures (5xx, timeouts, network errors) are **not cached**, so subsequent requests will retry the auth service.
## Error Reference
| Context | Condition | Response |
| ------- | --------- | -------- |
| MCP tool/resource | Missing API key (remote-hosted) | `RuntimeError` → MCP `isError: true` |
| MCP tool/resource | Invalid API key | `RuntimeError` → MCP `isError: true` |
| WebSocket connect | Missing API key | Close `4401` "API key required" |
| WebSocket connect | Invalid API key | Close `4403` "Invalid API key" |
| WebSocket connect | Auth service down | Close `1013` "Try again later" |
| `/api/auth/login-url` | Login URL not configured | HTTP `404` with admin guidance message |
| Server startup | Remote-hosted without validation URL | `SystemExit(1)` |
## Troubleshooting
### "API key authentication required" error on every tool call
The server is in remote-hosted mode but no API key is being sent. Ensure the MCP client configuration includes the `X-API-Key` header, or set it in the Unity plugin's connection settings.
### Server exits immediately with code 1
The `--http-remote-hosted` flag requires `--api-key-validation-url`. Provide the URL via CLI argument or `UNITY_MCP_API_KEY_VALIDATION_URL` environment variable.
### WebSocket connection closes with 4401
The Unity plugin is not sending an API key. Enter the key in the MCP for Unity window's connection settings.
### WebSocket connection closes with 1013
The external auth service is unreachable. Check network connectivity between the MCP server and the validation URL. The Unity plugin can retry the connection.
### User cannot see their Unity instance
Session isolation is active. The Unity editor and the MCP client must use API keys that resolve to the same `user_id`. Verify that the Unity plugin's WebSocket connection and the MCP client's HTTP requests use the same API key.
### Stale auth after key rotation
Validated keys are cached for `--api-key-cache-ttl` seconds (default: 300). After rotating or revoking a key, there is a delay equal to the TTL before the old key stops working. Lower the TTL for faster revocation at the cost of more frequent validation requests.
+54
View File
@@ -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.
+80
View File
@@ -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 47 tools. Activate vfx, animation, ui, testing, etc. only when you need them.
---
# Tool Groups
MCP for Unity ships 47 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 47 tools versus the 30 core tools, 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
+183
View File
@@ -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/<ver>/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://<YOUR_WSL_HOST_IP>: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/<ver>/bin/claude`).
**Q: I installed via NVM; where is `claude`?**
A: Typically `~/.nvm/versions/node/<ver>/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.
+110
View File
@@ -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 <UnityMcpServer/src>
uv sync
uv run server.py
```
+265
View File
@@ -0,0 +1,265 @@
---
title: v10 - Asset Generation and Docs Refresh
author: MCP for Unity Maintainers
date: 2026-06-30
---
# MCP for Unity v10 Release Notes
These notes cover v10: the full major-version change from
v9.0.0, the new AI asset generation/import surface, secure provider-key storage,
Blender/local-file handoff, and the README/docs/brand refresh.
For this comparison, **v9 means `v9.0.0`**, not the last v9 patch. The `v9.7.3`
tag is still useful for the release-to-release changelog, but it already
contains much of the v9 tool expansion.
## What changed since v9.0.0
At `v9.0.0`, MCP for Unity exposed 29 MCP tool entrypoints around the core Unity
Editor loop: scenes, GameObjects, components, scripts, prefabs, assets,
materials, shaders, VFX, console reads, editor refresh, async tests, custom
tools, and batch execution.
The v10 release exposes 47 MCP tool entrypoints across 10 groups:
`core`, `animation`, `asset_gen`, `docs`, `probuilder`, `profiling`,
`scripting_ext`, `testing`, `ui`, and `vfx`.
| Area | `v9.0.0` baseline | v10 release |
| --- | --- | --- |
| Tool catalog | 29 MCP tool entrypoints, with most tools registered directly into one visible surface. | 47 MCP tool entrypoints across grouped domains. |
| Tool visibility | No decorator-level group metadata and no `manage_tools` workflow for user-controlled visibility. | Tool registry has named groups; `core` is enabled by default and non-core groups are opt-in. |
| Editor automation domains | Core scene/object/component/script/asset/prefab/material/shader/VFX/test/editor operations. | Adds build orchestration, camera/Cinemachine control, render pipeline and graphics operations, package management, physics, animation, UI Toolkit, profiling, ProBuilder, and procedural texture generation. |
| Asset creation/import | Existing asset management and VFX/shader/script tools could create or modify project content, but external generation providers were not part of the product surface. | Adds the `asset_gen` group for Tripo/Meshy model generation, fal.ai/OpenRouter image generation, Sketchfab import, and local FBX/OBJ/glTF handoff from tools such as Blender. |
| API lookup and docs | API discovery depended on external docs or local project inspection. | Adds `unity_docs` and `unity_reflect`, plus generated tool/resource reference docs. |
| Safety model | Core tool execution, custom tools, async test polling, and instance routing were present. | Adds group-gated high-power tools, secure provider-key storage in Unity, project-scoped import hardening, archive/path validation, and more test coverage around transport, tool registry, provider adapters, and Unity compatibility. |
| Editor UI and docs | The window focused on connection/client setup and the docs grew around accumulated features. | Adds tool/resource visibility flows, Asset Gen setup, glTFast dependency guidance, refreshed README/docs navigation, icons/social assets, and consistent "MCP for Unity" product naming. |
Added MCP tool entrypoints since `v9.0.0`: `execute_code`,
`generate_image`, `generate_model`, `import_model`, `import_model_file`,
`manage_animation`, `manage_build`, `manage_camera`, `manage_graphics`,
`manage_packages`, `manage_physics`, `manage_probuilder`, `manage_profiler`,
`manage_texture`, `manage_tools`, `manage_ui`, `unity_docs`, and
`unity_reflect`.
## What v10 is about
v10 is organized around five concrete changes:
1. **A larger grouped tool surface** - the catalog grows from 29 to 47 MCP tool
entrypoints, with high-power domains split into opt-in groups.
2. **Asset generation and import** - first-class MCP tools for generating 3D
models, generating 2D images, importing marketplace models, and handing off
local files from tools like Blender.
3. **Safer agent operations** - provider keys stay in the Unity Editor, tools
are opt-in by group, long-running jobs are explicit and pollable, and file
writes are constrained to project assets.
4. **Clearer product surface** - refreshed README, docs site, branding, and
distribution metadata make it easier to understand what the project does and
where to start.
5. **Release confidence** - Python tests, Unity compile checks, docs builds, and
compatibility shims keep the wide Unity support window practical.
## AI Asset Generation
The headline v10 feature is the new `asset_gen` tool group. It is disabled by
default like other non-core tool groups, and can be enabled with `manage_tools`.
The group contains:
| Tool | Purpose |
| --- | --- |
| `generate_model` | Generate 3D models from text or image prompts through providers such as Tripo and Meshy. |
| `generate_image` | Generate 2D images through providers such as fal.ai and OpenRouter. |
| `import_model` | Search and import downloadable Sketchfab models. |
| `import_model_file` | Import a local model file already on disk, such as an FBX/OBJ/glTF exported from Blender. |
The tools use asynchronous job semantics for long-running work. A generation or
import request returns a `job_id`; clients then call the corresponding
`action="status"` operation until the job completes or fails. This keeps MCP
calls responsive and gives agents a predictable pattern for progress reporting.
### Provider keys
Asset providers are bring-your-own-key. Keys are entered in the Unity Editor's
Asset Gen tab and stored in the operating system secure store:
- macOS: Keychain
- Windows: Credential Manager
- Linux: libsecret / Secret Service compatible tooling
Keys are not written to project assets, `EditorPrefs`, generated docs, or MCP
tool parameters. The MCP client can request a generation job, but it does not
receive provider credentials.
### Local image inputs
v10 distinguishes hosted image inputs from local project images:
- `image_url` points at an externally hosted image.
- `image_path` points at a local file, commonly under `Assets/`.
Meshy image-to-3D and fal/OpenRouter image-to-image can accept local image files
by sending the image data inline as a base64 data URI. Tripo image-to-3D still
requires a hosted `image_url` until an upload flow is wired.
### Blender handoff
The `import_model_file` tool creates a clean boundary between DCC generation and
Unity import. BlenderMCP or another modeling workflow can create/export a model,
then MCP for Unity imports that local file into the Unity project and can place
it in the scene.
This is a handoff, not MCP for Unity controlling Blender directly:
1. The modeling tool creates or exports the asset.
2. MCP for Unity imports the file with `import_model_file`.
3. The Unity agent uses existing scene, material, prefab, and build tools to wire
the asset into the project.
## Safety model
Asset generation makes the bridge more powerful, so v10 calls out the guardrails
around provider calls and file import.
### Opt-in tool group
`asset_gen` is not part of the default core tool set. Users must explicitly
enable it with `manage_tools`, which keeps routine MCP sessions focused and
limits accidental provider calls.
### Project-scoped imports
Generated and imported assets resolve into the Unity project's `Assets/` folder,
with traversal and unsafe paths rejected. Archives are extracted through
allowlisted import paths and extensions rather than blindly writing every file
a provider returns.
### No hidden spend
Generation calls go to third-party providers using the user's own API keys:
- MCP for Unity does not bundle provider credits.
- Provider pricing, rate limits, and content policies are controlled by the
provider.
- Enable the tool group only when you intend to call generation or import
providers.
## Docs and brand refresh
v10 also updates the project front door:
- README trimmed into a clearer front door: what the project does, quickstart,
community, advanced links, and citation.
- Docs site reorganized around Getting Started, Guides, Reference,
Architecture, Contributing, Migrations, and Releases.
- Tool reference pages are generated from the tool registry so the docs match
the Python MCP layer.
- Distribution and analytics docs are explicit about what is measured and what
is not.
- Branding now consistently uses **MCP for Unity** in user-facing UI and docs.
## Compatibility posture
v10 continues the existing compatibility promise:
- Unity 2021.3 LTS remains the package floor.
- Unity 6.x stays in the supported matrix.
- Known Unity API changes route through compatibility helpers under
`MCPForUnity/Runtime/Helpers/` instead of scattering `#if UNITY_*` gates
across tool code.
- When touching shims or version-gated APIs, run `tools/check-unity-versions.sh`
against installed Unity Hub editors.
The CoreCLR 6.8 path matters here. Deprecation fixes belong in one shim layer,
not at every call site.
## Upgrade notes from v9
1. **Update the Unity package** to v10. Use the `main` branch for the latest
stable release, or pin `v10.0.0` when you need this exact release. Use
`beta` only for post-v10 preview builds.
2. **Reconfigure MCP clients** if the package prompts you to, especially after
transport or server URL changes.
3. **Install optional dependencies** only when needed. For example, GLB import
uses glTFast; FBX import does not require that package.
4. **Enable `asset_gen` explicitly** with `manage_tools` before calling asset
generation tools.
5. **Add provider keys in Unity**, not in MCP client config files.
6. **Keep generated assets under review** before committing them. Provider
output can be large and belongs in the same review path as other binary
project assets.
## What is intentionally not in v10
Call these out to avoid confusing expectations:
- No hosted MCP for Unity asset-generation credits.
- No guarantee that every provider supports every input mode.
- No automatic BlenderMCP configuration from Unity.
- No promise that provider-generated assets are production-ready without artist
review.
- No change to the rule that non-core tool groups start disabled.
## Final comparison
**Major-version comparison**: https://github.com/CoplayDev/unity-mcp/compare/v9.0.0...v10.0.0
**v9.7.3 patch comparison**: https://github.com/CoplayDev/unity-mcp/compare/v9.7.3...v10.0.0
## Troubleshooting
### `asset_gen` tools do not appear
The `asset_gen` group is disabled by default. Enable it with `manage_tools`:
```text
manage_tools action=activate group=asset_gen
```
If the tools still do not appear, refresh/reconnect the MCP server in the client.
Some clients cache tool lists until the server is restarted or refreshed.
### Provider key missing
Generation providers are bring-your-own-key. Add keys in Unity's **Asset Gen**
tab. Do not place provider keys in MCP client config files, prompts, project
assets, or generated docs.
### GLB import fails or has missing geometry/materials
GLB/glTF import depends on **glTFast**. Install it from the Dependencies tab or
via Package Manager before importing GLB assets. FBX imports do not require
glTFast.
### Tripo image-to-3D rejects `image_path`
Tripo image-to-3D currently needs a hosted `image_url`. Local `image_path` inputs
are supported by Meshy image-to-3D and fal/OpenRouter image-to-image, where the
image can be sent inline as a base64 data URI.
### Generated or imported files are larger than expected
Provider output can include large binary assets. Review generated files before
committing them, keep generated output under `Assets/Generated/` when possible,
and avoid committing experimental provider output that is not needed by the
project.
### Archive import is rejected
Archive extraction is intentionally constrained. Provider archives may be
rejected when they contain unsupported extensions, traversal paths, scripts, or
files outside the import allowlist. Import the model again with a supported
format or inspect the archive before bringing it into the Unity project.
## Related docs
- [Tool groups](/guides/tool-groups)
- [Asset generation tools](/reference/tools/asset_gen/)
- [`generate_model`](/reference/tools/asset_gen/generate_model)
- [`generate_image`](/reference/tools/asset_gen/generate_image)
- [`import_model`](/reference/tools/asset_gen/import_model)
- [`import_model_file`](/reference/tools/asset_gen/import_model_file)
- [Generated tool reference](/reference/tools/)
- [Unity compatibility shims](/architecture/unity-compat)
- [Project roadmap](/architecture/project-roadmap)
+53
View File
@@ -0,0 +1,53 @@
# MCP for Unity v5 Migration Guide
This guide will help you migrate from the legacy UnityMcpBridge installation to the new MCPForUnity package structure in version 5.
## Overview
Version 5 introduces a new package structure. The package is now installed from the `MCPForUnity` folder instead of the legacy `UnityMcpBridge` folder.
## Migration Steps
### Step 1: Uninstall the Current Package
1. Open the Unity Package Manager (**Window > Package Manager**)
2. Select **Packages: In Project** from the dropdown
3. Find **MCP for Unity** in the list
4. Click the **Remove** button to uninstall the legacy package
![Uninstalling the legacy package](/img/v5_01_uninstall.png)
### Step 2: Install from the New Path
1. In the Package Manager, click the **+** button in the top-left corner
2. Select **Add package from git URL...**
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](/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](/img/v5_03_open_mcp_window.png)
2. Click the **Rebuild MCP Server** button
![Rebuilding the MCP server](/img/v5_04_rebuild_mcp_server.png)
3. You should see a success message confirming the rebuild
![Rebuild success](/img/v5_05_rebuild_success.png)
## Verification
After completing these steps, verify the migration was successful:
- Check that the package appears in the Package Manager as **MCP for Unity**
- Confirm the package location shows the new `MCPForUnity` path
- Test basic MCP functionality to ensure everything works correctly
## Troubleshooting
- Check the Unity Console for specific error messages
- Ensure Python dependencies are properly installed
- Try pressing the rebuild button again
- Try restarting Unity and repeating the installation steps
+303
View File
@@ -0,0 +1,303 @@
# MCP for Unity v6 - New Editor Window
> **UI Toolkit-based window with service-oriented architecture**
![New MCP Editor Window Dark](/img/v6_new_ui_dark.png)
*Dark theme*
![New MCP Editor Window Light](/img/v6_new_ui_light.png)
*Light theme*
---
## Overview
The new MCP Editor Window is a complete rebuild using **UI Toolkit (UXML/USS)** with a **service-oriented architecture**. The design philosophy emphasizes **explicit over implicit** behavior, making the system more predictable, testable, and maintainable.
**Quick Access:** `Cmd/Ctrl+Shift+M` or `Window > MCP for Unity > Open MCP Window`
**Key Improvements:**
- 🎨 Modern UI that doesn't hide info as the window size changes
- 🏗️ Service layer separates business logic from UI
- 🔧 Explicit path overrides for troubleshooting
- 📦 Asset Store support with server download capability
- ⚡ Keyboard shortcut for quick access
---
## Key Differences at a Glance
| Feature | Old Window | New Window | Notes |
|---------|-----------|------------|-------|
| **Architecture** | Monolithic | Service-based | Better testability & reusability |
| **UI Framework** | IMGUI | UI Toolkit (UXML/USS) | Modern, responsive, themeable |
| **Auto-Setup** | ✅ Automatic | ❌ Manual | Users have explicit control |
| **Path Overrides** | ⚠️ Python only | ✅ Python + UV + Claude CLI | Advanced troubleshooting |
| **Bridge Health** | ⚠️ Hidden | ✅ Visible with test button | Separate from connection status |
| **Configure All** | ❌ None | ✅ Batch with summary | Configure all clients at once |
| **Manual Config** | ✅ Popup windows | ✅ Inline foldout | Less window clutter |
| **Server Download** | ❌ None | ✅ Asset Store support | Download server from GitHub |
| **Keyboard Shortcut** | ❌ None | ✅ Cmd/Ctrl+Shift+M | Quick access |
## What's New
### UI Enhancements
- **Advanced Settings Foldout** - Collapsible section for path overrides (MCP server, UV, Claude CLI)
- **Visual Path Validation** - Green/red indicators show whether override paths are valid
- **Bridge Health Indicator** - Separate from connection status, shows handshake and ping/pong results
- **Manual Connection Test Button** - Verify bridge health on demand without reconnecting
- **Inline Manual Configuration** - Copy config path and JSON without opening separate windows
### Functional Improvements
- **Configure All Detected Clients** - One-click batch configuration with summary dialog
- **Keyboard Shortcut** - `Cmd/Ctrl+Shift+M` opens the window quickly
### Asset Store Support
- **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](/img/v6_new_ui_asset_store_version.png)
*Asset Store version showing the "Download & Install Server" button*
---
## Features Not Supported (By Design)
The new window intentionally removes implicit behaviors and complex edge-case handling to provide a cleaner, more predictable UX.
### ❌ Auto-Setup on First Run
- **Old:** Automatically configured clients on first window open
- **Why Removed:** Users should explicitly choose which clients to configure
- **Alternative:** Use "Configure All Detected Clients" button
### ❌ Python Detection Warning
- **Old:** Warning banner if Python not detected on system
- **Why Removed:** Setup Wizard handles dependency checks, we also can't flood a bunch of error and warning logs when submitting to the Asset Store
- **Alternative:** Run Setup Wizard via `Window > MCP for Unity > Setup Wizard`
### ❌ Separate Manual Setup Windows
- **Old:** `VSCodeManualSetupWindow`, `ManualConfigEditorWindow` popup dialogs
- **Why Removed:** Looks neater, less visual clutter
- **Alternative:** Inline "Manual Configuration" foldout with copy buttons
### ❌ Server Installation Status Panel
- **Old:** Dedicated panel showing server install status with color indicators
- **Why Removed:** Simplified to focus on active configuration and the connection status, we now have a setup wizard for this
- **Alternative:** Server path override in Advanced Settings + Rebuild button
---
## Service Locator Architecture
The new window uses a **service locator pattern** to access business logic without tight coupling. This provides flexibility for testing and future dependency injection migration.
### MCPServiceLocator
**Purpose:** Central access point for MCP services
**Usage:**
```csharp
// Access bridge service
MCPServiceLocator.Bridge.Start();
// Access client configuration service
MCPServiceLocator.Client.ConfigureAllDetectedClients();
// Access path resolver service
string mcpServerPath = MCPServiceLocator.Paths.GetMcpServerPath();
```
**Benefits:**
- No constructor dependencies (easy to use anywhere)
- Lazy initialization (services created only when needed)
- Testable (supports custom implementations via `Register()`)
---
### IBridgeControlService
**Purpose:** Manages MCP for Unity Bridge lifecycle and health verification
**Key Methods:**
- `Start()` / `Stop()` - Bridge lifecycle management
- `Verify(port)` - Health check with handshake + ping/pong validation
- `IsRunning` - Current bridge status
- `CurrentPort` - Active port number
**Implementation:** `BridgeControlService`
**Usage Example:**
```csharp
var bridge = MCPServiceLocator.Bridge;
bridge.Start();
var result = bridge.Verify(bridge.CurrentPort);
if (result.Success && result.PingSucceeded)
{
Debug.Log("Bridge is healthy");
}
```
---
### IClientConfigurationService
**Purpose:** Handles MCP client configuration and registration
**Key Methods:**
- `ConfigureClient(client)` - Configure a single client
- `ConfigureAllDetectedClients()` - Batch configure with summary
- `CheckClientStatus(client)` - Verify client status + auto-rewrite paths
- `RegisterClaudeCode()` / `UnregisterClaudeCode()` - Claude Code management
- `GenerateConfigJson(client)` - Get JSON for manual configuration
**Implementation:** `ClientConfigurationService`
**Usage Example:**
```csharp
var clientService = MCPServiceLocator.Client;
var summary = clientService.ConfigureAllDetectedClients();
Debug.Log($"Configured: {summary.SuccessCount}, Failed: {summary.FailureCount}");
```
---
### IPathResolverService
**Purpose:** Resolves paths to required tools with override support
**Key Methods:**
- `GetMcpServerPath()` - MCP server directory
- `GetUvPath()` - UV executable path
- `GetClaudeCliPath()` - Claude CLI path
- `SetMcpServerOverride(path)` / `ClearMcpServerOverride()` - Manage MCP server overrides
- `SetUvPathOverride(path)` / `ClearUvPathOverride()` - Manage UV overrides
- `SetClaudeCliPathOverride(path)` / `ClearClaudeCliPathOverride()` - Manage Claude CLI overrides
- `IsPythonDetected()` / `IsUvDetected()` - Detection checks
**Implementation:** `PathResolverService`
**Usage Example:**
```csharp
var paths = MCPServiceLocator.Paths;
// Check if UV is detected
if (!paths.IsUvDetected())
{
Debug.LogWarning("UV not found");
}
// Set an override
paths.SetUvPathOverride("/custom/path/to/uv");
```
## Technical Details
### Files Created
**Services:**
```text
MCPForUnity/Editor/Services/
├── IBridgeControlService.cs # Bridge lifecycle interface
├── BridgeControlService.cs # Bridge lifecycle implementation
├── IClientConfigurationService.cs # Client config interface
├── ClientConfigurationService.cs # Client config implementation
├── IPathResolverService.cs # Path resolution interface
├── PathResolverService.cs # Path resolution implementation
└── MCPServiceLocator.cs # Service locator pattern
```
**Helpers:**
```text
MCPForUnity/Editor/Helpers/
└── AssetPathUtility.cs # Package path detection & package.json parsing
```
**UI:**
```text
MCPForUnity/Editor/Windows/
├── MCPForUnityEditorWindowNew.cs # Main window (~850 lines)
├── MCPForUnityEditorWindowNew.uxml # UI Toolkit layout
└── MCPForUnityEditorWindowNew.uss # UI Toolkit styles
```
**CI/CD:**
```text
.github/workflows/
└── bump-version.yml # Server upload to releases
```
### Key Files Modified
- `ServerInstaller.cs` - Added download/install logic for Asset Store
- `SetupWizard.cs` - Integration with new service locator
- `PackageDetector.cs` - Uses `AssetPathUtility` for version detection
---
## Migration Notes
### For Users
**Immediate Changes (v6.x):**
- Both old and new windows are available
- New window accessible via `Cmd/Ctrl+Shift+M` or menu
- Settings and overrides are shared between windows (same EditorPrefs keys)
- Services can be used by both windows
**Upcoming Changes (v8.x):**
- ⚠️ **Old window will be removed in v8.0**
- All users will automatically use the new window
- EditorPrefs keys remain the same (no migration needed)
- Custom scripts using old window APIs will need updates
### For Developers
**Using the Services:**
```csharp
// Accessing services from any editor script
var bridge = MCPServiceLocator.Bridge;
var client = MCPServiceLocator.Client;
var paths = MCPServiceLocator.Paths;
// Services are lazily initialized on first access
// No need to check for null
```
**Testing with Custom Implementations:**
```csharp
// In test setup
var mockBridge = new MockBridgeService();
MCPServiceLocator.Register(mockBridge);
// Services are now testable without Unity dependencies
```
**Reusing Service Logic:**
The service layer is designed to be reused by other parts of the codebase. For example:
- Build scripts can use `IClientConfigurationService` to auto-configure clients
- CI/CD can use `IBridgeControlService` to verify bridge health
- Tools can use `IPathResolverService` for consistent path resolution
**Notes:**
- A lot of Helpers will gradually be moved to the service layer
- Why not Dependency Injection? This change had a lot of changes, so we didn't want to add too much complexity to the codebase in one go
---
## Pull Request Reference
**PR #313:** [feat: New UI with service architecture](https://github.com/CoplayDev/unity-mcp/pull/313)
**Key Commits:**
- Service layer implementation
- UI Toolkit window rebuild
- Asset Store server download support
- CI/CD server upload automation
---
**Last Updated:** 2025-10-10
**Unity Versions:** Unity 2021.3+ through Unity 6.x
**Architecture:** Service Locator + UI Toolkit
**Status:** Active (Old window deprecated in v8.0)
+261
View File
@@ -0,0 +1,261 @@
---
title: v8 - New Networking Setup
author: Marcus Sanatan <marcus@coplay.dev>
date: 2025-11-15
---
# HTTP and Stdio Support
This project has 3 components:
- MCP Client
- MCP Server
- Unity Editor plugin
![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).
The MCP protocol defines how clients and servers can communicate, but we have to get creative when communicating with Unity. Let's learn more.
## How do MCP components communicate?
MCP servers support communicating over [stdio or via Streamable HTTP](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports).
### Stdio Architecture
MCP for Unity communicates via stdio. Particularly, the MCP server and the MCP client use stdio to communicate. The MCP server and the Unity plugin editor communicate via a locally opened port, typically 6400, but users can change it to any port.
Why can't the Unity plugin communicate to the server via stdio like the MCP client? When we create MCP configs that use `uvx`, MCP clients run the command in an *internal subprocess*, and communicate with the MCP server via stdio (think pipes in the OS e.g. `ls -l | grep "example.txt"`).
Unity can't reach that internal subprocess, so we listen to port 6400, which the MCP server can open and send/receive data.
> **Note**: Previously we used `uv`, and we installed the server locally in the plugin. Now we use `uvx` which installs the server for us, directly from our GitHub repo.
When the user sends a prompt:
1. The MCP client will send a request to the MCP server via stdio
2. The MCP server would process the request and connect to port 6400
3. The MCP server sends the command, and the Unity plugin responds via port 6400
4. The MCP server parses the response and returns JSON to the MCP client via stdio
In this new version of MCP for Unity, our MCP server supports both the stdio and HTTP protocols.
### HTTP Architecture
We create MCP configs that reference a URL, by default http://localhost:8080, however, users can change it to any address. MCP clients connect to the running HTTP server, and communicate with the MCP server via HTTP POST requests with JSON. Unlike in stdio, the MCP server is not a subprocess of the client, but is run independently of all other components.
What about the MCP server and Unity? We could maintain the communication channel that's used in stdio i.e. communicating via port 6400. However, this would limit the HTTP server to only being run locally. A remote HTTP server would not have access to a user's port 6400 (unless users open their ports to the internet, which may be hard for some and is an unnecessary security risk).
To work with both locally and remotely hosted HTTP servers, we set up a *WebSocket connection* between Unity and the MCP Server. This allows for real time communication between the two components.
When the user sends a prompt:
1. The MCP client will send an HTTP POST request to the MCP server
2. The MCP server would process the request and send a message to Unity via WebSockets
3. The Unity plugin sends a response via WebSockets to the MCP server
4. The MCP server parses the response and returns JSON to the MCP client via Server-Sent Events
MCP for Unity previously only supported local connections with MCP clients via stdio. Now, we continue to support local stdio connections, but additionally support local HTTP connections and remote HTTP connections.
## Why add HTTP support?
Let's discuss both technical and political reasons:
- More flexibility on where the HTTP server can be run:
- Do you want to run the MCP server in your terminal/PowerShell/Command Prompt? You can.
- Do you want to run the MCP server in Windows Subsystem for Linux (WSL), where you prefer to install Python/`uv`? You can.
- Do you want to run the MCP server in a docker container? You can.
- 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 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.
- Not having to setup Python and `uv` has benefits to non-asset store users, but I think to avoid maintaining this server, we'll explore running the MCP server inside the Unity plugin as a background process using the [official MCP C# SDK](https://github.com/modelcontextprotocol/csharp-sdk).
## How was it implemented?
Significant changes were made to the server and Unity plugin to support the HTTP protocol, as well as the new WebSocket connection, with the right amount of abstraction to support both stdio and HTTP.
### Server
`server.py` is still the main entrypoint for the backend, but now it's been modified to setup both HTTP and stdio connections. It processes command line arguments or environment variables for the HTTP mode. CLI args take precedence over the environment variables. The following code runs the server:
```python
mcp.run(transport=transport, host=host, port=port)
```
And that's pretty much it in terms of HTTP support between the MCP server and client. Things get more interesting for the connection to the Unity plugin.
Backward compatability with stdio connections was maintained, but we did make some small performance optimisations. Namely, we have an in-memory cache of unity isntances using the `StdioPortRegistry` class.
It still calls `PortDiscovery.discover_all_unity_instances()`, but we add a lock when calling it, so multiple attempts to retrieve the instances do not cause our app to run multiple file scans at the same time.
The `UnityConnection` class uses the cached ports to retrieve the open port for a specific instances when creating a new connection, and when sending a command.
For WebSocket connections, we need to understand the `PluginHub` and the `PluginRegistry` classes. The plugin hub is what manages the WebSocket connections with the MCP server in-memory. It also has the `send_command_for_instance` function, which actually sends the command to the Unity plugin.
The in-memory mapping of sessions to WebSockets connections in the plugin hub is done via the `PluginRegistry` class.
You're wondering if every function tool needs to use the `send_command_for_instance` and the current function and choose between WebSockets/stdio every invocation? No, to keep tool calls as simple as posisble, all users have to do is call the `send_with_unity_instance`, which delegates the actual sending of data to `send_command_for_instance` or `send_fn`, which is a function that's parsed to the arguments of `send_with_unity_instance`, typically `async_send_command_with_retry`.
### Unity Plugin
Let's start with how things worked before this change. The `MCPForUnityBridge` was a monolith of all networking logic. As we began to develop a service architecture, we created the `BridgeControlService` to wrap the `MCPForUnityBridge` class, to make the migration to the new architecture easier.
The `BridgeControlService` called functions in the `MCPForUnityBridge`, which managed the state and processing for TCP communication.
In this version `BridgeControlService` wraps around the `TransportManager`, it doesn't have hardcoded logic specific to stdio. The `TransportManager` object manages the state of the network and delegates the actual networking logic to the appropriate transport client - either WebSocket or stdio. The `TransportManager` interacts with objects that implement the `IMcpTransportClient` interface.
The legacy `McpForUnityBridge` was renamed and moved to `StdioBridgeHost`. The `StdioTransportClient` class is a thin wrapper over the `StdioBridgeHost` class, that implements the `IMcpTransportClient` interface. All the logic for the WebSocket connection is in the `WebSocketTransportClient` class.
### MCP Configs
### Stdio config updates
Since we support both HTTP and stdio connections, we had to do some work around the MCP config builders. The major change was reworking how stdio connections were constructed to use `uvx` with the remote package instead of the locally bundled server and `uv`, HTTP configs are much simpler.
The remote git URL we use to get the package is versioned, which added some complications. We frequently make changes to the `main` branch of this repo, some are breaking (the last version before this was v7, which was a major breaking change as well). We don't control how users update their MCP for Unity package. So if we point to the main branch, their plugin could be talking to an incompatible version of the server.
To address this, we have a process to auto-update stdio configurations. The `StdIoVersionMigration` class runs when the plugin is loaded. It checks a new editor pref that stores the last version we upgraded clients to. If the plugin was updated, the package version will mismatch the editor pref's version, and we'll cycle through a user's configured MCP clients and re-configure them.
This way, whenever a user updates the plugin, they will automatically point to the correct version of the MCP server for their MCP clients to use.
Relevant commits:
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/7dff06679b89564ad92c88d8fe70c08e8efcbc22
### Upgrading configs from v7 to v8
The new HTTP config and the new stdio config using `uvx` is a departure from the previous MCP configs which have `uv` and a path to `server.py`. No matter the protocol, all users would have to update their MCP configs. Not all users are on Discord where we can reach them, and not all our Discord users read our messages in any case. Forcing users to update their configs after updating is something they can easily ignore or forget.
So we added the `LegacyServerSrcMigration` class. It looks for the `MCPForUnity.UseEmbeddedServer` editor pref, which was used in earlier versions. If this pref exists, we will reconfigure all of a user's MCP clients (defaulting to HTTP) at startup. The editor pref is then deleted, so this config update only happens once.
Relevant commits:
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/996ca48894a669344e3a7f3eff3d9e9913caec7d
## Other changes
This version contains numerous other updates, including:
### Using `uvx` instead of `uv`
Previously, the MCP server was bundled with the plugin in the `UnityMcpServer~/src` folder. I don't have the context as to why this was done, but I imagine `uv` support for running remote packages was not available/popular at the time this repo was created.
By using `uvx` and remote packages, we can safely offload all aspects of server file management from our plugin.
Relevant commits:
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/64d64fde45af540229cf1995561cafc436bc3686
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/c830d56648710e4723a238a4692b7f85df4d4e42
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/85e934265c25b24cf44e4e758cb261fdb6eb333f
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/d217e2899e4b245ee25cb5f667dbb0be3dcf4948
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/50902b92f2f539b6292fec08e3fe9bedb91b2341
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/08b3d1893f003cc0c354079329879aa7b2ed8829
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/014f8c7db9c7b91054e177a64f30eb6bea3f9193
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/cad8c20faff9caf51bfc7772a40404f6fceeac33
### Asynchronous tools and resources
Previously we had `async_send_with_unity_instance` and `send_with_unity_instance` functions to communicate with the Unity. Now, we only have `send_with_unity_instance`, and it's asynchronous.
This was required for the HTTP server, because we cannot block the event loop with synchronous commands. This change does not affect how the server works when using stdio.
Relevant commits:
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/d5d738d83d96eabdc19e13bb650cd8fe578c58bc
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/8b4bcb65cdaf1bdefcb3828c170307de0588c18f
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/d6e2466b6869cc64ad8a358ec95d045830f37eff
### Custom tools
Custom tools were revamped once more, this time they're reached the simplest version that we wanted them to have - custom tools are written entirely in C# - no Python required. How does it work?
Like before, we do reflection on the `McpForUnityToolAttribute`. However, this time the attribute now accepts a `name`, `description`, and `AutoRegister`. The `AutoRegister` boolean is true by default, but for our core tools it's false, as they don't have their tool details nor parameters defined in C# as yet.
Parameters are defined using the `ToolParameterAttribute`, which contains `Name`, `Description`, `Required`, and `DefaultValue` properties.
The `ToolDiscoveryService` class uses reflection to find all classes with `McpForUnityToolAttribute`. It does the same for `ToolParameterAttribute`. With that data, it constructs a `ToolMetadata` object. These tools are stored in-memory in a dictionary that maps tool names with their metadata.
When we initiate a websocket connection, after successfully registering and retrieving a session ID, we call the `SendRegisterToolsAsync` function. This function sends a JSON payload to the server with all the tools that were found in the `ToolDiscoveryService`.
In the `plugin_hub`'s `on_receive` handler, we look out for the `register_tools` message type, and map the tools to the session ID. This is important, we only want custom tools to be available for the project they've been added to.
That requirement of keeping tools local to the projeect made this implementation a bit trickier. We have the requirement because in this project, we can run multiple Unity instances at the same time. So it doesn't make sense to make every tool globally available to all connected projects.
To make tools local to the project, we add a `mcpforunity://custom-tools` resource which lists all tools mapped to a session (which is retrieve from FastMCP's context). And then we add a `execute_custom_tool` function tool which can call the tools the user added. This worked surprisingly well, but required some tweaks:
- We removed the fallback for session IDs in the server. If there's more than one Unity instance connected to the server, the MCP client MUST call `set_active_instance` so the mapping between session IDs and Unity instances will be correct.
- We removed the `read_resources` tool. It simply did not work, and LLMs would go in circles for a long time before actually reading the resource directly. This only works because MCP resources have up to date information and gives the MCP clients the right context to call the tools.
> **Note**: FastMCP can register and deregister tools while the server is running, however, not all MCP clients can process the updates in real time. We recommend that users refresh/reconfigure the MCP servers in the clients so they can see the new custom tools.
Relevant commits:
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/b4be06893ef218a84468dbc71b9dc8614289e433
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/77641dae64e8b3c572dd876af0b59ea454f04b0c
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/f968c8f446dff6fb0c70d033b148de934c6aebf3
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/ea754042b645a22cefb4f2fb820d1f4756af4ded
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/e9254c7776d7d948722b58805ee047499fc5a65b
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/662656b56a1b77c3f59116522e89c78b9b8af76f
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/cd88e86762cf82e0db8e687a2e64211c25b47b80
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/95c5265816aa7205588130f211f86e5e1e2d637b
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/85cd5c0cf47582bb43eab7ec998f4044a6430275
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/a84c2c29a08cabc3345e50147afa896ea4ae37bf
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/4f22d54ae38f84cfc05e50ad30675f4bb728f76d
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/01976a507396bf7fca1fd253172dd4c83ff33867
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/7525dfa547db5730cd911db25d2baa8bad969c71
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/53a397597df3fcaa4fa54188e9920348158c7425
### Window logic has been split into separate classes
The main `MCPForUnityEditorWindow.cs` class, and the releated uxml and uss files, were getting quite long. We had a similar problem with the last immediate UI version of it. To keep it maintanable, we split the logic into 3 separate view classes: Settings, Connection andn ClientConfig. They correspond to the 3 visual sections the window has.
Each section has its own C#, uxml and uss files, but we use a common uss file for shared styles.
Relevant commits:
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/154b4ff3ad9c98f5f5ee8628cd8bcb79d0e108b5
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/1a9bb008a416a2b3abb0d91819a8173d362748b8
#### Setup Wizard
The Setup Wizard also got revamped. For starters, it's no longer a wizard, just a single window with a status and instructions. We check if Python and uv are installed, based on us being able to check their version by calling them in a process. That's the most reliable indicator of them being correctly installed. Otherwise, we have buttons that open up the webpages for users to download them as needed.
Relevant commits:
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/aa63f21ea42372853690618d928cd1fad73e7c25
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/cd4529c21f35e5be10a98dcf9303c210ebf42d2b
### Response classes
Previously, the Response class had helper functions that returned generic objects. It's not the worst option, but we've improved it with strongly typed classes. Instead of `Response.Success()` returning a success message, we now return `SuccessResponse` objects. Similarly, `Response.Error()` now returns `ErrorResponse` objects.
JSON serialization is the exact same, but it's clearer in the code what's being transmitted between the client and server.
Relevant commits:
- https://github.com/CoplayDev/unity-mcp/pull/375/commits/f917d9489540498a908f514a561160c08d9d1023
### Miscellaneous
- The shortcut (Cmd+Shift+M on macOS, Ctrl+Shift+M on Windows/Linux) can now be used to open and close the MCP for Unity window.
- The `McpLog` object now has a `Debug` function, which only logs when the user selects "Show debug logs" in the settings.
- All `EditorPrefs` are defined in `MCPForUnity/Editor/Constants/EditorPrefKeys.cs`. At a glance, we can see all the settings we have available.
## Future plans
This was a big change, and it touches all the repo. So a lot of inefficiencies and room for improvement were exposed while working on it. Here are some items to address:
- Loose types in Python. A lot of the new code would use dictionaries for structured data, which works, but we can benefit much more from using Pydantic classes with proper type checking. We always want to know when data is not being transferred in the format we expect it to. Plus, strong types make the code easier for humans and LLMs to reason about.
- A lot of tools define a `_coerce_int` function, why? Why are we redefining a function that's the same across files? Can we use a shared function, or maybe use it as middleware?
- Similarly, the `DummyMCP` class is defined in 10 server tests, we could set this up in `conftest.py`. These tests were originally indepdendent of the `Server` project, but in v7 they became integration tests we run with `pytest`. With `pytest` being the default test runner, we can relook at how the tests are structured and optimize their setup.
- `server_version.txt` is used in one place, but the server can now read its own pyproject.toml to get the version, so we can remove this.
- ~~Think about a structure of the MCP server some more. The `tools`, `resources` and `registry` folders make sense, but everything else just forms part of the high level repo. It's growing, so some thought about how we create modules will help with scalability.~~
- This was done, Server folder is much more hierarchical and structured.
- The way we register tools is a good platform for all tools to be defined by C#. Having all tools in the plugin makes it easier for us to maintain, the community to contribute, and users to modify this project to suit their needs. If all tools are registered from the plugin, we can allow users to select the tools they want to use, giving them even more control of their experience.
- Of course, we need some testing of this custom tool architecture to know if it can scale to all tools. ~~Also, custom tool registration is only supported with HTTP, so we'll need to support this feature when the stdio protocol is being used.~~
- Custom tools now work in both HTTP and stdio transports.
+96
View File
@@ -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 <command> [args]
# Run from a Server checkout
cd Server && uv run mcp-for-unity <command> [args]
# Run via the dedicated CLI entry point (alias)
uvx --from mcpforunityserver unity-mcp <command> [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).
+69
View File
@@ -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).
+260
View File
@@ -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 `<!-- examples:start --><!-- examples:end -->` 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.
@@ -0,0 +1,8 @@
{
"label": "animation",
"link": {
"type": "doc",
"id": "reference/tools/animation/index"
},
"collapsed": true
}
@@ -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.
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `animation` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,8 @@
{
"label": "asset_gen",
"link": {
"type": "doc",
"id": "reference/tools/asset_gen/index"
},
"collapsed": true
}
@@ -0,0 +1,51 @@
---
title: generate_image
sidebar_label: generate_image
description: "Generate 2D images with AI providers (fal.ai, OpenRouter) and import them as textures/sprites into the Unity project."
---
# `generate_image`
> **Auto-generated** from the Python tool registry. Do not hand-edit outside `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `asset_gen` &nbsp;·&nbsp; **Module:** `services.tools.generate_image`
## Description
Generate 2D images with AI providers (fal.ai, OpenRouter) and import them as textures/sprites into the Unity project. Bring-your-own-key: provider keys live in the editor's secure store and never cross the bridge.
ACTIONS:
- generate: Submit an image job (text->image or image->image). Returns { job_id }; poll with the status action. Params: provider, mode (text|image), prompt, image_path|image_url, model, transparent, width, height, name, output_folder.
- remove_background: Unsupported in this version; returns an error instead of a job_id.
- status: Poll an async job by job_id -> { state, progress, assetPath?, error? }.
- cancel: Cancel an in-flight job by job_id.
- list_providers: List configured image providers and capabilities (no key values).
## Parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `action` | `Literal['generate', 'remove_background', 'status', 'cancel', 'list_providers']` | yes | Action to perform. |
| `provider` | `str \| None` | — | Provider id (fal, openrouter). |
| `mode` | `str \| None` | — | Generation mode: text or image. |
| `prompt` | `str \| None` | — | Text prompt for text->image. |
| `image_path` | `str \| None` | — | Path to a source image for image->image mode. |
| `image_url` | `str \| None` | — | URL of a source image for image->image. |
| `model` | `str \| None` | — | Provider model id/slug (e.g. FLUX, gemini-2.5-flash-image). |
| `transparent` | `bool \| None` | — | Mark the imported texture as alpha-is-transparency. NOTE: fal/FLUX and OpenRouter have no generation-time transparency, so this only sets the Unity import flag — it does not make the model render a transparent background. |
| `width` | `int \| None` | — | Output width in pixels. |
| `height` | `int \| None` | — | Output height in pixels. |
| `name` | `str \| None` | — | Base name for the imported asset. |
| `output_folder` | `str \| None` | — | Destination folder under Assets/ for the import. |
| `job_id` | `str \| None` | — | Job id for status/cancel. |
## Returns
A `dict` containing the Unity response. The exact shape depends on the action.
## Examples
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,50 @@
---
title: generate_model
sidebar_label: generate_model
description: "Generate 3D models with AI providers (Tripo, Meshy) and import them into the Unity project."
---
# `generate_model`
> **Auto-generated** from the Python tool registry. Do not hand-edit outside `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `asset_gen` &nbsp;·&nbsp; **Module:** `services.tools.generate_model`
## Description
Generate 3D models with AI providers (Tripo, Meshy) and import them into the Unity project. Bring-your-own-key: provider keys live in the editor's secure store and never cross the bridge.
ACTIONS:
- generate: Submit a generation job (text->3D or image->3D). Returns { job_id } immediately; poll with the status action. Params: provider, mode (text|image), prompt, image_path|image_url, format (glb|fbx|obj|usdz), target_size, texture, tier, name, output_folder.
- status: Poll an async job by job_id -> { state, progress, assetPath?, error? }.
- cancel: Cancel an in-flight job by job_id.
- list_providers: List configured 3D providers and capabilities (no key values).
## Parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `action` | `Literal['generate', 'status', 'cancel', 'list_providers']` | yes | Action to perform. |
| `provider` | `str \| None` | — | Provider id (tripo, meshy). |
| `mode` | `str \| None` | — | Generation mode: text or image. |
| `prompt` | `str \| None` | — | Text prompt for text->3D. |
| `image_path` | `str \| None` | — | Path to a source image for image->3D. |
| `image_url` | `str \| None` | — | URL of a source image for image->3D. |
| `format` | `str \| None` | — | Output model format: glb, fbx, obj, or usdz. |
| `target_size` | `float \| None` | — | Normalize the largest dimension to this size (meters). |
| `texture` | `bool \| None` | — | Whether to generate textures for the model. |
| `tier` | `str \| None` | — | Provider quality/cost tier. |
| `name` | `str \| None` | — | Base name for the imported asset. |
| `output_folder` | `str \| None` | — | Destination folder under Assets/ for the import. |
| `job_id` | `str \| None` | — | Job id for status/cancel. |
## Returns
A `dict` containing the Unity response. The exact shape depends on the action.
## Examples
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,50 @@
---
title: import_model
sidebar_label: import_model
description: "Import 3D models from the Sketchfab marketplace into the Unity project."
---
# `import_model`
> **Auto-generated** from the Python tool registry. Do not hand-edit outside `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `asset_gen` &nbsp;·&nbsp; **Module:** `services.tools.import_model`
## Description
Import 3D models from the Sketchfab marketplace into the Unity project. Bring-your-own-key: the Sketchfab token lives in the editor's secure store and never crosses the bridge.
ACTIONS:
- search: Search Sketchfab. Params: query, categories, downloadable, count, cursor -> results with model uids.
- preview: Fetch model metadata (name, thumbnail URLs, license, vertex/face counts) for a uid before import.
- import: Download + import a model by uid. Returns { job_id } immediately; poll with the status action. Params: uid, target_size, name, output_folder.
- status: Poll an async import job by job_id -> { state, progress, assetPath?, error? }.
- cancel: Cancel an in-flight import by job_id.
- list_providers: List configured marketplace providers (no key values).
## Parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `action` | `Literal['search', 'preview', 'import', 'status', 'cancel', 'list_providers']` | yes | Action to perform. |
| `query` | `str \| None` | — | Search query for the search action. |
| `categories` | `str \| None` | — | Filter search by category. |
| `downloadable` | `bool \| None` | — | Restrict search to downloadable models. |
| `count` | `int \| None` | — | Maximum number of search results. |
| `cursor` | `str \| None` | — | Pagination cursor for search. |
| `uid` | `str \| None` | — | Sketchfab model uid for preview/import. |
| `target_size` | `float \| None` | — | Normalize the largest dimension to this size (meters). |
| `name` | `str \| None` | — | Base name for the imported asset. |
| `output_folder` | `str \| None` | — | Destination folder under Assets/ for the import. |
| `job_id` | `str \| None` | — | Job id for status/cancel. |
## Returns
A `dict` containing the Unity response. The exact shape depends on the action.
## Examples
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,42 @@
---
title: import_model_file
sidebar_label: import_model_file
description: "Import a local 3D model file that already exists on disk (e.g. an FBX/OBJ/glTF exported from Blender or another DCC tool) into the Unity project."
---
# `import_model_file`
> **Auto-generated** from the Python tool registry. Do not hand-edit outside `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `asset_gen` &nbsp;·&nbsp; **Module:** `services.tools.import_model_file`
## Description
Import a local 3D model file that already exists on disk (e.g. an FBX/OBJ/glTF exported from Blender or another DCC tool) into the Unity project. The file is copied under Assets/ and run through Unity's model-import pipeline (scale-normalize, material settings; glTF requires glTFast). Carries no API keys and no file bytes over the bridge.
Params: source_path (absolute or Assets-relative path to a .fbx/.obj/.glb/.gltf/.zip), name, output_folder (under Assets/), target_size, animation_type. Returns { asset_path, asset_guid }.
animation_type (FBX/OBJ only): pass 'generic' or 'humanoid' for a rigged/animated mesh so Unity surfaces its AnimationClips; omitted or 'none' imports no rig (this is the usual cause of a rigged FBX importing with zero clips); 'legacy' selects Unity's legacy Animation system (rarely needed). glTF/GLB ignore it — glTFast imports animation itself.
For multi-file exports (a text .gltf with an external .bin, or an .obj with a sibling .mtl/textures), zip them and pass the .zip — a bare .gltf/.obj is copied without its sidecars.
## Parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `source_path` | `str` | yes | Path to the model file on disk (.fbx/.obj/.glb/.gltf/.zip). |
| `name` | `str \| None` | — | Base name for the imported asset. |
| `output_folder` | `str \| None` | — | Destination folder under Assets/ for the import. |
| `target_size` | `float \| None` | — | Normalize the largest dimension to this size (meters). |
| `animation_type` | `Literal['none', 'generic', 'humanoid', 'legacy'] \| None` | — | FBX/OBJ only: rig/animation import mode. 'generic' or 'humanoid' surface the model's AnimationClips; 'legacy' selects Unity's legacy Animation system (rarely needed); omitted or 'none' imports no rig. Ignored for glTF/GLB. |
## Returns
A `dict` containing the Unity response. The exact shape depends on the action.
## Examples
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,14 @@
---
title: "asset_gen tools"
sidebar_label: "asset_gen"
description: "MCP for Unity tools in the asset_gen group."
---
# `asset_gen` tools
AI asset generation 3D model gen/import & 2D image gen (bring-your-own-key)
- **[`generate_image`](./generate_image.md)** — Generate 2D images with AI providers (fal.ai, OpenRouter) and import them as textures/sprites into the Unity project.
- **[`generate_model`](./generate_model.md)** — Generate 3D models with AI providers (Tripo, Meshy) and import them into the Unity project.
- **[`import_model`](./import_model.md)** — Import 3D models from the Sketchfab marketplace into the Unity project.
- **[`import_model_file`](./import_model_file.md)** — Import a local 3D model file that already exists on disk (e.g. an FBX/OBJ/glTF exported from Blender or another DCC tool) into the Unity project.
@@ -0,0 +1,8 @@
{
"label": "core",
"link": {
"type": "doc",
"id": "reference/tools/core/index"
},
"collapsed": true
}
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
### 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 **10100× 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.
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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.
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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": "<name>"} or {"guid": "...", "fileID": <id>}. 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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
### 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.
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
### 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.
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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": "<name>"}. Single-sprite textures auto-resolve. |
## Returns
A `dict` containing the Unity response. The exact shape depends on the action.
## Examples
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
### 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.
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
:::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.
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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, asset_gen, core, docs, probuilder, profiling, scripting_ext, testing, ui, vfx |
## Returns
A `dict` containing the Unity response. The exact shape depends on the action.
## Examples
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
:::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.
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `core` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,8 @@
{
"label": "docs",
"link": {
"type": "doc",
"id": "reference/tools/docs/index"
},
"collapsed": true
}
@@ -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.
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `docs` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `docs` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
+91
View File
@@ -0,0 +1,91 @@
---
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 `<!-- examples:start --><!-- examples:end -->` 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` &nbsp; (1 tool)
Animator control & AnimationClip creation
- **[`manage_animation`](./animation/manage_animation.md)** — Manage Unity animation: Animator control and AnimationClip creation.
## `asset_gen` &nbsp; (4 tools)
AI asset generation 3D model gen/import & 2D image gen (bring-your-own-key)
- **[`generate_image`](./asset_gen/generate_image.md)** — Generate 2D images with AI providers (fal.ai, OpenRouter) and import them as textures/sprites into the Unity project.
- **[`generate_model`](./asset_gen/generate_model.md)** — Generate 3D models with AI providers (Tripo, Meshy) and import them into the Unity project.
- **[`import_model`](./asset_gen/import_model.md)** — Import 3D models from the Sketchfab marketplace into the Unity project.
- **[`import_model_file`](./asset_gen/import_model_file.md)** — Import a local 3D model file that already exists on disk (e.g. an FBX/OBJ/glTF exported from Blender or another DCC tool) into the Unity project.
## `core` &nbsp; (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` &nbsp; (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` &nbsp; (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` &nbsp; (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` &nbsp; (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` &nbsp; (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` &nbsp; (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` &nbsp; (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).
@@ -0,0 +1,8 @@
{
"label": "probuilder",
"link": {
"type": "doc",
"id": "reference/tools/probuilder/index"
},
"collapsed": true
}
@@ -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.
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `probuilder` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,8 @@
{
"label": "profiling",
"link": {
"type": "doc",
"id": "reference/tools/profiling/index"
},
"collapsed": true
}
@@ -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.
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `profiling` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,8 @@
{
"label": "scripting_ext",
"link": {
"type": "doc",
"id": "reference/tools/scripting_ext/index"
},
"collapsed": true
}
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `scripting_ext` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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.
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `scripting_ext` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,8 @@
{
"label": "testing",
"link": {
"type": "doc",
"id": "reference/tools/testing/index"
},
"collapsed": true
}
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `testing` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -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.
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `testing` &nbsp;·&nbsp; **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
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,8 @@
{
"label": "ui",
"link": {
"type": "doc",
"id": "reference/tools/ui/index"
},
"collapsed": true
}
+11
View File
@@ -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).
@@ -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 `<!-- examples:start --><!-- examples:end -->` blocks — the generator (`tools/generate_docs_reference.py`) will overwrite them.
**Group:** `ui` &nbsp;·&nbsp; **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 <ui:Style> (with the ui: namespace prefix) in UXML, not bare <Style>. UI Builder will fail to open files that use <Style> without the prefix.
## Parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `action` | `Literal['ping', 'create', 'read', 'update', 'delete', 'attach_ui_document', 'detach_ui_document', 'create_panel_settings', 'update_panel_settings', 'get_visual_tree', 'render_ui', 'link_stylesheet', 'list', 'modify_visual_element']` | yes | Action to perform. |
| `path` | `str \| None` | — | Assets-relative path (e.g., 'Assets/UI/MainMenu.uxml' or 'Assets/UI/Styles.uss'). For render_ui: optional UXML path to render directly without a scene GameObject. |
| `contents` | `str \| None` | — | File content (UXML or USS markup). Plain text - encoding handled automatically. |
| `target` | `str \| None` | — | Target GameObject name or path for attach_ui_document / get_visual_tree / render_ui. |
| `source_asset` | `str \| None` | — | Path to UXML VisualTreeAsset (e.g., 'Assets/UI/MainMenu.uxml'). |
| `panel_settings` | `str \| None` | — | Path to PanelSettings asset. Auto-creates default if omitted. |
| `sort_order` | `int \| None` | — | UIDocument sort order (default 0). |
| `scale_mode` | `Literal['ConstantPixelSize', 'ConstantPhysicalSize', 'ScaleWithScreenSize'] \| None` | — | Panel scale mode. Legacy shorthand; prefer using 'settings' dict. |
| `reference_resolution` | `dict[str, int] \| None` | — | Reference resolution as {width, height}. Legacy shorthand; prefer using 'settings' dict. |
| `settings` | `dict[str, Any] \| None` | — | Generic PanelSettings properties dict for create_panel_settings. Keys: scaleMode (ConstantPixelSize\|ConstantPhysicalSize\|ScaleWithScreenSize), referenceResolution ({width,height}), screenMatchMode (MatchWidthOrHeight\|ShrinkToFit\|ExpandToFill), match (0-1 float), referenceDpi, fallbackDpi, sortingOrder, targetDisplay, clearColor (bool), colorClearValue (#RRGGBB or {r,g,b,a}), clearDepthStencil, themeStyleSheet (asset path), dynamicAtlasSettings ({minAtlasSize,maxAtlasSize,maxSubTextureSize,activeFilters}). |
| `max_depth` | `int \| None` | — | Max depth to traverse visual tree (default 10). |
| `width` | `int \| None` | — | Render width in pixels (default 1920). For render_ui. |
| `height` | `int \| None` | — | Render height in pixels (default 1080). For render_ui. |
| `include_image` | `bool \| None` | — | Return inline base64 PNG in the response (default false). For render_ui. |
| `max_resolution` | `int \| None` | — | Max resolution for inline base64 image (default 640). For render_ui. |
| `screenshot_file_name` | `str \| None` | — | Custom file name for the render output (default: auto-generated). For render_ui. |
| `output_folder` | `str \| None` | — | Optional folder for the render 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). For render_ui. |
| `stylesheet` | `str \| None` | — | Path to USS stylesheet to link (e.g., 'Assets/UI/Styles.uss'). For link_stylesheet. |
| `filter_type` | `str \| None` | — | Filter UI assets by type: 'uxml', 'uss', 'PanelSettings', or omit for all. For list. |
| `page_size` | `int \| None` | — | Number of results per page (default 50). For list. |
| `page_number` | `int \| None` | — | Page number, 1-based (default 1). For list. |
| `element_name` | `str \| None` | — | Name of the visual element to modify (the 'name' attribute in UXML). For modify_visual_element. |
| `text` | `str \| None` | — | New text content for Label/Button elements. For modify_visual_element. |
| `add_classes` | `list[str] \| None` | — | USS class names to add to the element. For modify_visual_element. |
| `remove_classes` | `list[str] \| None` | — | USS class names to remove from the element. For modify_visual_element. |
| `toggle_classes` | `list[str] \| None` | — | USS class names to toggle on the element. For modify_visual_element. |
| `style` | `dict[str, Any] \| None` | — | Inline styles to set (e.g., {'backgroundColor': '#FF0000', 'fontSize': 24}). For modify_visual_element. |
| `enabled` | `bool \| None` | — | Set element enabled/disabled state. For modify_visual_element. |
| `visible` | `bool \| None` | — | Set element visibility (display: flex/none). For modify_visual_element. |
| `tooltip` | `str \| None` | — | Set element tooltip text. For modify_visual_element. |
## Returns
A `dict` containing the Unity response. The exact shape depends on the action.
## Examples
<!-- examples:start -->
*No examples yet. Add usage examples here — they will be preserved across regenerations.*
<!-- examples:end -->
@@ -0,0 +1,8 @@
{
"label": "vfx",
"link": {
"type": "doc",
"id": "reference/tools/vfx/index"
},
"collapsed": true
}
+13
View File
@@ -0,0 +1,13 @@
---
title: "vfx tools"
sidebar_label: "vfx"
description: "MCP for Unity tools in the vfx group."
---
# `vfx` tools
Visual effects VFX Graph, shaders, procedural textures
- **[`manage_shader`](./manage_shader.md)** — Manages shader scripts in Unity (create, read, update, delete).
- **[`manage_texture`](./manage_texture.md)** — Procedural texture generation for Unity.
- **[`manage_vfx`](./manage_vfx.md)** — Manage Unity VFX components (ParticleSystem, VisualEffect, LineRenderer, TrailRenderer).

Some files were not shown because too many files have changed in this diff Show More