chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59ff83375c2c74c8385c4a22549778dd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using MCPForUnity.Editor.Constants;
|
||||
using MCPForUnity.Editor.Models;
|
||||
using UnityEditor;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class AntigravityConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
// Antigravity 2.x migrated its MCP config from ~/.gemini/antigravity/mcp_config.json
|
||||
// (where Antigravity also stores its own runtime state — conversations, scratch, etc.)
|
||||
// to a dedicated ~/.gemini/config/mcp_config.json. The migration drops a `.migrated`
|
||||
// marker in the new location and renames the previous folder to `antigravity-backup`.
|
||||
// The old path is no longer read by Antigravity at all, so writing there silently
|
||||
// fails to register UnityMCP on every modern install.
|
||||
public AntigravityConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Antigravity 2.0",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".gemini", "config", "mcp_config.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".gemini", "config", "mcp_config.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".gemini", "config", "mcp_config.json"),
|
||||
HttpUrlProperty = "serverUrl",
|
||||
DefaultUnityFields = { { "disabled", false } },
|
||||
StripEnvWhenNotRequired = true
|
||||
})
|
||||
{ }
|
||||
|
||||
// Detect Antigravity itself, not just its config dir. ~/.gemini/config/ is created on
|
||||
// first launch of Antigravity 2.x, so the inherited ParentDirectoryExists check
|
||||
// false-negatives on a fresh install where the user hasn't opened Antigravity yet.
|
||||
// ~/.antigravity/ is created by the installer (VS-Code-style support dir) and the
|
||||
// macOS app bundle is dropped by the installer; either is conclusive evidence that
|
||||
// Antigravity is installed, regardless of whether it has been launched.
|
||||
public override bool IsInstalled
|
||||
{
|
||||
get
|
||||
{
|
||||
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
if (Directory.Exists(Path.Combine(home, ".antigravity"))) return true;
|
||||
if (Directory.Exists(Path.Combine(home, ".gemini", "config"))) return true;
|
||||
if (Directory.Exists(Path.Combine(home, ".gemini", "antigravity"))) return true;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
return Directory.Exists("/Applications/Antigravity.app");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Open Antigravity 2.0",
|
||||
"Click the more_horiz menu in the Agent pane > MCP Servers",
|
||||
"Select 'Install' for Unity MCP or use the Configure button above",
|
||||
"Restart Antigravity if necessary"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 331b33961513042e3945d0a1d06615b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Constants;
|
||||
using MCPForUnity.Editor.Models;
|
||||
using UnityEditor;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
/// <summary>
|
||||
/// Antigravity IDE — the separate IDE build that ships its own ~/.gemini/antigravity-ide/
|
||||
/// runtime dir and reads its MCP config from that same folder. It did NOT migrate to
|
||||
/// ~/.gemini/config/ the way Antigravity 2.0 did, so it still uses the legacy in-folder
|
||||
/// mcp_config.json layout. The two apps coexist on the same machine, so we expose them
|
||||
/// as separate clients rather than trying to autodetect which one to write to.
|
||||
/// </summary>
|
||||
public class AntigravityIdeConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public AntigravityIdeConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Antigravity IDE",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".gemini", "antigravity-ide", "mcp_config.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".gemini", "antigravity-ide", "mcp_config.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".gemini", "antigravity-ide", "mcp_config.json"),
|
||||
HttpUrlProperty = "serverUrl",
|
||||
DefaultUnityFields = { { "disabled", false } },
|
||||
StripEnvWhenNotRequired = true
|
||||
})
|
||||
{ }
|
||||
|
||||
// ~/.gemini/antigravity-ide/ is created by the IDE on first launch and holds both
|
||||
// its runtime state (annotations/, brain/, conversations/, ...) and its mcp_config.json
|
||||
// — presence of the dir is the canonical "Antigravity IDE has been installed and
|
||||
// launched at least once" signal.
|
||||
public override bool IsInstalled
|
||||
{
|
||||
get
|
||||
{
|
||||
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
return Directory.Exists(Path.Combine(home, ".gemini", "antigravity-ide"));
|
||||
}
|
||||
}
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Open Antigravity IDE",
|
||||
"Click the more_horiz menu in the Agent pane > MCP Servers",
|
||||
"Select 'Install' for Unity MCP or use the Configure button above",
|
||||
"Restart Antigravity IDE if necessary"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c74a24c69bb0481682d5e35731cba6b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Constants;
|
||||
using MCPForUnity.Editor.Models;
|
||||
using MCPForUnity.Editor.Services;
|
||||
using UnityEditor;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class CherryStudioConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public const string ClientName = "Cherry Studio";
|
||||
|
||||
public CherryStudioConfigurator() : base(new McpClient
|
||||
{
|
||||
name = ClientName,
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Cherry Studio", "config"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Cherry Studio", "config"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "Cherry Studio", "config"),
|
||||
SupportsHttpTransport = false
|
||||
})
|
||||
{ }
|
||||
|
||||
public override bool SupportsAutoConfigure => false;
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Open Cherry Studio",
|
||||
"Go to Settings (⚙️) → MCP Server",
|
||||
"Click 'Add Server' button",
|
||||
"For STDIO mode (recommended):",
|
||||
" - Name: unity-mcp",
|
||||
" - Type: STDIO",
|
||||
" - Command: uvx",
|
||||
" - Arguments: Copy from the Manual Configuration JSON below",
|
||||
"Click Save and restart Cherry Studio",
|
||||
"",
|
||||
"Note: Cherry Studio uses UI-based configuration.",
|
||||
"Use the manual snippet below as reference for the values to enter."
|
||||
};
|
||||
|
||||
public override McpStatus CheckStatus(bool attemptAutoRewrite = true)
|
||||
{
|
||||
client.SetStatus(McpStatus.NotConfigured, "Cherry Studio requires manual UI configuration");
|
||||
return client.status;
|
||||
}
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Cherry Studio uses UI-based configuration. " +
|
||||
"Please use the Manual Configuration snippet and Installation Steps to configure manually."
|
||||
);
|
||||
}
|
||||
|
||||
public override string GetManualSnippet()
|
||||
{
|
||||
bool useHttp = EditorConfigurationCache.Instance.UseHttpTransport;
|
||||
|
||||
if (useHttp)
|
||||
{
|
||||
return "# Cherry Studio does not support WebSocket transport.\n" +
|
||||
"# Cherry Studio supports STDIO and SSE transports.\n" +
|
||||
"# \n" +
|
||||
"# To use Cherry Studio:\n" +
|
||||
"# 1. Switch transport to 'Stdio' in Advanced Settings below\n" +
|
||||
"# 2. Return to this configuration screen\n" +
|
||||
"# 3. Copy the STDIO configuration snippet that will appear\n" +
|
||||
"# \n" +
|
||||
"# OPTION 2: SSE mode (future support)\n" +
|
||||
"# Note: Unity MCP does not currently have an SSE endpoint.\n" +
|
||||
"# This may be added in a future update.";
|
||||
}
|
||||
|
||||
return base.GetManualSnippet() + "\n\n" +
|
||||
"# Cherry Studio Configuration Instructions:\n" +
|
||||
"# Cherry Studio uses UI-based configuration, not a JSON file.\n" +
|
||||
"# \n" +
|
||||
"# To configure:\n" +
|
||||
"# 1. Open Cherry Studio\n" +
|
||||
"# 2. Go to Settings (⚙️) → MCP Server\n" +
|
||||
"# 3. Click 'Add Server'\n" +
|
||||
"# 4. Enter the following values from the JSON above:\n" +
|
||||
"# - Name: unity-mcp\n" +
|
||||
"# - Type: STDIO\n" +
|
||||
"# - Command: (copy 'command' value from JSON)\n" +
|
||||
"# - Arguments: (copy 'args' array values, space-separated or as individual entries)\n" +
|
||||
"# - Active: true\n" +
|
||||
"# 5. Click Save\n" +
|
||||
"# 6. Restart Cherry Studio";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6de06c6bb0399154d840a1e4c84be869
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
/// <summary>
|
||||
/// Claude Code configurator using the CLI-based registration (claude mcp add/remove).
|
||||
/// This integrates with Claude Code's native MCP management.
|
||||
/// </summary>
|
||||
public class ClaudeCodeConfigurator : ClaudeCliMcpConfigurator
|
||||
{
|
||||
public ClaudeCodeConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Claude Code",
|
||||
SupportsHttpTransport = true,
|
||||
})
|
||||
{ }
|
||||
|
||||
public override bool SupportsSkills => true;
|
||||
|
||||
public override string GetSkillInstallPath()
|
||||
{
|
||||
var userHome = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
return Path.Combine(userHome, ".claude", "skills", "unity-mcp-skill");
|
||||
}
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Ensure Claude CLI is installed (comes with Claude Code)",
|
||||
"Click Configure to add UnityMCP via 'claude mcp add'",
|
||||
"The server will be automatically available in Claude Code",
|
||||
"Use Unregister to remove via 'claude mcp remove'"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0d22681fc594475db1c189f2d9abdf7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
using UnityEditor;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class ClaudeDesktopConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public const string ClientName = "Claude Desktop";
|
||||
|
||||
public ClaudeDesktopConfigurator() : base(new McpClient
|
||||
{
|
||||
name = ClientName,
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Claude", "claude_desktop_config.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "Claude", "claude_desktop_config.json"),
|
||||
SupportsHttpTransport = false,
|
||||
StripEnvWhenNotRequired = true
|
||||
})
|
||||
{ }
|
||||
|
||||
public override bool SupportsSkills => true;
|
||||
|
||||
public override string GetSkillInstallPath()
|
||||
{
|
||||
var userHome = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
return Path.Combine(userHome, ".claude", "skills", "unity-mcp-skill");
|
||||
}
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Open Claude Desktop",
|
||||
"Go to Settings > Developer > Edit Config\nOR open the config path",
|
||||
"Paste the configuration JSON",
|
||||
"Save and restart Claude Desktop"
|
||||
};
|
||||
|
||||
private static readonly ConfiguredTransport[] StdioOnly = { ConfiguredTransport.Stdio };
|
||||
public override IReadOnlyList<ConfiguredTransport> SupportedTransports => StdioOnly;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5e5d87c9db57495f842dc366f1ebd65
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class ClineConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public ClineConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Cline",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
|
||||
HttpTypeValue = "streamableHttp",
|
||||
DefaultUnityFields = { { "disabled", false }, { "autoApprove", new object[] { } } }
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Open Cline in VS Code",
|
||||
"Click the MCP Servers icon in the Cline pane",
|
||||
"Go to Configure tab and click 'Configure MCP Servers'\nOR open the config file at the path above",
|
||||
"Paste the configuration JSON into the mcpServers object",
|
||||
"Save and restart VS Code"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b8abf0951c7413d9ff97a053b0adf2d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the CodeBuddy CLI (~/.codebuddy.json) MCP settings.
|
||||
/// </summary>
|
||||
public class CodeBuddyCliConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public CodeBuddyCliConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "CodeBuddy CLI",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".codebuddy.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".codebuddy.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".codebuddy.json"),
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Install CodeBuddy CLI and ensure '~/.codebuddy.json' exists",
|
||||
"Click Configure to add the UnityMCP entry (or manually edit the file above)",
|
||||
"Restart your CLI session if needed"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 923728a98c8c74cfaa6e9203c408f34e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class CodexConfigurator : CodexMcpConfigurator
|
||||
{
|
||||
public CodexConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Codex",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".codex", "config.toml"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".codex", "config.toml"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".codex", "config.toml")
|
||||
})
|
||||
{ }
|
||||
|
||||
public override bool SupportsSkills => true;
|
||||
|
||||
public override string GetSkillInstallPath()
|
||||
{
|
||||
var userHome = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
return Path.Combine(userHome, ".codex", "skills", "unity-mcp-skill");
|
||||
}
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Run 'codex config edit' in a terminal\nOR open the config file at the path above",
|
||||
"Paste the configuration TOML",
|
||||
"Save and restart Codex"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7037ef8b168e49f79247cb31c3be75a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class CopilotCliConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public CopilotCliConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "GitHub Copilot CLI",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".copilot", "mcp-config.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".copilot", "mcp-config.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".copilot", "mcp-config.json")
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Install GitHub Copilot CLI (https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli)",
|
||||
"Open or create mcp-config.json at the path above",
|
||||
"Paste the configuration JSON (or use /mcp add in the CLI)",
|
||||
"Restart your Copilot CLI session"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14a4b9a7f749248d496466c2a3a53e56
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class CursorConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public CursorConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Cursor",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cursor", "mcp.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cursor", "mcp.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cursor", "mcp.json")
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Open Cursor",
|
||||
"Go to File > Preferences > Cursor Settings > MCP > Add new global MCP server\nOR open the config file at the path above",
|
||||
"Paste the configuration JSON",
|
||||
"Save and restart Cursor"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b708eda314746481fb8f4a1fb0652b03
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Constants;
|
||||
using MCPForUnity.Editor.Models;
|
||||
using UnityEditor;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class GeminiCliConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public GeminiCliConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Gemini CLI",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".gemini", "settings.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".gemini", "settings.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".gemini", "settings.json"),
|
||||
HttpUrlProperty = "httpUrl",
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Ensure Gemini CLI is installed (see https://geminicli.com/docs/get-started/installation/)",
|
||||
"Click Register to add UnityMCP via 'gemini mcp add'",
|
||||
"The server will be automatically available in Gemini CLI",
|
||||
"Use Unregister to remove via 'gemini mcp remove'"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5e9bbb45e552453ab5cb557a22d43e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class KiloCodeConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public KiloCodeConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Kilo Code",
|
||||
// Kilo Code v7.0.33+ moved MCP config out of the VS Code extension's
|
||||
// globalStorage/mcp_settings.json to a CLI-style kilo.jsonc under ~/.config/kilo.
|
||||
// The new schema (https://app.kilo.ai/config.json) uses an "mcp" container,
|
||||
// type:"remote" for HTTP servers, type:"local" for stdio, and an "enabled" flag.
|
||||
// ~/.config/kilo/kilo.jsonc on every OS (UserProfile resolves to C:\Users\<user> on Windows).
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "kilo", "kilo.jsonc"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "kilo", "kilo.jsonc"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "kilo", "kilo.jsonc"),
|
||||
IsVsCodeLayout = false,
|
||||
ServerContainerKey = "mcp",
|
||||
HttpTypeValue = "remote",
|
||||
StdioTypeValue = "local",
|
||||
SchemaUrl = "https://app.kilo.ai/config.json",
|
||||
DefaultUnityFields = { { "enabled", true } }
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Install or update Kilo Code (v7.0.33 or newer)",
|
||||
"Open the Kilo Code MCP Servers view\nOR edit the config file at the path above (~/.config/kilo/kilo.jsonc)",
|
||||
"Paste the configuration JSON into the \"mcp\" object",
|
||||
"Save and restart Kilo Code"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3286d62ffe5644f5ea60488fd7e6513d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
/// <summary>
|
||||
/// Kimi Code CLI MCP client configurator.
|
||||
/// Kimi Code uses a JSON-based configuration file with mcpServers section.
|
||||
/// Config path: ~/.kimi/mcp.json
|
||||
///
|
||||
/// Kimi Code supports both stdio (uvx) and HTTP transport modes.
|
||||
/// Default: stdio mode (works without Unity Editor for basic operations)
|
||||
/// HTTP mode: requires Unity Editor running with MCP HTTP server started
|
||||
/// </summary>
|
||||
public class KimiCodeConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public KimiCodeConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Kimi Code",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".kimi", "mcp.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".kimi", "mcp.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".kimi", "mcp.json"),
|
||||
SupportsHttpTransport = true,
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Ensure Kimi Code CLI is installed (pip install kimi-cli or see https://github.com/MoonshotAI/kimi-cli)",
|
||||
"Click 'Auto Configure' to automatically add UnityMCP to ~/.kimi/mcp.json",
|
||||
"OR click 'Manual Setup' to copy the configuration JSON",
|
||||
"Open ~/.kimi/mcp.json and paste the configuration",
|
||||
"Save and restart Kimi Code CLI",
|
||||
"Use 'kimi mcp list' to verify Unity MCP is connected",
|
||||
"Note: For full functionality, open Unity Editor and start HTTP server"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 562758226f6844438b5b1ae03a2cc7b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class KiroConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public KiroConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Kiro",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".kiro", "settings", "mcp.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".kiro", "settings", "mcp.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".kiro", "settings", "mcp.json"),
|
||||
EnsureEnvObject = true,
|
||||
DefaultUnityFields = { { "disabled", false } }
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Open Kiro",
|
||||
"Go to File > Settings > Settings > Search for \"MCP\" > Open Workspace MCP Config\nOR open the config file at the path above",
|
||||
"Paste the configuration JSON",
|
||||
"Save and restart Kiro"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9b73ff071a6043dda1f2ec7d682ef71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,398 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Constants;
|
||||
using MCPForUnity.Editor.Helpers;
|
||||
using MCPForUnity.Editor.Models;
|
||||
using MCPForUnity.Editor.Services;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
/// <summary>
|
||||
/// Configurator for OpenClaw via the openclaw-mcp-bridge plugin.
|
||||
/// OpenClaw stores config at ~/.openclaw/openclaw.json.
|
||||
/// </summary>
|
||||
public class OpenClawConfigurator : McpClientConfiguratorBase
|
||||
{
|
||||
private const string PluginName = "openclaw-mcp-bridge";
|
||||
private const string ServerName = "unityMCP";
|
||||
private const string HttpTransportName = "http";
|
||||
private const string StdioTransportName = "stdio";
|
||||
private const string StdioUrl = "stdio://local";
|
||||
|
||||
public OpenClawConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "OpenClaw",
|
||||
windowsConfigPath = BuildConfigPath(),
|
||||
macConfigPath = BuildConfigPath(),
|
||||
linuxConfigPath = BuildConfigPath()
|
||||
})
|
||||
{ }
|
||||
|
||||
private static string BuildConfigPath()
|
||||
{
|
||||
return Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
||||
".openclaw",
|
||||
"openclaw.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);
|
||||
client.configuredTransport = ConfiguredTransport.Unknown;
|
||||
return client.status;
|
||||
}
|
||||
|
||||
JObject root = LoadConfig(path);
|
||||
JObject pluginEntry = root["plugins"]?["entries"]?[PluginName] as JObject;
|
||||
JObject unityServer = FindUnityServer(pluginEntry?["config"]?["servers"]);
|
||||
|
||||
if (pluginEntry == null || unityServer == null)
|
||||
{
|
||||
client.SetStatus(McpStatus.MissingConfig);
|
||||
client.configuredTransport = ConfiguredTransport.Unknown;
|
||||
return client.status;
|
||||
}
|
||||
|
||||
if (!IsEnabled(pluginEntry) || !IsEnabled(unityServer))
|
||||
{
|
||||
client.SetStatus(McpStatus.NotConfigured);
|
||||
client.configuredTransport = ConfiguredTransport.Unknown;
|
||||
return client.status;
|
||||
}
|
||||
|
||||
bool matches = ServerMatchesCurrentEndpoint(unityServer);
|
||||
if (matches)
|
||||
{
|
||||
client.SetStatus(McpStatus.Configured);
|
||||
client.configuredTransport = ResolveTransport(unityServer);
|
||||
return client.status;
|
||||
}
|
||||
|
||||
if (attemptAutoRewrite)
|
||||
{
|
||||
Configure();
|
||||
}
|
||||
else
|
||||
{
|
||||
client.SetStatus(McpStatus.IncorrectPath);
|
||||
client.configuredTransport = ConfiguredTransport.Unknown;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
client.SetStatus(McpStatus.Error, ex.Message);
|
||||
client.configuredTransport = ConfiguredTransport.Unknown;
|
||||
}
|
||||
|
||||
return client.status;
|
||||
}
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
if (EditorPrefs.GetBool(EditorPrefKeys.LockCursorConfig, false))
|
||||
return;
|
||||
|
||||
string path = GetConfigPath();
|
||||
McpConfigurationHelper.EnsureConfigDirectoryExists(path);
|
||||
|
||||
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;
|
||||
pluginEntry["enabled"] = true;
|
||||
|
||||
JObject pluginConfig = pluginEntry["config"] as JObject ?? new JObject();
|
||||
pluginEntry["config"] = pluginConfig;
|
||||
pluginConfig.Remove("timeout"); // removed in openclaw-mcp-bridge v2+
|
||||
pluginConfig.Remove("retries"); // removed in openclaw-mcp-bridge v2+
|
||||
pluginConfig["servers"] = UpsertUnityServer(pluginConfig["servers"]);
|
||||
|
||||
McpConfigurationHelper.WriteAtomicFile(path, root.ToString(Formatting.Indented));
|
||||
client.SetStatus(McpStatus.Configured);
|
||||
client.configuredTransport = HttpEndpointUtility.GetCurrentServerTransport();
|
||||
}
|
||||
|
||||
public override string GetManualSnippet()
|
||||
{
|
||||
JObject snippet = new JObject
|
||||
{
|
||||
["plugins"] = new JObject
|
||||
{
|
||||
["entries"] = new JObject
|
||||
{
|
||||
[PluginName] = new JObject
|
||||
{
|
||||
["enabled"] = true,
|
||||
["config"] = new JObject
|
||||
{
|
||||
["servers"] = new JObject
|
||||
{
|
||||
[ServerName] = BuildUnityServerEntry()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return snippet.ToString(Formatting.Indented);
|
||||
}
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Install OpenClaw",
|
||||
"Install the bridge plugin: npm install -g openclaw-mcp-bridge (or pnpm add -g openclaw-mcp-bridge)",
|
||||
"In MCP for Unity, choose OpenClaw and click Configure",
|
||||
"OpenClaw uses the currently selected MCP for Unity transport (HTTP or stdio)",
|
||||
"OpenClaw exposes a proxy tool such as unityMCP__call for Unity MCP access",
|
||||
"Restart OpenClaw if the plugin does not hot-reload the new config"
|
||||
};
|
||||
|
||||
private JObject LoadConfig(string path)
|
||||
{
|
||||
string text = File.ReadAllText(path);
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
return new JObject();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject<JObject>(text) ?? new JObject();
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"OpenClaw config contains non-JSON content and cannot be safely auto-edited: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private JObject FindUnityServer(JToken serversToken)
|
||||
{
|
||||
if (serversToken is JObject serverMap)
|
||||
{
|
||||
return serverMap[ServerName] as JObject;
|
||||
}
|
||||
|
||||
if (serversToken is JArray legacyServers)
|
||||
{
|
||||
foreach (JToken token in legacyServers)
|
||||
{
|
||||
JObject server = token as JObject;
|
||||
if (server == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string name = server["name"]?.ToString();
|
||||
if (string.Equals(name, ServerName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return server;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private JObject UpsertUnityServer(JToken serversToken)
|
||||
{
|
||||
JObject servers = NormalizeServers(serversToken);
|
||||
JObject entry = servers[ServerName] as JObject ?? new JObject();
|
||||
JObject desiredEntry = BuildUnityServerEntry();
|
||||
|
||||
entry.Remove("name");
|
||||
entry.Remove("prefix");
|
||||
entry.Remove("healthCheck");
|
||||
entry.Remove("command");
|
||||
entry.Remove("args");
|
||||
entry.Remove("env");
|
||||
entry.Remove("connectTimeoutMs");
|
||||
|
||||
foreach (var property in desiredEntry.Properties())
|
||||
{
|
||||
entry[property.Name] = property.Value.DeepClone();
|
||||
}
|
||||
|
||||
servers[ServerName] = entry;
|
||||
|
||||
return servers;
|
||||
}
|
||||
|
||||
private static JObject NormalizeServers(JToken serversToken)
|
||||
{
|
||||
if (serversToken is JObject serverMap)
|
||||
{
|
||||
return serverMap;
|
||||
}
|
||||
|
||||
var normalized = new JObject();
|
||||
if (!(serversToken is JArray legacyServers))
|
||||
{
|
||||
return normalized;
|
||||
}
|
||||
|
||||
foreach (JToken token in legacyServers)
|
||||
{
|
||||
if (!(token is JObject legacyServer))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string name = legacyServer["name"]?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
normalized[name] = legacyServer;
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private static JObject BuildUnityServerEntry()
|
||||
{
|
||||
ConfiguredTransport transport = HttpEndpointUtility.GetCurrentServerTransport();
|
||||
if (transport == ConfiguredTransport.Stdio)
|
||||
{
|
||||
var (uvxPath, _, packageName) = AssetPathUtility.GetUvxCommandParts();
|
||||
if (string.IsNullOrWhiteSpace(uvxPath))
|
||||
{
|
||||
throw new InvalidOperationException("uvx not found. Install uv/uvx or set the override in Advanced Settings.");
|
||||
}
|
||||
|
||||
var args = new JArray();
|
||||
foreach (string value in AssetPathUtility.GetUvxDevFlagsList())
|
||||
{
|
||||
args.Add(value);
|
||||
}
|
||||
foreach (string value in AssetPathUtility.GetBetaServerFromArgsList())
|
||||
{
|
||||
args.Add(value);
|
||||
}
|
||||
args.Add(packageName);
|
||||
args.Add("--transport");
|
||||
args.Add("stdio");
|
||||
|
||||
return new JObject
|
||||
{
|
||||
["enabled"] = true,
|
||||
["url"] = StdioUrl,
|
||||
["transport"] = StdioTransportName,
|
||||
["command"] = uvxPath,
|
||||
["args"] = args,
|
||||
["toolPrefix"] = ServerName,
|
||||
["requestTimeoutMs"] = 60000,
|
||||
["connectTimeoutMs"] = 15000
|
||||
};
|
||||
}
|
||||
|
||||
return new JObject
|
||||
{
|
||||
["enabled"] = true,
|
||||
["url"] = HttpEndpointUtility.GetMcpRpcUrl(),
|
||||
["transport"] = HttpTransportName,
|
||||
["toolPrefix"] = ServerName,
|
||||
["requestTimeoutMs"] = 30000
|
||||
};
|
||||
}
|
||||
|
||||
private bool ServerMatchesCurrentEndpoint(JObject server)
|
||||
{
|
||||
if (server == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ConfiguredTransport expectedTransport = HttpEndpointUtility.GetCurrentServerTransport();
|
||||
ConfiguredTransport configuredTransport = ResolveTransport(server);
|
||||
if (configuredTransport != expectedTransport)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (configuredTransport == ConfiguredTransport.Stdio)
|
||||
{
|
||||
string configuredUrl = server["url"]?.ToString();
|
||||
string command = server["command"]?.ToString();
|
||||
if (!UrlsEqual(configuredUrl, StdioUrl) || string.IsNullOrWhiteSpace(command))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the --from package source hasn't drifted (e.g. stable vs prerelease switch)
|
||||
string[] args = (server["args"] as JArray)?.ToObject<string[]>();
|
||||
string configuredSource = McpConfigurationHelper.ExtractUvxUrl(args);
|
||||
string expectedSource = GetExpectedPackageSourceForValidation();
|
||||
if (!string.IsNullOrEmpty(configuredSource) && !string.IsNullOrEmpty(expectedSource) &&
|
||||
!McpConfigurationHelper.PathsEqual(configuredSource, expectedSource))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string configuredUrl = server["url"]?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(configuredUrl) ||
|
||||
(!UrlsEqual(configuredUrl, HttpEndpointUtility.GetLocalMcpRpcUrl()) &&
|
||||
!UrlsEqual(configuredUrl, HttpEndpointUtility.GetRemoteMcpRpcUrl())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
string toolPrefix = server["toolPrefix"]?.ToString();
|
||||
return string.IsNullOrWhiteSpace(toolPrefix) ||
|
||||
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>();
|
||||
}
|
||||
|
||||
private ConfiguredTransport ResolveTransport(JObject server)
|
||||
{
|
||||
string configuredTransport = server?["transport"]?.ToString();
|
||||
string configuredUrl = server?["url"]?.ToString();
|
||||
|
||||
if (string.Equals(configuredTransport, StdioTransportName, StringComparison.OrdinalIgnoreCase) ||
|
||||
UrlsEqual(configuredUrl, StdioUrl))
|
||||
{
|
||||
return ConfiguredTransport.Stdio;
|
||||
}
|
||||
|
||||
if (UrlsEqual(configuredUrl, HttpEndpointUtility.GetRemoteMcpRpcUrl()))
|
||||
{
|
||||
return ConfiguredTransport.HttpRemote;
|
||||
}
|
||||
|
||||
if (UrlsEqual(configuredUrl, HttpEndpointUtility.GetLocalMcpRpcUrl()))
|
||||
{
|
||||
return ConfiguredTransport.Http;
|
||||
}
|
||||
|
||||
return ConfiguredTransport.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19f29c88761345158fc766d24e7c18f3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,224 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Configurator for OpenCode (opencode.ai) - a Go-based terminal AI coding assistant.
|
||||
/// OpenCode uses ~/.config/opencode/opencode.json with a custom "mcp" format.
|
||||
/// </summary>
|
||||
public class OpenCodeConfigurator : McpClientConfiguratorBase
|
||||
{
|
||||
private const string ServerName = "unityMCP";
|
||||
private const string SchemaUrl = "https://opencode.ai/config.json";
|
||||
private const string RemoteType = "remote";
|
||||
private const string LocalType = "local";
|
||||
|
||||
public OpenCodeConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "OpenCode",
|
||||
windowsConfigPath = BuildConfigPath(),
|
||||
macConfigPath = BuildConfigPath(),
|
||||
linuxConfigPath = BuildConfigPath()
|
||||
})
|
||||
{ }
|
||||
|
||||
private static string BuildConfigPath()
|
||||
{
|
||||
string xdgConfigHome = Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
|
||||
string configBase = !string.IsNullOrEmpty(xdgConfigHome)
|
||||
? xdgConfigHome
|
||||
: Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config");
|
||||
return Path.Combine(configBase, "opencode", "opencode.json");
|
||||
}
|
||||
|
||||
public override string GetConfigPath() => CurrentOsPath();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load and parse the config file.
|
||||
/// Returns null if file doesn't exist or cannot be read.
|
||||
/// Returns parsed JObject if valid JSON found.
|
||||
/// Logs warning if file exists but contains malformed JSON.
|
||||
/// </summary>
|
||||
private JObject TryLoadConfig(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return null;
|
||||
|
||||
string content;
|
||||
try
|
||||
{
|
||||
content = File.ReadAllText(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UnityEngine.Debug.LogWarning($"[OpenCodeConfigurator] Failed to read config file {path}: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject<JObject>(content) ?? new JObject();
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
// Malformed JSON - log warning and return null.
|
||||
// When Configure() receives null, it will do: TryLoadConfig(path) ?? new JObject()
|
||||
// This creates a fresh empty JObject, which replaces the entire file with only the unityMCP section.
|
||||
// Existing config sections are lost. To preserve sections, a different recovery strategy
|
||||
// (e.g., line-by-line parsing, JSON repair, or manual user intervention) would be needed.
|
||||
UnityEngine.Debug.LogWarning($"[OpenCodeConfigurator] Malformed JSON in {path}: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override McpStatus CheckStatus(bool attemptAutoRewrite = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = GetConfigPath();
|
||||
var config = TryLoadConfig(path);
|
||||
|
||||
if (config == null)
|
||||
{
|
||||
client.SetStatus(McpStatus.NotConfigured);
|
||||
return client.status;
|
||||
}
|
||||
|
||||
var unityMcp = config["mcp"]?[ServerName] as JObject;
|
||||
|
||||
if (unityMcp == null)
|
||||
{
|
||||
client.SetStatus(McpStatus.NotConfigured);
|
||||
return client.status;
|
||||
}
|
||||
|
||||
if (EntryMatchesCurrentTransport(unityMcp))
|
||||
{
|
||||
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();
|
||||
McpConfigurationHelper.EnsureConfigDirectoryExists(path);
|
||||
|
||||
// Load existing config or start fresh, preserving all other properties and MCP servers
|
||||
var config = TryLoadConfig(path) ?? new JObject();
|
||||
|
||||
// Only add $schema if creating a new file
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
config["$schema"] = SchemaUrl;
|
||||
}
|
||||
|
||||
// Preserve existing mcp section and only update our server entry
|
||||
var mcpSection = config["mcp"] as JObject ?? new JObject();
|
||||
config["mcp"] = mcpSection;
|
||||
|
||||
mcpSection[ServerName] = BuildServerEntry();
|
||||
|
||||
McpConfigurationHelper.WriteAtomicFile(path, JsonConvert.SerializeObject(config, Formatting.Indented));
|
||||
client.SetStatus(McpStatus.Configured);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
client.SetStatus(McpStatus.Error, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetManualSnippet()
|
||||
{
|
||||
var snippet = new JObject
|
||||
{
|
||||
["mcp"] = new JObject { [ServerName] = BuildServerEntry() }
|
||||
};
|
||||
return JsonConvert.SerializeObject(snippet, Formatting.Indented);
|
||||
}
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"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"
|
||||
};
|
||||
|
||||
private static JObject BuildServerEntry()
|
||||
{
|
||||
if (HttpEndpointUtility.GetCurrentServerTransport() == ConfiguredTransport.Stdio)
|
||||
{
|
||||
var (uvxPath, _, packageName) = AssetPathUtility.GetUvxCommandParts();
|
||||
if (string.IsNullOrWhiteSpace(uvxPath))
|
||||
{
|
||||
throw new InvalidOperationException("uvx not found. Install uv/uvx or set the override in Advanced Settings.");
|
||||
}
|
||||
|
||||
var command = new JArray { uvxPath };
|
||||
foreach (string value in AssetPathUtility.GetUvxDevFlagsList())
|
||||
{
|
||||
command.Add(value);
|
||||
}
|
||||
foreach (string value in AssetPathUtility.GetBetaServerFromArgsList())
|
||||
{
|
||||
command.Add(value);
|
||||
}
|
||||
command.Add(packageName);
|
||||
command.Add("--transport");
|
||||
command.Add("stdio");
|
||||
|
||||
return new JObject
|
||||
{
|
||||
["type"] = LocalType,
|
||||
["command"] = command,
|
||||
["enabled"] = true
|
||||
};
|
||||
}
|
||||
|
||||
return new JObject
|
||||
{
|
||||
["type"] = RemoteType,
|
||||
["url"] = HttpEndpointUtility.GetMcpRpcUrl(),
|
||||
["enabled"] = true
|
||||
};
|
||||
}
|
||||
|
||||
private bool EntryMatchesCurrentTransport(JObject entry)
|
||||
{
|
||||
string entryType = entry["type"]?.ToString();
|
||||
ConfiguredTransport expected = HttpEndpointUtility.GetCurrentServerTransport();
|
||||
|
||||
if (expected == ConfiguredTransport.Stdio)
|
||||
{
|
||||
return string.Equals(entryType, LocalType, StringComparison.OrdinalIgnoreCase)
|
||||
&& entry["command"] is JArray;
|
||||
}
|
||||
|
||||
return string.Equals(entryType, RemoteType, StringComparison.OrdinalIgnoreCase)
|
||||
&& UrlsEqual(entry["url"]?.ToString(), HttpEndpointUtility.GetMcpRpcUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 489f99ffb7e6743e88e3203552c8b37b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
/// <summary>
|
||||
/// Qwen Code MCP client configurator.
|
||||
/// Qwen Code uses a JSON-based configuration file with mcpServers section.
|
||||
/// Config path: ~/.qwen/settings.json
|
||||
///
|
||||
/// Qwen Code supports both stdio (uvx) and HTTP transport modes.
|
||||
/// Default: stdio mode (works without Unity Editor for basic operations)
|
||||
/// HTTP mode: requires Unity Editor running with MCP HTTP server started
|
||||
/// </summary>
|
||||
public class QwenCodeConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public QwenCodeConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Qwen Code",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".qwen", "settings.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".qwen", "settings.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".qwen", "settings.json"),
|
||||
SupportsHttpTransport = true,
|
||||
// Default to stdio transport for Qwen Code (like Cursor)
|
||||
// User can switch to HTTP in Unity: Window > MCP for Unity > Settings
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Ensure Qwen Code is installed (npm install -g @qwen-code/qwen-code or download from https://github.com/QwenLM/qwen-code)",
|
||||
"Open Qwen Code",
|
||||
"Click 'Auto Configure' to automatically add UnityMCP to settings.json",
|
||||
"OR click 'Manual Setup' to copy the configuration JSON",
|
||||
"Open ~/.qwen/settings.json and paste the configuration",
|
||||
"Save and restart Qwen Code",
|
||||
"Use /mcp command in Qwen Code to verify Unity MCP is connected",
|
||||
"Note: For full functionality, open Unity Editor and start HTTP server"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46891bcdb00e468cbd04afbfb8f3095e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class RiderConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public RiderConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Rider GitHub Copilot",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "github-copilot", "intellij", "mcp.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "github-copilot", "intellij", "mcp.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "github-copilot", "intellij", "mcp.json"),
|
||||
IsVsCodeLayout = true
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Install GitHub Copilot plugin in Rider",
|
||||
"Open or create mcp.json at the path above",
|
||||
"Paste the configuration JSON",
|
||||
"Save and restart Rider"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2511b0d05271d486bb61f8cc9fd11363
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class TraeConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public TraeConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Trae",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Trae", "mcp.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Trae", "mcp.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "Trae", "mcp.json"),
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Open Trae and go to Settings > MCP",
|
||||
"Select Add Server > Add Manually",
|
||||
"Paste the JSON or point to the mcp.json file\n"+
|
||||
"Windows: %AppData%\\Trae\\mcp.json\n" +
|
||||
"macOS: ~/Library/Application Support/Trae/mcp.json\n" +
|
||||
"Linux: ~/.config/Trae/mcp.json\n",
|
||||
"Save and restart Trae"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3ab39e22ae0948ab94beae307f9902e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class VSCodeConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public VSCodeConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "VSCode GitHub Copilot",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Code", "User", "mcp.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Code", "User", "mcp.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "Code", "User", "mcp.json"),
|
||||
IsVsCodeLayout = true
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Install GitHub Copilot extension",
|
||||
"Open or create mcp.json at the path above",
|
||||
"Paste the configuration JSON",
|
||||
"Save and restart VSCode"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bcc7ead475a4d4ea2978151c217757b8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class VSCodeInsidersConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public VSCodeInsidersConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "VSCode Insiders GitHub Copilot",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Code - Insiders", "User", "mcp.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Code - Insiders", "User", "mcp.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "Code - Insiders", "User", "mcp.json"),
|
||||
IsVsCodeLayout = true
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Install GitHub Copilot extension in VS Code Insiders",
|
||||
"Open or create mcp.json at the path above",
|
||||
"Paste the configuration JSON",
|
||||
"Save and restart VS Code Insiders"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c4a1b0d3b34489cbf0f8c40c49c4f3b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients.Configurators
|
||||
{
|
||||
public class WindsurfConfigurator : JsonFileMcpConfigurator
|
||||
{
|
||||
public WindsurfConfigurator() : base(new McpClient
|
||||
{
|
||||
name = "Windsurf",
|
||||
windowsConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".codeium", "windsurf", "mcp_config.json"),
|
||||
macConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".codeium", "windsurf", "mcp_config.json"),
|
||||
linuxConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".codeium", "windsurf", "mcp_config.json"),
|
||||
HttpUrlProperty = "serverUrl",
|
||||
DefaultUnityFields = { { "disabled", false } },
|
||||
StripEnvWhenNotRequired = true
|
||||
})
|
||||
{ }
|
||||
|
||||
public override IList<string> GetInstallationSteps() => new List<string>
|
||||
{
|
||||
"Open Windsurf",
|
||||
"Go to File > Preferences > Windsurf Settings > MCP > Manage MCPs > View raw config\nOR open the config file at the path above",
|
||||
"Paste the configuration JSON",
|
||||
"Save and restart Windsurf"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b528971e189f141d38db577f155bd222
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,77 @@
|
||||
using MCPForUnity.Editor.Models;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Contract for MCP client configurators. Each client is responsible for
|
||||
/// status detection, auto-configure, and manual snippet/steps.
|
||||
/// </summary>
|
||||
public interface IMcpClientConfigurator
|
||||
{
|
||||
/// <summary>Stable identifier (e.g., "cursor").</summary>
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>Display name shown in the UI.</summary>
|
||||
string DisplayName { get; }
|
||||
|
||||
/// <summary>Current status cached by the configurator.</summary>
|
||||
McpStatus Status { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The transport type the client is currently configured for.
|
||||
/// Returns Unknown if the client is not configured or the transport cannot be determined.
|
||||
/// </summary>
|
||||
ConfiguredTransport ConfiguredTransport { get; }
|
||||
|
||||
/// <summary>True if this client supports auto-configure.</summary>
|
||||
bool SupportsAutoConfigure { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True if this client appears installed on the user's machine. Used to filter
|
||||
/// "configure all detected" so we don't write configs for apps the user doesn't have.
|
||||
/// Implementations should be cheap (filesystem stat or cached path lookup).
|
||||
/// </summary>
|
||||
bool IsInstalled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Transports this client can be configured with. Order is "preference if user has no opinion";
|
||||
/// the configure path picks the user's global preference if present in this list, else falls back to the first entry.
|
||||
/// </summary>
|
||||
System.Collections.Generic.IReadOnlyList<ConfiguredTransport> SupportedTransports { get; }
|
||||
|
||||
/// <summary>Label to show on the configure button for the current state.</summary>
|
||||
string GetConfigureActionLabel();
|
||||
|
||||
/// <summary>Returns the platform-specific config path (or message for CLI-managed clients).</summary>
|
||||
string GetConfigPath();
|
||||
|
||||
/// <summary>Checks and updates status; returns current status.</summary>
|
||||
McpStatus CheckStatus(bool attemptAutoRewrite = true);
|
||||
|
||||
/// <summary>Runs auto-configuration (register/write file/CLI etc.). Always idempotent
|
||||
/// — calling twice with the same settings is safe and is what the bulk "Configure All"
|
||||
/// path relies on to refresh transport / server-version drift across every detected
|
||||
/// client.</summary>
|
||||
void Configure();
|
||||
|
||||
/// <summary>
|
||||
/// Removes UnityMCP from this client's config (JSON entry, CLI registration, etc.).
|
||||
/// Default is a no-op for client types that don't yet implement removal (Codex TOML);
|
||||
/// callers should treat this as best-effort. The UI's per-client button routes here
|
||||
/// when <see cref="Status"/> is <see cref="McpStatus.Configured"/>.
|
||||
/// </summary>
|
||||
void Unregister();
|
||||
|
||||
/// <summary>Returns the manual configuration snippet (JSON/TOML/commands).</summary>
|
||||
string GetManualSnippet();
|
||||
|
||||
/// <summary>Returns ordered human-readable installation steps.</summary>
|
||||
System.Collections.Generic.IList<string> GetInstallationSteps();
|
||||
|
||||
/// <summary>True if this client supports skill installation/sync.</summary>
|
||||
bool SupportsSkills { get; }
|
||||
|
||||
/// <summary>Returns the absolute path where skills should be installed, or null if unsupported.</summary>
|
||||
string GetSkillInstallPath();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5a5078d9e6e14027a1abfebf4018634
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d408fd7733cb4a1eb80f785307db2ff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MCPForUnity.Editor.Helpers;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MCPForUnity.Editor.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Central registry that auto-discovers configurators via TypeCache.
|
||||
/// </summary>
|
||||
public static class McpClientRegistry
|
||||
{
|
||||
private static List<IMcpClientConfigurator> cached;
|
||||
|
||||
public static IReadOnlyList<IMcpClientConfigurator> All
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cached == null)
|
||||
{
|
||||
cached = BuildRegistry();
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<IMcpClientConfigurator> BuildRegistry()
|
||||
{
|
||||
var configurators = new List<IMcpClientConfigurator>();
|
||||
|
||||
foreach (var type in TypeCache.GetTypesDerivedFrom<IMcpClientConfigurator>())
|
||||
{
|
||||
if (type.IsAbstract || !type.IsClass || !type.IsPublic)
|
||||
continue;
|
||||
|
||||
// Require a public parameterless constructor
|
||||
if (type.GetConstructor(Type.EmptyTypes) == null)
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
if (Activator.CreateInstance(type) is IMcpClientConfigurator instance)
|
||||
{
|
||||
configurators.Add(instance);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
McpLog.Warn($"UnityMCP: Failed to instantiate configurator {type.Name}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Alphabetical order by display name
|
||||
configurators = configurators.OrderBy(c => c.DisplayName, StringComparer.OrdinalIgnoreCase).ToList();
|
||||
return configurators;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ce08555f995e4e848a826c63f18cb35
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user