diff --git a/MCPForUnity/Editor/Config.meta b/MCPForUnity/Editor/Config.meta
new file mode 100644
index 00000000..ae74d0cb
--- /dev/null
+++ b/MCPForUnity/Editor/Config.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 85b87f3586d7f4ab9a4c6299dd6f8e0b
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/MCPForUnity/Editor/Config/McpDistributionSettings.cs b/MCPForUnity/Editor/Config/McpDistributionSettings.cs
new file mode 100644
index 00000000..11616964
--- /dev/null
+++ b/MCPForUnity/Editor/Config/McpDistributionSettings.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using UnityEngine;
+
+namespace MCPForUnity.Editor.Config
+{
+ ///
+ /// Distribution controls so we can ship different defaults (Asset Store vs. git) without forking code.
+ ///
+ [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);
+
+ 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;
+ }
+ }
+
+ 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(ResourcePath);
+ if (_cached != null)
+ {
+ return _cached;
+ }
+
+ // No asset present (git/dev installs) - fall back to baked-in defaults.
+ _cached = ScriptableObject.CreateInstance();
+ _cached.name = "McpDistributionSettings (Runtime Defaults)";
+ return _cached;
+ }
+ }
+ }
+}
diff --git a/MCPForUnity/Editor/Config/McpDistributionSettings.cs.meta b/MCPForUnity/Editor/Config/McpDistributionSettings.cs.meta
new file mode 100644
index 00000000..afde627d
--- /dev/null
+++ b/MCPForUnity/Editor/Config/McpDistributionSettings.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 076640e601dc44b7ea64105223d6f0d3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/MCPForUnity/Editor/Helpers/HttpEndpointUtility.cs b/MCPForUnity/Editor/Helpers/HttpEndpointUtility.cs
index bda33cbb..53a1c843 100644
--- a/MCPForUnity/Editor/Helpers/HttpEndpointUtility.cs
+++ b/MCPForUnity/Editor/Helpers/HttpEndpointUtility.cs
@@ -1,6 +1,7 @@
using System;
using UnityEditor;
using MCPForUnity.Editor.Constants;
+using MCPForUnity.Editor.Config;
namespace MCPForUnity.Editor.Helpers
{
@@ -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;
///
/// Returns the normalized base URL currently stored in EditorPrefs.
diff --git a/MCPForUnity/Editor/Services/Transport/Transports/WebSocketTransportClient.cs b/MCPForUnity/Editor/Services/Transport/Transports/WebSocketTransportClient.cs
index 14ff7259..35011a80 100644
--- a/MCPForUnity/Editor/Services/Transport/Transports/WebSocketTransportClient.cs
+++ b/MCPForUnity/Editor/Services/Transport/Transports/WebSocketTransportClient.cs
@@ -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;
@@ -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))
diff --git a/MCPForUnity/Editor/Setup/SetupWindowService.cs b/MCPForUnity/Editor/Setup/SetupWindowService.cs
index b1c5ed6d..1bf4ad91 100644
--- a/MCPForUnity/Editor/Setup/SetupWindowService.cs
+++ b/MCPForUnity/Editor/Setup/SetupWindowService.cs
@@ -4,6 +4,7 @@
using MCPForUnity.Editor.Helpers;
using MCPForUnity.Editor.Windows;
using MCPForUnity.Editor.Constants;
+using MCPForUnity.Editor.Config;
using UnityEditor;
using UnityEngine;
@@ -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))