CoplayDev/unity-mcp · critical · ConnectionError
MCP for Unity requires FRAMING=1, got: {text!r}
Error message
MCP for Unity requires FRAMING=1, got: {text!r} What it means
Raised during the stdio TCP handshake (unity_connection.py:103). After connecting, the server reads the first line and expects it to contain the literal 'FRAMING=1'. When config.require_framing is True (the default) and the line lacks it, the server sends a best-effort advisory to the peer and refuses the connection, embedding whatever text was actually received as {text!r}.
Source
Thrown at Server/src/transport/legacy/unity_connection.py:103
break
buf.extend(chunk)
if b"\n" in buf:
break
except socket.timeout:
break
text = bytes(buf).decode('ascii', errors='ignore').strip()
if 'FRAMING=1' in text:
self.use_framing = True
logger.debug(
'MCP for Unity handshake received: FRAMING=1 (strict)')
else:
if require_framing:
# Best-effort plain-text advisory for legacy peers
with contextlib.suppress(Exception):
self.sock.sendall(
b'MCP for Unity requires FRAMING=1\n')
raise ConnectionError(
f'MCP for Unity requires FRAMING=1, got: {text!r}')
else:
self.use_framing = False
logger.warning(
'MCP for Unity handshake missing FRAMING=1; proceeding in legacy mode by configuration')
finally:
self.sock.settimeout(config.connection_timeout)
return True
except Exception as e:
logger.error(f"Failed to connect to Unity: {str(e)}")
try:
if self.sock:
self.sock.close()
except Exception:
pass
self.sock = None
return False
View on GitHub (pinned to c21bf496bc)
Solutions
- Update the MCPForUnity Unity package to a version that matches the Python server so it emits FRAMING=1.
- Confirm the resolved port actually belongs to the MCPForUnity bridge (check ~/.unity-mcp status files / port registry), not another process.
- Wait for Unity to finish booting before issuing commands.
- As a temporary interop escape hatch, set config.require_framing=False to allow legacy (unframed) mode — the server then logs a warning and proceeds.
Example fix
// before — strict (default) # config.require_framing == True -> raises on legacy peers // after — opt into legacy interop explicitly from core.config import config config.require_framing = False
Defensive patterns
Strategy: validation
Validate before calling
from core.config import config
def framing_interop_ok() -> bool:
# True only if the peer is known to emit FRAMING=1 (matched versions)
return config.require_framing or config.require_framing is False # see note Type guard
def is_framing_handshake_error(e: BaseException) -> bool:
return (isinstance(e, ConnectionError)
and 'requires FRAMING=1' in str(e)) Try / catch
try:
conn.connect()
except ConnectionError as e:
if 'requires FRAMING=1' in str(e):
# version mismatch — either upgrade the Unity package or allow legacy mode
from core.config import config
config.require_framing = False
conn.sock = None
conn.connect()
else:
raise Prevention
- Keep the Python server and the MCPForUnity Unity package on the same release line.
- Confirm the discovered port is the bridge, not another listener, before issuing commands.
- Wait for Unity to finish importing/booting before the first command.
When it happens
Trigger: send_command -> connect() where the peer on the discovered port is either an older Unity editor that does not speak the framing protocol, a different service entirely, or a Unity bridge still mid-boot that wrote something other than the FRAMING=1 banner.
Common situations: Version skew between the Python server and the MCPForUnity Unity package (server newer/stricter than the editor), a stale port pointed at another listener, or Unity not fully initialized when the first command fires.
Related errors
- Ping unsuccessful
- Invalid frame length: {length}
- Unexpected handshake from server: {line!r}
- Invalid frame length: {length}
- Unexpected handshake from server: {line!r}
AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13).
Data as JSON: /api/errors/192ebf52cf1e054d.
Report an issue: GitHub.