Skip to content

HTTP API

dcc_mcp_core — MCP Streamable HTTP 服务器(2025-03-26 规范)。

概述

dcc-mcp-http crate 提供了一个 MCP HTTP 服务器,将你的 ToolRegistry 通过 HTTP 暴露出来。MCP 客户端(如 Claude Desktop 或其他 LLM 集成)通过 HTTP POST 请求连接到 /mcp 端点。

后台线程

服务器在后台 Tokio 线程中运行,不会阻塞 DCC 主线程。可安全用于 Maya/Blender 等插件中。

McpHttpConfig

HTTP 服务器配置。

构造函数

python
from dcc_mcp_core import McpHttpConfig

cfg = McpHttpConfig(
    port=8765,                # TCP 端口(0 = 随机可用端口)
    server_name="maya-mcp",   # MCP initialize 响应中的名称
    server_version="1.0.0",   # MCP initialize 响应中的版本
    enable_cors=False,         # 浏览器客户端的 CORS 头
    request_timeout_ms=30000,  # 每个请求的超时时间(毫秒)
)

属性

属性类型默认值说明
portint8765服务器监听的 TCP 端口(0 = OS 分配)
hoststr"127.0.0.1"绑定的 IP 地址
endpoint_pathstr"/mcp"MCP 端点路径
server_namestr"dcc-mcp"MCP 响应中的服务器名称
server_versionstr包版本MCP 响应中的服务器版本
max_sessionsint100最大并发 SSE 会话数
request_timeout_msint30000每个请求的超时时间(毫秒)
enable_corsboolFalse是否启用浏览器客户端的 CORS
session_ttl_secsint3600空闲会话 TTL 秒数(0 禁用自动清理)
gateway_portint0竞争的网关端口(0 = 禁用)。参见网关
registry_dirstr | NoneNone共享 FileRegistry JSON 目录(默认 OS 临时目录)
stale_timeout_secsint30心跳超时秒数(实例视为过期)
heartbeat_secsint5心跳间隔秒数(0 = 禁用)
dcc_typestr | NoneNone注册表中报告的 DCC 类型(如 "maya""blender"
dcc_versionstr | NoneNone注册表中报告的 DCC 版本(如 "2025"
scenestr | NoneNone当前打开的场景文件 — 改善网关路由

McpServerHandle

McpHttpServer.start() 返回。用于获取 MCP 端点 URL 并优雅关闭。

别名

McpServerHandledcc_mcp_core 中也以 McpServerHandle 别名导出,两者指向同一个类。

python
from dcc_mcp_core import McpServerHandle  # McpServerHandle 的别名

属性

属性类型说明
portint服务器实际绑定的端口(当 port=0 时有用)
bind_addrstr绑定地址,如 "127.0.0.1:8765"
is_gatewaybool若本进程赢得网关端口竞争则为 True

方法

方法返回值说明
mcp_url()str完整的 MCP 端点 URL,如 "http://127.0.0.1:8765/mcp"
shutdown()None优雅关闭(阻塞直到停止)
signal_shutdown()None信号关闭而不阻塞

示例

python
from dcc_mcp_core import ToolRegistry, McpHttpServer, McpHttpConfig

registry = ToolRegistry()
registry.register("get_scene_info", description="获取当前场景信息",
                  category="scene", tags=[], dcc="maya", version="1.0.0")

server = McpHttpServer(registry, McpHttpConfig(port=8765))
handle = server.start()

print(f"MCP HTTP 服务器运行于 {handle.mcp_url()}")
# MCP 主机 POST 到 http://127.0.0.1:8765/mcp

# 完成后关闭
handle.shutdown()

McpHttpServer

MCP Streamable HTTP 服务器(2025-03-26 规范)。

构造函数

python
from dcc_mcp_core import ToolRegistry, McpHttpServer, McpHttpConfig

server = McpHttpServer(
    registry,         # ToolRegistry 实例
    config=None,      # McpHttpConfig(默认 port=8765,无 CORS)
)

方法

方法返回值说明
start()McpServerHandle在后台线程启动服务器并返回句柄
register_handler(action_name, handler)None注册 Python 可调用对象;处理器接收解码后的参数(通常是 dict
has_handler(action_name)bool检查是否已注册 Action 处理器

MCP 协议端点

服务器实现 MCP 2025-03-26 规范:

端点方法说明
/mcpPOSTMCP 请求(JSON-RPC 2.0)
/mcpGETSSE 兼容的事件流
/mcpDELETE终止 MCP 会话
/healthGET健康检查

请求/响应格式

MCP 请求使用 JSON-RPC 2.0:

json
// POST /mcp
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}
json
// POST /mcp 响应
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {"name": "get_scene_info", "description": "获取当前场景信息", ...}
    ]
  }
}

支持的 MCP 方法

方法说明
initialize协议握手,返回服务器能力
tools/list列出注册表中的所有 Action
tools/call按名称和参数调度 Action
resources/list列出可用资源(当前实现为空)
prompts/list列出可用提示(当前实现为空)
ping存活检查

完整示例:Maya MCP 服务器

python
from dcc_mcp_core import ToolRegistry, McpHttpServer, McpHttpConfig

# 构建工具注册表
registry = ToolRegistry()
registry.register(
    "get_scene_info",
    description="获取当前 Maya 场景信息",
    category="scene",
    tags=["query", "info"],
    dcc="maya",
    version="1.0.0",
    input_schema='{}',
)

def get_scene_info(params):
    # 实际中通过 pymel/cmdx 查询 Maya
    return {"scene_name": "untitled", "object_count": 0}

server = McpHttpServer(registry, McpHttpConfig(
    port=18812,
    server_name="maya-mcp",
    server_version="1.0.0",
))
server.register_handler("get_scene_info", get_scene_info)

# 启动 HTTP 服务器
handle = server.start()

print(f"Maya MCP 服务器: {handle.mcp_url()}")
# 输出: Maya MCP 服务器: http://127.0.0.1:18812/mcp

网关

当多个 DCC 实例同时启动时,其中一个会自动成为网关 — 一个统一的 /mcp 入口点,将所有运行中实例的工具聚合成单一 MCP 接口。

工作原理

  • 每个实例在共享的 FileRegistry(磁盘上的 JSON 文件)中注册自身,并定期发送心跳。
  • 首个绑定 gateway_port(默认:9765)的进程成为网关;其余为普通实例。
  • 互斥使用 SO_REUSEADDR=false(通过 socket2),确保跨平台(包括 Windows)的首个获胜语义。
  • 网关自动清理过期实例(在 stale_timeout_secs 内未收到心跳)。
  • 进程退出时,McpServerHandle 被 drop,实例自动注销。

网关端点

端点方法说明
/instancesGET所有活跃实例的 JSON 列表
/healthGET{"ok": true} 健康检查
/mcpPOST聚合 MCP 端点(合并所有后端工具)
/mcpGETSSE 事件流 — 推送 tools/list_changedresources/list_changed
/mcp/{instance_id}POST透明代理到指定实例(底层逃生通道)
/mcp/dcc/{dcc_type}POST代理到指定 DCC 类型的最佳实例

聚合式 Facade

网关的 POST /mcp 是一个统一 MCP 服务器,在单次 tools/list 响应中合并三层工具:

层级工具用途
发现元工具list_dcc_instancesget_dcc_instanceconnect_to_dcc枚举 / 查看活跃 DCC;需要直连时返回直接 MCP URL
技能管理list_skillssearch_skillsget_skill_infoload_skillunload_skill读操作向全部 DCC 扇出;load_skill / unload_skill 通过 instance_id / dcc 参数指向具体实例
后端工具所有活跃 DCC 自身的工具,带 8 字符实例前缀 — 例如 a1b2c3d4__create_sphere按前缀路由回原始后端

每个命名空间化的后端工具还会附带 _instance_id_instance_short_dcc_type 注解,以便 agent 消歧(比如 create_cube 在 Maya 和 Blender 上各注册一次时,会表现为两个带不同前缀的独立条目)。

网关声明 capabilities.tools.listChanged: true,每 3 秒轮询后端;当聚合集合发生变化(任何一处加载 / 卸载 skill)时,向所有连接的 SSE 客户端广播 notifications/tools/list_changed

Python 示例

python
from dcc_mcp_core import ToolRegistry, McpHttpServer, McpHttpConfig

registry = ToolRegistry()
registry.register("get_scene_info", description="获取场景信息", category="scene", dcc="maya")

config = McpHttpConfig(port=0, server_name="maya-mcp")
config.gateway_port = 9765    # 加入网关竞争;0 = 禁用
config.dcc_type = "maya"
config.dcc_version = "2025"
config.scene = "/proj/shot01.ma"  # 可选:帮助按场景路由

server = McpHttpServer(registry, config)
handle = server.start()

print(handle.is_gateway)        # True 表示本进程赢得了网关端口
print(handle.mcp_url())         # 本实例的直接 MCP URL
# → 若 is_gateway=True,网关在 http://127.0.0.1:9765/
# → 实例在 http://127.0.0.1:<port>/mcp

多 DCC、单入口

启动任意数量的 DCC 服务器 — 第一个赢得网关端口。Agent 始终连接 http://localhost:9765/mcp,在单一 tools/list 中看到所有后端工具(按实例命名空间化)。需要直连、不经代理时再使用 list_dcc_instances / connect_to_dcc

Skills-First + 网关

create_skill_server() 默认配置 gateway_port。如需参与网关,需在传入的 McpHttpConfig 上显式设置:

python
import os
from dcc_mcp_core import create_skill_server, McpHttpConfig

config = McpHttpConfig(port=0, server_name="maya")
config.gateway_port = 9765
config.dcc_type = "maya"

server = create_skill_server("maya", config)
handle = server.start()

CORS 配置

为浏览器 MCP 客户端启用 CORS:

python
cfg = McpHttpConfig(port=8765, enable_cors=True)
server = McpHttpServer(registry, cfg)
handle = server.start()
print(handle.mcp_url())

错误处理

服务器返回 JSON-RPC 错误响应:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: missing 'radius'",
    "data": null
  }
}

常见错误码:

含义
-32600无效请求
-32602无效参数
-32603内部错误
-32000Action 未找到
-32001Action 验证失败
-32002Action 处理器错误

性能说明

  • 服务器在后台 Tokio 线程运行 — 不会阻塞 DCC 主线程
  • 每个调用的请求超时(默认 30 秒)
  • HTTP 层无连接池(每个 POST 无状态)
  • 使用 IpcChannelAdapter 获取与 DCC 的持久 IPC 会话
  • 网关 FileRegistry 每次变更都刷新到磁盘 — 多进程安全但不适合高频写入

Released under the MIT License.