Skip to content

传输层

v0.14 已替换遗留传输栈(issue #251)。

旧版类 — TransportManagerFramedChannelFramedIoIpcListener(Python 版)、ListenerHandleRoutingStrategyConnectionPoolInstanceRouterCircuitBreakerMessageEnvelopeencode_request / encode_response / encode_notify / decode_envelopeconnect_ipc — 均已移除。请使用下方基于 ipckit 的 DccLink 适配器。

传输层(dcc-mcp-transport crate)提供 MCP 服务器与 DCC 应用实例之间的 IPC 通信,使用 DccLink 帧格式通过 Named Pipe(Windows)或 Unix Domain Socket(macOS/Linux)传输。

概览

新传输 API 围绕 DccLink 适配器 构建 —— 这是对 ipckit IPC 通道的轻量封装,使用二进制线格式([u32 len][u8 type][u64 seq][msgpack body])实现高效帧通信。

python
from dcc_mcp_core import IpcChannelAdapter, DccLinkFrame

# 服务端:创建命名通道并等待客户端
server = IpcChannelAdapter.create("my-dcc")
server.wait_for_client()

# 客户端:连接到服务端
client = IpcChannelAdapter.connect("my-dcc")

# 发送帧
frame = DccLinkFrame(msg_type=1, seq=0, body=b"hello")
client.send_frame(frame)

# 接收帧
received = server.recv_frame()
print(received.body)  # b"hello"

DccLinkFrame

DCC-Link 协议的二进制线帧。线格式:[u32 len][u8 type][u64 seq][msgpack body]

消息类型

标签类型说明
1Call请求调用
2Reply成功响应
3Err错误响应
4Progress进度更新
5Cancel取消信号
6Push服务端推送消息
7Ping心跳请求
8Pong心跳响应

构造函数

python
from dcc_mcp_core import DccLinkFrame

frame = DccLinkFrame(msg_type=1, seq=0, body=b"hello")
参数类型说明
msg_typeint消息类型标签(1-8)
seqint序列号
bodybytes | None载荷字节(默认 b""

属性

属性类型说明
msg_typeint消息类型标签(1=Call, 2=Reply, 3=Err, 4=Progress, 5=Cancel, 6=Push, 7=Ping, 8=Pong)
seqint序列号
bodybytes载荷字节

方法

方法返回值说明
encode()bytes将帧编码为 [len][type][seq][body] 字节
decode(data)DccLinkFrame从包含 4 字节长度前缀的字节中解码帧(静态方法)
python
frame = DccLinkFrame(msg_type=1, seq=0, body=b"payload")
encoded = frame.encode()
decoded = DccLinkFrame.decode(encoded)
assert decoded.msg_type == frame.msg_type
assert decoded.seq == frame.seq
assert decoded.body == frame.body

IpcChannelAdapter

基于 ipckit::IpcChannel 的轻量适配器,使用 DCC-Link 帧格式。支持通过 Named Pipe(Windows)或 Unix Domain Socket(macOS/Linux)的 1:1 连接。

创建服务端

python
from dcc_mcp_core import IpcChannelAdapter

server = IpcChannelAdapter.create("my-dcc")
server.wait_for_client()  # 阻塞等待客户端连接

作为客户端连接

python
from dcc_mcp_core import IpcChannelAdapter

client = IpcChannelAdapter.connect("my-dcc")

发送和接收帧

python
from dcc_mcp_core import IpcChannelAdapter, DccLinkFrame

# 服务端
server = IpcChannelAdapter.create("my-dcc")
server.wait_for_client()

# 客户端
client = IpcChannelAdapter.connect("my-dcc")

# 客户端发送 Call 帧
call_frame = DccLinkFrame(msg_type=1, seq=0, body=b"execute_python")
client.send_frame(call_frame)

# 服务端接收帧
received = server.recv_frame()  # 阻塞;通道关闭时返回 None
if received is not None:
    print(received.msg_type)  # 1
    print(received.body)      # b"execute_python"

    # 服务端发送 Reply 帧
    reply = DccLinkFrame(msg_type=2, seq=0, body=b"ok")
    server.send_frame(reply)

# 客户端接收回复
response = client.recv_frame()

静态方法

方法返回值说明
create(name)IpcChannelAdapter创建服务端 IPC 通道
connect(name)IpcChannelAdapter连接到已有的 IPC 通道

实例方法

方法返回值说明
wait_for_client()None等待客户端连接(仅服务端)
send_frame(frame)None向对端发送 DccLinkFrame
recv_frame()DccLinkFrame | None接收帧(阻塞)。通道关闭时返回 None

GracefulIpcChannelAdapter

IpcChannelAdapter 基础上增加了优雅关闭和 DCC 主线程集成。适用于需要在主线程处理 IPC 消息而不阻塞的 DCC 插件。

创建优雅服务端

python
from dcc_mcp_core import GracefulIpcChannelAdapter

server = GracefulIpcChannelAdapter.create("my-dcc")
server.bind_affinity_thread()  # 在 DCC 主线程上调用一次
server.wait_for_client()

在主线程上处理消息

在 DCC 应用中,IPC 消息通常需要在主线程上处理。在空闲回调中使用 pump_pending()

python
# Maya 示例:使用 scriptJob idleEvent
import maya.cmds as cmds

def on_idle():
    processed = server.pump_pending(budget_ms=50)
    # 返回已处理的条目数

cmds.scriptJob(idleEvent="python(\"on_idle()\")")

优雅关闭

python
server.shutdown()  # 信号通道优雅关闭

静态方法

方法返回值说明
create(name)GracefulIpcChannelAdapter创建服务端优雅 IPC 通道
connect(name)GracefulIpcChannelAdapter连接到已有的优雅 IPC 通道

实例方法

方法返回值说明
wait_for_client()None等待客户端连接(仅服务端)
send_frame(frame)None向对端发送 DccLinkFrame
recv_frame()DccLinkFrame | None接收帧(阻塞)。通道关闭时返回 None
shutdown()None信号通道优雅关闭
bind_affinity_thread()None将当前线程绑定为亲和线程。在 DCC 主线程上调用一次
pump_pending(budget_ms=100)int在亲和线程上按预算排空待处理工作项。返回已处理条目数

SocketServerAdapter

基于 Unix Domain Socket(macOS/Linux)或 Named Pipe(Windows)的多客户端 IPC 服务器。支持有界连接池。

创建 Socket 服务器

python
from dcc_mcp_core import SocketServerAdapter

server = SocketServerAdapter(
    path="/tmp/my-dcc.sock",  # Unix socket 路径或 Windows 管道名
    max_connections=10,        # 最大并发连接数
    connection_timeout_ms=30000,  # 连接超时(毫秒)
)

print(server.socket_path)      # 服务端监听路径
print(server.connection_count) # 当前连接的客户端数

server.shutdown()  # 优雅关闭

构造函数

参数类型默认值说明
pathstrSocket 路径(Unix)或管道名(Windows)
max_connectionsint10最大并发连接数
connection_timeout_msint30000连接超时(毫秒)

属性

属性类型说明
socket_pathstr服务端监听的 socket 路径
connection_countint当前连接的客户端数

实例方法

方法返回值说明
shutdown()None优雅关闭服务端(阻塞直到停止)
signal_shutdown()None发出关闭信号但不阻塞

传输辅助类

TransportAddress

协议无关的传输端点。支持 TCP、Named Pipe(Windows)和 Unix Domain Socket(macOS/Linux)。

python
from dcc_mcp_core import TransportAddress

# 工厂构造函数
addr = TransportAddress.tcp("127.0.0.1", 18812)
addr = TransportAddress.named_pipe("maya-mcp")          # Windows
addr = TransportAddress.unix_socket("/tmp/maya.sock")   # macOS/Linux

# 平台最优本地地址(以 PID 为唯一标识)
addr = TransportAddress.default_local("maya", pid=12345)

# 从 URI 字符串解析
addr = TransportAddress.parse("tcp://127.0.0.1:18812")
属性/方法返回值说明
schemestr"tcp""pipe""unix"
is_localbool是否为本机传输
is_tcpbool是否为 TCP
is_named_pipebool是否为 Named Pipe
is_unix_socketbool是否为 Unix Socket
to_connection_string()strURI 字符串,如 "tcp://127.0.0.1:18812"

TransportScheme

选择最优通信通道的策略:

常量说明
AUTO自动选择最优传输(Windows 用 Named Pipe,*nix 用 Unix Socket)
TCP_ONLY始终使用 TCP
PREFER_NAMED_PIPE优先 Named Pipe,降级到 TCP
PREFER_UNIX_SOCKET优先 Unix Socket,降级到 TCP
PREFER_IPC优先任意 IPC,降级到 TCP
python
from dcc_mcp_core import TransportScheme

addr = TransportScheme.AUTO.select_address("maya", "127.0.0.1", 18812, pid=12345)

ServiceEntry

已注册 DCC 服务实例的描述对象。

属性类型说明
dcc_typestrDCC 类型,如 "maya"
instance_idstrUUID 字符串
hoststr主机地址
portintTCP 端口
versionstr | NoneDCC 版本
scenestr | None当前打开的场景/文件
metadatadict[str, str]自定义字符串元数据
extrasdict[str, Any]JSON 类型的 DCC 元数据
statusServiceStatus实例状态
transport_addressTransportAddress | None首选 IPC 地址
last_heartbeat_msint最后心跳时间戳(Unix 毫秒)

ServiceStatus

DCC 服务健康状态枚举:

常量说明
AVAILABLE就绪,可接受请求
BUSY处理中,可能接受更多请求
UNREACHABLE心跳无响应
SHUTTING_DOWN正在优雅关闭

端到端示例

DCC 插件(服务端)

python
# Maya 插件内部
from dcc_mcp_core import GracefulIpcChannelAdapter, DccLinkFrame

server = GracefulIpcChannelAdapter.create("maya-ipc")
server.bind_affinity_thread()  # 在主线程调用一次
server.wait_for_client()

# Maya 空闲回调:
def on_idle():
    processed = server.pump_pending(budget_ms=50)

# 主消息循环
while True:
    frame = server.recv_frame()
    if frame is None:
        break  # 通道已关闭
    if frame.msg_type == 1:  # Call
        # 处理请求...
        reply = DccLinkFrame(msg_type=2, seq=frame.seq, body=b"ok")
        server.send_frame(reply)

server.shutdown()

MCP Agent(客户端)

python
from dcc_mcp_core import IpcChannelAdapter, DccLinkFrame

client = IpcChannelAdapter.connect("maya-ipc")

# 发送 Call 帧
call = DccLinkFrame(msg_type=1, seq=0, body=b"get_scene_info")
client.send_frame(call)

# 接收 Reply
reply = client.recv_frame()
if reply and reply.msg_type == 2:
    print(f"结果: {reply.body}")

Released under the MIT License.