DCC-MCP Creator
Use this skill when you are creating a new DCC-MCP adapter or modernizing an existing adapter repository: server composition, host-thread dispatch, sidecar/gateway wiring, readiness, resources, project state, diagnostics, install lifecycle, or cross-DCC verification.
For individual skill packages (SKILL.md, tools.yaml, scripts, groups, and
skill taxonomy), load dcc-mcp-skills-creator instead.
Runtime Vocabulary
- DCC startup hook: adapter code running inside the host at application startup; it prepares env/instance data and launches the service path without blocking the DCC UI/main thread.
- Per-DCC service: one registered runtime row for one concrete DCC instance; Python
DccServerBaseand Rust sidecars both participate as per-DCC services. - Sidecar: the Rust
dcc-mcp-sidecarchild launched through the stabledcc-mcp-server sidecarcommand; it bridges host RPC to MCP/REST and exits when the watched DCC dies. - Gateway daemon: the one machine-wide
dcc-mcp-server gatewayprocess that owns routing, dynamic capability search/describe/call, and Gateway Admin. - Guardian: a lightweight loop inside daemon-backed services that probes gateway
/healthand re-ensures the daemon throughgateway-launch.lock; it is not a separate process. - Service heartbeat: registry freshness for the service row only. Do not describe heartbeat as the gateway restart trigger.
Fast Workflow
- Classify the host integration:
- Embedded Python host: Blender, 3ds Max Python, Houdini, Maya, Nuke.
- External bridge host: ZBrush, Photoshop, Unity, custom tools.
- Game/editor host with mixed Python or C++ bridge: Unreal, Unity.
- Read the relevant reference:
- ADAPTER_WORKFLOW.md for the build path.
- HOST_PATTERN_MATRIX.md for host-specific wiring.
- CORE_ESCALATION_CHECKLIST.md before adding adapter-local glue.
- TESTING_AND_RELEASE.md before validating or publishing.
- docs/guide/adapter-release-checklist.md for release train compliance.
- docs/guide/new-adapter-onboarding.md for new adapter scaffolding.
- docs/guide/adapter-compatibility-matrix.md for the per-DCC compatibility table.
- Start from
DccServerBase+DccServerOptions.from_env(...). - Route host API calls through
HostExecutionBridge; do not hand-roll a second script executor. - Keep DCC identity data-driven:
dcc_name,server_name, env-var prefix, skill names, and gateway metadata. - Use core helpers for skill discovery,
MinimalModeConfig, project tools, resources, diagnostics, context snapshots, install lifecycle, and gateway failover before writing adapter-local wrappers. PythonDccServerBase.collect_skill_search_paths()includes marketplace-installed skills under~/.dcc-mcp/marketplace/<dcc>(orDCC_MCP_MARKETPLACE_INSTALL_ROOT/<dcc>) when the directory exists, so adapters should not add a second marketplace path convention. - Choose the
dcc-mcp-serverrun mode deliberately, but treat it as a runtime surface rather than the primary user UX; humans and agents should normally usedcc-mcp-cli gateway register,gateway set,gateway daemon ..., andlist/search/describe/callprofiles. No subcommand,auto, andserveensure the machine-wide gateway daemon, register this process as a backend, keep a lightweight guardian running after registration, and stampgateway_runtime_mode/gateway_guardian_enabledinto the service row;serve --no-auto-gatewayis per-DCC only,auto --legacy-gateway-electionrestores the old embedded first-wins gateway, andgatewayruns the machine-wide daemon with no inline DCC execution. Explicitdcc-mcp-server gateway --daemonrespawns the current executable as a detached child instead of forking inside the async runtime;--pidfile PATHimplies daemon mode, records the detached child PID, and fails fast if respawn or pidfile writing fails. CLI daemon stop/restart treats the pidfile as a hint only: before terminating a PID, it must match a live__gateway__sentinel for the target health URL viagateway_process_pid/gateway_health_url; otherwise the CLI refuses with stale-pidfile guidance. Standalone gateway daemon mode shuts down after the last routable backend has been absent for the configured grace period; the manualgatewayCLI default is30seconds, while daemon auto-ensure passesDCC_MCP_GATEWAY_IDLE_TIMEOUT_SECS=300unless the operator overrides it; sidecar auto-ensure preserves0as persist mode but clamps tiny non-zero values below 30 seconds so the gateway cannot exit before first backend registration. Set--gateway-persist/DCC_MCP_GATEWAY_PERSIST=1or--gateway-idle-timeout-secs 0for studio/headless deployments that must keep the daemon alive with no local backends.GET /v1/readyzreports the effectivegateway_lifecycle.persistandgateway_lifecycle.idle_timeout_secs, so diagnostics must read that field instead of inferring policy from env defaults. PythonDccServerBaseadapters, Rustdcc-mcp-server sidecarprocesses withgateway_port > 0, and registereddcc-mcp-server translatebridges follow the same daemon-first contract at startup and keep the same daemon guardian running in daemon-backed mode so a surviving DCC or bridge can re-ensure the daemon after/healthdisappears; the sharedgateway-launch.lockis reclaimed afterDCC_MCP_GATEWAY_LAUNCH_LOCK_STALE_SECSif a launcher crashes mid-startup, so adapters should shareDCC_MCP_REGISTRY_DIRand not delete the lock manually. Gateway auto-launch failures keep a sidecar boot row withfailure_stage,failure_reason,gateway_health_url,gateway_launch_lock, andregistry_dir; the registry directory also containsgateway-autolaunch-<port>.json, stdout, and stderr logs when a process was spawned, and active gateway sentinel rows expose health/MCP URLs, PID, executable, start time, persist, and idle-timeout metadata.dcc_diagnostics__gateway_failovershould reportdaemon-backedorembedded-fallbackso operators can distinguish the mode. - When a DCC startup hook must spawn the per-DCC sidecar without importing native core, use
dcc_mcp_core.install_lifecycle.build_sidecar_command(...)orlaunch_sidecar(...); they produce the canonicaldcc-mcp-server sidecarargv, stamp the shared registry/gateway env, capture stdout/stderr to<registry_dir>/logsby default (stdio.stdout_path/stdio.stderr_path), returnserver_binarydiagnostics (command,source, resolvedpath, boundedversionorversion_error), and let the child ensure the daemon without blocking the DCC main process unlessno_ensure_gateway=Trueorlegacy_gateway_election=True. For in-process plugin startup hooks, omitwatch_pidand let the helper bind to the current DCC process; pass explicitwatch_pidonly when an external supervisor or module CLI command is launching the sidecar on behalf of that DCC host. If an in-process MCP/REST server remains available for discovery, passdiscovery_mcp_url=<handle.mcp_url()>so gateway search, describe, OpenAPI/skill inventory, prompts, and resources refresh through that read-only endpoint while tool execution still routes through the sidecar dispatch endpoint.build_sidecar_command()also returnsreadiness_selector,readiness_argv,readiness_command(honouringDCC_MCP_PYTHON_EXECUTABLE),dispatch_contract(uri_valid,validation_error,dispatch_ready_capable), andreadiness_contract(ready_on_launch=false,direct_use_status), andlaunch_sidecar(wait_ready_timeout_secs=..., probe_tool=...)can include the same bounded dispatch verdict when called from an installer, supervisor, or background startup task; leave it unset on the DCC UI thread. The Python API keepsliveness_check_secs=0.0by default for non-blocking UI hooks; the module CLIlaunch-sidecardefaults to a 1-second startup liveness window for installer/supervisor use. Passliveness_check_secs=...in API calls or--liveness-check-secs 0on the CLI only when overriding that policy; if the sidecar exits during that short window, the helper returnssuccess=false,status="exited",reason="sidecar_exited_during_startup", an exit code, stdio log paths, and anearly_exitdiagnostic withstdout_tail,stderr_tail, and value-free argv metadata so adapter launchers can show the Rust CLI parse error instead of a vague exit code. Withoutwait_ready_timeout_secs,launch_sidecar()deliberately returnsready=false,readiness_checked=false, and areadinesspayload whose status isnot_checked(ordispatch_not_capablefor diagnostics-only schemes), so spawn success must never be treated as "open DCC, directly usable". Passrequire_dispatch_capable=Trueor CLI--require-dispatch-capablewhen startup code must fail fast on malformed real host RPC URIs,stub://, or unsupported host RPC schemes before claiming "open DCC, directly usable"; keep it false only for diagnostics-only rows. The Rust implementation lives indcc-mcp-sidecar; adapters should still depend on the lifecycle helpers and stabledcc-mcp-server sidecarCLI surface, not construct a new ad-hoc binary command. Do not treat aper-dcc-sidecarregistry row alone as proof that tools are callable: the adapter must expose a supported host RPC bridge to its DCC dispatcher/skills, and startup code or installers should usesidecar_readiness_status(...)/wait_for_sidecar_ready(...)for a bounded import-light verdict before claiming the plugin is ready. For instance-level startup proof, pass the fullreadiness_selector; ifinstance_idorhost_rpcmatches multiple live sidecars, those helpers returnstatus="ambiguous"instead of choosing an arbitrary row. Passprobe_tool="<dcc>_diagnostics__ping"(or CLI--probe-tool) when the adapter needs proof that one realtools/callreaches the host dispatcher; probe failures keep the verdict unready until timeout. Operators should seedispatch_ready=Truefrom those helpers, the nesteddispatchobject inquery_runtime_state(...),GET /admin/api/workers, or the nesteddispatchobject ongateway://instances/GET /v1/instances; gatewayGET /v1/readyzalso carries per-instancedispatchplus dispatch-ready counts so launchers and admin panels can distinguish listed DCC processes from callable sidecar dispatchers. Daemon-backed sidecars, PythonDccServerBaseadapters,dcc-mcp-serverbackends, and registered translate bridges publishgateway_runtime_mode,gateway_guardian_enabled,gateway_recovery_driver, andregistration_refresh_mode;gateway_recovery_driver="daemon_guardian"means recovery is driven by guardian/healthprobes, whileregistration_refresh_mode="file_registry_heartbeat"means the service row stays fresh through registry heartbeat and the restarted gateway re-reads it rather than requiring an explicit re-register. GatewayGET /v1/readyzmirrors this with per-instancegateway,gateway_recovery_driver_counts,registration_refresh_mode_counts,gateway_daemon_guardian_instance_count, andgateway_daemon_guardian_readyso startup checks and admin panels can answer whether any live DCC service can restart the daemon. Failed host RPC startup stays registered withdispatch_ready=False,metadata.dispatch_status=unavailable, andfailure_stage/failure_reasonfor diagnostics. A failed sidecar may still publishmetadata.mcp_urlas a diagnostic endpoint:/v1/readyzmust reportdispatcher=false, andtools/callmust return a structuredtransport-error; do not route gateway traffic through it untildispatch_status=ready. For real supported schemes (commandport://,qtserver://,ws:///wss://), the sidecar keeps reconnecting while the parent DCC is alive and promotes that same row when the host bridge appears;stub://is test-only and staysdispatch_status=unavailableby default even when it connects, so never use it as adapter startup proof. Mayacommandport://sidecars return a structuredsidecar-dispatcher-unavailablebackend envelope whendcc_mcp_mayais present but its sidecar dispatcher is missing, so treat that as a partial adapter install rather than a gateway routing failure. If a ready backend later returns terminalhost-died, gateway removes that instance from the capability index plus its FileRegistry or HTTP registration row immediately; do not design adapters around waiting for stale heartbeat cleanup after a terminal host failure. - Pass
instance_idto sidecar launch helpers only when it is a real UUID for the DCC service. During early startup, omit it or passNone;build_sidecar_command()rejects cosmetic values such as"unknown"withsuccess=falseandreason="invalid_instance_id"so adapters do not spawn a child that can only fail with a CLI argument error. - Adapter supervisors that must stop the sidecar on plugin unload should call
launch_sidecar(..., return_process=True, detached=False)instead of reimplementingsubprocess.Popen; keepreturn_process=Falsefor CLI/JSON paths because the process handle is not serializable. - If the adapter cannot share the gateway
FileRegistry, register remotely throughPOST /v1/instances/register, refresh with/heartbeat, and deregister on shutdown; the gateway will expose the row assource: "http"ingateway://instances/GET /v1/instances, preserveinstance_shortandmcp_url, and route it through the samelive_instancescontract. - For same-LAN convenience discovery, build with
mdnsand pair adapter-side--advertise-mdnswith gateway-side--discover-mdns; treat this as a multicast discovery hint only, keep auth/TLS policy explicit, and prefer HTTP registration or relay for routed/subnet-crossing production deployments. - For NAT or routed-subnet deployments, run the tunnel agent with stable
instance_id,capabilities_fingerprint,adapter_version, andscenemetadata, then configure the standalone gateway with--relay-source ADMIN_URL=PUBLIC_BASE_URL; the gateway will expose active tunnels assource: "relay"rows with relay details insource_metaafter probing/v1/healthzthrough<PUBLIC_BASE_URL>/tunnel/<tunnel_id>/mcp. - Preserve gateway caller attribution when adding adapter wrappers or admin/debug routes: let MCP
initialize.params.clientInfo, MCP_meta.agent_context, RESTmeta.agent_context,x-dcc-mcp-*headers, and safeUser-Agentfallbacks flow through core rather than logging raw prompts or local machine data. - For lifecycle/memory/telemetry policy, use
register_lifecycle_hooks(...),search_skills(..., session_id=...),dispatch_session_start(...),dispatch_before_tool_call(...),dispatch_after_tool_call(...), anddispatch_session_end(...); pairMemoryRecorder(InMemoryMemoryStore()).install(hooks)with those hooks when adapters need bounded memory summaries, failed-pattern avoidance, or session compaction, and disable the recorder for privacy-sensitive deployments. Open a focused core issue/RFC only when those public hooks cannot express the adapter boundary. - Add one executable smoke path: unit tests for construction plus either headless DCC, mock dispatcher MCP calls, gateway REST replay, mDNS same-LAN discovery smoke, relay-source smoke, or
just idle-memory-smokefor standalone server idle/regression checks. - For gateway/admin observability, surface explicit state instead of silent zeroes: traffic panels should report disabled, unavailable, filtered, or genuine no-traffic states; skill panels should distinguish discovered, loaded, searched, selected, called, failed, and low-adoption skills; and admin-facing frames/paths should stay metadata-only or aliased unless an operator explicitly configures a private raw sink.
- Preserve workflow observability: adapter calls should carry request, parent, trace, session, DCC, transport, and artifact/validation metadata so the Admin workflow graph can show Intent → Discovery → Skill Load → Tool Calls → Fallbacks → Artifacts → Validation → Report without raw log reading.
- Preserve bounded
agent_contexttask/session/turn metadata and artifact/validation-friendly tool names so Admin task outcomes can group workflows, calls, deliverables, and checks without reading raw payloads or local paths.
Example: New Nuke Adapter
When asked to create a Nuke MCP adapter, start by mapping the host lifecycle: how Python is loaded, how the UI/main thread must be entered, what headless mode is available, how plugins are installed, and which operations should be bundled as default skills. Then scaffold the adapter around core primitives:
DccServerBasefor MCP/HTTP and skill catalog behavior.DccServerOptions.from_env("NUKE")or an adapter-specific equivalent for env-driven configuration.HostExecutionBridgeplus a Nuke dispatcher for all Nuke API calls.- Core project, readiness, resource, diagnostics, and gateway helpers before adapter-local glue.
dcc-mcp-skills-creatorfor the firstnuke-*skill packages.
Non-Negotiables
- Do not touch a DCC API from a Tokio/HTTP worker thread.
- Do not parse or rewrite
SKILL.md,tools.yaml,groups.yaml, or prompt/workflow files in adapter runtime code when core exposes a typed object or catalog API. - Do not reach into
server._serverunless no public core API exists; if you must, file a core issue and keep the adapter shim small. - Do not create Maya-only abstractions in shared core or adapter templates.
- Do not expose raw script execution as the primary user workflow when a typed skill can cover the task.
- Do not publish local paths, private machine names, or source-attribution markers in public issues or PR text.
Scan to join WeChat group