using System;
using System.Net;
using System.Net.Sockets;
using UnityEngine;
namespace LocalMcp.UnityServer
{
/// <summary>
/// Manages port allocation with fallback for MCP servers
/// </summary>
public static class McpPortManager
{
/// <summary>
/// Checks if a port is available
/// </summary>
public static bool IsPortAvailable(int port)
{
TcpListener listener = null;
try
{
listener = new TcpListener(IPAddress.Loopback, port);
listener.Start();
return true;
}
catch (SocketException)
{
// Port is already in use
return false;
}
finally
{
listener?.Stop();
}
}
/// <summary>
/// Finds an available port starting from the given port
/// </summary>
public static int FindAvailablePort(int startPort, int maxAttempts = 50)
{
for (int i = 0; i < maxAttempts; i++)
{
int port = startPort + (i * 2); // Increment by 2 to keep WS and HTTP ports paired
if (IsPortAvailable(port))
{
return port;
}
}
throw new Exception($"[MCP Port] Could not find available port after {maxAttempts} attempts starting from {startPort}");
}
/// <summary>
/// Gets the actual port to use with fallback logic
/// </summary>
public static int GetServerPort(int preferredPort, string serverType)
{
// First, try the preferred port
if (IsPortAvailable(preferredPort))
{
Debug.Log($"[MCP Port] {serverType} using preferred port: {preferredPort}");
return preferredPort;
}
// If preferred port is in use, find an alternative
Debug.LogWarning($"[MCP Port] {serverType} preferred port {preferredPort} is in use");
int alternativePort = FindAvailablePort(preferredPort + 2);
Debug.Log($"[MCP Port] {serverType} using alternative port: {alternativePort}");
return alternativePort;
}
/// <summary>
/// Allocates paired ports for WebSocket and HTTP servers
/// Ensures both ports are consecutive and available
/// </summary>
public static (int wsPort, int httpPort) AllocatePairedPorts(int preferredWsPort, int preferredHttpPort)
{
// Try preferred ports first
if (IsPortAvailable(preferredWsPort) && IsPortAvailable(preferredHttpPort))
{
Debug.Log($"[MCP Port] Using preferred ports - WS: {preferredWsPort}, HTTP: {preferredHttpPort}");
return (preferredWsPort, preferredHttpPort);
}
// Find alternative paired ports
Debug.LogWarning($"[MCP Port] Preferred ports unavailable (WS: {preferredWsPort}, HTTP: {preferredHttpPort})");
int startSearchPort = preferredWsPort;
int maxAttempts = 50;
for (int i = 0; i < maxAttempts; i++)
{
int wsPort = startSearchPort + (i * 2);
int httpPort = wsPort + 1;
if (IsPortAvailable(wsPort) && IsPortAvailable(httpPort))
{
Debug.Log($"[MCP Port] Using alternative ports - WS: {wsPort}, HTTP: {httpPort}");
return (wsPort, httpPort);
}
}
throw new Exception($"[MCP Port] Could not find available port pair after {maxAttempts} attempts");
}
}
}