@pixeldojo/mcp 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1464,13 +1464,23 @@ async function applyCast(ctx, filmId, cast) {
1464
1464
  role: c.name,
1465
1465
  ...c.character_id ? { characterId: c.character_id } : {},
1466
1466
  ...c.image_urls ? { imageUrls: c.image_urls } : {},
1467
- ...c.prompt ? { prompt: c.prompt } : {}
1467
+ ...c.prompt ? { prompt: c.prompt } : {},
1468
+ ...c.replace ? { replace: true } : {},
1469
+ ...c.remove ? { remove: true } : {}
1468
1470
  }
1469
1471
  );
1470
- if (r.status === 200 && r.data.creditCost) charged = true;
1471
- if (r.status !== 200) return `Could not cast ${c.name}: ${r.data.error ?? r.status}`;
1472
- if (r.data.alreadyCast) return `${c.name} was already cast; nothing changed.`;
1473
- return `Cast ${c.name}${r.data.creditCost ? ` (portrait, ${r.data.creditCost} credits)` : ""}${r.data.boundShots ? `, in ${r.data.boundShots} shot(s)` : ""}.`;
1472
+ if (r.data.creditCost) charged = true;
1473
+ if (r.status !== 200) {
1474
+ const where2 = r.data.code === "cast-rendered" ? ` Storyboard: ${ctx.baseUrl}/film-studio/${filmId}` : "";
1475
+ return `Could not ${c.remove ? "remove" : c.replace ? "replace" : "cast"} ${c.name}: ${r.data.error ?? r.status}${where2}`;
1476
+ }
1477
+ if (r.data.removed) return `Removed ${c.name} from the film and every shot.`;
1478
+ if (r.data.alreadyCast) {
1479
+ return c.replace ? `${c.name} is already played by that character; nothing changed.` : `${c.name} is already cast; nothing changed. To swap who plays ${c.name}, send the entry again with replace: true.`;
1480
+ }
1481
+ const cost = r.data.creditCost ? ` (portrait, ${r.data.creditCost} credits)` : "";
1482
+ const where = r.data.boundShots ? `, in ${r.data.boundShots} shot(s)` : "";
1483
+ return r.data.replaced ? `Replaced ${r.data.replaced.name} with ${r.data.character?.name ?? "the new cast member"}${r.data.character?.id ? ` (character_id ${r.data.character.id})` : ""} as ${c.name}${cost}${where}.` : `Cast ${c.name}${cost}${where}.`;
1474
1484
  }));
1475
1485
  return { lines, charged };
1476
1486
  }
@@ -1773,7 +1783,7 @@ async function run8(input, ctx) {
1773
1783
  if (action === "plan") return plan(input, ctx);
1774
1784
  if (!input.film_id) return { kind: "text", text: "produce/status/cast need the film_id returned by the plan step." };
1775
1785
  if (action === "cast") {
1776
- if (!input.cast?.length) return { kind: "text", text: "Pass cast: [{ name, prompt | image_urls | character_id }] to cast characters." };
1786
+ if (!input.cast?.length) return { kind: "text", text: "Pass cast: [{ name, prompt | image_urls | character_id }] to cast characters (add replace: true to swap someone already cast, or remove: true to take them off)." };
1777
1787
  const { lines } = await applyCast(ctx, input.film_id, input.cast);
1778
1788
  const uncast = await uncastRolesOf(ctx, input.film_id);
1779
1789
  return {
@@ -1806,15 +1816,17 @@ var init_film = __esm({
1806
1816
  aspect: z.enum(["16:9", "9:16"]).default("16:9"),
1807
1817
  length: z.enum(["30s", "60s", "2-3min", "5min"]).default("60s").describe("Target length; drives the shot count (~6/12/24/60 shots)."),
1808
1818
  film_id: z.string().max(40).optional().describe("Existing film id (from a previous call) for produce/status/cast."),
1809
- action: z.enum(["plan", "produce", "status", "cast"]).default("plan").describe("'plan' creates + storyboards (free). 'cast' casts characters on an existing film. 'produce' starts charged generation. 'status' advances production and reports progress; poll it every ~30s until it returns the finished film."),
1819
+ action: z.enum(["plan", "produce", "status", "cast"]).default("plan").describe("'plan' creates + storyboards (free). 'cast' casts, replaces or removes characters on an existing film. 'produce' starts charged generation. 'status' advances production and reports progress; poll it every ~30s until it returns the finished film."),
1810
1820
  cast: z.array(
1811
1821
  z.object({
1812
1822
  name: z.string().trim().min(1).max(60),
1813
1823
  image_urls: z.array(z.string().url().startsWith("https://").max(2048)).min(1).max(8).optional(),
1814
1824
  prompt: z.string().trim().min(1).max(600).optional(),
1815
- character_id: z.string().max(40).optional()
1825
+ character_id: z.string().max(40).optional(),
1826
+ replace: z.boolean().optional(),
1827
+ remove: z.boolean().optional()
1816
1828
  })
1817
- ).max(8).optional().describe("Cast members, one per named character. Each gives image_urls (your own photos), a prompt (a portrait is generated, charged), or a character_id (a Character Studio character); with none of these the Character Studio character of that name is used."),
1829
+ ).max(8).optional().describe("Cast members, one per named character. Each gives image_urls (your own photos), a prompt (a portrait is generated, charged), or a character_id (a Character Studio character); with none of these the Character Studio character of that name is used. replace: true swaps out whoever already plays that name; remove: true takes them off the film."),
1818
1830
  soundtrack: z.enum(["scene-synced", "flat", "none"]).default("scene-synced").describe("scene-synced composes one musical section per scene, pinned to the scene lengths (default). flat is a single cohesive bed. none skips music."),
1819
1831
  music_job_id: z.string().max(80).optional().describe("The music_job_id from the previous status reply while the score is composing, so that score is attached. A status call without it, once all clips are ready and no score is attached, starts and charges for a new score.")
1820
1832
  });
@@ -1843,12 +1855,12 @@ var init_film = __esm({
1843
1855
  action: {
1844
1856
  type: "string",
1845
1857
  enum: ["plan", "produce", "status", "cast"],
1846
- description: "plan (default, free): writes the script and plans shots, returns film_id, a cost estimate, and any characters still to cast. cast: casts characters on an existing film (pass film_id and cast). produce (charged): starts rendering frames; refused until every named character is cast. status: advances production one step and reports progress; call it every ~30s until it returns the finished film URL."
1858
+ description: "plan (default, free): writes the script and plans shots, returns film_id, a cost estimate, and any characters still to cast. cast: casts, replaces or removes characters on an existing film (pass film_id and cast). produce (charged): starts rendering frames; refused until every named character is cast. status: advances production one step and reports progress; call it every ~30s until it returns the finished film URL."
1847
1859
  },
1848
1860
  cast: {
1849
1861
  type: "array",
1850
1862
  maxItems: 8,
1851
- description: 'Cast members, one per named character. Every named character must be cast before frames render, so faces, ages and species hold in every shot. Pass them on the plan call (the script then stars them by name) or later with action "cast" using the names the plan reports. Each entry: name, plus ONE of image_urls (your own photos of an adult, made into a character), prompt (a portrait is generated from it, charged like any image), or character_id (a Character Studio character). An entry with only a name uses your Character Studio character of that name.',
1863
+ description: 'Cast members, one per named character. Every named character must be cast before frames render, so faces, ages and species hold in every shot. Pass them on the plan call (the script then stars them by name) or later with action "cast" using the names the plan reports. Each entry: name, plus ONE of image_urls (your own photos of an adult, made into a character), prompt (a portrait is generated from it, charged like any image), or character_id (a Character Studio character). An entry with only a name uses your Character Studio character of that name. A name that is already cast is left alone unless the entry sets replace: true, which hands that part (every shot, outfit and voice) to the new cast member. remove: true with only the name takes that cast member off the film; the part then needs a new cast member before frames render. replace and remove work until the shots of that cast member are rendered; after that, recast on the storyboard, where the frames that show them can be redone.',
1852
1864
  items: {
1853
1865
  type: "object",
1854
1866
  properties: {
@@ -1858,7 +1870,15 @@ var init_film = __esm({
1858
1870
  type: "string",
1859
1871
  description: 'A description to generate the portrait from: species if not human, gender, adult age, look and outfit (e.g. "man in his late 50s, grey mustache, sunburnt, red windbreaker").'
1860
1872
  },
1861
- character_id: { type: "string", description: "A Character Studio character id." }
1873
+ character_id: { type: "string", description: "A Character Studio character id." },
1874
+ replace: {
1875
+ type: "boolean",
1876
+ description: "Swap out whoever already plays this name for the image_urls, prompt or character_id given here, before their shots are rendered. Without it, an already-cast name is left unchanged."
1877
+ },
1878
+ remove: {
1879
+ type: "boolean",
1880
+ description: "Take whoever plays this name off the film and every shot (free), before their shots are rendered. Give only the name."
1881
+ }
1862
1882
  },
1863
1883
  required: ["name"]
1864
1884
  }
@@ -1905,8 +1925,8 @@ var init_film = __esm({
1905
1925
  };
1906
1926
  filmSkill = {
1907
1927
  name: "pixeldojo_film",
1908
- description: "Make a finished short film from one idea: screenplay, storyboard frames (AI-reviewed), video clips with spoken dialogue, scene-synced soundtrack, stitched export. Or a music video: pass song_path (a local file) or song_url (your own PixelDojo upload from pixeldojo_upload, never a third-party link) with optional lyrics; the film is cut to that song, each clip lip-synced to its slice on the studio music video engine, and no score is composed: the export plays the song. Every named character must be cast (cast: your own images, a portrait prompt, or a Character Studio character) before frames render. Phased: plan is free; cast; produce starts charged generation; status advances production (poll every ~30s).",
1909
- hostedDescription: "Make a finished short film from one idea: screenplay, storyboard frames (AI-reviewed), video clips with spoken dialogue, scene-synced soundtrack, stitched export. Or a music video: pass song_url (your own PixelDojo upload made with POST /api/v1/upload, never a third-party link) with optional lyrics; the film is cut to that song, each clip lip-synced to its slice on the studio music video engine, and no score is composed: the export plays the song. Every named character must be cast (cast: your own images, a portrait prompt, or a Character Studio character) before frames render. Phased: plan is free; cast; produce starts charged generation; status advances production (poll every ~30s).",
1928
+ description: "Make a finished short film from one idea: screenplay, storyboard frames (AI-reviewed), video clips with spoken dialogue, scene-synced soundtrack, stitched export. Or a music video: pass song_path (a local file) or song_url (your own PixelDojo upload from pixeldojo_upload, never a third-party link) with optional lyrics; the film is cut to that song, each clip lip-synced to its slice on the studio music video engine, and no score is composed: the export plays the song. Every named character must be cast (cast: your own images, a portrait prompt, or a Character Studio character) before frames render; cast entries can also replace or remove someone. Phased: plan is free; cast; produce starts charged generation; status advances production (poll every ~30s).",
1929
+ hostedDescription: "Make a finished short film from one idea: screenplay, storyboard frames (AI-reviewed), video clips with spoken dialogue, scene-synced soundtrack, stitched export. Or a music video: pass song_url (your own PixelDojo upload made with POST /api/v1/upload, never a third-party link) with optional lyrics; the film is cut to that song, each clip lip-synced to its slice on the studio music video engine, and no score is composed: the export plays the song. Every named character must be cast (cast: your own images, a portrait prompt, or a Character Studio character) before frames render; cast entries can also replace or remove someone. Phased: plan is free; cast; produce starts charged generation; status advances production (poll every ~30s).",
1910
1930
  inputZod: InputSchema8,
1911
1931
  inputJsonSchema: InputJsonSchema8,
1912
1932
  allowedModels: [],
@@ -3383,7 +3403,7 @@ function makeRedactedLogger(target = console) {
3383
3403
  }
3384
3404
 
3385
3405
  // src/server.ts
3386
- var PACKAGE_VERSION = "0.17.0" ;
3406
+ var PACKAGE_VERSION = "0.18.0" ;
3387
3407
  var SERVER_INSTRUCTIONS = "PixelDojo generates images, video, audio and short films across 100+ models, billed in credits from the connected PixelDojo account. A job that runs past the 30-second wait returns a jobId to check later; check it rather than submitting again, since every new submission is charged. Generated asset URLs are deleted one hour after they are created, so download anything the user wants to keep. Finished films are the exception and stay in the account library.";
3388
3408
  function buildServer(options) {
3389
3409
  if (!options.apiKey) {