Skip to content

Cross-DCC Verification

Prove an asset produced by one DCC through its MCP server can be consumed, inspected, and validated by a second DCC. This page explains the contract dcc-mcp-core ships and how downstream DCC repositories plug into it.

Why a contract, not an implementation

Every DCC (Blender, Maya, Unreal, Photoshop, Houdini, ...) has its own native import API, its own scene traversal primitives, and its own idea of what counts as a "mesh". dcc-mcp-core stays out of that jungle on purpose: it only defines the shape of a verifier's result and the skill template every downstream implementation is expected to clone. Keeping the shape tiny (three fields) is what makes the contract portable.

The actual import_and_inspect logic lives in the downstream repos:

DCCRepositorySkill name (convention)
Blenderdcc-mcp-blenderblender-fbx-verifier
Mayadcc-mcp-mayamaya-fbx-verifier
Unrealdcc-mcp-unrealunreal-fbx-verifier
Photoshopdcc-mcp-photoshopphotoshop-psd-verifier

The SceneStats contract

python
from dcc_mcp_core import SceneStats

observed = SceneStats(
    object_count=1,
    vertex_count=482,
    has_mesh=True,
    extra={"dcc": "blender-3.6"},  # optional DCC-specific enrichments
)
FieldTypeMeaning
object_countintTop-level objects seen after import.
vertex_countintTotal vertex count across all mesh geometry.
has_meshboolTrue when any imported object is polygon geometry.
extradictFree-form enrichments. Survives serialisation, ignored by the core comparison.

Comparing producer vs verifier

The helper SceneStats.matches() implements the only comparison semantics core endorses:

  • Strict on object_count (structural invariant).
  • Strict on has_mesh (detects silent empty imports).
  • Fuzzy on vertex_count (±5% by default) because FBX normals, UV seams, and tangent basis changes can split vertices on re-import.
python
produced = SceneStats(object_count=1, vertex_count=482, has_mesh=True)
observed = verifier_skill__import_and_inspect("/tmp/sphere.fbx")

assert produced.matches(observed, vertex_tolerance=0.05), (
    f"round-trip drift: expected {produced}, got {observed}"
)

Extra fields beyond the three core ones belong in extra. The comparator does not read extra, which keeps DCC-specific telemetry from ever breaking a round-trip assertion.

Writing a verifier skill

Scaffold a skill with dcc-mcp-skills-creator, then wire it to dcc_mcp_core.SceneStats. To create a verifier for a new DCC:

  1. Scaffold a new skill directory in your downstream repo (e.g. dcc-mcp-blender/skills/blender-fbx-verifier/).
  2. Edit SKILL.md: set dcc: blender (or similar) and rename the skill to match your repo's convention.
  3. Replace the stub body of scripts/import_and_inspect.py with your DCC's native import + inspection calls. Return a SceneStats.to_dict() payload wrapped by skill_success(...).
  4. Add a CI job in your downstream repo that:
    • Boots two DCC processes (or one producer + one verifier).
    • Runs a producer skill to create and export an asset.
    • Runs your new verifier skill on the exported file.
    • Asserts produced.matches(observed) using dcc_mcp_core.SceneStats.

Example stub (Blender)

python
import bpy

from dcc_mcp_core import SceneStats
from dcc_mcp_core.skill import skill_entry, skill_success


def main(params):
    bpy.ops.wm.read_factory_settings(use_empty=True)
    bpy.ops.import_scene.fbx(filepath=params["file_path"])
    objects = list(bpy.context.scene.objects)
    meshes = [o for o in objects if o.type == "MESH"]
    vertex_count = sum(len(m.data.vertices) for m in meshes)

    stats = SceneStats(
        object_count=len(objects),
        vertex_count=vertex_count,
        has_mesh=bool(meshes),
        extra={"blender_version": bpy.app.version_string},
    )
    return skill_success("Imported and inspected", **stats.to_dict())


if __name__ == "__main__":
    skill_entry(main)

Where the round-trip CI lives

dcc-mcp-core does not ship a Blender-with-FBX round-trip job. That belongs in whichever downstream repo owns the producer or verifier binary, because only those repos pin the DCC version matrix. The invariant core asserts is shape-only, exercised by tests/test_verifier_contract.py.

Downstream repos following this contract should add a CI job along these lines:

1. Start producer DCC in headless mode, load producer skill.
2. mcpcall call: producer__create_sphere, producer__export_fbx.
3. Start verifier DCC in headless mode, load verifier skill.
4. mcpcall call: verifier__import_and_inspect(/tmp/sphere.fbx).
5. Python assertion: SceneStats.from_dict(...).matches(produced).

FAQ

Why only three fields? What about bounding boxes, materials, animations?

Every field that enters the core contract has to mean the same thing across every DCC, forever. Three fields (objects / vertices / has-mesh) is the set where we could rigorously define and test the semantics. Anything DCC-specific (materials, cameras, animation frame counts, bounding boxes) can travel through extra without committing core to a cross-DCC definition.

Can I extend SceneStats in a downstream repo?

Do not subclass. Put downstream-specific data in extra. If a field becomes genuinely universal across all supported DCCs we'll promote it to the core contract in a minor release.

What if my DCC doesn't expose vertex counts?

Return vertex_count=0 and set an explanatory note in extra. Round- trip tests that target that DCC should then pass has_mesh as the only real assertion.

  • dcc-thread-safety.md — main-thread dispatcher primitives that verifier skills rely on when running inside a live DCC session.
  • host-adapter.md — the HostAdapter base class downstream repos extend to plug a verifier into their DCC's idle loop.
  • skills.md — SKILL.md format the verifier template is built on.

Released under the MIT License.