Feature/roslyn installer (set to 4.2.0)#841
Conversation
…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.
…onder/unity-mcp into feature/roslyn-installer
Reviewer's GuideAdds 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 windowsequenceDiagram
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
Class diagram for RoslynInstaller and MCPForUnityEditorWindow integrationclassDiagram
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
Flow diagram for RoslynInstaller installation logicgraph 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
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review infoConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds 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
Sequence DiagramsequenceDiagram
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The
RoslynInstallercurrently usesWebClient(which is obsolete) with explicit pragma suppression; consider switching toHttpClientorUnityWebRequestto avoid relying on deprecated APIs and future-proof the download logic. - The custom ZIP parsing in
ExtractFileFromZipmanually walks local file headers and assumes a specific layout; this is brittle for general .nupkg handling—if possible, preferZipArchive(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 useTools > 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.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
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
📒 Files selected for processing (5)
MCPForUnity/Editor/Setup/RoslynInstaller.csMCPForUnity/Editor/Setup/RoslynInstaller.cs.metaMCPForUnity/Editor/Windows/MCPForUnityEditorWindow.csMCPForUnity/package.jsonREADME.md
| 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."); | ||
| } |
There was a problem hiding this comment.
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.
| 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"); |
There was a problem hiding this comment.
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.
| 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.
There was a problem hiding this comment.
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
RoslynInstallerutility that downloads required NuGet packages and extracts DLLs intoAssets/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`. |
There was a problem hiding this comment.
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.
| 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`. |
| 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"); |
There was a problem hiding this comment.
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.
| 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"), |
There was a problem hiding this comment.
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.
| 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"); | ||
| } |
There was a problem hiding this comment.
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.
| 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); |
There was a problem hiding this comment.
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.
| 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; | ||
| } |
There was a problem hiding this comment.
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.
README.md
Outdated
| <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`. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
📒 Files selected for processing (2)
MCPForUnity/Editor/Setup/RoslynInstaller.csREADME.md
🚧 Files skipped from review as they are similar to previous changes (1)
- README.md
Description
Easier way to install Roslyn with one click.
Type of Change
Save your change type
Changes Made
Testing/Screenshots/Recordings
Documentation Updates
tools/UPDATE_DOCS_PROMPT.md(recommended)tools/UPDATE_DOCS.mdRelated 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:
Enhancements:
Summary by CodeRabbit
New Features
Documentation