dcc-mcp-core — DCC MCP Ecosystem Foundation
SkillDocs & knowledgeFoundation 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.
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the dcc-mcp-core skill
What this skill tells your AI
The instructions your AI receives, as published by dcc-mcp/dcc-mcp-core in .agents/skills/dcc-mcp-core/SKILL.md and read by ahel’s review.
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 |
|---|---|---|
| Operate a live DCC from an agent | dcc-mcp + dcc-mcp-cli | embedding the Python API in the agent |
| Create or modernize a DCC-MCP adapter | dcc-mcp-creator | adapter-local copies of core wiring |
| Create a DCC-specific Skill package | dcc-mcp-skills-creator | a new adapter repository |
| Analyze or report a failed DCC call | dcc-mcp recovery flow: doctor, failure-filtered stats, dcc_feedback__report, public-safe issue report | raw unreviewed logs |
| 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
The CLI refreshes the official signed installation catalog independently of its
binary version. Inspect plan.catalog for source, digest, expiry, and
latest_checked; --offline explicitly uses a valid signed cache or bundled
metadata. Never treat an integrity failure as permission to bypass verification.
Adapter promotion must preserve curated versions, immutable artifact hashes,
withdrawal policy, and minimum Core compatibility. See
verified-install-catalog.md.
For agent-side DCC control, install the published dcc-mcp Skill and use its
CLI workflow; the Python package below is for adapters and embedded runtimes:
openclaw skills install @loonghao/dcc-mcp
# Direct ClawHub CLI:
npx --yes clawhub@0.23.1 install @loonghao/dcc-mcp
Use dcc-mcp-creator
only for a complete adapter/runtime, and
dcc-mcp-skills-creator
only for a DCC-specific Skill package.
pip install dcc-mcp-core
# Python 3.7-3.14, zero runtime dependencies
Local Dependency Maintenance
Use the repository-pinned vx toolchain for Rust dependency refreshes and CI
parity:
vx --version # CI pins loonghao/vx@v0.9.7
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"
# One call: creates registry + dispatcher + catalog + discovers skills + server
server = create_skill_server("maya", McpHttpConfig(port=8765))
handle = server.start()
print(f"Maya MCP server: {handle.mcp_url()}")
# Agents connect and use on-demand skill discovery:
# → search_tools(query="bevel") or search_skills(query="modeling")
# → get_skill_info(skill_name="maya-bevel") to inspect schemas
# → load_skill("maya-bevel") only when selected
# → tools/call maya_bevel__bevel to execute
# Do not treat the first tools/list page as complete; follow nextCursor if listing.
handle.shutdown()
Pattern 2: Return structured results (always use factories)
from dcc_mcp_core import success_result, error_result, from_exception
# All actions should return ActionResultModel
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
# Connect to a DCC process via named pipe / Unix domain socket
channel = IpcChannelAdapter.connect("dcc-mcp-maya-12345")
try:
# Send a Call frame and receive the reply
channel.send_frame(DccLinkFrame(msg_type=1, seq=1, body=b'{"method":"execute_python","params":"cmds.sphere()"}'))
reply = channel.recv_frame() # DccLinkFrame
if reply.msg_type == 2: # Reply
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
# All skill methods, hot-reload, gateway are ready:
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") # immediate load + start watching
# Get always-up-to-date snapshot
current_skills = watcher.skills() # -> List[SkillMetadata]
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"]})
# Introspect handlers
dispatcher.has_handler("create_sphere") # True
dispatcher.handler_count() # 1
dispatcher.handler_names() # ["create_sphere"]
dispatcher.remove_handler("create_sphere") # True
result = dispatcher.dispatch("create_sphere", json.dumps({"radius": 2.0}))
# result == {"action": "create_sphere", "output": {"created": True, "r": 2.0}, "validation_skipped": False}
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() # replace with the DCC UI-thread dispatcher
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,
)
Pattern 10: Launch an isolated DCC child
Use child-only environment overrides instead of mutating os.environ when
multiple artist and automation sessions share a machine:
from dcc_mcp_core import PyDccLauncher
launcher = PyDccLauncher()
info = launcher.launch(
name="nuke-mcp",
executable="Nuke15.2",
args=["--disable-nuke-frameserver", "project.nk"],
environment={
"NUKE_DISABLE_FRAMESERVER": "1",
"DCC_MCP_NUKE_PORT": "0",
},
working_directory="/projects/solar-system",
)
Creating a Custom Skill (Zero Python Code)
# 1. Create directory structure
mkdir -p my-tool/scripts/
# 2. Write SKILL.md (name is required, follows agentskills.io spec)
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
---
# My Tool
Automation scripts for Maya workflow optimization.
EOF
# 3. Add the sibling tool declaration referenced by metadata.dcc-mcp.tools
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
# 4. Add a script
cat > my-tool/scripts/list_selected.py << 'PYEOF'
#!/usr/bin/env python3
"""List selected objects in the Maya scene."""
import json
result = {"selected": ["pSphere1", "pCube1"], "count": 2}
print(json.dumps(result))
PYEOF
# 5. Use it
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 (47 members total) │
│ 46 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, iteration playbook |
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
- dcc-mcp-rpyc — RPyC bridge for remote DCC operations
- dcc-mcp-maya — Maya MCP server implementation
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.
Iteration Playbook
Repeating work in a DCC host has three shipped moves. Full details live in the
Iteration Playbook section of docs/guide/agents-reference.md.
- Reuse a materialized script —
materialize_script(..., reuse=True, reuse_key="...")returns a derived, stablefile_path({reuse_key}_{sha256[:12]}under~/.dcc-mcp/<dcc_type>/temp/<instance_id>/<session_id>/); a byte-identical repeat comes back withreused=Trueinstead of writing a second copy.resolve_materialized_scriptre-verifies hash + expiry and fails closed. - Change a value, not the script — re-send the same
file_pathwith a newparamsobject. The contract isFileBackedScriptExecutionParams;paramsis derived frommain(**params)byderive_script_parameters_schema(parsed withast, never executed). No CLI flag, no params file, no re-materialize. - Resume an interrupted workflow —
workflows_resumetakesworkflow_idplus optionalforce_steps/expected_spec_hash/strict. It is Rust-only (MCPtools/callor REST/v1/call) and needsWorkflowStorage+ thejob-persist-sqlitefeature.
Common Pitfalls
scan_and_loadreturns(List[SkillMetadata], List[str])— always unpack:skills, skipped = scan_and_load(...)- Prefer public
HostExecutionBridge/ dispatcher wiring; useDeferredExecutoronly when followingdocs/guide/dcc-thread-safety.mdlow-level guidance - Register ALL actions before
server.start()— server reads from registry at startup only - Use
IpcChannelAdapter+DccLinkFramefor IPC (v0.14+) —FramedChannel/connect_ipcwere removed in #251 ToolDispatcher(registry)takes ONE arg — novalidator=parameter- Action naming:
{skill_name.replace('-','_')}__{script_stem}(double underscore) - SKILL.md
namemust match parent directory name (agentskills.io spec) allowed-toolsin SKILL.md is space-separated string, not a list (agentskills.io spec)DccServerBaseprovides 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-Versionheader is mandatory in 2025-06-18 — handled byMcpHttpServerinternally
Signals
- GitHub stars
- 48
- Forks
- 4
- Last commit
- Oct 2026
ahel review
K1binfo
installs-packages
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Item type
- skill
- Key
dcc-mcp-core- Source
- github.com/dcc-mcp/dcc-mcp-core
github.com/dcc-mcp/dcc-mcp-core
Related picks
Skill · thedaviddias
The pick for JavaScriptmodern-javascript-patterns
Skill · wshobson
The pick for JavaScriptpython-performance-optimization
Skill · wshobson
The pick for Pythonpython-pro
Skill · jeffallan
The pick for Pythonomh-rust
Skill · rlaope
The pick for Rustrust-sdk-specialist
Skill · a5c-ai
The pick for Rust