Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
a5a99ee
fix: don't let stale path-variant keys shadow Claude registrations
crowdedfire Jul 20, 2026
2d00ed2
fix: resolve Claude registrations for git-worktree Unity projects
crowdedfire Jul 20, 2026
8368342
fix(stdio): refresh port registry before reconnect backoff
SeojunKim-pumisj Aug 25, 2026
8f0e5b1
fix: suppress broker command resends instead of running the work twice
ananttheant Sep 1, 2026
49f9790
fix: read the command queue under its lock in the resend test
ananttheant Sep 1, 2026
1041e03
chore: sync main (v10.2.0) into beta
actions-user Sep 1, 2026
20969c0
chore: set beta version to 10.2.1-beta.1 after release v10.2.0
actions-user Sep 1, 2026
b2fd964
Merge pull request #1368 from CoplayDev/sync/main-v10.2.0-into-beta-3…
github-actions[bot] Sep 1, 2026
3147b0d
perf(discovery): drop the redundant assembly walk from tool discovery…
ananttheant Sep 2, 2026
2c8406a
fix(discovery): break full-name ties by assembly when ordering tool t…
ananttheant Sep 2, 2026
eeb4f90
feat: add Blender Bridge tool with a Generative-tab settings panel
Seungpyo1007 Sep 2, 2026
e0d7577
feat(server): expose blender_bridge tool and CLI
Seungpyo1007 Sep 2, 2026
4e6bd57
test: cover blender_bridge routing, socket parsing and addons dir det…
Seungpyo1007 Sep 2, 2026
35580e8
docs: regenerate tool reference for blender_bridge
Seungpyo1007 Sep 2, 2026
06c82bd
fix: address review feedback on Blender Bridge
Seungpyo1007 Sep 2, 2026
1853d01
fix: unique temp file names, redacted remote URLs, updated tool count
Seungpyo1007 Sep 2, 2026
4b9d168
feat: play imported clips, save prefabs, Bloom setup and side-by-side…
Seungpyo1007 Sep 2, 2026
c90f63d
ci: make compile-check.sh work from a Windows checkout
Scriptwonder Sep 2, 2026
df0cba7
chore: keep Server/uv.lock in step with the version bump
Scriptwonder Sep 2, 2026
5ad752e
fix(editor): pin stdio for the CI boot session without rewriting Edit…
Scriptwonder Sep 2, 2026
e9372a1
fix(harness): build editor paths with the target platform's separator
Scriptwonder Sep 2, 2026
9c6b20d
fix(server): close three audit findings on the remote-hosted auth sur…
Scriptwonder Sep 2, 2026
e87e5d0
ci: stop xtrace from echoing Unity credentials during activation
Scriptwonder Sep 2, 2026
7fda9b3
fix: fail setup_bloom when Bloom is not added; redact query and fragm…
Seungpyo1007 Sep 2, 2026
0f33a2a
Merge pull request #1369 from ananttheant/perf/typecache-tool-discovery
Scriptwonder Sep 2, 2026
dadd26e
chore: update Unity package to beta version 10.2.1-beta.2
actions-user Sep 2, 2026
c2c101b
Merge pull request #1377 from CoplayDev/beta-version-10.2.1-beta.2-33…
github-actions[bot] Sep 2, 2026
cfcd488
Merge pull request #1280 from conjoyco/fix/claude-config-key-matching
Scriptwonder Sep 2, 2026
a3d503a
chore: update Unity package to beta version 10.2.1-beta.3
actions-user Sep 2, 2026
acf5e3d
Merge pull request #1378 from CoplayDev/beta-version-10.2.1-beta.3-33…
github-actions[bot] Sep 2, 2026
a4a003e
fix: address review comments on the hardening PR
Scriptwonder Sep 2, 2026
c026cb4
fix(read_console): stop the Console window's filters from hiding entries
KamilDev Aug 23, 2026
353cb22
Merge pull request #1361 from ananttheant/fix/stdio-suppress-broker-r…
Scriptwonder Sep 5, 2026
bc9d156
chore: update Unity package to beta version 10.2.1-beta.4
actions-user Sep 5, 2026
dbc9e7c
Merge pull request #1381 from CoplayDev/beta-version-10.2.1-beta.4-33…
github-actions[bot] Sep 5, 2026
560ad14
Merge pull request #1342 from KamilDev/fix/read-console-ui-filter-leak
Scriptwonder Sep 5, 2026
de879ff
Merge pull request #1345 from SeojunKim-pumisj/fix/refresh-stdio-port…
Scriptwonder Sep 5, 2026
16568a8
chore: update Unity package to beta version 10.2.1-beta.5
actions-user Sep 5, 2026
5957b73
Merge pull request #1382 from CoplayDev/beta-version-10.2.1-beta.5-33…
github-actions[bot] Sep 5, 2026
2e74eac
Merge pull request #1376 from Scriptwonder/fix/hardening-2026-09-02
Scriptwonder Sep 5, 2026
70222ac
feat(setup): show git status in the setup window and explain the Git-…
Scriptwonder Sep 3, 2026
56f4e45
chore: update Unity package to beta version 10.2.1-beta.6
actions-user Sep 5, 2026
311536b
Merge pull request #1384 from CoplayDev/beta-version-10.2.1-beta.6-33…
github-actions[bot] Sep 5, 2026
dfe6795
fix(setup): keep the optional row neutral and correct the safe.direct…
shutong-bot Sep 5, 2026
9d93c42
Merge pull request #1383 from Scriptwonder/feat/git-prerequisite-status
Scriptwonder Sep 5, 2026
bbc0caa
test(setup): look up UpdateDependencyStatus as static too
Scriptwonder Sep 5, 2026
2fcc179
Merge pull request #1385 from Scriptwonder/fix/characterization-stati…
Scriptwonder Sep 5, 2026
a0f59c2
fix: make refresh_unity's compile wait observable across the domain r…
KamilDev Aug 26, 2026
2513976
fix: resolve the compile-start wait inline when a reload is already i…
KamilDev Aug 26, 2026
229b611
fix: report `compile_started` and gate the compile-start wait on `wai…
KamilDev Sep 6, 2026
19966ba
fix: resolve the compile-start wait on `compilationStarted` so the re…
KamilDev Sep 6, 2026
da91669
fix(dependencies): resolve Windows Python behind Store App execution …
Pikaswelt Sep 7, 2026
246c195
fix: find Volumes through UnityFindObjectsCompat for the 2021.3/2022.…
Seungpyo1007 Sep 7, 2026
ee752e6
fix: use a TextField for the Blender port so the panel compiles on 20…
Seungpyo1007 Sep 7, 2026
d3b7cfb
fix: normalize line endings in the generated Blender export script
Seungpyo1007 Sep 7, 2026
cf21a72
Merge remote-tracking branch 'upstream/beta' into pr/blender-bridge
Seungpyo1007 Sep 7, 2026
538c170
test: cover every blender CLI command
Seungpyo1007 Sep 7, 2026
43810be
feat: add Trae CN MCP client configurator
8ddieHu0314 Sep 8, 2026
f9e3e7b
fix(animation): resolve the Animator on child objects, not just the e…
BurakErdemci Aug 21, 2026
4060ca1
docs(cli): the animation commands no longer require the Animator on t…
BurakErdemci Aug 21, 2026
e447a8e
Fix Unity 6000.6 InstanceIDToObjectCompat NotImplementedException
claude Sep 13, 2026
990f446
docs(reference): add run_tests and get_test_job examples
RizgarOzan Sep 13, 2026
18956e7
docs(reference): add unity_docs and unity_reflect examples
RizgarOzan Sep 13, 2026
1c3995f
docs(reference): fix unity_docs lookup example package-docs claim
RizgarOzan Sep 14, 2026
1a31da8
docs(reference): describe full unity_reflect get_type response
RizgarOzan Sep 14, 2026
f8e58c6
fix(roslyn): drop Workspaces-layer formatting so USE_ROSLYN compiles …
comedianhhh Sep 15, 2026
143837f
test(setup): document RoslynAsmdefReferenceTests helpers
comedianhhh Sep 17, 2026
3aa5bb1
docs(skill): say where to look when a tool is not in the tool list
RizgarOzan Sep 18, 2026
12a1638
docs(skill): note tool-group defaults differ between HTTP and stdio
RizgarOzan Sep 18, 2026
4d57cd1
Merge pull request #1406 from RizgarOzan/docs/skill-custom-tool-fallback
Scriptwonder Sep 19, 2026
6b9d8c9
Merge pull request #1392 from 8ddieHu0314/feat/support-trae-cn-solo
Scriptwonder Sep 20, 2026
6320265
Merge pull request #1404 from comedianhhh/fix/roslyn-formatting-needs…
Scriptwonder Sep 20, 2026
17a270f
fix(ci): avoid publishing Unity results with a read-only token
Scriptwonder Sep 22, 2026
25cd9bf
fix(testing): target and restore Windows focus nudges safely
Scriptwonder Sep 22, 2026
6d0fe54
fix(ci): gate Unity results on runner outcome and valid NUnit output
Scriptwonder Sep 22, 2026
ff712fa
fix(tests): bound focus recovery per job across concurrent polls
Scriptwonder Sep 22, 2026
9f8152c
fix(tests): recover test job callbacks and terminal errors after reload
Scriptwonder Sep 22, 2026
836b2ab
docs(reference): note declared-only get_type lists and search result cap
RizgarOzan Sep 27, 2026
fe33c98
docs(reference): correct get_test_job result and clear_stuck notes
RizgarOzan Sep 27, 2026
8e34e75
docs(reference): say when get_test_job sets error and failures_capped
RizgarOzan Sep 27, 2026
4742860
docs(reference): list result fields and all get_test_job error cases
RizgarOzan Sep 27, 2026
8be7d96
Merge pull request #1401 from RizgarOzan/docs/docs-tool-examples
Scriptwonder Sep 27, 2026
d51ac4a
feat(clients): auto-configure Pi
frostebite Sep 28, 2026
f8d3088
Merge pull request #1399 from yuseres/fix/6000-6-instanceid-resolve
Scriptwonder Sep 30, 2026
ba8a975
Merge pull request #1400 from RizgarOzan/docs/testing-tool-examples
Scriptwonder Sep 30, 2026
a9670cf
fix: serialize Unity.Mathematics structs by their fields, not their s…
RizgarOzan Oct 1, 2026
081adf3
Merge pull request #1337 from BurakErdemci/fix/animator-child-lookup
Scriptwonder Oct 2, 2026
674ffbf
Merge pull request #1347 from KamilDev/fix/compile-edges-survive-doma…
Scriptwonder Oct 2, 2026
5eefb7a
Merge pull request #1418 from RizgarOzan/fix/unity-mathematics-serial…
Scriptwonder Oct 2, 2026
1a08a10
Merge pull request #1414 from frostebite/feat/pi-client-configurator
Scriptwonder Oct 2, 2026
a1ae80a
fix(tests): adapt Unity test fixtures and validate CI results
Scriptwonder Oct 2, 2026
91eb0f4
Merge pull request #1389 from Pikaswelt/fix/windows-pyenv-detection
Scriptwonder Oct 2, 2026
f11fc1d
fix(ci): activate and return Unity licenses consistently in E2E
Scriptwonder Oct 2, 2026
5fb7703
fix(ci): verify NUnit records and report domain test failures
Scriptwonder Oct 2, 2026
5fcd671
fix(ci): prepare a saved E2E scene and retain Unity diagnostics
Scriptwonder Oct 2, 2026
b128e61
fix(tests): isolate transport fixtures from the resident MCP session
Scriptwonder Oct 2, 2026
b7a2f5a
fix(ci): preserve reports when retry scene preparation fails
Scriptwonder Oct 2, 2026
0abe62d
fix(ci): report complete Unity results and preserve skipped states
Scriptwonder Oct 2, 2026
5b77b6b
fix: upper-case Roslyn severity with the invariant culture
RizgarOzan Oct 3, 2026
c040d6d
Merge pull request #1420 from RizgarOzan/fix/roslyn-severity-invariant
Scriptwonder Oct 3, 2026
6abce3e
Merge pull request #1410 from CoplayDev/codex/fix-uncovered-p1-issues
Scriptwonder Oct 3, 2026
3daf3d5
fix(windows): restore focus to the original window by handle
SeojunKim-pumisj Sep 22, 2026
3bb0ace
Merge pull request #1409 from SeojunKim-pumisj/fix/windows-focus-rest…
Scriptwonder Oct 3, 2026
9e4af8e
fix: protect Blender Git diagnostics and align HTTP timeouts
Scriptwonder Oct 3, 2026
837f2d1
feat: discover and validate current fal asset models
Scriptwonder Oct 3, 2026
5836034
Merge pull request #1375 from Seungpyo1007/pr/blender-bridge
Scriptwonder Oct 3, 2026
e34b2c8
docs: shorten asset model catalog guidance
Scriptwonder Oct 3, 2026
2b8d046
Discover complete fal and OpenRouter catalogs with on-demand compatib…
Scriptwonder Oct 3, 2026
93bd974
Bound recursive nullable schema parsing
Scriptwonder Oct 3, 2026
9b9393e
Fix asset model dropdowns: no slash submenus, capped menus, one fal k…
Scriptwonder Oct 3, 2026
d173c5e
Hide the empty license caveat box when no model is selected
Scriptwonder Oct 3, 2026
2c109c8
Keep generation preflight out of the catalog refresh queue; raise cac…
Scriptwonder Oct 4, 2026
c7c37a2
Merge beta into PR #1421 (retargeted to beta)
Scriptwonder Oct 4, 2026
ff7f6d3
Merge pull request #1421 from Scriptwonder/codex/dynamic-fal-model-ca…
Scriptwonder Oct 4, 2026
021a8e6
Blender Bridge panel: auto-detect the addon and report the real insta…
Scriptwonder Oct 4, 2026
842aa4b
Merge pull request #1422 from Scriptwonder/feat/blender-bridge-detect…
Scriptwonder Oct 4, 2026
d3e36c3
test: end ExecPathBatchShimTests.cs.meta with a newline so Unity 6 ca…
Scriptwonder Oct 4, 2026
7f481f3
Merge pull request #1423 from CoplayDev/fix/execpath-shim-meta-newline
Scriptwonder Oct 4, 2026
3d034ab
chore: merge beta into main for release
actions-user Oct 4, 2026
e8bf07d
chore: bump version to 10.3.0
actions-user Oct 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .claude/skills/unity-mcp-skill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ Before applying a template:
5. Verify results → read_console, manage_camera(action="screenshot"), resources
```

**If a tool you need is not in your tool list, it is not necessarily missing.** Check these before troubleshooting the connection:

- **Project custom tools** (C# `[McpForUnityTool]`): with project-scoped tools enabled on the server, they are *not* callable by name. List them via `mcpforunity://custom-tools` and run them with `execute_custom_tool(tool_name="...", parameters={...})`. With it disabled, they are registered as ordinary tools and appear in your list.
- **Disabled tool groups**: over HTTP, a session starts with only the `core` group enabled. Over stdio, all groups start enabled and are then synced to the tool toggles in the Unity editor, so a tool can still be hidden. `manage_tools(action="list_groups")` shows the groups, `manage_tools(action="activate", group="...")` enables one.

## Critical Best Practices

### 1. After Writing/Editing Scripts: Wait for Compilation and Check Console
Expand Down
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Shell scripts must keep LF: tools/compile-check.sh runs inside a Linux container,
# where CRLF would fail with "bad interpreter".
*.sh text eol=lf

# compile-check.sh reads these line by line; a CR from a core.autocrlf checkout would
# become part of every -define: symbol and reference name.
tools/compile-defines.txt text eol=lf
tools/compile-refs/*.txt text eol=lf
96 changes: 26 additions & 70 deletions .github/workflows/e2e-bridge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ on:
- "Server/src/**"
- "Server/tests/e2e/**"
- "tools/local_harness.py"
- "tools/ci_unity_license.py"
- "tools/tests/test_ci_unity_license.py"
- ".github/workflows/e2e-bridge.yml"

permissions:
Expand Down Expand Up @@ -50,7 +52,9 @@ jobs:
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
run: |
set -e
if [ -n "$UNITY_LICENSE" ] || { [ -n "$UNITY_EMAIL" ] && [ -n "$UNITY_PASSWORD" ] && [ -n "$UNITY_SERIAL" ]; }; then
# Only absent secrets skip a fork run. Partial configuration must fail
# explicitly in prepare, rather than silently look like missing access.
if [ -n "$UNITY_LICENSE$UNITY_EMAIL$UNITY_PASSWORD$UNITY_SERIAL" ]; then
echo "unity_ok=true" >> "$GITHUB_OUTPUT"
else
echo "unity_ok=false" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -90,87 +94,39 @@ jobs:
echo "$GITHUB_WORKSPACE/.venv/bin" >> "$GITHUB_PATH"
uv pip install -e Server
# --- License staging (mirrors claude-nl-suite.yml) ---
- name: Decide license sources
id: lic
shell: bash
# Activate with the same pinned GameCI implementation that runs our tests.
# Personal account credentials do not require a professional serial key.
- name: Prepare Unity license and activation helpers
id: prepare_license
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
run: |
set -eu
use_ulf=false; use_ebl=false
[[ -n "${UNITY_LICENSE:-}" ]] && use_ulf=true
[[ -n "${UNITY_EMAIL:-}" && -n "${UNITY_PASSWORD:-}" && -n "${UNITY_SERIAL:-}" ]] && use_ebl=true
echo "use_ulf=$use_ulf" >> "$GITHUB_OUTPUT"
echo "use_ebl=$use_ebl" >> "$GITHUB_OUTPUT"
- name: Stage Unity .ulf license (from secret)
if: steps.lic.outputs.use_ulf == 'true'
id: ulf
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
shell: bash
run: |
set -eu
mkdir -p "$RUNNER_TEMP/unity-license-ulf" "$RUNNER_TEMP/unity-local/Unity"
f="$RUNNER_TEMP/unity-license-ulf/Unity_lic.ulf"
if printf "%s" "$UNITY_LICENSE" | base64 -d - >/dev/null 2>&1; then
printf "%s" "$UNITY_LICENSE" | base64 -d - > "$f"
else
printf "%s" "$UNITY_LICENSE" > "$f"
fi
chmod 600 "$f" || true
if grep -qi '<Signature>' "$f"; then
cp -f "$f" "$RUNNER_TEMP/unity-local/Unity/Unity_lic.ulf"
echo "ok=true" >> "$GITHUB_OUTPUT"
else
echo "ok=false" >> "$GITHUB_OUTPUT"
fi
run: python3 tools/ci_unity_license.py prepare

- name: Activate Unity (EBL via container)
if: steps.lic.outputs.use_ebl == 'true'
shell: bash
- name: Activate Unity license
env:
UNITY_IMAGE: ${{ env.UNITY_IMAGE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/unity-config" "$RUNNER_TEMP/unity-local"
docker run --rm --network host \
-e HOME=/root -e UNITY_EMAIL -e UNITY_PASSWORD -e UNITY_SERIAL \
-v "$RUNNER_TEMP/unity-config:/root/.config/unity3d" \
-v "$RUNNER_TEMP/unity-local:/root/.local/share/unity3d" \
"$UNITY_IMAGE" bash -lc '
set -euxo pipefail
/opt/unity/Editor/Unity -batchmode -nographics -logFile - \
-username "$UNITY_EMAIL" -password "$UNITY_PASSWORD" -serial "$UNITY_SERIAL" -quit || true
'
run: python3 tools/ci_unity_license.py activate

- name: Warm up project (import Library once)
shell: bash
env:
UNITY_IMAGE: ${{ env.UNITY_IMAGE }}
ULF_OK: ${{ steps.ulf.outputs.ok }}
run: |
set -euxo pipefail
manual_args=()
if [[ "${ULF_OK:-false}" == "true" ]]; then
manual_args=(-manualLicenseFile "/root/.local/share/unity3d/Unity/Unity_lic.ulf")
fi
docker run --rm --network host \
-e HOME=/root \
-v "$RUNNER_TEMP/unity-machine-id:/etc/machine-id:ro" \
-v "${{ github.workspace }}:${{ github.workspace }}" -w "${{ github.workspace }}" \
-v "$RUNNER_TEMP/unity-config:/root/.config/unity3d" \
-v "$RUNNER_TEMP/unity-local:/root/.local/share/unity3d" \
-v "$RUNNER_TEMP/unity-cache:/root/.cache/unity3d" \
"$UNITY_IMAGE" /opt/unity/Editor/Unity -batchmode -nographics -logFile - \
-projectPath "${{ github.workspace }}/TestProjects/UnityMCPTests" \
"${manual_args[@]}" -quit
-quit
- name: Clean old MCP status
run: |
Expand All @@ -182,32 +138,32 @@ jobs:
shell: bash
env:
UNITY_IMAGE: ${{ env.UNITY_IMAGE }}
ULF_OK: ${{ steps.ulf.outputs.ok }}
run: |
set -euxo pipefail
# In --ci mode the harness drives the DockerLauncher: it runs the same
# docker container (repo .unity-mcp status dir, docker liveness/teardown,
# log redaction), waits on the status file, derives the instance, then
# runs the smoke + EditMode + PlayMode legs over the bridge.
license_args=()
if [[ "${ULF_OK:-false}" == "true" ]]; then
license_args=(--editor-arg -manualLicenseFile \
--editor-arg "/root/.local/share/unity3d/Unity/Unity_lic.ulf")
fi
python3 tools/local_harness.py --ci \
--legs smoke,editmode,playmode \
--project-path TestProjects/UnityMCPTests \
--reports reports \
"${license_args[@]}"
--reports reports
- name: Unity logs on failure
if: failure()
run: docker logs unity-mcp --tail 200 | sed -E 's/((email|serial|license|password|token)[^[:space:]]*)/[REDACTED]/Ig' || true
- name: Return Unity license seat
if: always() && steps.prepare_license.outcome == 'success'
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
run: python3 tools/ci_unity_license.py return

- name: Upload E2E report
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-bridge-report
path: reports/junit-*.xml
# The harness snapshots redacted Editor logs before removing its container.
path: |
reports/junit-*.xml
reports/unity-editor-*.log
if-no-files-found: ignore
7 changes: 5 additions & 2 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@ jobs:
- name: Install dependencies
run: |
cd Server
uv sync
uv pip install -e ".[dev]"
# --locked fails if uv.lock disagrees with pyproject.toml instead of silently
# re-resolving, so a dependency or version bump that forgot `uv lock` shows up here.
# The dev extra is resolved in the lock too, so pytest runs against pinned versions
# instead of whatever `uv pip install` would fetch today.
uv sync --locked --extra dev
- name: Run tests with coverage
run: |
Expand Down
8 changes: 7 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ from services.registry import mcp_for_unity_tool

@mcp_for_unity_tool(
description="Does something in Unity.",
group="core", # core (default), vfx, animation, ui, scripting_ext, testing, probuilder, profiling, docs
group="core", # core (default), vfx, animation, ui, scripting_ext, testing, probuilder, profiling, docs, asset_gen
)
async def manage_something(
ctx: Context,
Expand Down Expand Up @@ -165,6 +165,12 @@ cd Server && uv run pytest tests/ -k "test_create_material" -v
# Local multi-version compile check (parity with CI matrix, see tools/unity-versions.json)
tools/check-unity-versions.sh # compile-only across installed Unity Hub editors
tools/check-unity-versions.sh --full # full EditMode test run

# License-free Roslyn compile of MCPForUnity, the same gate compile-check.yml runs on every PR.
# No Editor launch, ~1 min per version. EXTRA_REFS must hold Newtonsoft.Json.dll and
# nunit.framework.dll (copy them from TestProjects/UnityMCPTests/Library/PackageCache);
# the script header has the full recipe, including the Windows/Git Bash form.
UNITY_DATA=/path/to/Editor/Data UNITY_VERSION=2021.3.45f2 EXTRA_REFS=/path/to/refs tools/compile-check.sh
```

#### Local headless test harness
Expand Down
98 changes: 98 additions & 0 deletions MCPForUnity/Editor/Clients/Configurators/PiConfigurator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.IO;
using MCPForUnity.Editor.Models;

namespace MCPForUnity.Editor.Clients.Configurators
{
/// <summary>
/// Pi (pi.dev) configurator.
///
/// Two things make Pi different from every other JSON client in this folder, and both are
/// load-bearing rather than cosmetic:
///
/// 1. <b>Pi has no built-in MCP client.</b> As of pi 0.84.x there is no <c>mcp</c> subcommand,
/// no <c>--mcp-config</c> equivalent, and no <c>mcp.json</c> reader anywhere in the
/// distributed package; its own README states "No MCP. Build CLI tools with READMEs, or
/// build an extension that adds MCP support." Reaching this server from Pi therefore
/// requires an MCP extension, and the <c>unityMCP</c> entry written below is what that
/// extension reads. <see cref="GetInstallationSteps"/> names the extension explicitly,
/// because on Pi a config file alone is a silent no-op — the exact "configured, enabled, and
/// silently providing nothing" shape this window exists to prevent.
///
/// 2. <b>The file is shared, so presence cannot be inferred from it.</b> Pi MCP extensions read
/// the tool-agnostic <c>~/.config/mcp/mcp.json</c>, not a Pi-owned path. That makes the
/// inherited <c>IsInstalled</c> ("does the config path's parent directory exist") wrong in
/// both directions — see <see cref="IsInstalled"/>.
/// </summary>
public class PiConfigurator : JsonFileMcpConfigurator
{
public PiConfigurator() : base(new McpClient
{
name = "Pi",
windowsConfigPath = GetSharedMcpConfigPath(),
macConfigPath = GetSharedMcpConfigPath(),
linuxConfigPath = GetSharedMcpConfigPath()
})
{ }

/// <summary>
/// Pi-exclusive presence check, deliberately NOT the inherited
/// <c>ParentDirectoryExists(GetConfigPath())</c>.
///
/// <para>
/// The config path here is a SHARED, tool-agnostic file. Its parent directory therefore says
/// nothing about whether Pi exists: a Cursor or Claude Code user has a
/// <c>~/.config/mcp</c> tree without ever installing Pi, and a Pi user who has not yet
/// configured any MCP server has no <c>~/.config/mcp</c> at all. Keying detection on that
/// path would make "Configure All Detected Clients" offer Pi on machines that do not have
/// it while skipping the exact machines this configurator exists to fix.
/// </para>
///
/// <para>
/// Pi's own agent directory is the correct marker: pi creates it on first run for settings,
/// sessions and auth, nothing else writes there, and <c>PI_CODING_AGENT_DIR</c> relocates
/// it — so an explicitly relocated install is detected too rather than hardcoding
/// <c>~/.pi</c>.
/// </para>
/// </summary>
public override bool IsInstalled
{
get
{
string agentDir = GetPiAgentDirectory();
return !string.IsNullOrEmpty(agentDir) && Directory.Exists(agentDir);
}
}

public override IList<string> GetInstallationSteps() => new List<string>
{
"Install an MCP extension for Pi — Pi ships no MCP client of its own:\npi install npm:pi-mcp-adapter",
"Restart Pi so the extension loads (extensions are read at startup)",
"Paste the configuration JSON into the file at the path above, or use Configure",
"Start Pi and ask it to search MCP — e.g. \"search MCP for manage_gameobject\""
};

/// <summary>The tool-agnostic shared MCP config Pi MCP extensions read, in the user's home.</summary>
private static string GetSharedMcpConfigPath()
{
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
return Path.Combine(home, ".config", "mcp", "mcp.json");
}

/// <summary>
/// Pi's agent directory: <c>$PI_CODING_AGENT_DIR</c> when set (Pi's own documented
/// relocation override), else <c>~/.pi/agent</c>. Null when the home directory cannot be
/// resolved, which callers must treat as "not installed" rather than as a match.
/// </summary>
private static string GetPiAgentDirectory()
{
string overrideDir = Environment.GetEnvironmentVariable("PI_CODING_AGENT_DIR");
if (!string.IsNullOrWhiteSpace(overrideDir))
return overrideDir.Trim();

string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
return string.IsNullOrEmpty(home) ? null : Path.Combine(home, ".pi", "agent");
}
}
}
11 changes: 11 additions & 0 deletions MCPForUnity/Editor/Clients/Configurators/PiConfigurator.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions MCPForUnity/Editor/Clients/Configurators/TraeCnConfigurator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.IO;
using MCPForUnity.Editor.Models;

namespace MCPForUnity.Editor.Clients.Configurators
{
public class TraeCnConfigurator : JsonFileMcpConfigurator
{
public TraeCnConfigurator() : base(new McpClient
{
name = "Trae CN",
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Trae CN", "User", "mcp.json"),
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Trae CN", "User", "mcp.json"),
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "Trae CN", "User", "mcp.json"),
})
{ }

public override IList<string> GetInstallationSteps() => new List<string>
{
"Open Trae CN and go to Settings > MCP",
"Select Add Server > Add Manually",
"Paste the JSON or point to the mcp.json file\n"+
"Windows: %AppData%\\Trae CN\\User\\mcp.json\n" +
"macOS: ~/Library/Application Support/Trae CN/User/mcp.json\n" +
"Linux: ~/.config/Trae CN/User/mcp.json\n",
"Save and restart Trae CN"
};
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading