/* ┌──────────────────────────────────────────────────────────────────┐ │ Author: Ivan Murzak (https://github.com/IvanMurzak) │ │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │ │ Copyright (c) 2025 Ivan Murzak │ │ Licensed under the Apache License, Version 2.0. │ │ See the LICENSE file in the project root for more information. │ └──────────────────────────────────────────────────────────────────┘ */ #nullable enable using System; using System.Collections.Generic; using System.Text.Json.Serialization; using com.IvanMurzak.McpPlugin; using com.IvanMurzak.McpPlugin.Common; using com.IvanMurzak.McpPlugin.Common.Utils; using com.IvanMurzak.Unity.MCP.Runtime.Utils; using static com.IvanMurzak.McpPlugin.Common.Consts.MCP.Server; namespace com.IvanMurzak.Unity.MCP { public partial class UnityMcpPlugin { protected readonly object configMutex = new(); protected UnityConnectionConfig unityConnectionConfig = null!; // Set by subclass constructors public class UnityConnectionConfig : ConnectionConfig { public static string DefaultHost => $"http://localhost:{GeneratePortFromDirectory()}"; public static List DefaultTools => new(); public static List DefaultPrompts => new(); public static List DefaultResources => new(); /// /// Backing field for the local server URL. Serialized as "host" in JSON. /// Use for the active connection URL (routes through Cloud mode). /// [JsonPropertyName("host")] public string LocalHost { get; set; } = DefaultHost; /// /// Backing field for the local auth token. Serialized as "token" in JSON. /// Use for the active token (routes through Cloud mode). /// [JsonPropertyName("token")] public string? LocalToken { get; set; } public const string DefaultCloudServerBaseUrl = "https://ai-game.dev"; public static string CloudServerBaseUrl { get { var args = ArgsUtils.ParseCommandLineArguments(); var envValue = args.GetValueOrDefault(EnvironmentUtils.EnvCloudUrl) ?? Environment.GetEnvironmentVariable(EnvironmentUtils.EnvCloudUrl); if (string.IsNullOrWhiteSpace(envValue)) return DefaultCloudServerBaseUrl; var normalized = envValue.Trim().Trim('"').TrimEnd('/'); if (!Uri.TryCreate(normalized, UriKind.Absolute, out var uri) || (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)) { return DefaultCloudServerBaseUrl; } // Strip trailing "/mcp" so CloudServerUrl doesn't produce "/mcp/mcp" if (normalized.EndsWith("/mcp", StringComparison.OrdinalIgnoreCase)) normalized = normalized[..^4]; return normalized; } } public static string CloudServerUrl => CloudServerBaseUrl + "/mcp"; /// /// Returns the active connection host based on . /// In Cloud mode, returns . /// In Local mode, returns . /// [JsonIgnore] public override string Host { get => ConnectionMode == ConnectionMode.Cloud ? CloudServerUrl : LocalHost; set => LocalHost = value; } /// /// Gets/sets the active auth token based on . /// In Cloud mode, routes to . /// In Local mode, routes to . /// Setter mirrors the getter so env-var / CLI overrides (which write via /// the generic Token property) land on the right field regardless of mode. /// [JsonIgnore] public override string? Token { get => ConnectionMode == ConnectionMode.Cloud ? CloudToken : LocalToken; set { if (ConnectionMode == ConnectionMode.Cloud) CloudToken = value; else LocalToken = value; } } public LogLevel LogLevel { get; set; } = LogLevel.Warning; public bool KeepServerRunning { get; set; } = false; public TransportMethod TransportMethod { get; set; } = TransportMethod.streamableHttp; public AuthOption AuthOption { get; set; } = AuthOption.none; public ConnectionMode ConnectionMode { get; set; } = ConnectionMode.Cloud; public string? CloudToken { get; set; } public List Tools { get; set; } = new(); public List Prompts { get; set; } = new(); public List Resources { get; set; } = new(); public Dictionary SkillAutoGenerate { get; set; } = new(); /// /// When non-null, only the tools whose names appear in this list are enabled; /// all others are disabled. Set by the UNITY_MCP_TOOLS environment variable /// (comma-separated tool IDs). Not persisted to disk. /// [JsonIgnore] public List? EnabledToolsOverride { get; set; } public UnityConnectionConfig() { SetDefault(); } public UnityConnectionConfig SetDefault() { Host = DefaultHost; var isCi = EnvironmentUtils.IsCi(); KeepConnected = !isCi; KeepServerRunning = !isCi; GenerateSkillFiles = false; SkillsPath = ".claude/skills"; // default skills location for Claude Code SkillAutoGenerate = new(); TransportMethod = TransportMethod.streamableHttp; AuthOption = AuthOption.none; ConnectionMode = ConnectionMode.Cloud; CloudToken = null; LogLevel = LogLevel.Warning; TimeoutMs = Consts.Hub.DefaultTimeoutMs; Tools = DefaultTools; Prompts = DefaultPrompts; Resources = DefaultResources; Token = GenerateToken(); return this; } public class McpFeature { public string Name { get; set; } = string.Empty; public bool Enabled { get; set; } = true; public McpFeature() { } public McpFeature(string name, bool enabled) { Name = name; Enabled = enabled; } } } } public enum ConnectionMode { Custom, Cloud } }