| name | dcc-mcp-core |
| description | Foundation library for the DCC Model Context Protocol (MCP) ecosystem. Provides Rust-powered action management, skills system, IPC transport, MCP Streamable HTTP server (2025-03-26 spec, with 2025-06-18 and 2025-11-25 awareness), sandbox security, shared memory, screen capture, USD scene support, and telemetry for AI-assisted DCC workflows. Use when working with Maya, Blender, Houdini, 3ds Max, or any DCC MCP integration. |
| allowed-tools | Bash Read Write Edit |
| compatibility | Python 3.7-3.13; Rust 1.95+ required to build from source; zero runtime Python dependencies |
| version | 0.17.47 |
dcc-mcp-core — DCC MCP Ecosystem Foundation
The foundational library enabling AI assistants to interact with Digital Content Creation (DCC) software through the Model Context Protocol (MCP).
Quick Decision Guide — Use the Right API
| Task | Use this | Not this |
|---|
| Return action result | success_result() / error_result() | raw dicts |
| Load skills | scan_and_load() → (skills, skipped) | manual file scanning |
| One-call MCP server | create_skill_server("maya", McpHttpConfig(port=8765)) | manual wiring |
| Validate params | ToolValidator.from_schema_json() | isinstance checks |
| Connect to DCC | IpcChannelAdapter.connect(name) or SocketServerAdapter(path) | raw sockets |
| Define MCP tool | ToolDefinition + ToolAnnotations | raw JSON |
| Serve MCP over HTTP | McpHttpServer(registry, McpHttpConfig(port=8765)) | raw HTTP server |
| Build DCC adapter | DccServerOptions.from_env(...) + DccServerBase(options=opts) | legacy 17-parameter constructor |
| Main-thread DCC calls | HostExecutionBridge / dispatcher passed via DccServerOptions | private _core imports |
| Enable skill hot-reload | DccSkillHotReloader(dcc_name, server) | custom file watchers |
| Gateway failover | DccGatewayElection(dcc_name, server) | manual election logic |
| Write skill scripts | skill_entry + skill_success / skill_error | manual JSON output |
What This Library Does
| Capability | Description |
|---|
| Action Management | Register, validate, dispatch, and execute actions with typed inputs/outputs |
| Skills System | Zero-code script registration (Python/MEL/Batch/Shell/JS) as MCP tools via SKILL.md |
| Transport Layer | High-performance IPC via ipckit with DccLink framing (IpcChannelAdapter, SocketServerAdapter) |
| MCP HTTP Server | MCP Streamable HTTP (2025-03-26 spec) powered by axum/Tokio, runs in background thread |
| Process Management | Launch, monitor, auto-recover DCC processes (Maya, Blender, Houdini, etc.) |
| Sandbox Security | Policy-based access control, input validation, audit logging |
| Shared Memory | LZ4-compressed inter-process data exchange for large scenes |
| Screen Capture | Cross-platform DCC viewport capture for visual feedback |
| USD Support | Read/write Universal Scene Description for pipeline integration |
| Telemetry | Structured tracing and recording for observability |
| MCP Protocol Types | Complete Tool/Resource/Prompt schema implementations |
| DCC Server Base | Reusable base class for DCC adapters (hot-reload, gateway election, lifecycle) |
| Gateway Failover | Automatic gateway election when primary gateway becomes unreachable |
| Skill Hot-Reload | File-watching auto-reload for live skill development |
Installation
pip install dcc-mcp-core
Local Dependency Maintenance
Use the repository-pinned vx toolchain for Rust dependency refreshes and CI
parity:
vx --version
vx cargo update
vx cargo tree -d
vx cargo build --workspace --all-targets --timings
Review duplicate dependency output before editing manifests, and keep generated
lockfile changes only when they are part of the intended dependency refresh.
Core Patterns
Pattern 1: Skills-First — one-call MCP server (recommended)
import os
from dcc_mcp_core import create_skill_server, McpHttpConfig
os.environ["DCC_MCP_MAYA_SKILL_PATHS"] = "/opt/my-skills"
server = create_skill_server("maya", McpHttpConfig(port=8765))
handle = server.start()
print(f"Maya MCP server: {handle.mcp_url()}")
handle.shutdown()
Pattern 2: Return structured results (always use factories)
from dcc_mcp_core import success_result, error_result, from_exception
def my_action(params):
try:
result = do_work(params)
return success_result(
f"Created {result['name']}",
prompt="Object created. You can now modify its properties.",
object_name=result["name"],
)
except Exception as e:
return from_exception(str(e), message="Action failed")
Pattern 3: Validate action inputs
import json
from dcc_mcp_core import ToolValidator, error_result
schema = json.dumps({
"type": "object",
"required": ["name", "radius"],
"properties": {
"name": {"type": "string", "maxLength": 64},
"radius": {"type": "number", "minimum": 0.001},
},
})
validator = ToolValidator.from_schema_json(schema)
ok, errors = validator.validate(json.dumps(params))
if not ok:
return error_result("Invalid parameters", "; ".join(errors))
Pattern 4: Connect to a running DCC via IPC
from dcc_mcp_core import DccLinkFrame, IpcChannelAdapter, success_result, error_result
channel = IpcChannelAdapter.connect("dcc-mcp-maya-12345")
try:
channel.send_frame(DccLinkFrame(msg_type=1, seq=1, body=b'{"method":"execute_python","params":"cmds.sphere()"}'))
reply = channel.recv_frame()
if reply.msg_type == 2:
return success_result(reply.body.decode())
else:
return error_result("DCC call failed", reply.body.decode())
finally:
channel.shutdown() if hasattr(channel, 'shutdown') else None
Pattern 5: Build a DCC adapter with DccServerBase
from pathlib import Path
from dcc_mcp_core import DccServerBase, DccServerOptions
class BlenderMcpServer(DccServerBase):
def __init__(self, port: int = 8765, **kwargs):
opts = DccServerOptions.from_env(
"blender",
Path(__file__).parent / "skills",
port=port,
**kwargs,
)
super().__init__(options=opts)
def _version_string(self) -> str:
import bpy
return bpy.app.version_string
server = BlenderMcpServer(port=8765)
server.register_builtin_actions()
handle = server.start()
print(f"MCP: {handle.mcp_url()}")
Pattern 6: Watch skills for live reload
from dcc_mcp_core import SkillWatcher
watcher = SkillWatcher(debounce_ms=300)
watcher.watch("/my/dev/skills")
current_skills = watcher.skills()
Pattern 7: ActionDispatcher with handlers
import json
from dcc_mcp_core import ToolRegistry, ToolDispatcher
reg = ToolRegistry()
reg.register("create_sphere",
input_schema=json.dumps({"type": "object", "required": ["radius"],
"properties": {"radius": {"type": "number", "minimum": 0.0}}}))
dispatcher = ToolDispatcher(reg)
dispatcher.register_handler("create_sphere", lambda params: {"created": True, "r": params["radius"]})
dispatcher.has_handler("create_sphere")
dispatcher.handler_count()
dispatcher.handler_names()
dispatcher.remove_handler("create_sphere")
result = dispatcher.dispatch("create_sphere", json.dumps({"radius": 2.0}))
Pattern 8: DCC main-thread safety
Most DCC applications (Maya, Blender, Houdini) require scene API calls on their main thread.
For Python adapters, prefer the public host bridge/dispatcher stack and pass it through DccServerOptions before skills are loaded. Low-level DeferredExecutor details are covered in docs/guide/dcc-thread-safety.md.
from pathlib import Path
from dcc_mcp_core import DccServerBase, DccServerOptions, HostExecutionBridge, InProcessCallableDispatcher
dispatcher = InProcessCallableDispatcher()
bridge = HostExecutionBridge(dispatcher=dispatcher)
opts = DccServerOptions.from_env("maya", Path("skills"), execution_bridge=bridge)
server = DccServerBase(options=opts)
handle = server.start()
Pattern 9: Write skill scripts with skill_entry
from dcc_mcp_core.skill import skill_entry, skill_success, skill_error, skill_exception
@skill_entry
def create_sphere(radius: float = 1.0, name: str = "sphere") -> dict:
import maya.cmds as cmds
obj = cmds.polySphere(r=radius, n=name)[0]
return skill_success(
f"Created sphere '{obj}' with radius {radius}",
prompt="You can now adjust properties or add materials.",
object_name=obj,
radius=radius,
)
Creating a Custom Skill (Zero Python Code)
mkdir -p my-tool/scripts/
cat > my-tool/SKILL.md << 'EOF'
---
name: my-tool
description: "My custom DCC automation tools. Use when automating scene setup or batch operations."
compatibility: "python>=3.7"
allowed-tools: "python"
metadata:
dcc-mcp:
dcc: maya
version: "1.0.0"
layer: example
tags: ["automation", "custom"]
tools: tools.yaml
---
Automation scripts for Maya workflow optimization.
EOF
cat > my-tool/tools.yaml << 'YEOF'
tools:
- name: list_selected
description: List selected objects in the Maya scene.
input_schema:
type: object
properties: {}
read_only: true
idempotent: true
source_file: scripts/list_selected.py
YEOF
cat > my-tool/scripts/list_selected.py << 'PYEOF'
"""List selected objects in the Maya scene."""
import json
result = {"selected": ["pSphere1", "pCube1"], "count": 2}
print(json.dumps(result))
PYEOF
export DCC_MCP_SKILL_PATHS="$(pwd)/my-tool"
python -c "
from dcc_mcp_core import scan_and_load
skills, _ = scan_and_load(dcc_name='maya')
print(f'Loaded: {[s.name for s in skills]}')
# Action: my_tool__list_selected
"
Architecture Overview
┌─────────────────────────────────────────────────────┐
│ Python Layer │
│ dcc_mcp_core/__init__.py → _core (PyO3 cdyll) │
│ 380+ public symbols re-exported from Rust core │
│ + Pure-Python: DccServerBase, DccServerOptions, │
│ gateway election, hot-reload, factory, helpers │
└──────────────────────┬──────────────────────────────┘
│ PyO3 bindings
┌──────────────────────▼──────────────────────────────┐
│ Rust Workspace (35 members total) │
│ 34 functional crates + workspace-hack │
│ naming → models → actions → skills → protocols │
│ gateway/http-types/http-server/http-py/http │
│ host → transport → process → sandbox → telemetry │
└─────────────────────────────────────────────────────┘
Environment Variables
| Variable | Purpose |
|---|
DCC_MCP_SKILL_PATHS | Colon/semicolon-separated paths to scan for SKILL.md dirs |
DCC_MCP_{APP}_SKILL_PATHS | Per-app skill paths (e.g. DCC_MCP_MAYA_SKILL_PATHS) |
DCC_MCP_GATEWAY_PORT | Gateway port for multi-DCC setup |
DCC_MCP_REGISTRY_DIR | Directory for FileRegistry JSON |
MCP_LOG_LEVEL | Log level override (DEBUG, INFO, WARN) |
DCC_MCP_IPC_ADDRESS | IPC endpoint address (auto-set by register_diagnostic_handlers) |
DCC_MCP_GATEWAY_PROBE_INTERVAL | Seconds between gateway health probes (default 1) |
DCC_MCP_GATEWAY_PROBE_TIMEOUT | Timeout per probe in seconds (default 2) |
DCC_MCP_GATEWAY_PROBE_FAILURES | Consecutive failures before election (default 2) |
Key Files in This Repository
| File | Purpose |
|---|
AGENTS.md | AI agent navigation map — entry point, decision tables, top traps |
docs/guide/agents-reference.md | Detailed agent rules — traps, do/don't, code style, project-specific architecture |
llms.txt | Concise API reference for LLMs |
llms-full.txt | Comprehensive API reference with all examples |
python/dcc_mcp_core/__init__.py | Complete public API (380+ symbols, ground truth for imports) |
python/dcc_mcp_core/_core.pyi | Generated type stubs — authoritative parameter names after a dev/stub build |
examples/skills/ | 15 complete skill package examples |
tests/ | Python integration tests (executable usage examples) |
Supported DCC Software
- Autodesk Maya — MEL/Python scripting (
dcc: maya)
- Blender — Python API (
dcc: blender)
- SideFX Houdini — HScript/Python (
dcc: houdini)
- Autodesk 3ds Max — MaxScript/Python (
dcc: 3dsmax)
- Any DCC — Generic Python wrapper (
dcc: python)
Related Projects
MCP Specification Roadmap
The library currently implements MCP 2025-03-26 (Streamable HTTP). The ecosystem has since released:
| Version | Key Features | Status in dcc-mcp-core |
|---|
| 2025-03-26 | Streamable HTTP, Tool Annotations, OAuth 2.1 | Implemented |
| 2025-06-18 | Structured Tool Output, Elicitation, Resource Links, JSON-RPC batching removed, MCP-Protocol-Version header mandatory | Planned |
| 2025-11-25 | Icon metadata, Tasks (experimental), Sampling with tool calls, JSON Schema 2020-12, enhanced OAuth | Planned |
AI Agents: Do NOT implement draft features manually. Wait for dcc-mcp-core to expose them via McpHttpServer. Track progress at the GitHub repository.
Common Pitfalls
scan_and_load returns (List[SkillMetadata], List[str]) — always unpack: skills, skipped = scan_and_load(...)
- Prefer public
HostExecutionBridge / dispatcher wiring; use DeferredExecutor only when following docs/guide/dcc-thread-safety.md low-level guidance
- Register ALL actions before
server.start() — server reads from registry at startup only
- Use
IpcChannelAdapter + DccLinkFrame for IPC (v0.14+) — FramedChannel/connect_ipc were removed in #251
ToolDispatcher(registry) takes ONE arg — no validator= parameter
- Action naming:
{skill_name.replace('-','_')}__{script_stem} (double underscore)
- SKILL.md
name must match parent directory name (agentskills.io spec)
allowed-tools in SKILL.md is space-separated string, not a list (agentskills.io spec)
DccServerBase provides all skill/lifecycle/gateway/hot-reload methods — don't reimplement
- MCP 2025-06-18 removes JSON-RPC batching — do not implement batch calls manually
MCP-Protocol-Version header is mandatory in 2025-06-18 — handled by McpHttpServer internally