dcc-mcp-core · "0.20.36" # x-release-please-version · 2026-09-26 · sha256 696cdb869938d763
dcc-mcp-core "0.20.36" # x-release-please-versionA
Immutable. This exact content never changes and is served at /api/v1/blob/696cdb869938d763.
---
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.14; Rust 1.95+ required to build from source; zero runtime Python dependencies"
version: "0.20.36" # x-release-please-version
---
# 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 |
|------|----------|----------|
| Operate a live DCC from an agent | [`dcc-mcp`](https://clawhub.ai/loonghao/skills/dcc-mcp) + `dcc-mcp-cli` | embedding the Python API in the agent |
| Create or modernize a DCC-MCP adapter | [`dcc-mcp-creator`](https://clawhub.ai/loonghao/skills/dcc-mcp-creator) | adapter-local copies of core wiring |
| Create a DCC-specific Skill package | [`dcc-mcp-skills-creator`](https://clawhub.ai/loonghao/skills/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`](../../../docs/guide/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:
```bash
openclaw skills install @loonghao/dcc-mcp
# Direct ClawHub CLI:
npx --yes clawhub@0.23.1 install @loonghao/dcc-mcp
```
Use [`dcc-mcp-creator`](https://clawhub.ai/loonghao/skills/dcc-mcp-creator)
only for a complete adapter/runtime, and
[`dcc-mcp-skills-creator`](https://clawhub.ai/loonghao/skills/dcc-mcp-skills-creator)
only for a DCC-specific Skill package.
```bash
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:
```bash
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)
```python
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)
```python
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
```python
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
```python
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
```python
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
```python
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
```python
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`.
```python
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
```python
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:
```python
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)
```bash
# 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](https://github.com/loonghao/dcc-mcp-rpyc) — RPyC bridge for remote DCC operations
- [dcc-mcp-maya](https://github.com/loonghao/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`](../../../docs/guide/agents-reference.md#iteration-playbook).
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