diff --git a/MCPForUnity/Editor/Clients/Configurators/OpenCodeConfigurator.cs b/MCPForUnity/Editor/Clients/Configurators/OpenCodeConfigurator.cs new file mode 100644 index 00000000..3107fb5b --- /dev/null +++ b/MCPForUnity/Editor/Clients/Configurators/OpenCodeConfigurator.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.IO; +using MCPForUnity.Editor.Helpers; +using MCPForUnity.Editor.Models; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace MCPForUnity.Editor.Clients.Configurators +{ + /// + /// Configurator for OpenCode (opencode.ai) - a Go-based terminal AI coding assistant. + /// OpenCode uses ~/.config/opencode/opencode.json with a custom "mcp" format. + /// + public class OpenCodeConfigurator : McpClientConfiguratorBase + { + private const string ServerName = "unityMCP"; + + public OpenCodeConfigurator() : base(new McpClient + { + name = "OpenCode", + windowsConfigPath = BuildConfigPath(), + macConfigPath = BuildConfigPath(), + linuxConfigPath = BuildConfigPath() + }) + { } + + private static string BuildConfigPath() + { + string configDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + return Path.Combine(configDir, ".config", "opencode", "opencode.json"); + } + + public override string GetConfigPath() => CurrentOsPath(); + + public override McpStatus CheckStatus(bool attemptAutoRewrite = true) + { + try + { + string path = GetConfigPath(); + if (!File.Exists(path)) + { + client.SetStatus(McpStatus.NotConfigured); + return client.status; + } + + string json = File.ReadAllText(path); + var config = JsonConvert.DeserializeObject(json); + var mcpSection = config?["mcp"] as JObject; + + if (mcpSection == null || mcpSection[ServerName] == null) + { + client.SetStatus(McpStatus.NotConfigured); + return client.status; + } + + var unityMcp = mcpSection[ServerName] as JObject; + if (unityMcp == null) + { + client.SetStatus(McpStatus.NotConfigured); + return client.status; + } + + string configuredUrl = unityMcp["url"]?.ToString(); + string expectedUrl = HttpEndpointUtility.GetMcpRpcUrl(); + + if (UrlsEqual(configuredUrl, expectedUrl)) + { + client.SetStatus(McpStatus.Configured); + } + else if (attemptAutoRewrite) + { + Configure(); + } + else + { + client.SetStatus(McpStatus.IncorrectPath); + } + } + catch (Exception ex) + { + client.SetStatus(McpStatus.Error, ex.Message); + } + + return client.status; + } + + public override void Configure() + { + try + { + string path = GetConfigPath(); + string dir = Path.GetDirectoryName(path); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + + JObject config; + if (File.Exists(path)) + { + string existingJson = File.ReadAllText(path); + config = JsonConvert.DeserializeObject(existingJson) ?? new JObject(); + } + else + { + config = new JObject + { + ["$schema"] = "https://opencode.ai/config.json" + }; + } + + var mcpSection = config["mcp"] as JObject; + if (mcpSection == null) + { + mcpSection = new JObject(); + config["mcp"] = mcpSection; + } + + string httpUrl = HttpEndpointUtility.GetMcpRpcUrl(); + + mcpSection[ServerName] = new JObject + { + ["type"] = "remote", + ["url"] = httpUrl, + ["enabled"] = true + }; + + string output = JsonConvert.SerializeObject(config, Formatting.Indented); + File.WriteAllText(path, output); + + client.SetStatus(McpStatus.Configured); + } + catch (Exception ex) + { + throw new InvalidOperationException("Failed to configure OpenCode.", ex); + } + } + + public override string GetManualSnippet() + { + string httpUrl = HttpEndpointUtility.GetMcpRpcUrl(); + var snippet = new JObject + { + ["mcp"] = new JObject + { + [ServerName] = new JObject + { + ["type"] = "remote", + ["url"] = httpUrl, + ["enabled"] = true + } + } + }; + return JsonConvert.SerializeObject(snippet, Formatting.Indented); + } + + public override IList GetInstallationSteps() => new List + { + "Install OpenCode (https://opencode.ai)", + "Click Configure to add Unity MCP to ~/.config/opencode/opencode.json", + "Restart OpenCode", + "The Unity MCP server should be detected automatically" + }; + } +} diff --git a/MCPForUnity/Editor/Clients/Configurators/OpenCodeConfigurator.cs.meta b/MCPForUnity/Editor/Clients/Configurators/OpenCodeConfigurator.cs.meta new file mode 100644 index 00000000..8094fb1d --- /dev/null +++ b/MCPForUnity/Editor/Clients/Configurators/OpenCodeConfigurator.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 489f99ffb7e6743e88e3203552c8b37b \ No newline at end of file