‹ All posts

Five production trackers, one contract: a tracker-MCP quintet and a hub

Production trackers don't talk to each other. ShotGrid, ftrack, Kitsu, AYON and NIM each hold the same kind of data (projects, shots, assets, tasks, statuses, casting) behind five incompatible APIs, and moving a show from one to another is a manual, lossy slog. I built an MCP for each, and a hub on top. tracker-mcp-hub.

The trick is one shared shape. Every tracker MCP emits the same normalized snapshot (project_summary), so an agent reads a project out of ShotGrid and recreates it in Kitsu without knowing either SDK. Five standalone servers, published and credited separately, all speaking one contract. A sixth tracker is just one more MCP that emits the same shape; everything downstream then works on it for free.

One contract across every production tracker: each tracker emits project_summary, the hub does verify / migrate / audit / snapshot / rollup

The hub is where that uniform contract pays off. It does five things no single tracker can: verify (diff two snapshots), audit (one source of truth against many mirrors), rollup (totals across every production), snapshot (a portable versioned archive), and migrate (an orchestrated read → write → verify that ends with proof). Most of it is pure: verify, audit, rollup and snapshot never touch a tracker SDK, they just operate on the normalized JSON. Only migrate does any writing.

The hub found real drift on its own the first time I aimed it at one project copied into all three original trackers. The ftrack copy came back short 8 tasks, carrying 615 status mismatches and 357 casting mismatches, plus name-collision assets ftrack had silently created. Every one of those is a documented cross-tracker incompatibility, surfaced by diffing snapshots instead of by hand. And an orchestrated migrate of a slice ended with VERIFY: PASS. Every count matched.

Write safety was non-negotiable, since these point at real production databases. Every create, update, delete and status change takes a two-level dry run: a client-side plan, or a preflight that resolves references against live data, validates statuses against the schema, and returns a before→after diff while writing nothing. The whole thing is v0.1 and honest about its edges: the migrate reference copies structure, statuses and casting, and reports any media gap rather than pretending to move the heavy publish bytes.

‹ Back to the devlog