Skip to content

Feature/roslyn installer (set to 4.2.0)#841

Merged
Scriptwonder merged 8 commits intoCoplayDev:betafrom
Scriptwonder:feature/roslyn-installer
Feb 28, 2026
Merged

Feature/roslyn installer (set to 4.2.0)#841
Scriptwonder merged 8 commits intoCoplayDev:betafrom
Scriptwonder:feature/roslyn-installer

Conversation

@Scriptwonder
Copy link
Collaborator

@Scriptwonder Scriptwonder commented Feb 28, 2026

Description

Easier way to install Roslyn with one click.

Type of Change

Save your change type

  • New feature (non-breaking change that adds functionality)
  • Documentation update

Changes Made

Testing/Screenshots/Recordings

image

Documentation Updates

  • I have added/removed/modified tools or resources
  • If yes, I have updated all documentation files using:
    • The LLM prompt at tools/UPDATE_DOCS_PROMPT.md (recommended)
    • Manual updates following the guide at tools/UPDATE_DOCS.md

Related Issues

Additional Notes

Summary by Sourcery

Add a built-in Roslyn runtime code execution installer and surface its status in the MCP for Unity editor window.

New Features:

  • Introduce a Roslyn installer utility that downloads required NuGet packages and installs Roslyn DLLs into the project.
  • Expose a Runtime Code Execution (Roslyn) section in the MCP for Unity editor window to show install status and trigger installation from the UI.
  • Add a menu command to install or reinstall Roslyn DLLs from the Unity menu bar.

Enhancements:

  • Update documentation to recommend the new one-click Roslyn installer and adjust manual installation instructions.
  • Bump the MCP for Unity package version to 9.4.8-beta.8.

Summary by CodeRabbit

  • New Features

    • One-click Roslyn DLL installer in the editor with installation status, progress feedback, retry and manual-install guidance.
    • Installer automates downloading, extracting, and placing required Roslyn DLLs.
  • Documentation

    • Setup docs updated with a recommended "One-click installer" flow and steps to install via the editor (Window > MCP For Unity > Install Roslyn DLLs).
    • Manual installation steps retained and relocated to Assets/Plugins/Roslyn.

actions-user and others added 5 commits February 27, 2026 18:40
…499094106

chore: update Unity package to beta version 9.4.8-beta.8
Add RoslynInstaller.cs that downloads Microsoft.CodeAnalysis.Common, Microsoft.CodeAnalysis.CSharp, System.Collections.Immutable, and System.Reflection.Metadata NuGet packages with an inline ZIP parser (no System.IO.Compression dependency). Adds GUI button in the Scripts/Validation tab of the MCP for Unity editor window.
Add RoslynInstaller.cs that downloads Microsoft.CodeAnalysis.Common, Microsoft.CodeAnalysis.CSharp, System.Collections.Immutable, and System.Reflection.Metadata NuGet packages with an inline ZIP parser (no System.IO.Compression dependency). Adds GUI button in the Scripts/Validation tab of the MCP for Unity editor window.
Copilot AI review requested due to automatic review settings February 28, 2026 03:15
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Feb 28, 2026

Reviewer's Guide

Adds a one-click Roslyn DLL installer (using Roslyn 4.12.0) integrated into the MCP for Unity editor window and menu, with supporting ZIP extraction logic, updates the README to recommend the installer, and bumps the package version.

Sequence diagram for Roslyn one-click installation from editor window

sequenceDiagram
    actor UnityDeveloper
    participant MCPForUnityEditorWindow
    participant RoslynInstaller
    participant WebClient
    participant NuGetOrg
    participant FileSystem
    participant AssetDatabase
    participant EditorUtility

    UnityDeveloper->>MCPForUnityEditorWindow: Click Install_Roslyn_DLLs button
    MCPForUnityEditorWindow->>RoslynInstaller: Install(interactive true)

    RoslynInstaller->>RoslynInstaller: IsInstalled()
    alt Already installed and interactive
        RoslynInstaller->>EditorUtility: DisplayDialog(Reinstall?)
        alt User cancels
            RoslynInstaller-->>MCPForUnityEditorWindow: Return
        else User confirms reinstall
            RoslynInstaller->>FileSystem: CreateDirectory(Assets/Plugins/Roslyn)
        end
    else Not installed or non_interactive
        RoslynInstaller->>FileSystem: CreateDirectory(Assets/Plugins/Roslyn)
    end

    loop For_each_NuGet_entry
        RoslynInstaller->>EditorUtility: DisplayProgressBar(Downloading package)
        RoslynInstaller->>WebClient: DownloadData(nupkg URL)
        WebClient->>NuGetOrg: HTTP GET nupkg
        NuGetOrg-->>WebClient: nupkg bytes
        WebClient-->>RoslynInstaller: nupkg bytes
        RoslynInstaller->>RoslynInstaller: ExtractFileFromZip(zipBytes, dllPath)
        alt DLL_found
            RoslynInstaller->>FileSystem: WriteAllBytes(Assets/Plugins/Roslyn/dll)
        else DLL_missing
            RoslynInstaller->>EditorUtility: LogError(missing DLL)
        end
    end

    RoslynInstaller->>EditorUtility: DisplayProgressBar(Refreshing assets)
    RoslynInstaller->>AssetDatabase: Refresh(ForceSynchronousImport)
    RoslynInstaller->>EditorUtility: ClearProgressBar()
    RoslynInstaller->>EditorUtility: DisplayDialog(Roslyn Installed)
    RoslynInstaller-->>MCPForUnityEditorWindow: Return

    MCPForUnityEditorWindow->>RoslynInstaller: IsInstalled()
    RoslynInstaller-->>MCPForUnityEditorWindow: true
    MCPForUnityEditorWindow->>MCPForUnityEditorWindow: Update statusLabel text
Loading

Class diagram for RoslynInstaller and MCPForUnityEditorWindow integration

classDiagram
    class RoslynInstaller {
        <<static>>
        - const string PluginsRelPath
        - static (string packageId, string version, string dllPath, string dllName)[] NuGetEntries
        + static void InstallViaMenu()
        + static bool IsInstalled()
        + static void Install(bool interactive)
        - static byte[] ExtractFileFromZip(byte[] zipBytes, string entryPath)
        - static ushort ReadUInt16LE(byte[] buf, int offset)
        - static uint ReadUInt32LE(byte[] buf, int offset)
    }

    class MCPForUnityEditorWindow {
        + void CreateGUI()
        + static void BuildRoslynSection(VisualElement container)
    }

    class VisualElement {
        + void AddToClassList(string className)
        + void Add(VisualElement child)
    }

    class Label {
        + string text
        + void AddToClassList(string className)
    }

    class Button {
        + string text
        + Button(System.Action onClick)
        + void AddToClassList(string className)
    }

    MCPForUnityEditorWindow ..> RoslynInstaller : uses
    MCPForUnityEditorWindow ..> VisualElement : builds_UI_with
    MCPForUnityEditorWindow ..> Label : displays_status
    MCPForUnityEditorWindow ..> Button : triggers_install
Loading

Flow diagram for RoslynInstaller installation logic

graph TD
    A_Start[Start Install interactive] --> B_CheckInstalled{IsInstalled?}
    B_CheckInstalled -->|Yes and interactive| C_PromptReinstall[EditorUtility.DisplayDialog Reinstall?]
    B_CheckInstalled -->|No or non_interactive| E_CreateDir[CreateDirectory Assets/Plugins/Roslyn]

    C_PromptReinstall -->|Cancel| Z_End[Return]
    C_PromptReinstall -->|Reinstall| E_CreateDir

    E_CreateDir --> F_TryBlock{Try}

    F_TryBlock --> G_LoopEntries[For each NuGet entry]
    G_LoopEntries --> H_DisplayProgress[DisplayProgressBar Downloading]
    H_DisplayProgress --> I_DownloadNupkg[WebClient.DownloadData]
    I_DownloadNupkg --> J_ExtractDll[ExtractFileFromZip]

    J_ExtractDll --> K_DllFound{dllBytes != null?}
    K_DllFound -->|Yes| L_WriteFile[File.WriteAllBytes to Assets/Plugins/Roslyn]
    K_DllFound -->|No| M_LogError[Debug.LogError missing DLL]

    L_WriteFile --> N_NextEntry[Next entry]
    M_LogError --> N_NextEntry
    N_NextEntry -->|More entries| G_LoopEntries
    N_NextEntry -->|No more entries| O_RefreshAssets[AssetDatabase.Refresh]

    O_RefreshAssets --> P_ClearProgress[EditorUtility.ClearProgressBar]
    P_ClearProgress --> Q_ShowSuccess[EditorUtility.DisplayDialog Roslyn Installed]
    Q_ShowSuccess --> R_LogSuccess[Debug.Log installation complete]
    R_LogSuccess --> Z_End

    F_TryBlock -->|Exception| S_Catch[Catch Exception]
    S_Catch --> T_ClearProgressError[EditorUtility.ClearProgressBar]
    T_ClearProgressError --> U_LogError[Debug.LogError installation failed]
    U_LogError --> V_ShowFailureDialog[EditorUtility.DisplayDialog Installation Failed]
    V_ShowFailureDialog --> Z_End
Loading

File-Level Changes

Change Details Files
Introduce a Roslyn DLL installer utility that downloads required NuGet packages, extracts DLLs, and places them under Assets/Plugins/Roslyn with progress UI and error handling.
  • Add RoslynInstaller static class with Install, InstallViaMenu, and IsInstalled entry points
  • Download Roslyn-related NuGet .nupkg files via WebClient and extract specific DLLs using a custom ZIP reader that supports Store and Deflate methods
  • Write extracted DLLs to Assets/Plugins/Roslyn and refresh the AssetDatabase, with editor dialogs and logging for success and failure paths
MCPForUnity/Editor/Setup/RoslynInstaller.cs
MCPForUnity/Editor/Setup/RoslynInstaller.cs.meta
Expose Roslyn installation controls and status within the MCP for Unity editor window.
  • Add using directive for the new Setup namespace
  • Build a new Runtime Code Execution (Roslyn) section in the Scripts/Validation tab that shows installation status and an Install/Reinstall button wired to RoslynInstaller
  • Keep advanced section event wiring logically unchanged aside from minor formatting
MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs
Update documentation and package metadata to reflect the new installer and directory layout.
  • Document the one-click Roslyn installer workflow in the README and adjust the manual installation section to use Assets/Plugins/Roslyn
  • Increment the MCP for Unity package version from 9.4.8-beta.7 to 9.4.8-beta.8
README.md
MCPForUnity/package.json

Possibly linked issues

  • #(unknown): PR’s Roslyn installer and updated docs directly address misinstalled/missing Roslyn DLLs that cause the reported CS0234 error.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 94fc9a7 and 99e3627.

📒 Files selected for processing (1)
  • MCPForUnity/Editor/Setup/RoslynInstaller.cs

📝 Walkthrough

Walkthrough

Adds a Roslyn DLL installer that downloads NuGet packages, extracts specified DLLs into Assets/Plugins/Roslyn, integrates an install UI into the MCPForUnity editor window, and updates docs and package version to 9.4.8-beta.8.

Changes

Cohort / File(s) Summary
Roslyn Installer
MCPForUnity/Editor/Setup/RoslynInstaller.cs, MCPForUnity/Editor/Setup/RoslynInstaller.cs.meta
New static RoslynInstaller with InstallViaMenu(), IsInstalled(), and Install(bool); downloads NuGet .nupkg files (v3 flatcontainer), extracts configured DLLs from ZIP entries, writes to Assets/Plugins/Roslyn, refreshes Unity assets, and shows interactive progress and error dialogs.
Editor UI Integration
MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs
Adds BuildRoslynSection UI block showing installation status and an Install/Reinstall button; wires the Roslyn section into the editor window and adds MCPForUnity.Editor.Setup using directive.
Docs & Package
MCPForUnity/package.json, README.md
Version bumped to 9.4.8-beta.8. README adds a recommended one‑click Roslyn installer path (Window > MCP For Unity > Install Roslyn DLLs) and updates manual install target to Assets/Plugins/Roslyn/.

Sequence Diagram

sequenceDiagram
    actor User
    participant Menu as "Unity Menu"
    participant Installer as "RoslynInstaller"
    participant NuGet as "NuGet Server"
    participant FS as "File System"
    participant Unity as "Unity Assets"

    User->>Menu: Trigger "Install Roslyn DLLs"
    Menu->>Installer: InstallViaMenu()
    Installer->>Installer: IsInstalled()
    loop per NuGet entry
        Installer->>NuGet: Download .nupkg (v3 flatcontainer URL)
        NuGet-->>Installer: Return .nupkg bytes
        Installer->>FS: Extract specified DLL from .nupkg (ZIP)
        FS-->>Installer: DLL bytes
        Installer->>FS: Write DLL to Assets/Plugins/Roslyn/
    end
    Installer->>Unity: Refresh assets
    Installer-->>User: Show completion or error dialog
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Suggested labels

codex

Suggested reviewers

  • dsarno

Poem

🐰 I hopped through NuGet, nibbling zip pies,
Extracted bright DLLs beneath sunny skies.
One click and they land in Plugins/Roslyn’s den —
Hooray! The editor hums and I dance again. 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: adding a Roslyn installer feature. It is concise, specific, and directly relates to the primary changeset.
Description check ✅ Passed The description follows the template with all major sections completed: includes a clear description, identifies change type as new feature and documentation update, lists specific changes made, provides a screenshot for testing, confirms documentation was updated, and includes a summary of features.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 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.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The RoslynInstaller currently uses WebClient (which is obsolete) with explicit pragma suppression; consider switching to HttpClient or UnityWebRequest to avoid relying on deprecated APIs and future-proof the download logic.
  • The custom ZIP parsing in ExtractFileFromZip manually walks local file headers and assumes a specific layout; this is brittle for general .nupkg handling—if possible, prefer ZipArchive (or a small, battle-tested ZIP helper) to improve robustness and maintainability.
  • The installer menu is registered under Window/MCP For Unity/Install Roslyn DLLs, but the README instructs users to use Tools > MCP for Unity > Install Roslyn DLLs; align the menu path or docs so users can find the command reliably.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `RoslynInstaller` currently uses `WebClient` (which is obsolete) with explicit pragma suppression; consider switching to `HttpClient` or `UnityWebRequest` to avoid relying on deprecated APIs and future-proof the download logic.
- The custom ZIP parsing in `ExtractFileFromZip` manually walks local file headers and assumes a specific layout; this is brittle for general .nupkg handling—if possible, prefer `ZipArchive` (or a small, battle-tested ZIP helper) to improve robustness and maintainability.
- The installer menu is registered under `Window/MCP For Unity/Install Roslyn DLLs`, but the README instructs users to use `Tools > MCP for Unity > Install Roslyn DLLs`; align the menu path or docs so users can find the command reliably.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@MCPForUnity/Editor/Setup/RoslynInstaller.cs`:
- Around line 78-106: The installer currently continues when dllBytes == null
but still shows success UI; modify RoslynInstaller flow to track a failure flag
(e.g., bool extractionFailed = false) inside the loop where dllBytes is checked
and set extractionFailed = true when dllBytes == null (and keep the continue),
then after AssetDatabase.Refresh check extractionFailed before showing success
UI/logs: if extractionFailed, clear progress bar (if interactive), show an error
dialog via EditorUtility.DisplayDialog and log an error (including which DLLs
failed if you tracked names), and avoid logging the successful completion
message that uses NuGetEntries.Length; otherwise proceed with the existing
success dialog and Debug.Log. Ensure references to dllBytes, destPath,
PluginsRelPath, interactive, AssetDatabase.Refresh and NuGetEntries.Length are
used to locate the change.

In `@MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs`:
- Around line 694-702: The button label can remain stale after running the click
handler because you only set button.text once using the outer "installed" value;
inside the click handler recalculate installation status after
RoslynInstaller.Install(interactive: true) (by calling
RoslynInstaller.IsInstalled()) and update button.text accordingly (e.g., set
button.text to "Reinstall Roslyn DLLs" or "Install Roslyn DLLs"); also update
statusLabel.text as you already do so the UI stays consistent. Use the existing
symbols: button, statusLabel, RoslynInstaller.Install,
RoslynInstaller.IsInstalled and the prior installed logic to determine the
correct label.

In `@README.md`:
- Line 170: The README's menu path text "Tools > MCP for Unity > Install Roslyn
DLLs" is inconsistent with the implemented menu registration; update the README
so the menu path matches the actual registered menu name "Window > MCP For Unity
> Install Roslyn DLLs" (replace the Tools path string with the Window > MCP For
Unity > Install Roslyn DLLs string) to prevent navigation mismatch in the docs.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08b8eac and edfdc2d.

📒 Files selected for processing (5)
  • MCPForUnity/Editor/Setup/RoslynInstaller.cs
  • MCPForUnity/Editor/Setup/RoslynInstaller.cs.meta
  • MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs
  • MCPForUnity/package.json
  • README.md

Comment on lines +78 to +106
if (dllBytes == null)
{
Debug.LogError($"[MCP] Could not find {dllPathInZip} in {packageId}.{pkgVersion}.nupkg");
continue;
}

string destPath = Path.Combine(destFolder, dllName);
File.WriteAllBytes(destPath, dllBytes);
Debug.Log($"[MCP] Extracted {dllName} ({dllBytes.Length / 1024}KB) → Assets/{PluginsRelPath}/{dllName}");
}
}

if (interactive)
EditorUtility.DisplayProgressBar("Installing Roslyn", "Refreshing assets...", 0.95f);

AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);

if (interactive)
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog(
"Roslyn Installed",
$"Roslyn DLLs and dependencies installed to Assets/{PluginsRelPath}/.\n\n" +
"The execute_code tool is now available via MCP.",
"OK");
}

Debug.Log($"[MCP] Roslyn installation complete ({NuGetEntries.Length} DLLs). execute_code is now available.");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Installer reports success even when one or more DLL extractions fail.

When dllBytes == null, the code continues, but the flow still shows the success dialog and completion log. That can leave a partial install while claiming it succeeded.

Suggested completion-state fix
             try
             {
                 Directory.CreateDirectory(destFolder);
+                int installedCount = 0;
+                var failedPackages = new System.Collections.Generic.List<string>();

 `#pragma` warning disable SYSLIB0014
                 using (var client = new WebClient())
 `#pragma` warning restore SYSLIB0014
                 {
@@
                         if (dllBytes == null)
                         {
                             Debug.LogError($"[MCP] Could not find {dllPathInZip} in {packageId}.{pkgVersion}.nupkg");
+                            failedPackages.Add($"{packageId} v{pkgVersion}");
                             continue;
                         }

                         string destPath = Path.Combine(destFolder, dllName);
                         File.WriteAllBytes(destPath, dllBytes);
+                        installedCount++;
                         Debug.Log($"[MCP] Extracted {dllName} ({dllBytes.Length / 1024}KB) → Assets/{PluginsRelPath}/{dllName}");
                     }
                 }
@@
-                if (interactive)
-                {
-                    EditorUtility.ClearProgressBar();
-                    EditorUtility.DisplayDialog(
-                        "Roslyn Installed",
-                        $"Roslyn DLLs and dependencies installed to Assets/{PluginsRelPath}/.\n\n" +
-                        "The execute_code tool is now available via MCP.",
-                        "OK");
-                }
-
-                Debug.Log($"[MCP] Roslyn installation complete ({NuGetEntries.Length} DLLs). execute_code is now available.");
+                bool installComplete = failedPackages.Count == 0
+                    && installedCount == NuGetEntries.Length
+                    && IsInstalled();
+
+                if (interactive)
+                {
+                    EditorUtility.ClearProgressBar();
+                    if (installComplete)
+                    {
+                        EditorUtility.DisplayDialog(
+                            "Roslyn Installed",
+                            $"Roslyn DLLs and dependencies installed to Assets/{PluginsRelPath}/.\n\n" +
+                            "The execute_code tool is now available via MCP.",
+                            "OK");
+                    }
+                    else
+                    {
+                        EditorUtility.DisplayDialog(
+                            "Installation Incomplete",
+                            "Some Roslyn DLLs could not be installed. Check the Console for details and retry.",
+                            "OK");
+                    }
+                }
+
+                if (installComplete)
+                    Debug.Log($"[MCP] Roslyn installation complete ({installedCount} DLLs). execute_code is now available.");
+                else
+                    Debug.LogError($"[MCP] Roslyn installation incomplete ({installedCount}/{NuGetEntries.Length}). Failed: {string.Join(", ", failedPackages)}");
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MCPForUnity/Editor/Setup/RoslynInstaller.cs` around lines 78 - 106, The
installer currently continues when dllBytes == null but still shows success UI;
modify RoslynInstaller flow to track a failure flag (e.g., bool extractionFailed
= false) inside the loop where dllBytes is checked and set extractionFailed =
true when dllBytes == null (and keep the continue), then after
AssetDatabase.Refresh check extractionFailed before showing success UI/logs: if
extractionFailed, clear progress bar (if interactive), show an error dialog via
EditorUtility.DisplayDialog and log an error (including which DLLs failed if you
tracked names), and avoid logging the successful completion message that uses
NuGetEntries.Length; otherwise proceed with the existing success dialog and
Debug.Log. Ensure references to dllBytes, destPath, PluginsRelPath, interactive,
AssetDatabase.Refresh and NuGetEntries.Length are used to locate the change.

Comment on lines +694 to +702
var button = new Button(() =>
{
RoslynInstaller.Install(interactive: true);
statusLabel.text = RoslynInstaller.IsInstalled()
? "\u2713 Roslyn DLLs are installed. The execute_code tool is available."
: "Installation incomplete. Check the console for errors.";
});
button.text = installed ? "Reinstall Roslyn DLLs" : "Install Roslyn DLLs";
button.AddToClassList("action-button");
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Button label is not refreshed after install/reinstall.

After the click handler runs, status text is updated but the button can remain on the old label (Install vs Reinstall), which causes a stale UI state.

Suggested UI state sync fix
-            var button = new Button(() =>
-            {
-                RoslynInstaller.Install(interactive: true);
-                statusLabel.text = RoslynInstaller.IsInstalled()
-                    ? "\u2713  Roslyn DLLs are installed. The execute_code tool is available."
-                    : "Installation incomplete. Check the console for errors.";
-            });
-            button.text = installed ? "Reinstall Roslyn DLLs" : "Install Roslyn DLLs";
+            var button = new Button();
+            button.text = installed ? "Reinstall Roslyn DLLs" : "Install Roslyn DLLs";
+            button.clicked += () =>
+            {
+                RoslynInstaller.Install(interactive: true);
+                bool isInstalledNow = RoslynInstaller.IsInstalled();
+                statusLabel.text = isInstalledNow
+                    ? "\u2713  Roslyn DLLs are installed. The execute_code tool is available."
+                    : "Installation incomplete. Check the console for errors.";
+                button.text = isInstalledNow ? "Reinstall Roslyn DLLs" : "Install Roslyn DLLs";
+            };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var button = new Button(() =>
{
RoslynInstaller.Install(interactive: true);
statusLabel.text = RoslynInstaller.IsInstalled()
? "\u2713 Roslyn DLLs are installed. The execute_code tool is available."
: "Installation incomplete. Check the console for errors.";
});
button.text = installed ? "Reinstall Roslyn DLLs" : "Install Roslyn DLLs";
button.AddToClassList("action-button");
var button = new Button();
button.text = installed ? "Reinstall Roslyn DLLs" : "Install Roslyn DLLs";
button.clicked += () =>
{
RoslynInstaller.Install(interactive: true);
bool isInstalledNow = RoslynInstaller.IsInstalled();
statusLabel.text = isInstalledNow
? "\u2713 Roslyn DLLs are installed. The execute_code tool is available."
: "Installation incomplete. Check the console for errors.";
button.text = isInstalledNow ? "Reinstall Roslyn DLLs" : "Install Roslyn DLLs";
};
button.AddToClassList("action-button");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs` around lines 694 -
702, The button label can remain stale after running the click handler because
you only set button.text once using the outer "installed" value; inside the
click handler recalculate installation status after
RoslynInstaller.Install(interactive: true) (by calling
RoslynInstaller.IsInstalled()) and update button.text accordingly (e.g., set
button.text to "Reinstall Roslyn DLLs" or "Install Roslyn DLLs"); also update
statusLabel.text as you already do so the UI stays consistent. Use the existing
symbols: button, statusLabel, RoslynInstaller.Install,
RoslynInstaller.IsInstalled and the prior installed logic to determine the
correct label.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an in-Editor “one click” Roslyn DLL installer so projects can enable Roslyn-dependent features (script validation / runtime compilation) without manually downloading NuGet packages.

Changes:

  • Adds a new RoslynInstaller utility that downloads required NuGet packages and extracts DLLs into Assets/Plugins/Roslyn/.
  • Adds a Roslyn installation/status section to the MCP for Unity EditorWindow (Scripts tab).
  • Updates README installation guidance and bumps package version.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
README.md Documents the new one-click Roslyn installation path and updates manual install folder path.
MCPForUnity/package.json Bumps package version to 9.4.8-beta.8.
MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs Adds a new “Runtime Code Execution (Roslyn)” UI section and an install button.
MCPForUnity/Editor/Setup/RoslynInstaller.cs Implements download + extraction logic for Roslyn-related DLLs and registers a Unity menu item.
MCPForUnity/Editor/Setup/RoslynInstaller.cs.meta Adds Unity meta for the new installer script.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

README.md Outdated

Open `Window > MCP for Unity`, scroll to the **Runtime Code Execution (Roslyn)** section in the Scripts/Validation tab, and click **Install Roslyn DLLs**. This downloads the required NuGet packages and places the DLLs in `Assets/Plugins/Roslyn/` automatically.

You can also run it from the menu: `Tools > MCP for Unity > Install Roslyn DLLs`.
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

README references running the installer from Tools > MCP for Unity > Install Roslyn DLLs, but the new menu item is registered under Window/MCP For Unity/Install Roslyn DLLs (see RoslynInstaller). Update the README menu path to match the actual Unity menu location so users can find it.

Suggested change
You can also run it from the menu: `Tools > MCP for Unity > Install Roslyn DLLs`.
You can also run it from the menu: `Window/MCP For Unity/Install Roslyn DLLs`.

Copilot uses AI. Check for mistakes.
Comment on lines +685 to +690
bool installed = RoslynInstaller.IsInstalled();

var statusLabel = new Label(installed
? "\u2713 Roslyn DLLs are installed. The execute_code tool is available."
: "Roslyn DLLs are required for the execute_code tool (runtime C# compilation).");
statusLabel.AddToClassList("validation-description");
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The new UI copy claims the execute_code tool becomes available after installing Roslyn, but there is no execute_code tool defined anywhere in the repo (only these strings reference it). Consider updating this text to refer to the actual Roslyn-gated functionality (e.g., Roslyn-based script validation / runtime_compilation) and/or mention that USE_ROSLYN must be added to Scripting Define Symbols for Roslyn code paths to compile.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +18
private static readonly (string packageId, string version, string dllPath, string dllName)[] NuGetEntries =
{
("microsoft.codeanalysis.common", "4.12.0", "lib/netstandard2.0/Microsoft.CodeAnalysis.dll", "Microsoft.CodeAnalysis.dll"),
("microsoft.codeanalysis.csharp", "4.12.0", "lib/netstandard2.0/Microsoft.CodeAnalysis.CSharp.dll","Microsoft.CodeAnalysis.CSharp.dll"),
("system.collections.immutable", "8.0.0", "lib/netstandard2.0/System.Collections.Immutable.dll", "System.Collections.Immutable.dll"),
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

PR title says "set to 4.2.0", but the installer pins Microsoft.CodeAnalysis packages to 4.12.0. Either update the title/README to match 4.12.0, or change the pinned versions here to the intended Roslyn version to avoid confusion and accidental version drift.

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +103
if (dllBytes == null)
{
Debug.LogError($"[MCP] Could not find {dllPathInZip} in {packageId}.{pkgVersion}.nupkg");
continue;
}

string destPath = Path.Combine(destFolder, dllName);
File.WriteAllBytes(destPath, dllBytes);
Debug.Log($"[MCP] Extracted {dllName} ({dllBytes.Length / 1024}KB) → Assets/{PluginsRelPath}/{dllName}");
}
}

if (interactive)
EditorUtility.DisplayProgressBar("Installing Roslyn", "Refreshing assets...", 0.95f);

AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);

if (interactive)
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog(
"Roslyn Installed",
$"Roslyn DLLs and dependencies installed to Assets/{PluginsRelPath}/.\n\n" +
"The execute_code tool is now available via MCP.",
"OK");
}
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The install loop continues when a DLL can't be extracted, but the code still shows a "Roslyn Installed" success dialog/log afterwards. Track whether all required DLLs were successfully downloaded/extracted (and consider deleting partial installs), and show a failure/partial-install message when any entry fails so the UI doesn't report success when IsInstalled() is false.

Copilot uses AI. Check for mistakes.
Comment on lines +84 to +93
string destPath = Path.Combine(destFolder, dllName);
File.WriteAllBytes(destPath, dllBytes);
Debug.Log($"[MCP] Extracted {dllName} ({dllBytes.Length / 1024}KB) → Assets/{PluginsRelPath}/{dllName}");
}
}

if (interactive)
EditorUtility.DisplayProgressBar("Installing Roslyn", "Refreshing assets...", 0.95f);

AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

DLLs are written under Assets/Plugins/Roslyn/ but no plugin import settings are applied. By default, managed DLLs under Assets/Plugins are often included in player builds, which can bloat builds or cause conflicts. After writing each DLL (or after refresh), set the corresponding PluginImporter to be Editor-only (or otherwise match the intended compatibility) before calling AssetDatabase.Refresh/reimport.

Copilot uses AI. Check for mistakes.
Comment on lines +134 to +174
while (pos + 30 <= zipBytes.Length)
{
// Local file header signature = 0x04034b50
uint sig = ReadUInt32LE(zipBytes, pos);
if (sig != 0x04034b50)
break;

ushort method = ReadUInt16LE(zipBytes, pos + 8);
uint compressedSize = ReadUInt32LE(zipBytes, pos + 18);
uint uncompressedSize = ReadUInt32LE(zipBytes, pos + 22);
ushort nameLen = ReadUInt16LE(zipBytes, pos + 26);
ushort extraLen = ReadUInt16LE(zipBytes, pos + 28);

string name = Encoding.UTF8.GetString(zipBytes, pos + 30, nameLen);
int dataStart = pos + 30 + nameLen + extraLen;

if (name.Replace('\\', '/').Equals(entryPath, StringComparison.OrdinalIgnoreCase))
{
if (method == 0) // Store
{
byte[] result = new byte[uncompressedSize];
Buffer.BlockCopy(zipBytes, dataStart, result, 0, (int)uncompressedSize);
return result;
}
if (method == 8) // Deflate
{
using (var compressed = new MemoryStream(zipBytes, dataStart, (int)compressedSize))
using (var deflate = new System.IO.Compression.DeflateStream(compressed, System.IO.Compression.CompressionMode.Decompress))
using (var output = new MemoryStream((int)uncompressedSize))
{
deflate.CopyTo(output);
return output.ToArray();
}
}

Debug.LogWarning($"[MCP] Unsupported ZIP method {method} for {name}");
return null;
}

pos = dataStart + (int)compressedSize;
}
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

ExtractFileFromZip walks local file headers sequentially and assumes compressedSize/uncompressedSize are present in the local header. ZIPs that use the data-descriptor flag (common) can have sizes set to 0 in the local header, which would break the pos = dataStart + compressedSize advance (potential infinite loop) or cause incorrect extraction. Prefer using System.IO.Compression.ZipArchive (available in Unity’s .NET profile) or extend this parser to handle the general-purpose bit flag + data descriptor / central directory sizes safely.

Copilot uses AI. Check for mistakes.
README.md Outdated
Comment on lines +165 to +170
<details>
<summary>Manual DLL installation (if NuGetForUnity isn't available)</summary>
<summary>One-click installer (recommended)</summary>

Open `Window > MCP for Unity`, scroll to the **Runtime Code Execution (Roslyn)** section in the Scripts/Validation tab, and click **Install Roslyn DLLs**. This downloads the required NuGet packages and places the DLLs in `Assets/Plugins/Roslyn/` automatically.

You can also run it from the menu: `Tools > MCP for Unity > Install Roslyn DLLs`.
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The surrounding section still instructs users to install NuGetForUnity + extra SQLite packages before enabling Roslyn, but the new one-click installer downloads the DLLs directly and doesn't depend on NuGetForUnity. Consider updating this block so the one-click path is a standalone alternative (or the recommended first step), otherwise readers may do unnecessary setup that the installer bypasses.

Copilot uses AI. Check for mistakes.
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@MCPForUnity/Editor/Setup/RoslynInstaller.cs`:
- Around line 71-78: The download loop in RoslynInstaller
(UnityWebRequest.Get(url), request.SendWebRequest(), while (!request.isDone))
can hang indefinitely; add a timeout check: set request.timeout to a sensible
number (e.g., 30s) and/or track elapsed time with a Stopwatch around the while
loop and break/throw if it exceeds the limit, then ensure the existing check of
request.result != UnityWebRequest.Result.Success still runs and throws a
descriptive exception including the packageId and timeout info.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between edfdc2d and 94fc9a7.

📒 Files selected for processing (2)
  • MCPForUnity/Editor/Setup/RoslynInstaller.cs
  • README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • README.md

@Scriptwonder Scriptwonder merged commit 710e9ac into CoplayDev:beta Feb 28, 2026
1 check passed
@Scriptwonder Scriptwonder deleted the feature/roslyn-installer branch February 28, 2026 04:22
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.

3 participants