Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions MCPForUnity/Editor/Config.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

105 changes: 105 additions & 0 deletions MCPForUnity/Editor/Config/McpDistributionSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.Net;
using System.Net.Sockets;
using UnityEngine;

namespace MCPForUnity.Editor.Config
{
/// <summary>
/// Distribution controls so we can ship different defaults (Asset Store vs. git) without forking code.
/// </summary>
[CreateAssetMenu(menuName = "MCP/Distribution Settings", fileName = "McpDistributionSettings")]
public class McpDistributionSettings : ScriptableObject
{
[SerializeField] internal string defaultHttpBaseUrl = "http://localhost:8080";
[SerializeField] internal bool skipSetupWindowWhenRemoteDefault = false;

internal bool IsRemoteDefault =>
!string.IsNullOrWhiteSpace(defaultHttpBaseUrl)
&& !IsLocalAddress(defaultHttpBaseUrl);
}

internal static class McpDistribution
{
private const string ResourcePath = "McpDistributionSettings";
private static McpDistributionSettings _cached;

internal static McpDistributionSettings Settings
{
get
{
if (_cached != null)
{
return _cached;
}

_cached = UnityEngine.Resources.Load<McpDistributionSettings>(ResourcePath);
if (_cached != null)
{
return _cached;
}

// No asset present (git/dev installs) - fall back to baked-in defaults.
_cached = ScriptableObject.CreateInstance<McpDistributionSettings>();
_cached.name = "McpDistributionSettings (Runtime Defaults)";
return _cached;
}
}

private static bool IsLocalAddress(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return true;
}

if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
{
return false;
}

string host = uri.Host;

if (string.Equals(host, "localhost", StringComparison.OrdinalIgnoreCase))
{
return true;
}

if (IPAddress.TryParse(host, out var ip))
{
if (IPAddress.IsLoopback(ip))
{
return true;
}

if (ip.AddressFamily == AddressFamily.InterNetwork)
{
var bytes = ip.GetAddressBytes();
// 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16
if (bytes[0] == 10) return true;
if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31) return true;
if (bytes[0] == 192 && bytes[1] == 168) return true;
if (bytes[0] == 169 && bytes[1] == 254) return true;
}
else if (ip.AddressFamily == AddressFamily.InterNetworkV6)
{
// ::1 loopback or fe80::/10 link-local
if (ip.IsIPv6LinkLocal || ip.Equals(IPAddress.IPv6Loopback))
{
return true;
}
}

return false;
}

// Hostname: treat *.local as local network; otherwise assume remote.
if (host.EndsWith(".local", StringComparison.OrdinalIgnoreCase))
{
return true;
}

return false;
}
}
}
11 changes: 11 additions & 0 deletions MCPForUnity/Editor/Config/McpDistributionSettings.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion MCPForUnity/Editor/Helpers/HttpEndpointUtility.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using UnityEditor;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Config;

namespace MCPForUnity.Editor.Helpers
{
Expand All @@ -12,7 +13,7 @@ namespace MCPForUnity.Editor.Helpers
public static class HttpEndpointUtility
{
private const string PrefKey = EditorPrefKeys.HttpBaseUrl;
private const string DefaultBaseUrl = "http://localhost:8080";
private static string DefaultBaseUrl => McpDistribution.Settings.defaultHttpBaseUrl;

/// <summary>
/// Returns the normalized base URL currently stored in EditorPrefs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MCPForUnity.Editor.Config;
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Services.Transport;
using Newtonsoft.Json;
Expand Down Expand Up @@ -667,7 +668,7 @@ private static Uri BuildWebSocketUri(string baseUrl)
{
if (string.IsNullOrWhiteSpace(baseUrl))
{
baseUrl = "http://localhost:8080";
baseUrl = McpDistribution.Settings.defaultHttpBaseUrl;
}

if (!Uri.TryCreate(baseUrl, UriKind.Absolute, out var httpUri))
Expand Down
11 changes: 11 additions & 0 deletions MCPForUnity/Editor/Setup/SetupWindowService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Windows;
using MCPForUnity.Editor.Constants;
using MCPForUnity.Editor.Config;
using UnityEditor;
using UnityEngine;

Expand Down Expand Up @@ -44,6 +45,16 @@ private static void CheckSetupNeeded()
// Check if setup was already completed or dismissed in previous sessions
bool setupCompleted = EditorPrefs.GetBool(SETUP_COMPLETED_KEY, false);
bool setupDismissed = EditorPrefs.GetBool(SETUP_DISMISSED_KEY, false);
bool userOverrodeHttpUrl = EditorPrefs.HasKey(EditorPrefKeys.HttpBaseUrl);

// In Asset Store builds with a remote default URL (and no user override), skip the local setup wizard.
if (!userOverrodeHttpUrl
&& McpDistribution.Settings.skipSetupWindowWhenRemoteDefault
&& McpDistribution.Settings.IsRemoteDefault)
{
McpLog.Info("Skipping Setup Window because this distribution ships with a hosted MCP URL. Open Window/MCP For Unity/Setup Window if you want to configure a local runtime.", always: false);
return;
}

// Only show Setup Window if it hasn't been completed or dismissed before
if (!(setupCompleted || setupDismissed))
Expand Down