Skip to content

Commit 31d4816

Browse files
authored
Merge pull request #525 from IvanMurzak/ci/unity-with-claude
2 parents 8216ab5 + de4f587 commit 31d4816

21 files changed

Lines changed: 669 additions & 76 deletions
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
# ┌──────────────────────────────────────────────────────────────────┐
2+
# │ Author: Ivan Murzak (https://github.com/IvanMurzak) │
3+
# │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
4+
# │ Copyright (c) 2025 Ivan Murzak │
5+
# │ Licensed under the Apache License, Version 2.0. │
6+
# │ See the LICENSE file in the project root for more information. │
7+
# └──────────────────────────────────────────────────────────────────┘
8+
9+
name: "Setup Unity MCP"
10+
description: "Start MCP Server and Unity Editor in Docker containers with license activation"
11+
12+
inputs:
13+
unity-email:
14+
description: "Unity account email for license activation"
15+
required: true
16+
unity-password:
17+
description: "Unity account password for license activation"
18+
required: true
19+
unity-project-path:
20+
description: "Relative path to the Unity project folder"
21+
required: false
22+
default: "Unity-MCP-Plugin"
23+
cache-library:
24+
description: "Enable caching of the Unity Library folder"
25+
required: false
26+
default: "true"
27+
unity-mcp-tools:
28+
description: "Comma-separated list of MCP tool IDs to enable (optional)"
29+
required: false
30+
default: ""
31+
32+
runs:
33+
using: "composite"
34+
steps:
35+
- name: Read Unity version
36+
id: unity-version
37+
run: |
38+
UNITY_VERSION=$(grep "^m_EditorVersion:" ${{ inputs.unity-project-path }}/ProjectSettings/ProjectVersion.txt | awk '{print $2}')
39+
echo "unity_version=${UNITY_VERSION}" >> "$GITHUB_OUTPUT"
40+
shell: bash
41+
42+
- name: Cache Unity Library
43+
if: inputs.cache-library == 'true'
44+
uses: actions/cache@v4
45+
with:
46+
path: ${{ inputs.unity-project-path }}/Library
47+
key: unity-library-${{ steps.unity-version.outputs.unity_version }}-ubuntu-base
48+
49+
- name: Start AI-Game-Developer MCP Server
50+
run: |
51+
docker rm -f unity-mcp-server 2>/dev/null || true
52+
53+
docker run -d \
54+
--name unity-mcp-server \
55+
--network host \
56+
-e MCP_PLUGIN_PORT=8080 \
57+
-e MCP_PLUGIN_CLIENT_TRANSPORT=streamableHttp \
58+
-e MCP_AUTHORIZATION=none \
59+
ivanmurzakdev/unity-mcp-server:latest
60+
61+
echo "Waiting for MCP Server to be ready..."
62+
for i in $(seq 1 12); do
63+
sleep 5
64+
if docker logs unity-mcp-server 2>&1 | grep -q "Start listening on port:"; then
65+
echo "MCP Server is ready."; break
66+
fi
67+
echo "Still waiting... ($((i*5))s)"
68+
if [ "$i" -eq 12 ]; then
69+
echo "Timeout waiting for MCP Server"
70+
docker logs unity-mcp-server
71+
exit 1
72+
fi
73+
done
74+
shell: bash
75+
76+
- name: Setup Node.js
77+
uses: actions/setup-node@v4
78+
with:
79+
node-version: "20"
80+
81+
- name: Install unity-license-activate
82+
run: npm install --global unity-license-activate
83+
shell: bash
84+
85+
- name: Generate Unity activation file (.alf)
86+
id: alf
87+
env:
88+
UNITY_VERSION: ${{ steps.unity-version.outputs.unity_version }}
89+
run: |
90+
mkdir -p "${GITHUB_WORKSPACE}/.unity-license"
91+
92+
docker run --rm \
93+
-v "${GITHUB_WORKSPACE}/.unity-license:/output" \
94+
-v "${GITHUB_WORKSPACE}/.unity-license:/root/.local/share/unity3d/Unity/" \
95+
-w /output \
96+
unityci/editor:ubuntu-${UNITY_VERSION}-base-3 \
97+
unity-editor -batchmode -createManualActivationFile -logFile /dev/stdout || true
98+
99+
ALF_FILE=$(find "${GITHUB_WORKSPACE}/.unity-license" -name "*.alf" | head -1)
100+
if [ -z "$ALF_FILE" ]; then
101+
echo "Failed to generate .alf file"
102+
exit 1
103+
fi
104+
echo "Generated ALF file: $ALF_FILE"
105+
echo "alf_path=${ALF_FILE}" >> "$GITHUB_OUTPUT"
106+
shell: bash
107+
108+
- name: Activate Unity license
109+
run: |
110+
MAX_RETRIES=5
111+
for attempt in $(seq 1 $MAX_RETRIES); do
112+
echo "=== License activation attempt $attempt of $MAX_RETRIES ==="
113+
if unity-license-activate \
114+
"${{ inputs.unity-email }}" \
115+
"${{ inputs.unity-password }}" \
116+
"${{ steps.alf.outputs.alf_path }}"; then
117+
echo "unity-license-activate succeeded on attempt $attempt"
118+
break
119+
fi
120+
if [ "$attempt" -eq "$MAX_RETRIES" ]; then
121+
echo "All $MAX_RETRIES license activation attempts failed"
122+
exit 1
123+
fi
124+
echo "Attempt $attempt failed, retrying in 10s..."
125+
sleep 10
126+
done
127+
128+
echo "--- Searching for .ulf file in workspace root ---"
129+
find "${GITHUB_WORKSPACE}" -maxdepth 1 -name "*.ulf" -ls 2>/dev/null
130+
131+
ULF_FILE=$(find "${GITHUB_WORKSPACE}" -maxdepth 1 -name "*.ulf" | head -1)
132+
if [ -z "$ULF_FILE" ]; then
133+
echo "Failed to obtain .ulf license file"
134+
exit 1
135+
fi
136+
echo "Found ULF file: $ULF_FILE"
137+
cp "$ULF_FILE" "${GITHUB_WORKSPACE}/.unity-license/Unity_lic.ulf"
138+
echo "--- License directory contents ---"
139+
ls -la "${GITHUB_WORKSPACE}/.unity-license/"
140+
echo "Unity license activated successfully"
141+
shell: bash
142+
143+
- name: Upload error screenshot
144+
if: failure()
145+
uses: actions/upload-artifact@v4
146+
with:
147+
name: unity-license-error
148+
path: error.png
149+
if-no-files-found: ignore
150+
151+
- name: Start Unity Editor in background
152+
env:
153+
UNITY_VERSION: ${{ steps.unity-version.outputs.unity_version }}
154+
UNITY_MCP_TOOLS: ${{ inputs.unity-mcp-tools }}
155+
run: |
156+
docker rm -f unity-editor 2>/dev/null || true
157+
158+
TOOLS_ENV=""
159+
if [ -n "$UNITY_MCP_TOOLS" ]; then
160+
TOOLS_ENV="-e UNITY_MCP_TOOLS=${UNITY_MCP_TOOLS}"
161+
fi
162+
163+
docker run -d \
164+
--name unity-editor \
165+
--network host \
166+
-e UNITY_MCP_HOST=http://localhost:8080 \
167+
-e UNITY_MCP_KEEP_CONNECTED=true \
168+
-e UNITY_MCP_AUTH_OPTION=none \
169+
${TOOLS_ENV} \
170+
-v "${GITHUB_WORKSPACE}:/workspace" \
171+
-v "${GITHUB_WORKSPACE}/.unity-license:/root/.local/share/unity3d/Unity/" \
172+
unityci/editor:ubuntu-${UNITY_VERSION}-base-3 \
173+
unity-editor -batchmode -projectPath /workspace/${{ inputs.unity-project-path }} -logFile /dev/stdout
174+
175+
echo "Waiting for Unity project to load..."
176+
for i in $(seq 1 48); do
177+
sleep 5
178+
# Fail fast if the container already exited
179+
if [ "$(docker inspect -f '{{.State.Status}}' unity-editor 2>/dev/null)" = "exited" ]; then
180+
echo "Unity Editor container exited early!"
181+
docker logs unity-editor
182+
exit 1
183+
fi
184+
if docker logs unity-editor 2>&1 | grep -q "Loading completed\|Compilation finished\|All assemblies built"; then
185+
echo "Unity is ready."; break
186+
fi
187+
echo "Still waiting... ($((i*5))s)"
188+
if [ "$i" -eq 48 ]; then
189+
echo "Timeout waiting for Unity Editor"
190+
docker logs unity-editor 2>&1 | tail -50
191+
exit 1
192+
fi
193+
done
194+
shell: bash

.github/workflows/bump_version.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# ┌──────────────────────────────────────────────────────────────────┐
2+
# │ Author: Ivan Murzak (https://github.com/IvanMurzak) │
3+
# │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
4+
# │ Copyright (c) 2025 Ivan Murzak │
5+
# │ Licensed under the Apache License, Version 2.0. │
6+
# │ See the LICENSE file in the project root for more information. │
7+
# └──────────────────────────────────────────────────────────────────┘
8+
19
name: bump version
210

311
on:
@@ -20,7 +28,7 @@ jobs:
2028
fi
2129
2230
- name: Checkout repository
23-
uses: actions/checkout@v4
31+
uses: actions/checkout@v5
2432
with:
2533
token: ${{ secrets.GITHUB_TOKEN }}
2634

.github/workflows/claude.yml

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
# ┌──────────────────────────────────────────────────────────────────┐
2+
# │ Author: Ivan Murzak (https://github.com/IvanMurzak) │
3+
# │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
4+
# │ Copyright (c) 2025 Ivan Murzak │
5+
# │ Licensed under the Apache License, Version 2.0. │
6+
# │ See the LICENSE file in the project root for more information. │
7+
# └──────────────────────────────────────────────────────────────────┘
8+
19
name: Claude Code
210

311
on:
12+
workflow_dispatch:
413
issue_comment:
514
types: [created]
615
pull_request_review_comment:
@@ -13,6 +22,7 @@ on:
1322
jobs:
1423
claude:
1524
if: |
25+
github.event_name == 'workflow_dispatch' ||
1626
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
1727
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
1828
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
@@ -33,15 +43,23 @@ jobs:
3343
9.0.x
3444
3545
- name: Checkout repository
36-
uses: actions/checkout@v4
46+
uses: actions/checkout@v5
3747
with:
3848
fetch-depth: 1
3949

50+
- name: Setup Unity MCP
51+
uses: ./.github/actions/setup-unity-mcp
52+
with:
53+
unity-email: ${{ secrets.UNITY_EMAIL }}
54+
unity-password: ${{ secrets.UNITY_PASSWORD }}
55+
unity-mcp-tools: ${{ secrets.UNITY_MCP_TOOLS != '' && secrets.UNITY_MCP_TOOLS || 'assets-refresh,console-get-logs,script-execute,tests-run' }}
56+
4057
- name: Run Claude Code
4158
id: claude
4259
uses: anthropics/claude-code-action@v1
4360
with:
4461
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
62+
github_token: ${{ github.token }}
4563

4664
# This is an optional setting that allows Claude to read CI results on PRs
4765
additional_permissions: |
@@ -54,11 +72,28 @@ jobs:
5472
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
5573
# or https://code.claude.com/docs/en/cli-reference for available options
5674
claude_args: >-
57-
--allowedTools Bash
58-
--allowedTools Edit
59-
--allowedTools Write
60-
--allowedTools Glob
61-
--allowedTools Grep
62-
--allowedTools Read
63-
--allowedTools WebFetch
64-
--allowedTools WebSearch
75+
--allowedTools Bash(*)
76+
--allowedTools Read(*)
77+
--allowedTools Write(*)
78+
--allowedTools Edit(*)
79+
--allowedTools Glob(*)
80+
--allowedTools Grep(*)
81+
--allowedTools WebFetch(*)
82+
--allowedTools WebSearch(*)
83+
--allowedTools Agent(*)
84+
--allowedTools NotebookEdit(*)
85+
--allowedTools TodoWrite
86+
--allowedTools Skill(*)
87+
--allowedTools TaskOutput(*)
88+
--allowedTools TaskStop(*)
89+
--allowedTools EnterPlanMode
90+
--allowedTools ExitPlanMode
91+
--allowedTools EnterWorktree
92+
--allowedTools AskUserQuestion
93+
--mcp-config '{"mcpServers":{"ai-game-developer":{"type":"streamableHttp","url":"http://localhost:8080"}}}'
94+
95+
- name: Cleanup Docker containers
96+
if: always()
97+
run: |
98+
docker rm -f unity-mcp-server unity-editor 2>/dev/null || true
99+
shell: bash
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# ┌──────────────────────────────────────────────────────────────────┐
2+
# │ Author: Ivan Murzak (https://github.com/IvanMurzak) │
3+
# │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
4+
# │ Copyright (c) 2025 Ivan Murzak │
5+
# │ Licensed under the Apache License, Version 2.0. │
6+
# │ See the LICENSE file in the project root for more information. │
7+
# └──────────────────────────────────────────────────────────────────┘
8+
9+
name: "Copilot Setup Steps"
10+
11+
# Automatically run the setup steps when they are changed to allow for easy validation, and
12+
# allow manual testing through the repository's "Actions" tab
13+
on:
14+
workflow_dispatch:
15+
push:
16+
paths:
17+
- .github/workflows/copilot-setup-steps.yml
18+
pull_request:
19+
paths:
20+
- .github/workflows/copilot-setup-steps.yml
21+
22+
jobs:
23+
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
24+
copilot-setup-steps:
25+
runs-on: ubuntu-latest
26+
27+
# Set the permissions to the lowest permissions possible needed for your steps.
28+
# Copilot will be given its own token for its operations.
29+
permissions:
30+
# If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete.
31+
contents: read
32+
33+
# You can define any steps you want, and they will run before the agent starts.
34+
# If you do not check out your code, Copilot will do this for you.
35+
steps:
36+
- name: Checkout code
37+
uses: actions/checkout@v5
38+
39+
- name: Setup Unity MCP
40+
uses: ./.github/actions/setup-unity-mcp
41+
with:
42+
unity-email: ${{ secrets.UNITY_EMAIL }}
43+
unity-password: ${{ secrets.UNITY_PASSWORD }}
44+
unity-mcp-tools: ${{ secrets.UNITY_MCP_TOOLS != '' && secrets.UNITY_MCP_TOOLS || 'assets-refresh,console-get-logs,script-execute,tests-run' }}

0 commit comments

Comments
 (0)