Skip to content

Conversation

@dsarno
Copy link
Collaborator

@dsarno dsarno commented Dec 10, 2025

Bringing the CI testing framework back up-to-date / online, after it broke during the v8 upgrades. Includes some bug fixes to Stdio brdige and logging, and lots of fiddling with the CI workflow file. Re-addded the find_in_file python tool as it has disappeared at one point, and claude script editing uses that.

dsarno added 30 commits October 10, 2025 06:53
…_exit(code) and use timers with args\n- Consistent behavior on BrokenPipeError (no immediate exit)\n- Exit code 1 on unexpected exceptions\n\nTests: restore telemetry module after disabling to avoid bleed-over
…e _force_exit(code) and use timers with args\n- Consistent behavior on BrokenPipeError (no immediate exit)\n- Exit code 1 on unexpected exceptions\n\nTests: restore telemetry module after disabling to avoid bleed-over"

This reverts commit 74d35d3.
* 'main' of https://github.com/CoplayDev/unity-mcp:
  Harden PlayMode test runs (CoplayDev#396)
  Enable the `rmcp_client` feature so it works with Codex CLI (CoplayDev#395)
  chore: bump version to 8.0.0
  HTTP Server, uvx, C# only custom tools (CoplayDev#375)
  [CUSTOM TOOLS] Roslyn Runtime Compilation Feature (CoplayDev#371)
* 'main' of github.com:dsarno/unity-mcp:
* 'main' of https://github.com/CoplayDev/unity-mcp:
  chore: bump version to 8.1.4
  Fix Claude Windows config and CLI status refresh (CoplayDev#412)
  chore: bump version to 8.1.3
  fix: restrict fastmcp version to avoid potential KeyError (CoplayDev#411)
  chore: bump version to 8.1.2
  Revert project script change
  chore: bump version to 8.1.1
  Fix CLI entry point path in pyproject.toml (CoplayDev#407)
  Fix manage prefabs (CoplayDev#405)
  Remove automatic version bumping from README files and switch to unversioned git URLs
  chore: bump version to 8.1.0
  Add distribution settings for Asset Store vs git defaults (CoplayDev#404)
  Add CodeBuddy CLI configurator (CoplayDev#403)
  Fix stdio reloads (CoplayDev#402)
  Simplify MCP client configs (CoplayDev#401)
  chore: bump version to 8.0.1
* 'main' of github.com:dsarno/unity-mcp:
* 'main' of github.com:dsarno/unity-mcp:
  Revert "Server: refine shutdown logic per bot feedback\n- Parameterize _force_exit(code) and use timers with args\n- Consistent behavior on BrokenPipeError (no immediate exit)\n- Exit code 1 on unexpected exceptions\n\nTests: restore telemetry module after disabling to avoid bleed-over"
  Server: refine shutdown logic per bot feedback\n- Parameterize _force_exit(code) and use timers with args\n- Consistent behavior on BrokenPipeError (no immediate exit)\n- Exit code 1 on unexpected exceptions\n\nTests: restore telemetry module after disabling to avoid bleed-over
  Update github-repo-stats.yml
dsarno added 23 commits December 8, 2025 17:17
* unity-tests-fork-backup: (26 commits)
  diag
  fixes
  Cleanup
  Fixes to improve CI testing
  Add MCP preflight workflow and update NL suite
  another try
  Point MCP server to src/server.py and fix preflight
  Fix YAML indentation for MCP preflight step
  Use latest claude sonnet/haiku models in workflow
  Use available Anthropic models for T pass
  Write Unity logs to file and list config dir in debug
  Allow Unity config dir writable for MCP heartbeat/logs
  Mount Unity cache rw and dump Editor log for MCP debug
  Allow Unity local share writable for MCP status
  Fail fast when Unity MCP status file missing
  Add Unity bridge debug step in CI
  update yaml
  Fix CI: share unity-mcp status dir
  update claude haiku version for NL/T tests
  Harden NL suite prompts for deterministic anchors
  ...
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 10, 2025

Walkthrough

Adds CI preflight and expanded NL-suite workflows, a fork-specific Unity test workflow, a Unity editor CI bootstrap entrypoint, environment-configurable stdio bridge status/heartbeat handling and reload behavior, a new server-side file-search tool, port-discovery robustness for reloading instances, and small metadata adjustments.

Changes

Cohort / File(s) Summary
GitHub Actions — Workflows (new & modified)
/.github/workflows/claude-mcp-preflight.yml, /.github/workflows/claude-nl-suite.yml, /.github/workflows/unity-tests.yml, /.github/workflows/unity-tests-fork.yml, /.github/workflows/github-repo-stats.yml
Added a MCP preflight workflow; major rework of claude-nl-suite (runner upgrade, MCP server setup, preflight probes, model/fallback changes, artifact/debugging additions, relaxed ID parsing); added a fork-targeted unity-tests-fork workflow with license handling; added repo-owner guard to unity-tests; restricted github-repo-stats job to a specific repo.
Unity Editor — CI bootstrap & transport changes
MCPForUnity/Editor/McpCiBoot.cs, MCPForUnity/Editor/McpCiBoot.cs.meta, MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs, MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs
New McpCiBoot.StartStdioForCi entrypoint; StdioBridgeHost status path now configurable via UNITY_MCP_STATUS_DIR (fallback ~/.unity-mcp) and WriteHeartbeat made public; reload handler considers StdioBridgeHost.IsRunning, waits synchronously with timeout when stopping, and writes a reload heartbeat.
Server — Tools & discovery
Server/src/services/tools/find_in_file.py, Server/src/transport/legacy/port_discovery.py, Server/src/services/tools/manage_script.py
Added find_in_file tool with URI normalization, Unity-backed read, decoding, regex search, line-numbered matches and result limits; port_discovery now respects UNITY_MCP_STATUS_DIR, preserves recently reloading instances (<60s) using tz-aware freshness checks and dedupes by port; tightened encodedContents decoding check in manage_script._split_uri.
Docs / Prompts / Meta
.claude/prompts/nl-unity-suite-nl.md, TestProjects/UnityMCPTests/Assets/Scripts/Editor.meta
Updated NL prompt/patterns for anchor/brace-based insertion and Update() regex anchors; removed an Editor.meta asset file.

Sequence Diagram(s)

mermaid
sequenceDiagram
autonumber
participant GH as GitHub Actions
participant Server as MCP Server (uv)
participant Unity as Unity Editor (MCPForUnity)
participant FS as Status Dir / Filesystem

GH->>Server: start MCP server (uv) with UNITY_MCP_STATUS_DIR
Server->>FS: write status file / heartbeat
GH->>Server: run preflight probe (Python) -> request discovery/health
Server->>FS: read status files, return instances (preserve recent reloading)
GH->>Unity: trigger Unity CI (StartStdioForCi)
Unity->>Server: StdioBridgeHost auto-connect (stdio)
Unity->>FS: WriteHeartbeat(reloading=false)
Server->>GH: respond with discovery/health OK
GH->>GH: run NL/T passes, collect/upload artifacts (includes mcp-server-startup-debug.log)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay extra attention to:
    • .github/workflows/claude-nl-suite.yml (complex orchestration, retries, env propagation, artifact handling)
    • Server/src/services/tools/find_in_file.py (regex usage, decoding, URI resolution, security/IO assumptions)
    • Server/src/transport/legacy/port_discovery.py (freshness/tz handling, reloading-preservation logic)
    • MCPForUnity/Editor/Services/* (synchronous Stop wait, public heartbeat semantics, status-path configurability)

Possibly related PRs

Suggested reviewers

  • Scriptwonder

Poem

🐰
I tap the pipe, I write the beat,
Files sing statuses beneath my feet.
I probe, I hop, I start the run,
CI hums — another build is done. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Unity MCP CI Test Improvements' is directly related to the changeset's main focus on enhancing CI test workflows and infrastructure.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dsarno dsarno changed the title Unity tests fork backup Unity MCP CI Test Improvements Dec 10, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
Server/src/transport/legacy/port_discovery.py (2)

279-281: Consider moving the import to the top of the file.

The timezone import inside the conditional block works but is unconventional. Moving it to the top-level imports improves readability and avoids repeated import overhead if this code path is hit multiple times.

-from datetime import datetime
+from datetime import datetime, timezone

Then update the usage:

                    if freshness.tzinfo:
-                        from datetime import timezone
                        now = datetime.now(timezone.utc)

275-290: Consider inverting the condition to eliminate the empty pass block.

The current logic uses pass with a comment. Inverting the condition improves readability by making the "skip" case explicit.

                if not is_alive:
-                    # If Unity says it's reloading and the status is fresh, don't drop the instance.
-                    freshness = last_heartbeat or file_mtime
-                    now = datetime.now()
-                    if freshness.tzinfo:
-                        from datetime import timezone
-                        now = datetime.now(timezone.utc)
-                    
-                    age_s = (now - freshness).total_seconds()
-                    
-                    if is_reloading and age_s < 60:
-                        pass  # keep it, status="reloading"
-                    else:
-                        logger.debug(
-                            f"Instance {project_name}@{hash_value} has heartbeat but port {port} not responding")
-                        continue
+                    # If Unity says it's reloading and the status is fresh, keep the instance
+                    freshness = last_heartbeat or file_mtime
+                    now = datetime.now()
+                    if freshness.tzinfo:
+                        now = datetime.now(timezone.utc)
+                    
+                    age_s = (now - freshness).total_seconds()
+                    
+                    if not (is_reloading and age_s < 60):
+                        logger.debug(
+                            f"Instance {project_name}@{hash_value} has heartbeat but port {port} not responding")
+                        continue
.claude/prompts/nl-unity-suite-nl.md (2)

106-109: Clarify anchor selection logic and fallback behavior for NL-1.

Line 107 states "Prefer GetCurrentTarget() if unique; otherwise use another unique method such as ApplyBlend," but the validation step (line 108) doesn't explicitly address what happens if neither preferred anchor is unique or if neither exists. The term "unique" is ambiguous—does it mean "appears exactly once in the file" or "has a distinctive signature"?

Recommend adding:

  1. A definition of "unique" (e.g., "appears exactly once by method signature").
  2. A fallback strategy if both preferred anchors fail to satisfy uniqueness (e.g., use find_in_file to select the first occurrence of the anchor, or abort with clear error).
  3. An explicit validation expectation (similar to NL-2 line 116: "Expect exactly one match; if multiple, fail clearly").

115-119: Consider documenting the regex pattern rationale and testing it against edge cases.

The anchor pattern for Update() is well-crafted for robustness (optional access modifiers, flexible whitespace), but the complexity warrants a brief explanation. For instance:

  • Why does it tolerate (?:public|private|protected|internal)? but Update() is typically public?
  • Does the pattern correctly exclude method overloads (e.g., Update(float))?

Recommend adding a comment explaining the tolerance level and test coverage assumptions (e.g., "Assumes single parameterless Update() method per Unity class").

MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs (1)

1022-1028: Consider extracting status directory resolution.

The status directory resolution logic (reading UNITY_MCP_STATUS_DIR with fallback) is duplicated between Stop() (lines 466-471) and WriteHeartbeat(). Extracting this to a helper method would reduce duplication and improve maintainability.

Apply this diff to extract the logic:

+private static string GetStatusDirectory()
+{
+    string dir = Environment.GetEnvironmentVariable("UNITY_MCP_STATUS_DIR");
+    if (string.IsNullOrWhiteSpace(dir))
+    {
+        dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".unity-mcp");
+    }
+    return dir;
+}
+
 public static void Stop()
 {
     // ... existing code ...
     try
     {
-        string dir = Environment.GetEnvironmentVariable("UNITY_MCP_STATUS_DIR");
-        if (string.IsNullOrWhiteSpace(dir))
-        {
-            dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".unity-mcp");
-        }
+        string dir = GetStatusDirectory();
         string statusFile = Path.Combine(dir, $"unity-mcp-status-{ComputeProjectHash(Application.dataPath)}.json");
         // ... rest of Stop logic ...
     }
 }

 public static void WriteHeartbeat(bool reloading, string reason = null)
 {
     try
     {
-        string dir = Environment.GetEnvironmentVariable("UNITY_MCP_STATUS_DIR");
-        if (string.IsNullOrWhiteSpace(dir))
-        {
-            dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".unity-mcp");
-        }
+        string dir = GetStatusDirectory();
         Directory.CreateDirectory(dir);
         // ... rest of WriteHeartbeat logic ...
     }
 }
Server/src/services/tools/find_in_file.py (1)

72-76: Unused parameter acknowledged but consider documenting the intent.

The project_root parameter is flagged as unused by static analysis (ARG001). The inline comment on line 76 explains it's kept for interface consistency, which is reasonable. Consider using a leading underscore (_project_root) to suppress the linter warning and signal intent more clearly.

-    project_root: Annotated[str | None, "Optional project root path"] = None,
+    _project_root: Annotated[str | None, "Optional project root path (reserved for future use)"] = None,

Then remove or update the comment on line 76.

.github/workflows/claude-nl-suite.yml (1)

512-525: Preflight check validates CLI loading, not MCP connectivity.

The retry loop (lines 512-525) only runs --help to verify the CLI loads, not that it can connect to Unity. The actual connectivity is tested by the Python probe above (lines 487-510). Consider adding a comment clarifying this is a CLI sanity check, not a full connectivity test.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a987862 and 0e20067.

📒 Files selected for processing (13)
  • .claude/prompts/nl-unity-suite-nl.md (2 hunks)
  • .github/workflows/claude-mcp-preflight.yml (1 hunks)
  • .github/workflows/claude-nl-suite.yml (17 hunks)
  • .github/workflows/github-repo-stats.yml (1 hunks)
  • .github/workflows/unity-tests-fork.yml (1 hunks)
  • .github/workflows/unity-tests.yml (1 hunks)
  • MCPForUnity/Editor/McpCiBoot.cs (1 hunks)
  • MCPForUnity/Editor/McpCiBoot.cs.meta (1 hunks)
  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs (2 hunks)
  • MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs (2 hunks)
  • Server/src/services/tools/find_in_file.py (1 hunks)
  • Server/src/transport/legacy/port_discovery.py (2 hunks)
  • TestProjects/UnityMCPTests/Assets/Scripts/Editor.meta (0 hunks)
💤 Files with no reviewable changes (1)
  • TestProjects/UnityMCPTests/Assets/Scripts/Editor.meta
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 316
File: TestProjects/UnityMCPTests/Assets/Tests/EditMode/Resources.meta:1-8
Timestamp: 2025-10-13T13:27:23.040Z
Learning: UnityMcpBridge is a legacy project kept for backwards compatibility; MCPForUnity is the only active Unity plugin project. GUID collisions between UnityMcpBridge and MCPForUnity are acceptable.
📚 Learning: 2025-10-13T13:27:23.040Z
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 316
File: TestProjects/UnityMCPTests/Assets/Tests/EditMode/Resources.meta:1-8
Timestamp: 2025-10-13T13:27:23.040Z
Learning: UnityMcpBridge is a legacy project kept for backwards compatibility; MCPForUnity is the only active Unity plugin project. GUID collisions between UnityMcpBridge and MCPForUnity are acceptable.

Applied to files:

  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs
  • MCPForUnity/Editor/McpCiBoot.cs
  • MCPForUnity/Editor/McpCiBoot.cs.meta
📚 Learning: 2025-09-04T01:01:11.927Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 260
File: UnityMcpBridge/UnityMcpServer~/src/server_version.txt:1-1
Timestamp: 2025-09-04T01:01:11.927Z
Learning: The UnityMcpBridge project is not maintaining changelogs yet, so don't suggest adding changelog entries for version bumps.

Applied to files:

  • MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs
  • MCPForUnity/Editor/McpCiBoot.cs.meta
📚 Learning: 2025-10-13T13:41:00.086Z
Learnt from: JohanHoltby
Repo: CoplayDev/unity-mcp PR: 309
File: MCPForUnity/Editor/Helpers/ServerInstaller.cs:478-508
Timestamp: 2025-10-13T13:41:00.086Z
Learning: In the MCPForUnityTools feature (MCPForUnity/Editor/Helpers/ServerInstaller.cs), the design intentionally forces users to have only one .py file per MCPForUnityTools folder to keep file tracking simple. Package-style tools (subdirectories with __init__.py) are not supported.

Applied to files:

  • Server/src/services/tools/find_in_file.py
  • MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs
📚 Learning: 2025-11-27T21:09:35.011Z
Learnt from: msanatan
Repo: CoplayDev/unity-mcp PR: 401
File: MCPForUnity/Editor/Clients/Configurators/VSCodeConfigurator.cs:10-18
Timestamp: 2025-11-27T21:09:35.011Z
Learning: VS Code GitHub Copilot MCP configuration supports mcp.json files placed directly in the Code/User directory: %APPDATA%\Code\User\mcp.json on Windows, ~/Library/Application Support/Code/User/mcp.json on macOS, and ~/.config/Code/User/mcp.json on Linux. This is in addition to workspace-scoped .vscode/mcp.json files.

Applied to files:

  • MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs
📚 Learning: 2025-09-05T16:22:04.960Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 265
File: README.md:204-204
Timestamp: 2025-09-05T16:22:04.960Z
Learning: In the Unity MCP project, the ServerInstaller.cs creates a symlink from ~/Library/AppSupport to ~/Library/Application Support on macOS to mitigate argument parsing and quoting issues in some MCP clients. The README documentation should use the shortened AppSupport path, not the full "Application Support" path with spaces.

Applied to files:

  • MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs
📚 Learning: 2025-09-05T16:22:04.960Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 265
File: README.md:204-204
Timestamp: 2025-09-05T16:22:04.960Z
Learning: In the Unity MCP project, the ServerInstaller.cs creates a symlink from ~/Library/AppSupport to ~/Library/Application Support on macOS to avoid spaces in paths that can cause arg parsing and quoting issues in some MCP clients. The README documentation should use the shortened AppSupport path, not the full "Application Support" path.

Applied to files:

  • MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs
🧬 Code graph analysis (2)
MCPForUnity/Editor/McpCiBoot.cs (2)
MCPForUnity/Editor/Constants/EditorPrefKeys.cs (1)
  • EditorPrefKeys (7-48)
MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs (2)
  • StdioBridgeHost (122-171)
  • StartAutoConnect (83-101)
Server/src/services/tools/find_in_file.py (2)
Server/src/transport/unity_transport.py (1)
  • send_with_unity_instance (78-103)
Server/src/transport/legacy/unity_connection.py (1)
  • async_send_command_with_retry (753-785)
🪛 Ruff (0.14.8)
Server/src/services/tools/find_in_file.py

72-72: Unused function argument: project_root

(ARG001)

🔇 Additional comments (26)
Server/src/transport/legacy/port_discovery.py (1)

34-44: LGTM!

Good refactoring to delegate path construction to get_registry_dir, avoiding duplication. The environment variable override for UNITY_MCP_STATUS_DIR is clean and allows flexible configuration for testing and custom deployments.

.claude/prompts/nl-unity-suite-nl.md (1)

122-132: NL-3 pattern is safe for the current test file structure.

The pattern (?m)^\\s*}\\s*$ works correctly for LongUnityScriptClaudeTest.cs because the file has a straightforward, single-class structure with no nested classes or properties with block bodies. The last closing brace in the file (line 2037) is indeed the class closing brace at indentation 0, as the pattern assumes.

The file's structure—300+ padding methods all at class level—ensures that selecting the final brace-only line reliably targets the class closing brace. If the file structure changes to include nested classes or properties with block bodies, the concern becomes valid and a more specific anchor (such as matching public class line or using a sentinel comment) would be necessary. For the current test design, no changes are required.

Likely an incorrect or invalid review comment.

.github/workflows/github-repo-stats.yml (1)

4-7: LGTM! Scheduled runs disabled.

The cron-based schedule trigger has been disabled while preserving manual workflow_dispatch execution. This is appropriate if automated stats collection is being replaced or deferred.

.github/workflows/unity-tests.yml (1)

14-15: LGTM! Fork protection added.

The owner guard ensures Unity tests only run on the upstream repository, preventing unauthorized use of Unity licenses and protecting repository secrets on forks. This aligns with the new fork-specific workflow.

MCPForUnity/Editor/McpCiBoot.cs.meta (1)

1-12: LGTM! Standard Unity meta file.

The meta file correctly registers the McpCiBoot.cs editor script with Unity, using a unique GUID and standard MonoImporter configuration.

MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs (2)

466-471: LGTM! Configurable status directory for CI.

Environment variable support via UNITY_MCP_STATUS_DIR enables flexible status-file placement in CI/testing environments while maintaining backward compatibility with the default user-profile location.


1018-1018: LGTM! WriteHeartbeat exposed for reload signaling.

Making WriteHeartbeat public enables StdioBridgeReloadHandler to signal reload status to clients, improving the stdio bridge lifecycle management during domain reloads.

MCPForUnity/Editor/Services/StdioBridgeReloadHandler.cs (2)

28-31: LGTM! Dual-check for CI bootstrap compatibility.

The additional StdioBridgeHost.IsRunning check ensures reload handling works correctly when the stdio bridge is started directly via CI bootstrap (McpCiBoot.StartStdioForCi) bypassing TransportManager state. The inline comment clearly documents the rationale.


40-45: LGTM! Improved reload signaling.

The synchronous stop with timeout followed by WriteHeartbeat(true, "reloading") ensures clients receive reload status even when the bridge is stopped, improving the client experience during domain reloads.

MCPForUnity/Editor/McpCiBoot.cs (1)

10-19: LGTM! Clean CI bootstrap entry point.

The StartStdioForCi() method provides a straightforward entry point for CI workflows to initialize the stdio bridge. The defensive try-catch around EditorPrefs ensures robustness if preferences are unavailable, and calling StdioBridgeHost.StartAutoConnect() is the correct approach for establishing the bridge.

.github/workflows/unity-tests-fork.yml (6)

19-20: Verify fork owner guard matches intended user.

The workflow is guarded to run only when github.repository_owner == 'dsarno', which should match the PR author and fork owner. Ensure this is the intended configuration.


27-67: LGTM! Comprehensive credential detection.

The multi-stage credential detection correctly identifies ULF license files, entitlement-based licensing (EBL) with email/password, and optional serial numbers. The outputs enable flexible license activation strategies downstream.


69-96: LGTM! Robust ULF staging with fallbacks.

The ULF staging step handles base64-encoded licenses with a fallback to plain-text, and intelligently detects misplaced entitlement XML files (which should be in the licenses directory instead). This defensive approach improves reliability across different secret configurations.


98-136: LGTM! Flexible Unity activation supporting Pro and named-user EBL.

The activation step correctly handles both Pro licenses (with serial) and named-user entitlement-based licensing via Docker host-mount. The fallback to ULF-only execution when entitlements are unavailable ensures the workflow doesn't fail prematurely.


138-159: LGTM! Warm-up step prevents cold-start issues.

Running an initial import pass to populate the Library folder before tests prevents cold-start performance issues and improves test reliability.


162-186: LGTM! Test execution with proper license handling.

The test step correctly passes the manual license file argument when ULF is available and executes editmode tests with proper result formatting and artifact output.

.github/workflows/claude-mcp-preflight.yml (2)

22-35: LGTM! Flexible dependency installation.

The installation step supports both modern pyproject.toml and legacy requirements.txt with clear error handling if neither is found.


37-53: LGTM! No-Unity preflight validation.

The preflight step correctly validates the MCP server can initialize in stdio mode without a running Unity instance. The dummy status file and UNITY_MCP_STATUS_DIR environment variable align with the configurability changes in StdioBridgeHost.cs. Using --help is appropriate for validation without requiring actual Unity connectivity.

Server/src/services/tools/find_in_file.py (2)

15-64: LGTM on URI parsing logic.

The _split_uri helper correctly handles unity://path/, file://, and plain path formats, with proper percent-decoding, UNC path handling, Windows drive-letter normalization, and Assets-relative path extraction.


128-164: LGTM on regex search and result mapping.

The match iteration, line number calculation, and excerpt extraction logic is sound. Properly handles edge cases like matches at EOF (line 149-150) and caps results to avoid payload bloat.

.github/workflows/claude-nl-suite.yml (6)

18-18: Runner pinned to specific Ubuntu version.

Pinning to ubuntu-24.04 instead of ubuntu-latest is good for reproducibility. However, be aware this will require manual updates when newer runners are needed.


439-448: Shell script generation looks correct.

The f-string correctly interpolates {workspace} and {uv_cmd} while preserving bash constructs ($LOG, $@, $(...)) since Python's f-strings only interpret {} placeholders. The stderr-to-log redirect with stdout for MCP communication is the right approach.


819-822: Good: Relaxed regex patterns handle inconsistent agent output.

The patterns NL-?(\d+) and T-?([A-J]) now accept both hyphenated (NL-0, T-A) and non-hyphenated (NL0, TA) variants from agent output, while the normalization logic ensures consistent canonical format with hyphens.


1208-1219: LGTM: Debug log added to artifacts.

Including .unity-mcp/mcp-server-startup-debug.log in artifacts aids post-mortem debugging of MCP server startup issues.


277-312: Good observability instrumentation.

The debug step provides comprehensive diagnostics: container state, logs (with credential redaction), status directory listings, and port probes. The fail-fast on missing status file prevents wasted CI time.


647-648: Model identifiers are valid Anthropic snapshots. Anthropic publishes dated model IDs (e.g., claude-sonnet-4-5-20250929) for reproducible behavior across environments, which is the recommended practice for CI/CD workflows. The claude-sonnet-4-5-20250929 identifier matches its Sep 29, 2025 release date exactly. The claude-haiku-4-5-20251001 identifier uses Oct 1 as the snapshot date, which aligns with Haiku's Oct 15 announcement timeline. No action needed.

@dsarno dsarno merged commit d06eaef into CoplayDev:main Dec 10, 2025
1 check was pending
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
Server/src/services/tools/find_in_file.py (2)

72-76: Silence Ruff ARG001 for project_root while keeping the interface stable.

project_root is intentionally unused but will keep triggering Ruff’s ARG001. To preserve the public signature while satisfying linting, consider annotating it with a noqa comment.

-    project_root: Annotated[str | None, "Optional project root path"] = None,
+    project_root: Annotated[str | None, "Optional project root path"] = None,  # noqa: ARG001 - kept for interface compatibility

152-160: Preserve indentation in line excerpts by avoiding strip().

Using line_content.strip() removes leading spaces, which can make C# lines harder to recognize in context. Prefer trimming only the trailing newline so indentation is preserved.

-            "content": line_content.strip(), # detailed match info?
+            "content": line_content.rstrip("\n"),  # preserve indentation, strip only newline
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ec42fb and 03f5cc7.

📒 Files selected for processing (2)
  • Server/src/services/tools/find_in_file.py (1 hunks)
  • Server/src/services/tools/manage_script.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-13T13:41:00.086Z
Learnt from: JohanHoltby
Repo: CoplayDev/unity-mcp PR: 309
File: MCPForUnity/Editor/Helpers/ServerInstaller.cs:478-508
Timestamp: 2025-10-13T13:41:00.086Z
Learning: In the MCPForUnityTools feature (MCPForUnity/Editor/Helpers/ServerInstaller.cs), the design intentionally forces users to have only one .py file per MCPForUnityTools folder to keep file tracking simple. Package-style tools (subdirectories with __init__.py) are not supported.

Applied to files:

  • Server/src/services/tools/find_in_file.py
🧬 Code graph analysis (1)
Server/src/services/tools/find_in_file.py (3)
Server/src/transport/unity_transport.py (1)
  • send_with_unity_instance (78-103)
Server/src/transport/legacy/unity_connection.py (1)
  • async_send_command_with_retry (753-785)
Server/src/services/tools/manage_script.py (1)
  • _split_uri (14-63)
🪛 Ruff (0.14.8)
Server/src/services/tools/find_in_file.py

72-72: Unused function argument: project_root

(ARG001)

🔇 Additional comments (3)
Server/src/services/tools/manage_script.py (1)

120-129: Encoded contents guard now correctly requires both flags before decoding.

The updated condition if not contents and data.get("contentsEncoded") and data.get("encodedContents"): closes the earlier hole where an absent encodedContents could lead to decoding an empty string. The fallback on decode failure remains safe, and this matches the pattern used in the other tools.

Server/src/services/tools/find_in_file.py (2)

15-64: URI normalization helper looks robust and consistent with manage_script.

_split_uri correctly normalizes unity://path/..., file://..., and plain paths, handles UNC/file URIs, and derives an Assets-relative directory where possible. This matches the behavior in Server/src/services/tools/manage_script.py and should give consistent name/path resolution across tools.


98-107: Base64 decoding guard and fallback behavior are sound.

The condition if not contents and data.get("contentsEncoded") and data.get("encodedContents"): ensures you only attempt base64 decoding when both flags are present, preventing silent decoding of an empty string. Falling back to contents or "" on decode failure is a safe, predictable behavior for the search tool.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant