A first-class meta-skill for creating, validating, and reviewing DCC-MCP skill
packages. It bundles scaffold/validation tools together with agent-facing
authoring guidance for SKILL.md, tools.yaml, scripts, groups, prompts, and
progressive-loading taxonomy.
Use dcc-mcp-creator when the task is to create a full adapter repository for
a host such as Nuke, Blender, 3ds Max, Unreal, ZBrush, Houdini, or Maya. Use
this skill when the task is to create or improve the skill packages loaded by
those adapters.
Install and Route
Install the published
@loonghao/dcc-mcp-skills-creator
package, then start a new agent turn:
openclaw skills install @loonghao/dcc-mcp-skills-creator
npx --yes clawhub@0.23.1 install @loonghao/dcc-mcp-skills-creator
Distribution Boundary
A Skill remains the runtime and authoring unit. Use an Agent Plugin only as a distribution unit when several Skills share release, compatibility, trust, and uninstall boundaries:
my-plugin/
|-- plugin.json
`-- skills/
|-- inspect/SKILL.md
`-- act/SKILL.md
The root manifest targets
https://agent-plugins.org/schemas/1.0.0/plugin.schema.json. Do not move
independently versioned or optional Skills into one plugin merely because they
share a repository. Existing DCC-MCP packages with multiple explicit
source.skillRoots remain valid skill-bundle packages.
Use dcc-mcp to operate an
existing DCC and
dcc-mcp-creator to build
a complete adapter. A repository checkout may load this directory directly;
DCC_MCP_SKILL_PATHS and extra_paths are runtime paths for DCC adapters, not
installation instructions for an agent host.
CLI-First Control Path
Use the dcc-mcp skill and dcc-mcp-cli for skill discovery, loading,
validation, and live calls whenever the agent can run shell commands. Start a
live validation with dcc-mcp-cli list: if the process launches, the CLI is
installed and the result checks the gateway plus DCC/MCP inventory. Diagnose a
failed health/inventory result with dcc-mcp-cli doctor; do not reinstall the
CLI, probe import dcc_mcp_core, or read server internals to infer readiness.
Only a shell-level command-not-found result means the CLI is missing. Ask for
consent; after explicit approval, immediately run the verified dcc-mcp helper
python scripts/check_cli.py --ensure-cli --pretty from that Skill's directory.
It installs the official CLI and rechecks health/inventory in the same attempt,
without a second confirmation. Keep it current with dcc-mcp-cli update check,
then dcc-mcp-cli update apply; apply stages the next CLI launch and does not
replace a running server binary.
Quick Start
Create a new skill
# Call the loaded MCP tool:
# dcc_mcp_skills_creator__create_skill(
# name="maya-rigging",
# parent_dir="/path/to/skills/dir",
# dcc="maya",
# tool_name="create_locator",
# affinity="main",
# )
Validate an existing skill
dcc-mcp-cli lint /path/to/my-skill
The CLI loads the sibling tools.yaml table and invokes every declaration
through Core's real router with deterministic mock handlers. CI fails if a
sync declaration produces a job envelope or an async declaration produces a
direct result. Adapter/DCC code is never imported or executed by this probe.
Get a SKILL.md template
# Call the loaded MCP tool:
# dcc_mcp_skills_creator__skill_template()
Skill Directory Structure
my-skill/
|-- SKILL.md # Required: metadata frontmatter + instructions
|-- tools.yaml # Required when metadata.dcc-mcp.tools points here
|-- scripts/ # Optional: tool implementation scripts
| `-- create_locator.py
`-- references/ # Optional: recipes, examples, and long-form docs
|-- RECIPES.md
`-- NOTES.md
Current Tool Contract
Generated tools.yaml entries follow the modern contract:
- Local tool names are snake_case and client-safe. Do not use dotted names.
- Loaded tools are published as
<skill-name>__<tool_name>when namespacing is needed. - Skill package version metadata lives at
metadata.dcc-mcp.versioninSKILL.md; a top-levelversionkey is rejected by the strict loader. - Set
metadata.dcc-mcp.dccto the concrete host. Usedcc: anyonly when the same implementation is safe in every host; concrete-host tools override a same-namedanytool during scoped lookup. - Inter-skill dependencies live at
metadata.dcc-mcp.dependsas skill names, not repo names or prose-only instructions. Use it when one skill must be discovered or loaded before another, for exampledepends: ["qt-ui-inspector"]. input_schemaandoutput_schemaare declared explicitly.- A zero-argument tool still declares a closed schema:
{"type":"object","properties":{},"additionalProperties":false}. - Runtime discovery never imports or executes tool scripts to infer missing
schemas by default. Treat Python-derived schemas as an authoring-time helper:
generate them before publishing, then commit the JSON Schema to
tools.yaml. - Keep MCP-facing
input_schemashapes simple: prefer a top-level object withproperties,required, primitivetype, bounds, and descriptions. Put mutually exclusive forms, conditional requirements, and cross-field rules in the tool script or handler validation instead ofanyOf,oneOf,allOf,not,if/then/else, or dependent-schema keywords. When a complex schema is unavoidable, discovery must route throughdescribebefore call. executionissyncorasync; useasyncfor deferred/long-running work.job_strategyismonolithic(default),chunked, orisolated. Agents use it to select a safe execution and recovery workflow.affinityis explicit. Usemainfor host API or scene mutation work andanyfor pure work.enforce_thread_affinity: trueis emitted so adapter dispatch stays honest.annotationsexplicitly declare booleanread_only_hint,destructive_hint,idempotent_hint, andopen_world_hint. Missing safety fields forcedescribe, even for a zero-argument tool;deferred_hintstays optional.- Keep tool groups independently usable. A correlated load carrying
target_tool_slugactivates only that tool's group; do not rely on a sibling default-active group being activated with it. call_examples: optional list of ready-to-copy argument payloads. Each entry hasarguments(JSON object matchinginput_schema.properties) and an optionalnote. Surfaced in describe responses atmetadata.dcc.call_examplesso agents can construct correct arguments on the first attempt.
Long-Running Main-Affinity Tools
execution: async changes the job lifecycle; it does not make one monolithic
host call interruptible. For long scene mutations:
execution: async
job_strategy: chunked
affinity: main
enforce_thread_affinity: true
annotations:
deferred_hint: true
When the adapter supports HostUiDispatcherBase.submit_chunked_runner(),
define bounded steps with the shared helper:
from dcc_mcp_core import chunked_job
@chunked_job(total=100)
def build_bake_steps():
for frame in range(100):
yield lambda frame=frame: bake_one_frame(frame)
Return the runner from the declarative entry point. HostExecutionBridge
automatically submits it to the shared host pump and binds it to the outer
JobManager cancellation probe. Do not create a skill-local timer, thread,
pump, or second job registry.
Keep each yielded callable bounded, return a string when a progress message is
useful, and let cancellation become terminal only after a runner checkpoint.
If the adapter does not expose the shared chunked path, document that the tool
is monolithic and request an adapter/core integration instead of claiming
mid-call interruption.
Use job_strategy: isolated when the typed tool launches a process- or
service-owned operation and returns a durable job id immediately. Declare the
poll and cancel tools in next-tools and in the result recovery context.
Status must remain readable after a transport disconnect or adapter restart;
state cancellation ownership honestly when it cannot be reconstructed.
The launch result must include the same durable job_id plus one canonical
status. To make CLI --wait follow the adapter operation, declare the status
tool in next-tools.on-success with execution: sync, a string job_id as its
only required input, and both read_only_hint: true and idempotent_hint: true.
Every other input must be optional and safe when omitted. Core rejects async,
mutating, optional-id, multi-required-input, and untyped pollers. The status tool must
return the queried ID or an explicit unknown-ID error; it must never create a
new operation while polling.
Render and cook status tools should reuse the Core progress vocabulary:
status, progress.current, progress.total, and progress.message.
current and total are monotonic work-unit counts such as completed/total
frames; clients derive the percentage and render one progress bar. Prefer the
renderer or cook service's native counters. If files are the only source, keep
that counting inside the typed status tool instead of making the agent run
repeated directory scans.
During an active turn, agents should start once and use CLI --wait, REST job
events, or the declared status tool. Do not create an OS or DCC-MCP scheduled
workflow merely to poll one running operation. Only after the user explicitly
requests cross-session monitoring may an agent create a one-shot follow-up that
stores the existing job/operation id, performs read-only status checks, and
self-stops at a terminal state; it must never relaunch the render or cook.
Mirror this contract in agents/openai.yaml: tell the Agent to start once,
follow typed progress to a terminal state, and query the same job id after a
timeout instead of relaunching work.
For one indivisible DCC-native call, keep job_strategy: monolithic. Prefer
execution: async so the initial transport returns a core job id, then poll
the instance-routable jobs_get_status. A transport timeout is not completion
or cancellation: rediscover the instance and query the job before retrying.
Do not publish a potentially long tool as execution: sync with no timeout
metadata. A positive timeout_hint_secs also makes Core return a job envelope;
use it when duration is known but the tool otherwise retains synchronous
semantics inside the worker.
The creator scaffold deliberately emits monolithic for async tools; change it
only with the matching chunked runner or isolated status/cancel implementation.
Computer Use Fallback Contract
- Reuse the bundled
ui-controlskill instead of creating another screenshot, pointer, keyboard, or WindowsSendInputtool set. Declaremetadata.dcc-mcp.depends: ["ui-control"]only when it is a hard workflow dependency. Native UI Control requires standalonedcc-cua0.4.0 or newer; do not preserve or add a legacy Core Host fallback. - Keep the visual loop as
ui_control__snapshot->ui_control__act->ui_control__snapshot, and pass the latestsnapshot_idunchanged. End every path withui_control__stop_computer_use. Screenshot coordinates belong to that observation only. - Preserve
capture_provenancewith saved evidence. A livebackend=dcc-cuasnapshot pluspixels_captured=trueproves native application capture; keep the logical UI Controlsession_iddistinct from the gateway agent session used for stats attribution. - Stateful UI tools must declare
requires_in_process: trueindependently ofaffinity; keep UI Control ataffinity: anyso it does not block the DCC UI thread while preserving one persistent CUA bridge. The shared standalone Host owns observations, Esc interruption, markers, and cross-session input serialization; skill scripts must not instantiate another automation stack. - Prefer a
control_idand semantic UI Automation action. Use raw coordinates only when the UI does not expose a stable semantic control. - For native application menu bars, use the negotiated
invoke_menuaction with an explicitmenu_pathwhen a semantic menu click or Alt mnemonic cannot prove that a popup opened. Never guess pixels or report native delivery as completion; take a fresh snapshot and honorverification_requiredbefore another mutation. - For custom-drawn canvases, viewport manipulators, or face controls, use one
dragpath from the latest snapshot.keysmay hold Ctrl, Shift, or Alt for pointer-modified drags; snapshot again immediately before deriving another path. - Never set
DCC_MCP_CUA_ALLOW_RAW_INPUTfrom a skill script. Native input is enabled by default, and the operator-ownedfalsesetting disables it. Native input also requires the adapter/operator to bind its DCC withDCC_MCP_UI_CONTROL_PROCESS_IDorDCC_MCP_UI_CONTROL_WINDOW_HANDLE; a skill request may only narrow that trusted scope. Propagateuser_interruptedimmediately; do not retry the action or fall back to another input path after Esc interrupts a session. - Never enter or retry another UI/input path after a policy, authorization,
authentication, security, confirmation,
desktop_unavailable, oruser_interruptedresult. Computer Use is a capability fallback, not a way around a control boundary. - Keep mutating UI Control tools annotated as destructive. An optional
consequence
intentcan only raise the native host's independent UIA/input classification. Never add a model-controlledconfirmedorapprovedargument or treat an environment variable as per-action user approval. - Generated record-replay Skills must stay local until reviewed. Compile
structured calls to
WorkflowSpectool steps, compile semantic UI actions as freshsnapshot->find-> oneact-> verified wait/snapshot loops, and reject raw captured control ids or coordinates. Keep the demonstrated instance id as review provenance only. Never serialize approvals, grants, credentials, prompts, or secret-shaped fields. Visual fallback assets must be content-addressed, exact-window bounded, confidence gated, stable across multiple frames, and fail closed on geometry/DPI/topology drift.
Authoring Workflow
-
Decide whether the skill is infrastructure, domain, thin-harness, or example.
-
Give the skill a kebab-case name and each local tool a snake_case name.
-
Keep host API calls inside scripts, with lazy imports so discovery works without the host running.
-
Import same-directory helper modules directly; in-process runners expose the executing script's directory only for the call, so scripts must not mutate
sys.pathfor sibling imports. In particular, do not repeat the legacy pattern shown in houdini#157:script_dir = str(Path(__file__).resolve().parent) if script_dir not in sys.path: sys.path.insert(0, script_dir)That mutates process-global import state and leaks across skills. Script-directory lifetime is runtime ownership; use a direct sibling import and let the executor scope resolution to the current call.
-
Import dependency-light runtime helpers from
dcc_mcp_core.skills_helperfirst: JSON/YAML codecs, bounded HTTP helpers, safe file/path helpers, validation, cancellation checks, and result helpers. -
Declare
metadata.dcc-mcp.dependsfor prerequisite skills, then declareexecution,affinity,timeout_hint_secs, schemas, annotations, and failure recovery chains intools.yaml. Do not rely on runtime Python introspection for missing schemas. For high-frequency tools, addcall_examplesso agents can copy argument payloads without trial-and-error. -
Put long examples, recipes, and host-specific notes under
references/. -
Validate with
validate_skill_dirordcc_mcp_core.validate_skill()before loading it in an adapter. For discovery/load performance regressions, assert deterministic backend operation counts; use elapsed-time thresholds only as supplemental evidence. -
If the desired behavior requires parsing core internals or adapter-private YAML at runtime, stop and request a core API instead.
Improve Skills From Completed Tasks
Use retained gateway evidence only after the user-visible task and its
validation are complete. Keep one stable session_id in call metadata, then
query the narrowest useful slice:
dcc-mcp-cli stats --range 24h --dcc-type <dcc> --session-id <session-id>
Get the review_skill_improvement prompt from this skill and supply the stats
JSON plus bounded task and validation summaries. Treat total_calls == 0 as
missing evidence, not success. Never include hidden reasoning, raw prompts,
credentials, or unredacted payloads.
Prefer no_change, then improving an existing skill, and create a new skill
only for a repeated, reusable workflow that no current skill owns. Validate any
accepted change with validate_skill_dir or dcc-mcp-cli lint before loading
it. Statistics inform a proposal; they never authorize editing or publishing a
skill without the task owner's requested scope.
For a failed task, first use the dcc-mcp recovery flow: retain the
request_id, run doctor for runtime/readiness faults, query
stats --status failure --session-id <session-id>, and record structured
feedback through the gateway-owned dcc-mcp-cli feedback command. A live
adapter's dcc_feedback__report is only a shared Core forwarder to that same
gateway contract. The public-safe
/v1/debug/issue-reports/<request_id> payload is suitable for a reviewed issue;
never publish ?mode=raw automatically.
Published Skills should declare metadata.dcc-mcp.links.repo and
metadata.dcc-mcp.links.issues. Copy those exact values into Finding v1
evidence.routing before using dcc-mcp-cli feedback route; never infer a
tracker from a package name. Missing, non-canonical, or conflicting ownership
must fail closed, and resolving a route never authorizes issue creation.
Fix this Skill only when the evidence identifies its schema, script,
description, next-tool, or workflow contract. Route adapter/runtime failures to
dcc-mcp-creator and shared CLI/gateway/core failures to dcc-mcp-core. A
one-off tool bug is not evidence for creating another Skill.
When reviewing existing skills, reject top-level DCC-MCP extension keys such
as dcc, version, tags, tools, groups, depends, search-hint,
runtimes, prompts, and resources. Move them under
metadata.dcc-mcp.*; for version metadata, use
metadata.dcc-mcp.version: "1.0.0". Validate the installable skill directory
that contains the SKILL.md loaded by adapters, not only mirrored repository
docs or marketplace metadata.
Read AUTHORING_WORKFLOW.md and DCC_TOOL_CONTRACTS.md before changing a production skill package.
Gateway-Facing Tag Taxonomy
Gateway search treats tags as a narrowing filter. Use a small shared vocabulary
so pipeline, production-tracking, and documentation connectors rank and filter
consistently across hosts. When authoring SKILL.md frontmatter, include the
appropriate tags under metadata.dcc-mcp.tags:
| Tag | Use for |
|---|---|
pipeline |
Studio pipeline systems, publish/intake/review automation, and production data hand-offs. |
production-tracking |
Shot/asset/task/status tracking systems regardless of vendor. |
shotgrid |
Autodesk Flow Production Tracking / ShotGrid-specific tools. |
ftrack |
ftrack-specific tools. |
docs |
Documentation, product help, reference lookup, and guide resources. |
read-only |
Discovery/read operations. Also set MCP readOnlyHint (annotations.read_only_hint: true in tools.yaml); the tag is for search, not policy. |
destructive |
Mutating or irreversible operations. Also set MCP destructiveHint (annotations.destructive_hint: true in tools.yaml); the tag is for search, not policy. |
Filter semantics:
dcc_type(singular) +dcc_types[]— OR: a result matching any listed DCC family passes. Includedcc_type: "maya"withdcc_types: ["blender"]to match records from either host in one request.tags[]— AND: a result must carry every listed tag. Usepipeline+production-trackingto narrow to records that carry both.tags_any[]— OR: a result carrying any listed tag passes. Combines with the AND filter above:tags: ["pipeline"]+tags_any: ["read-only", "docs"]returns pipeline records that are read-only OR documentation.
Vendor tags can be added when they sharpen routing without replacing the
canonical tags. For example, Autodesk Product Help should use docs,
read-only, and the vendor tag autodesk. Do not add docs to a
production-tracking search unless the user explicitly asks for help or reference
material.
Python 3.7 Policy
All authored skills must declare compatibility: "Python 3.7+" in their
frontmatter when they are installed into an LTS DCC host. This applies to every
skill that is installed into a DCC host embedding Python 3.7 (Maya 2022,
Blender 2.83, 3ds Max 2022, etc.). py37-lite is a supported fallback but
does not replace the native Linux and Windows cp37 compatibility gates. See
ADR 011 and compatibility/python.json for the deprecation and CI contract.
In lite mode, create_skill_server() supports local metadata discovery
(list_skills, search_skills, and get_skill) only. The Rust sidecar is
dispatch-only, so gateway discovery and declarative load_skill execution
require a native Python 3.7 wheel; lite activation fails explicitly.
For hermetic CI or tests, set DCC_MCP_DISABLE_DEFAULT_SKILL_PATHS=1 so an
operator's local/platform defaults, marketplace installs, and Admin custom
paths cannot alter discovery results. Explicit, bundled, and
DCC_MCP_*_SKILL_PATHS paths remain active under this mode.
Skill SKILL.md example (frontmatter excerpt):
metadata:
dcc-mcp:
dcc: shotgrid
layer: domain
tags: [pipeline, production-tracking, shotgrid]
search-hint: "ShotGrid task status, find shots, update task assignments"
tools: tools.yaml
# Read-only docs connector (SKILL.md excerpt)
metadata:
dcc-mcp:
dcc: autodesk-help
layer: infrastructure
tags: [docs, autodesk, read-only, infrastructure]
search-hint: "Autodesk Product Help, Maya help, 3ds Max help, API reference"
tools: tools.yaml
Individual read tools should also carry read-only in their tool-level tags;
mutating publish/update tools should carry destructive when applicable.
Validation Rules
The validator checks:
- SKILL.md exists and is readable
- YAML frontmatter is well-formed
- Required fields:
name,description - Name format: kebab-case, <=64 chars, matches directory name
- Field lengths: description <=1024, compatibility <=500
- Tool declarations: non-empty names, no duplicates, snake_case client-safe format
- Script files:
source_filereferences exist inscripts/ - Sidecar files:
metadata.dcc-mcp.tools/groups/promptsreferences exist - Dependencies:
metadata.dcc-mcp.dependsconsistency - Spec compliance: non-standard top-level keys are frontmatter errors; dcc-mcp-core extensions must live under
metadata.dcc-mcp.*and point to sibling files - Version metadata:
metadata.dcc-mcp.versionis accepted and projected toSkillMetadata.version; top-levelversionfails with an actionable migration hint - Skill helper adoption:
validate_skill_diremitsskill-helper-adoptionwarnings when scripts import avoidable dependencies covered bydcc_mcp_core.skills_helper, such asrequests,httpx, PyYAML, or local JSON/HTTP/file/path helper modules