Conversation
Reviewer's GuideAdds first-class OpenClaw MCP client support via a new configurator and updates documentation to describe OpenClaw setup and behavior across guides and READMEs. Sequence diagram for OpenClawConfigurator MCP setup and transport selectionsequenceDiagram
actor User
participant UnityEditorWindow
participant OpenClawConfigurator
participant FileSystem
participant HttpEndpointUtility
participant OpenClawApp
participant OpenClawMcpBridgePlugin
participant UnityMcpServer
User->>UnityEditorWindow: Select OpenClaw client and click Configure
UnityEditorWindow->>OpenClawConfigurator: Configure()
OpenClawConfigurator->>OpenClawConfigurator: GetConfigPath()
OpenClawConfigurator->>FileSystem: EnsureConfigDirectoryExists(path)
FileSystem-->>OpenClawConfigurator: Directory exists/created
alt Config file exists
OpenClawConfigurator->>FileSystem: Read openclaw.json
FileSystem-->>OpenClawConfigurator: Raw JSON text
OpenClawConfigurator->>OpenClawConfigurator: LoadConfig(text)
else No config file
OpenClawConfigurator->>OpenClawConfigurator: Create new JObject root
end
OpenClawConfigurator->>OpenClawConfigurator: Ensure plugins.entries[PluginName]
OpenClawConfigurator->>OpenClawConfigurator: UpsertUnityServer(serversToken)
OpenClawConfigurator->>HttpEndpointUtility: GetCurrentServerTransport()
HttpEndpointUtility-->>OpenClawConfigurator: ConfiguredTransport (Http or Stdio)
alt Transport is Stdio
OpenClawConfigurator->>OpenClawConfigurator: BuildUnityServerEntry() with stdio
else Transport is HTTP/HTTP remote
OpenClawConfigurator->>HttpEndpointUtility: GetMcpRpcUrl()
HttpEndpointUtility-->>OpenClawConfigurator: http://127.0.0.1:port/mcp
OpenClawConfigurator->>OpenClawConfigurator: BuildUnityServerEntry() with HTTP URL
end
OpenClawConfigurator->>FileSystem: WriteAtomicFile(openclaw.json, updated JSON)
FileSystem-->>OpenClawConfigurator: Write complete
OpenClawConfigurator->>UnityEditorWindow: Return (status Configured)
User->>OpenClawApp: Start OpenClaw
OpenClawApp->>FileSystem: Load openclaw.json
FileSystem-->>OpenClawApp: Config JSON with openclaw-mcp-bridge
OpenClawApp->>OpenClawMcpBridgePlugin: Initialize with servers.unityMCP
alt Transport is HTTP
OpenClawMcpBridgePlugin->>UnityMcpServer: JSON-RPC over HTTP /mcp
else Transport is Stdio
OpenClawMcpBridgePlugin->>UnityMcpServer: Spawn uvx subprocess with --transport stdio
UnityMcpServer-->>OpenClawMcpBridgePlugin: JSON-RPC over stdio
end
User->>OpenClawApp: Call unityMCP__call tool
OpenClawApp->>OpenClawMcpBridgePlugin: Execute proxy tool
OpenClawMcpBridgePlugin->>UnityMcpServer: Forward MCP tool invocation
UnityMcpServer-->>OpenClawMcpBridgePlugin: Result
OpenClawMcpBridgePlugin-->>OpenClawApp: Result
OpenClawApp-->>User: Display Unity MCP response
Class diagram for OpenClaw MCP client configuratorclassDiagram
class McpClientConfiguratorBase {
<<abstract>>
+McpClient client
+string GetConfigPath()
+McpStatus CheckStatus(bool attemptAutoRewrite)
+void Configure()
+string GetManualSnippet()
+IList~string~ GetInstallationSteps()
}
class McpClient {
+string name
+string windowsConfigPath
+string macConfigPath
+string linuxConfigPath
+McpStatus status
+ConfiguredTransport configuredTransport
+void SetStatus(McpStatus status)
+void SetStatus(McpStatus status, string message)
}
class OpenClawConfigurator {
-const string PluginName
-const string ServerName
-const string HttpTransportName
-const string StdioTransportName
-const string StdioUrl
+OpenClawConfigurator()
+string GetConfigPath()
+McpStatus CheckStatus(bool attemptAutoRewrite)
+void Configure()
+string GetManualSnippet()
+IList~string~ GetInstallationSteps()
-static string BuildConfigPath()
-JObject LoadConfig(string path)
-JObject FindUnityServer(JToken serversToken)
-JObject UpsertUnityServer(JToken serversToken)
-static JObject NormalizeServers(JToken serversToken)
-static JObject BuildUnityServerEntry()
-bool ServerMatchesCurrentEndpoint(JObject server)
-static bool IsEnabled(JObject entry)
-ConfiguredTransport ResolveTransport(JObject server)
}
class HttpEndpointUtility {
+ConfiguredTransport GetCurrentServerTransport()
+string GetMcpRpcUrl()
+string GetLocalMcpRpcUrl()
+string GetRemoteMcpRpcUrl()
}
class McpConfigurationHelper {
+void EnsureConfigDirectoryExists(string path)
+void WriteAtomicFile(string path, string contents)
+string ExtractUvxUrl(string[] args)
+bool PathsEqual(string a, string b)
}
class AssetPathUtility {
+(string uvxPath, string fromSource, string packageName) GetUvxCommandParts()
+IEnumerable~string~ GetUvxDevFlagsList()
+IEnumerable~string~ GetBetaServerFromArgsList()
}
class ConfiguredTransport {
<<enum>>
Http
HttpRemote
Stdio
Unknown
}
class McpStatus {
<<enum>>
NotConfigured
MissingConfig
IncorrectPath
Configured
Error
}
OpenClawConfigurator --|> McpClientConfiguratorBase
OpenClawConfigurator o--> McpClient
OpenClawConfigurator ..> HttpEndpointUtility
OpenClawConfigurator ..> McpConfigurationHelper
OpenClawConfigurator ..> AssetPathUtility
OpenClawConfigurator ..> ConfiguredTransport
OpenClawConfigurator ..> McpStatus
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughIntroduces OpenClawConfigurator, a new MCP client configurator managing OpenClaw plugin configuration at ~/.openclaw/openclaw.json with support for HTTP and stdio transports. Updates documentation across README files to replace Windsurf with OpenClaw in Quick Start prerequisites and configuration guidance. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ 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 found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="MCPForUnity/Editor/Clients/Configurators/OpenClawConfigurator.cs" line_range="368-372" />
<code_context>
+ string.Equals(toolPrefix, ServerName, StringComparison.OrdinalIgnoreCase);
+ }
+
+ private static bool IsEnabled(JObject entry)
+ {
+ JToken enabledToken = entry["enabled"];
+ return enabledToken == null || enabledToken.Type != JTokenType.Boolean || enabledToken.Value<bool>();
+ }
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Non-boolean `enabled` values are treated as enabled, which may hide misconfigurations.
`enabledToken == null || enabledToken.Type != JTokenType.Boolean || enabledToken.Value<bool>()` means any non-boolean `enabled` (e.g., "false" as a string, numbers, etc.) is treated as `true`, so malformed configs look the same as explicitly enabled ones. If you want stricter behavior, consider `enabledToken == null || (enabledToken.Type == JTokenType.Boolean && enabledToken.Value<bool>())`, or even treating non-boolean values as disabled to fail fast on misconfiguration.
```suggestion
private static bool IsEnabled(JObject entry)
{
JToken enabledToken = entry["enabled"];
// Default to enabled when not specified, but require a boolean when present
if (enabledToken == null)
{
return true;
}
return enabledToken.Type == JTokenType.Boolean && enabledToken.Value<bool>();
}
```
</issue_to_address>
### Comment 2
<location path="MCPForUnity/Editor/Clients/Configurators/OpenClawConfigurator.cs" line_range="110-119" />
<code_context>
+ JObject root = File.Exists(path) ? LoadConfig(path) : new JObject();
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Configure will throw on invalid JSON configs instead of surfacing a controlled status/error.
Since `Configure` calls `LoadConfig(path)` directly, any non-JSON or corrupted config will cause `InvalidOperationException` to escape this method, unlike `CheckStatus` which handles it locally. Consider catching `InvalidOperationException` here and mapping it to `McpStatus.Error` (with a similar message to `CheckStatus`) so UI callers see a controlled, user-friendly error instead of an unhandled exception.
Suggested implementation:
```csharp
JObject root;
try
{
root = File.Exists(path) ? LoadConfig(path) : new JObject();
}
catch (InvalidOperationException ex)
{
// Mirror CheckStatus behavior: surface a controlled, user-friendly error
SetStatus(McpStatus.Error, $"Failed to load configuration from '{path}': {ex.Message}");
return;
}
```
1. Ensure `OpenClawConfigurator` (or a base class) has a `SetStatus(McpStatus status, string message)` (or equivalent) method; if the name/signature differs, adjust the call in the `catch` block accordingly.
2. Confirm that `McpStatus.Error` is the correct enum member; if your status enum uses a different naming (e.g. `McpStatus.Failed`), update it in the replacement block.
3. Make sure `using System;` is present at the top of the file so `InvalidOperationException` is in scope; if it’s missing, add `using System;`.
4. If `CheckStatus` uses a specific error message format users are already familiar with, you may want to copy or factor that message into a shared helper and call it here instead of the inline string.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| private static bool IsEnabled(JObject entry) | ||
| { | ||
| JToken enabledToken = entry["enabled"]; | ||
| return enabledToken == null || enabledToken.Type != JTokenType.Boolean || enabledToken.Value<bool>(); | ||
| } |
There was a problem hiding this comment.
suggestion (bug_risk): Non-boolean enabled values are treated as enabled, which may hide misconfigurations.
enabledToken == null || enabledToken.Type != JTokenType.Boolean || enabledToken.Value<bool>() means any non-boolean enabled (e.g., "false" as a string, numbers, etc.) is treated as true, so malformed configs look the same as explicitly enabled ones. If you want stricter behavior, consider enabledToken == null || (enabledToken.Type == JTokenType.Boolean && enabledToken.Value<bool>()), or even treating non-boolean values as disabled to fail fast on misconfiguration.
| private static bool IsEnabled(JObject entry) | |
| { | |
| JToken enabledToken = entry["enabled"]; | |
| return enabledToken == null || enabledToken.Type != JTokenType.Boolean || enabledToken.Value<bool>(); | |
| } | |
| private static bool IsEnabled(JObject entry) | |
| { | |
| JToken enabledToken = entry["enabled"]; | |
| // Default to enabled when not specified, but require a boolean when present | |
| if (enabledToken == null) | |
| { | |
| return true; | |
| } | |
| return enabledToken.Type == JTokenType.Boolean && enabledToken.Value<bool>(); | |
| } |
| JObject root = File.Exists(path) ? LoadConfig(path) : new JObject(); | ||
|
|
||
| JObject plugins = root["plugins"] as JObject ?? new JObject(); | ||
| root["plugins"] = plugins; | ||
|
|
||
| JObject entries = plugins["entries"] as JObject ?? new JObject(); | ||
| plugins["entries"] = entries; | ||
|
|
||
| JObject pluginEntry = entries[PluginName] as JObject ?? new JObject(); | ||
| entries[PluginName] = pluginEntry; |
There was a problem hiding this comment.
suggestion (bug_risk): Configure will throw on invalid JSON configs instead of surfacing a controlled status/error.
Since Configure calls LoadConfig(path) directly, any non-JSON or corrupted config will cause InvalidOperationException to escape this method, unlike CheckStatus which handles it locally. Consider catching InvalidOperationException here and mapping it to McpStatus.Error (with a similar message to CheckStatus) so UI callers see a controlled, user-friendly error instead of an unhandled exception.
Suggested implementation:
JObject root;
try
{
root = File.Exists(path) ? LoadConfig(path) : new JObject();
}
catch (InvalidOperationException ex)
{
// Mirror CheckStatus behavior: surface a controlled, user-friendly error
SetStatus(McpStatus.Error, $"Failed to load configuration from '{path}': {ex.Message}");
return;
}- Ensure
OpenClawConfigurator(or a base class) has aSetStatus(McpStatus status, string message)(or equivalent) method; if the name/signature differs, adjust the call in thecatchblock accordingly. - Confirm that
McpStatus.Erroris the correct enum member; if your status enum uses a different naming (e.g.McpStatus.Failed), update it in the replacement block. - Make sure
using System;is present at the top of the file soInvalidOperationExceptionis in scope; if it’s missing, addusing System;. - If
CheckStatususes a specific error message format users are already familiar with, you may want to copy or factor that message into a shared helper and call it here instead of the inline string.
There was a problem hiding this comment.
Pull request overview
Adds OpenClaw as a supported MCP client in MCP for Unity, including a custom configurator that writes OpenClaw’s plugin-driven configuration format, plus documentation updates to mention OpenClaw in setup guides/READMEs.
Changes:
- Add
OpenClawConfiguratorto read/write~/.openclaw/openclaw.jsonfor theopenclaw-mcp-bridgeplugin. - Update top-level and Chinese READMEs with OpenClaw links and connection notes.
- Extend configurator guide docs with OpenClaw-specific details.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/i18n/README-zh.md | Mentions OpenClaw as an MCP client and updates connection instructions. |
| docs/guides/MCP_CLIENT_CONFIGURATORS.md | Documents OpenClaw as a special/plugin-based client with custom config rules. |
| README.md | Mentions OpenClaw in prerequisites and updates client connection instructions. |
| MCPForUnity/README.md | Adds OpenClaw to editor plugin guide + describes its bridge-based configuration. |
| MCPForUnity/Editor/Clients/Configurators/OpenClawConfigurator.cs.meta | Unity meta for the new configurator asset. |
| MCPForUnity/Editor/Clients/Configurators/OpenClawConfigurator.cs | Implements plugin-based config reading/writing + status detection for OpenClaw. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| private static bool IsEnabled(JObject entry) | ||
| { | ||
| JToken enabledToken = entry["enabled"]; | ||
| return enabledToken == null || enabledToken.Type != JTokenType.Boolean || enabledToken.Value<bool>(); | ||
| } |
There was a problem hiding this comment.
IsEnabled treats any non-boolean enabled value as enabled (e.g. "enabled": "false" will be considered enabled). This can cause status checks to report Configured when the plugin/server is actually disabled. Consider handling strings/integers explicitly (or defaulting non-boolean values to disabled) while still treating a missing key as enabled for backward compatibility.
| using MCPForUnity.Editor.Constants; | ||
| using MCPForUnity.Editor.Helpers; | ||
| using MCPForUnity.Editor.Models; | ||
| using MCPForUnity.Editor.Services; |
There was a problem hiding this comment.
using MCPForUnity.Editor.Services; appears to be unused in this file. Removing unused using directives keeps compile output cleaner and avoids implying dependencies that aren’t needed.
| * **Unity 2021.3 LTS+** — [Download Unity](https://unity.com/download) | ||
| * **Python 3.10+** and **uv** — [Install uv](https://docs.astral.sh/uv/getting-started/installation/) | ||
| * **An MCP Client** — [Claude Desktop](https://claude.ai/download) | [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | [Cursor](https://www.cursor.com/en/downloads) | [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview) | [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli) | [Windsurf](https://windsurf.com) | ||
| * **An MCP Client** — [Claude Desktop](https://claude.ai/download) | [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | [Cursor](https://www.cursor.com/en/downloads) | [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview) | [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli) | [OpenClaw](https://openclaw.ai) |
There was a problem hiding this comment.
PR description says this is an accidental branch merge/release flow change, but this diff introduces new OpenClaw client support + documentation updates. Please update the PR title/description (or split into a separate PR) so the change intent matches what’s being merged/released.
| * **Unity 2021.3 LTS+** — [Download Unity](https://unity.com/download) | ||
| * **Python 3.10+** and **uv** — [Install uv](https://docs.astral.sh/uv/getting-started/installation/) | ||
| * **An MCP Client** — [Claude Desktop](https://claude.ai/download) | [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | [Cursor](https://www.cursor.com/en/downloads) | [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview) | [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli) | [Windsurf](https://windsurf.com) | ||
| * **An MCP Client** — [Claude Desktop](https://claude.ai/download) | [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | [Cursor](https://www.cursor.com/en/downloads) | [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview) | [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli) | [OpenClaw](https://openclaw.ai) |
There was a problem hiding this comment.
This prerequisites list removed Windsurf, but later in the same README the manual configuration section still says the default HTTP config works with Windsurf. Either keep Windsurf in the client list (and/or step 5) or update the later sections so the supported-client guidance is consistent.
| * **Unity 2021.3 LTS+** — [下载 Unity](https://unity.com/download) | ||
| * **Python 3.10+** 和 **uv** — [安装 uv](https://docs.astral.sh/uv/getting-started/installation/) | ||
| * **一个 MCP 客户端** — [Claude Desktop](https://claude.ai/download) | [Cursor](https://www.cursor.com/en/downloads) | [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview) | [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli) | [Windsurf](https://windsurf.com) | ||
| * **一个 MCP 客户端** — [Claude Desktop](https://claude.ai/download) | [Cursor](https://www.cursor.com/en/downloads) | [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview) | [GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli) | [OpenClaw](https://openclaw.ai) |
There was a problem hiding this comment.
This prerequisites list removed Windsurf, but later in this doc the manual configuration section still references Windsurf as a supported HTTP client. Please keep the client mentions consistent (either add Windsurf back here / in the connection step, or remove/update the later Windsurf references).
| - For Claude Code, ensure the `claude` CLI is installed. | ||
| 4. Click “Start Bridge” if the Unity Bridge shows “Stopped”. | ||
| 5. Use your MCP client (Cursor, VS Code, Windsurf, Claude Code) to connect. | ||
| 5. Use your MCP client (Cursor, VS Code, OpenClaw, Claude Code) to connect. |
There was a problem hiding this comment.
Quick start step 5 drops Windsurf from the example client list, but later in this guide Windsurf is still referenced as a supported client in the MCP Client Configuration section. Please align the example lists (either include Windsurf here as well, or update the later section to avoid implying Windsurf support).
Accidentally merge the branch into main, gonna first merge it to beta and then do a release.
Summary by Sourcery
Add first-class OpenClaw MCP client support, including configuration logic and user documentation.
New Features:
Enhancements:
Documentation:
Summary by CodeRabbit
New Features
Documentation