How to Debug Unity MCP Connection Issues: WebSocket and HTTP Troubleshooting Guide
Unity MCP connection failures most commonly originate from invalid HTTP endpoint configurations, bind-all address resolution errors, or WebSocket lifecycle mismatches that can be isolated by inspecting TransportState.Error and validating output from HttpEndpointUtility.GetBaseUrl().
When AI assistants cannot communicate with the Unity Editor through the Model Context Protocol, the root cause typically lies in the transport layer implementation within the CoplayDev/unity-mcp repository. Understanding how TransportManager coordinates WebSocketTransportClient and how HttpEndpointUtility resolves base URLs allows you to systematically diagnose registration failures, dropped keep-alive pings, and authentication errors.
Unity MCP Transport Architecture Overview
The Unity MCP SDK implements a pluggable transport layer with distinct components responsible for connection lifecycle management.
Key Architectural Components
- TransportManager (
MCPForUnity/Editor/Services/Transport/TransportManager.cs): Creates and controls the active client instance, handling start/stop operations and state aggregation for both HTTP and stdio modes. - WebSocketTransportClient (
MCPForUnity/Editor/Services/Transport/Transports/WebSocketTransportClient.cs): Manages the persistent WebSocket connection, tool registration, keep-alive loops, and exponential backoff reconnection logic. - HttpEndpointUtility (
MCPForUnity/Editor/Helpers/HttpEndpointUtility.cs): Resolves the base URL for local (http://127.0.0.1:8080) or remote scopes and validates security policies including HTTPS requirements. - TransportState (
MCPForUnity/Editor/Services/Transport/TransportState.cs): Provides an immutable snapshot of connection status, exposingIsConnected,SessionId, andErrorproperties for runtime inspection.
Connection Initialization Flow
- Manager Startup:
TransportManager.StartAsync(TransportMode.Http)instantiatesWebSocketTransportClientthrough its internal factory. - Endpoint Resolution: The client queries
HttpEndpointUtility.GetBaseUrl()to determine the target server address. - URI Construction:
WebSocketTransportClient.BuildWebSocketUri(baseUrl)rewrites bind-only hosts (0.0.0.0→127.0.0.1,::→::1) and appends/hub/pluginto the path. - Socket Establishment:
EstablishConnectionAsynciterates candidate URIs, createsClientWebSocket, and applies API key headers fromEditorPrefs.GetString(EditorPrefKeys.ApiKey). - Registration: Upon successful connection, the client transmits a register payload containing
project_nameandproject_hash, then synchronizes enabled tools. - Keep-Alive: A background task pings the server every 15 seconds (
keepAliveInterval); failure triggersAttemptReconnectAsyncusing exponential backoff (0s to 30s) followed by steady 30-second intervals.
Diagnosing Common Unity MCP Connection Problems
Connection symptoms map directly to specific failure points in the architecture. Use targeted diagnostics for each error pattern.
"Connection failed. Check that the server URL is correct…"
This error indicates HttpEndpointUtility cannot resolve a valid base URL or the server is unreachable.
- Verify the active URL via
HttpEndpointUtility.GetBaseUrl()in the Unity Console. - Confirm Editor > Advanced Settings matches the server's listening address and port (default:
8080). - For remote connections, ensure the scheme is
httpsunless Allow Insecure Remote HTTP is explicitly enabled.
Bind-All Address Warnings (0.0.0.0 Resolution)
When the log displays "Base URL host '0.0.0.0' is bind-only; using '127.0.0.1' for client connection", the MCP server was launched with a bind-all flag that clients cannot use directly.
- Reconfigure the server launch arguments to
--bind 127.0.0.1instead of0.0.0.0. - Alternatively, enable Allow LAN Bind for HTTP Local in the Unity MCP settings to permit non-loopback addresses.
- Check
McpLog.Warnentries to confirm the host rewrite occurred inBuildWebSocketUri.
WebSocket Disconnection During Send Operations
Errors stating "WebSocket is not open" or "SendJsonAsync – WebSocket is not initialised" occur when the socket closes before a command transmission, often following a failed keep-alive ping.
- Inspect
TransportManager.GetState(TransportMode.Http).Errorvia a custom Editor script to retrieve the specific disconnection reason. - Review logs prefixed with
[WebSocket] Receive loop errorto identify server-side terminations. - Verify the MCP server process remains active and has not crashed from unhandled exceptions.
API Key Authentication Failures in Remote Mode
Remote HTTP mode requires a valid API key header injected during EstablishConnectionAsync (lines 70-73 of WebSocketTransportClient.cs).
- Validate that
EditorPrefs.GetString(EditorPrefKeys.ApiKey)returns a non-empty string matching your server configuration. - Connection will silently fail or return authorization errors if this preference is unset or expired.
Command Execution Timeouts
Tools that exceed DefaultCommandTimeout (30 seconds) will trigger timeout exceptions.
- Extend the deadline by passing a larger
timeoutvalue (in seconds) within theexecutemessage payload. - Optimize tool implementations to complete within the default window, or implement progress reporting to prevent keep-alive starvation.
Debugging Code Examples for Unity MCP
Use these snippets to programmatically inspect connection health and force recovery.
Manually Starting the HTTP Transport
Call this from an Editor script or test fixture to validate the full startup sequence:
using MCPForUnity.Editor.Services;
using MCPForUnity.Editor.Services.Transport;
using System.Threading.Tasks;
using UnityEngine;
public static async Task<bool> ValidateMcpConnectionAsync()
{
var manager = new TransportManager();
bool isConnected = await manager.StartAsync(TransportMode.Http);
if (!isConnected)
{
var state = manager.GetState(TransportMode.Http);
Debug.LogError($"MCP HTTP start failed: {state.Error}");
}
return isConnected;
}
Forcing Reconnection After Network Outage
When the socket enters a stale state, force a clean restart:
public static async Task RecoverConnectionAsync()
{
var manager = new TransportManager();
// Terminates the existing client without graceful close
manager.ForceStop(TransportMode.Http);
// Re-runs the full connection and registration flow
await manager.StartAsync(TransportMode.Http);
}
Inspecting Current Endpoint Configuration
Debug endpoint resolution and security scope:
using MCPForUnity.Editor.Helpers;
using UnityEngine;
public static void DiagnoseEndpoint()
{
string baseUrl = HttpEndpointUtility.GetBaseUrl();
bool isRemote = HttpEndpointUtility.IsRemoteScope();
Debug.Log($"MCP endpoint ({(isRemote ? "remote" : "local")}): {baseUrl}");
if (isRemote && baseUrl.StartsWith("http://"))
{
Debug.LogWarning("Insecure remote HTTP detected. Enable 'AllowInsecureRemoteHttp' or switch to HTTPS.");
}
}
Adjusting Keep-Alive Intervals (Advanced)
Modify the ping frequency before calling StartAsync() using reflection:
var client = new WebSocketTransportClient();
var field = client.GetType().GetField(
"_keepAliveInterval",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance
);
field?.SetValue(client, System.TimeSpan.FromSeconds(30));
await client.StartAsync();
Reading Transport State and Logs
All WebSocket activity logs use the [WebSocket] prefix, categorized by severity through McpLog. To surface runtime diagnostics:
- Query
TransportManager.GetState(TransportMode.Http)to accessTransportState.IsConnectedandTransportState.Error. - Enable verbose logging in the Unity Console to capture
McpLog.Debugmessages containing raw JSON payloads inReceiveLoopAsync. - Monitor
BridgeControlService(MCPForUnity/Editor/Services/BridgeControlService.cs) for UI-level connection indicators in the Editor toolbar.
Summary
- Validate endpoints first: Use
HttpEndpointUtility.GetBaseUrl()to confirm the client targets the correct server address and scheme. - Handle bind-all addresses: Replace
0.0.0.0with127.0.0.1in server configuration or enable LAN binding to prevent connection refusals. - Inspect TransportState:
TransportManager.GetState(mode).Errorprovides the definitive reason for disconnection. - Check authentication: Remote mode requires
EditorPrefKeys.ApiKeyto be set beforeEstablishConnectionAsyncexecutes. - Force recovery: Use
ForceStopfollowed byStartAsyncto clear stale sockets and trigger fresh registration when automatic reconnection stalls.
Frequently Asked Questions
Why does Unity MCP show "Connection failed. Check that the server URL is correct…"?
This error appears when HttpEndpointUtility resolves a base URL that is unreachable or malformed. Verify the URL in Editor > Advanced Settings matches your MCP server's listening address, ensure the port is correct (default 8080), and confirm remote URLs use HTTPS unless AllowInsecureRemoteHttp is enabled.
How do I fix the "Base URL host '0.0.0.0' is bind-only" warning?
The warning indicates your MCP server launched with --bind 0.0.0.0, which accepts connections on all interfaces but cannot be used as a client destination. Configure the server to bind specifically to 127.0.0.1 for local development, or enable Allow LAN Bind for HTTP Local in Unity MCP settings to permit the client to connect to non-loopback addresses.
What does "WebSocket is not open" mean and how do I resolve it?
This error occurs when WebSocketTransportClient attempts to send data while the underlying ClientWebSocket is closed or null, typically due to a failed keep-alive ping or server termination. Check TransportState.Error for the specific failure reason, verify the server process is running, and use ForceStop followed by StartAsync to reset the connection state if the automatic reconnection loop has stalled.
How can I check the current connection status programmatically?
Call TransportManager.GetState(TransportMode.Http) to retrieve a TransportState object containing IsConnected, SessionId, and Error properties. This immutable snapshot reflects the live status of the WebSocket transport and can be polled in Editor scripts or displayed in custom debugging windows to monitor MCP health in real-time.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →