Problem
On Windows, the MCP server uses Python's default ProactorEventLoop (IOCP-based). A transient Windows networking error, WinError 64: "The specified network name is no longer available", permanently kills the IPv4 socket accept loop while the IPv6 listener survives. Since the Unity plugin connects via ws://127.0.0.1:8080/hub/plugin (IPv4), all reconnect attempts fail and the plugin stays permanently disconnected.
MCP clients connecting over IPv6 (e.g., Claude Code via [::1]:8080) continue working fine, masking the issue.
How I Identified It
Server logs showed the IOCP accept failure:
asyncio - ERROR - Task exception was never retrieved
future: <Task finished coro=<IocpProactor.accept.<locals>.accept_coro() done>
exception=OSError(22, 'The specified network name is no longer available', None, 64, None)>
asyncio - ERROR - Accept failed on a socket
socket: <asyncio.TransportSocket fd=980, family=2, type=1, proto=0, laddr=('127.0.0.1', 8080)>
OSError: [WinError 64] The specified network name is no longer available
After this error, netstat confirmed only the IPv6 listener survived:
TCP [::1]:8080 [::]:0 LISTENING (server PID)
The 127.0.0.1:8080 listener was gone. The Unity plugin disconnected (WebSocket close code 1005), exhausted all 6 reconnect attempts against the dead IPv4 address, and gave up permanently.
Reproduction
- OS: Windows 11, Python 3.12
- Server version: 9.4.7
- Transport: HTTP (
--transport http --http-url http://localhost:8080)
Happens intermittently. The IOCP WinError 64 is a known class of transient errors on Windows that the ProactorEventLoop doesn't recover from gracefully on the accept path.
Fix
One-line fix in Server/src/main.py. Force SelectorEventLoop on Windows, which uses select() instead of IOCP and is immune to this bug:
import sys
import asyncio
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
Place this early in main.py, after the asyncio import and before any event loop is created. SelectorEventLoop fully supports HTTP + WebSocket serving. The only features it lacks vs ProactorEventLoop are subprocess pipes and named pipes, which the MCP server doesn't use.
After applying this, both IPv4 and IPv6 listeners survive indefinitely and the Unity plugin reconnects normally.
Secondary Issue: Plugin Reconnect Gives Up Permanently
WebSocketTransportClient.AttemptReconnectAsync tries only 6 times (0s, 1s, 3s, 5s, 10s, 30s) then sets state to "Failed to reconnect" with no further retry. If the server has any transient issue lasting longer than ~49 seconds, the plugin is permanently dead until manually restarted. Consider adding an infinite retry tail (e.g., every 30s after the initial schedule).
Problem
On Windows, the MCP server uses Python's default
ProactorEventLoop(IOCP-based). A transient Windows networking error,WinError 64: "The specified network name is no longer available", permanently kills the IPv4 socket accept loop while the IPv6 listener survives. Since the Unity plugin connects viaws://127.0.0.1:8080/hub/plugin(IPv4), all reconnect attempts fail and the plugin stays permanently disconnected.MCP clients connecting over IPv6 (e.g., Claude Code via
[::1]:8080) continue working fine, masking the issue.How I Identified It
Server logs showed the IOCP accept failure:
After this error,
netstatconfirmed only the IPv6 listener survived:The
127.0.0.1:8080listener was gone. The Unity plugin disconnected (WebSocket close code 1005), exhausted all 6 reconnect attempts against the dead IPv4 address, and gave up permanently.Reproduction
--transport http --http-url http://localhost:8080)Happens intermittently. The IOCP
WinError 64is a known class of transient errors on Windows that theProactorEventLoopdoesn't recover from gracefully on the accept path.Fix
One-line fix in
Server/src/main.py. ForceSelectorEventLoopon Windows, which usesselect()instead of IOCP and is immune to this bug:Place this early in
main.py, after theasyncioimport and before any event loop is created.SelectorEventLoopfully supports HTTP + WebSocket serving. The only features it lacks vsProactorEventLoopare subprocess pipes and named pipes, which the MCP server doesn't use.After applying this, both IPv4 and IPv6 listeners survive indefinitely and the Unity plugin reconnects normally.
Secondary Issue: Plugin Reconnect Gives Up Permanently
WebSocketTransportClient.AttemptReconnectAsynctries only 6 times (0s, 1s, 3s, 5s, 10s, 30s) then sets state to "Failed to reconnect" with no further retry. If the server has any transient issue lasting longer than ~49 seconds, the plugin is permanently dead until manually restarted. Consider adding an infinite retry tail (e.g., every 30s after the initial schedule).