dcc-mcp-core — DCC MCP Ecosystem Foundation

SkillDocs & knowledge

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.

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

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

TaskUse thisNot this
Operate a live DCC from an agentdcc-mcp + dcc-mcp-cliembedding the Python API in the agent
Create or modernize a DCC-MCP adapterdcc-mcp-creatoradapter-local copies of core wiring
Create a DCC-specific Skill packagedcc-mcp-skills-creatora new adapter repository
Analyze or report a failed DCC calldcc-mcp recovery flow: doctor, failure-filtered stats, dcc_feedback__report, public-safe issue reportraw unreviewed logs
Return action resultsuccess_result() / error_result()raw dicts
Load skillsscan_and_load() → (skills, skipped)manual file scanning
One-call MCP servercreate_skill_server("maya", McpHttpConfig(port=8765))manual wiring
Validate paramsToolValidator.from_schema_json()isinstance checks
Connect to DCCIpcChannelAdapter.connect(name) or SocketServerAdapter(path)raw sockets
Define MCP toolToolDefinition + ToolAnnotationsraw JSON
Serve MCP over HTTPMcpHttpServer(registry, McpHttpConfig(port=8765))raw HTTP server
Build DCC adapterDccServerOptions.from_env(...) + DccServerBase(options=opts)legacy 17-parameter constructor
Main-thread DCC callsHostExecutionBridge / dispatcher passed via DccServerOptionsprivate _core imports
Enable skill hot-reloadDccSkillHotReloader(dcc_name, server)custom file watchers
Gateway failoverDccGatewayElection(dcc_name, server)manual election logic
Write skill scriptsskill_entry + skill_success / skill_errormanual JSON output

What This Library Does

CapabilityDescription
Action ManagementRegister, validate, dispatch, and execute actions with typed inputs/outputs
Skills SystemZero-code script registration (Python/MEL/Batch/Shell/JS) as MCP tools via SKILL.md
Transport LayerHigh-performance IPC via ipckit with DccLink framing (IpcChannelAdapter, SocketServerAdapter)
MCP HTTP ServerMCP Streamable HTTP (2025-03-26 spec) powered by axum/Tokio, runs in background thread
Process ManagementLaunch, monitor, auto-recover DCC processes (Maya, Blender, Houdini, etc.)
Sandbox SecurityPolicy-based access control, input validation, audit logging
Shared MemoryLZ4-compressed inter-process data exchange for large scenes
Screen CaptureCross-platform DCC viewport capture for visual feedback
USD SupportRead/write Universal Scene Description for pipeline integration
TelemetryStructured tracing and recording for observability
MCP Protocol TypesComplete Tool/Resource/Prompt schema implementations
DCC Server BaseReusable base class for DCC adapters (hot-reload, gateway election, lifecycle)
Gateway FailoverAutomatic gateway election when primary gateway becomes unreachable
Skill Hot-ReloadFile-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

VariablePurpose
DCC_MCP_SKILL_PATHSColon/semicolon-separated paths to scan for SKILL.md dirs
DCC_MCP_{APP}_SKILL_PATHSPer-app skill paths (e.g. DCC_MCP_MAYA_SKILL_PATHS)
DCC_MCP_GATEWAY_PORTGateway port for multi-DCC setup
DCC_MCP_REGISTRY_DIRDirectory for FileRegistry JSON
MCP_LOG_LEVELLog level override (DEBUG, INFO, WARN)
DCC_MCP_IPC_ADDRESSIPC endpoint address (auto-set by register_diagnostic_handlers)
DCC_MCP_GATEWAY_PROBE_INTERVALSeconds between gateway health probes (default 1)
DCC_MCP_GATEWAY_PROBE_TIMEOUTTimeout per probe in seconds (default 2)
DCC_MCP_GATEWAY_PROBE_FAILURESConsecutive failures before election (default 2)

Key Files in This Repository

FilePurpose
AGENTS.mdAI agent navigation map — entry point, decision tables, top traps
docs/guide/agents-reference.mdDetailed agent rules — traps, do/don't, code style, project-specific architecture, iteration playbook
llms.txtConcise API reference for LLMs
llms-full.txtComprehensive API reference with all examples
python/dcc_mcp_core/__init__.pyComplete public API (380+ symbols, ground truth for imports)
python/dcc_mcp_core/_core.pyiGenerated 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:

VersionKey FeaturesStatus in dcc-mcp-core
2025-03-26Streamable HTTP, Tool Annotations, OAuth 2.1Implemented
2025-06-18Structured Tool Output, Elicitation, Resource Links, JSON-RPC batching removed, MCP-Protocol-Version header mandatoryPlanned
2025-11-25Icon metadata, Tasks (experimental), Sampling with tool calls, JSON Schema 2020-12, enhanced OAuthPlanned

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.

  1. Reuse a materialized script — materialize_script(..., reuse=True, reuse_key="...") returns a derived, stable file_path ({reuse_key}_{sha256[:12]} under ~/.dcc-mcp/<dcc_type>/temp/<instance_id>/<session_id>/); a byte-identical repeat comes back with reused=True instead of writing a second copy. resolve_materialized_script re-verifies hash + expiry and fails closed.
  2. Change a value, not the script — re-send the same file_path with a new params object. The contract is FileBackedScriptExecutionParams; params is derived from main(**params) by derive_script_parameters_schema (parsed with ast, never executed). No CLI flag, no params file, no re-materialize.
  3. Resume an interrupted workflow — workflows_resume takes workflow_id plus optional force_steps / expected_spec_hash / strict. It is Rust-only (MCP tools/call or REST /v1/call) and needs WorkflowStorage + the job-persist-sqlite feature.

Common Pitfalls

  1. scan_and_load returns (List[SkillMetadata], List[str]) — always unpack: skills, skipped = scan_and_load(...)
  2. Prefer public HostExecutionBridge / dispatcher wiring; use DeferredExecutor only when following docs/guide/dcc-thread-safety.md low-level guidance
  3. Register ALL actions before server.start() — server reads from registry at startup only
  4. Use IpcChannelAdapter + DccLinkFrame for IPC (v0.14+) — FramedChannel/connect_ipc were removed in #251
  5. ToolDispatcher(registry) takes ONE arg — no validator= parameter
  6. Action naming: {skill_name.replace('-','_')}__{script_stem} (double underscore)
  7. SKILL.md name must match parent directory name (agentskills.io spec)
  8. allowed-tools in SKILL.md is space-separated string, not a list (agentskills.io spec)
  9. DccServerBase provides all skill/lifecycle/gateway/hot-reload methods — don't reimplement
  10. MCP 2025-06-18 removes JSON-RPC batching — do not implement batch calls manually
  11. MCP-Protocol-Version header is mandatory in 2025-06-18 — handled by McpHttpServer internally

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