Transport Specification¶
This is the implementation-facing contract for the commandPort transport.
If a change affects connection lifecycle, host validation, timeout semantics, retry behavior, or response parsing, review this page before changing code.
Core Invariants¶
These should remain true unless an ADR explicitly changes them:
- the transport is the only server-side code allowed to communicate with Maya
- the transport accepts only
localhostand127.0.0.1 - transport policy is centralized here, not reimplemented in tool modules
- connection failures become typed Maya MCP errors
Scope¶
The transport layer is the only part of Maya MCP that talks to Maya directly.
Its implementation lives in src/maya_mcp/transport/commandport.py.
Purpose¶
The transport is responsible for:
- connecting to Maya's
commandPort - enforcing localhost-only host validation
- sending commands and receiving responses
- retrying connection attempts with backoff
- translating socket failures into typed Maya MCP errors
Connection Defaults¶
| Setting | Default |
|---|---|
| host | localhost |
| port | 7001 |
| connect timeout | 5.0 seconds |
| command timeout | 30.0 seconds |
| max retries | 3 |
| retry base delay | 0.5 seconds |
Only localhost and 127.0.0.1 are valid hosts.
The defaults above are code-level behavior and should stay aligned with ConnectionConfig and client initialization.
Lifecycle¶
The transport tracks three states:
OFFLINERECONNECTINGOK
Typical flow:
- A tool needs Maya.
- The transport connects if no healthy socket exists.
- On success, state becomes
OK. - If Maya is unavailable or the socket breaks, state drops to
OFFLINE. - The next request can trigger reconnect attempts.
Retry Behavior¶
Connection retries use exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | 0.5s |
| 2 | 1.0s |
| 3 | 2.0s |
Retries are used for connection failures, not for tool-level validation or Maya-side command errors.
Send-phase reconnect-and-retry is allowed only when the command was not successfully delivered. Once send has completed, the transport must not blindly replay the command.
Timeout Behavior¶
Connect timeout¶
Used while opening the socket to Maya.
If it expires, Maya MCP treats Maya as unavailable.
Command timeout¶
Used after the command is sent and the server is waiting for Maya to respond.
If it expires, Maya MCP raises MayaTimeoutError.
Response Handling¶
Maya commandPort can echo output, include null bytes, or return duplicate JSON fragments when echoOutput=True.
The transport normalizes that noise before tool code sees the result:
- strips empty and
Nonefragments - drops known Maya startup/plugin warning lines that can arrive on the commandPort stream before command output
- prefers JSON-like payloads when present
- deduplicates repeated JSON echoes
- returns the last unique JSON block when Maya printed more than one
- preserves useful non-JSON output lines after cleanup when a command does not return JSON
That keeps parsing logic centralized instead of spreading it across tool modules.
Tool modules should not implement their own socket read loops or commandPort response cleanup.
Typed Errors¶
Low-level failures are translated into the shared error types:
| Situation | Error |
|---|---|
| Maya cannot be reached | MayaUnavailableError |
| Maya stops responding before timeout | MayaTimeoutError |
| Invalid transport configuration | ValidationError |
Maya-side command failures are surfaced by higher layers as MayaCommandError.
Client-facing error payloads should stay structured enough for recovery logic and must not include secrets or raw tracebacks.
Why commandPort¶
Maya MCP uses commandPort because it:
- ships with Maya
- works across supported desktop platforms
- executes inside the live Maya process
- supports Python and MEL
The decision is recorded in ADR-0001 CommandPort.
Recommended Maya-Side Setup¶
import maya.cmds as cmds
try:
cmds.commandPort(name=":7001", close=True)
except RuntimeError:
pass
cmds.commandPort(
name=":7001",
sourceType="python",
echoOutput=True,
noreturn=False,
bufferSize=16384,
)
Operational Notes¶
- The transport serializes commandPort access per client. Concurrent server handlers can call the same client, but socket send/receive work still runs one request at a time.
- The module-level shared transport client is initialized under a singleton lock so concurrent first access still creates only one process-wide default client.
connect,disconnect, andreconfigureshare the same per-client serialization, so lifecycle changes cannot mutate socket state during an active command.- The per-client lock does not coordinate separate
CommandPortClientinstances. Live tests and MCP server flows should route tool calls through the shared transport client instead of keeping multiple commandPort sockets open to the same Maya session. - Restart the MCP server after local code changes when validating against a live Maya session.
- Restart Maya if
commandPortstate becomes confused or stale.
When To Update This Doc¶
Update this page when changing:
- host validation rules
- retry or reconnect rules
- timeout defaults or semantics
- command send/receive behavior
- response parsing behavior
- typed transport error mapping