DEVELOPERS · MCP

Plug ABCD into your AI stack

ABCD Studio exposes its full production pipeline — text-to-image, text-to-video, and end-to-end film assembly — as a Model Context Protocol server. Any MCP-aware client (Claude Desktop, ChatGPT custom connectors, OpenAI o-series apps, agentic frameworks) can direct a film from a single conversation.

What you get

  • 49 tools — the full ABCD pipeline, one-shot ad/film directors, media primitives, edit/enhance, audio and series planning. Full catalog below.
  • Managed rate limits — per-hour caps per API key, live-tunable by ABCD staff.
  • Per-user credit charging — pass an ABCD JWT via abcd_token and the generation runs on that user's credits.
  • Streamable HTTP transport — the same wire format Claude Desktop and ChatGPT Connectors already speak.
Full tool catalog (49)

Film pipeline (create → assemble) · 12

  • create_film_project
  • add_character
  • approve_cast
  • swap_character_look
  • generate_script
  • set_creative_brief
  • generate_scenes
  • approve_scene
  • adjust_scene_camera
  • revise_camera_plan
  • animate_scenes
  • assemble_film

Project control · 8

  • get_project_status
  • wait_for_film
  • list_film_projects
  • fix_and_resume_film
  • production_action
  • get_prompt_audit
  • get_requirements
  • get_generation_options

One-shot ad & film directors · 6

  • marketing_director
  • create_product_ad
  • create_ugc_ad
  • create_food_commercial
  • create_brand_story
  • create_real_estate_ad

Media primitives · 7

  • generate_image
  • generate_video
  • poll_job
  • search_vault
  • publish_asset
  • get_character
  • publish_film_to_tv

Edit & enhance · 7

  • enhance_video
  • remix_video
  • get_enhance_status
  • refine_story
  • rerender_best_scene
  • edit_scene
  • add_scene_voice

Audio · 5

  • separate_stems
  • remix_audio
  • replace_vocals
  • rebuild_mix
  • set_session_music

Series · 2

  • create_series
  • plan_episode

Deep research (ChatGPT) · 2

  • search
  • fetch
📊 Live activity — last 28 days
Anonymised per-tool call counts aggregated from our activity log. No user data, no payloads — just the shape of the load so integrators can gauge platform trust.
0 total tool calls
12tools active
28dwindow
Top 5 tools
get_project_status
7,575
production_action
70
wait_for_film
25
generate_video
15
generate_image
6
Weekly breakdown
09-282333
10-05366
10-124879
10-26130

Quickstart

  1. Get a URL or a key. Signed-in users: Settings → Connect via MCP shows a personal URL that carries a rotating mcp_sess_… session token — the raw key never travels over the wire. Developers: contact hi@abcdstudio.ai or open the SuperAdmin → API Keys panel and mint a scope-limited mcp_live_… key.
  2. Point your MCP client at /api/mcp — either the personal ?token=mcp_sess_… URL, or the bare endpoint with an X-ABCD-API-Key header.
  3. Keep the token out of the URL where you can. Cursor, Claude Code (CLI), VS Code, Windsurf and Codex accept headers — send X-ABCD-Token: mcp_sess_… (or Authorization: Bearer mcp_sess_…) to the bare endpoint instead. claude.ai / Claude Desktop connectors, ChatGPT and Kimi take a URL only, so use the masked personal URL and treat it like a password. The Connect page masks the token (👁 reveals it for 20 s) and ↻ Regenerate token invalidates a leaked one instantly without touching your client setup — just paste the new URL.
  4. Call any of the tools below. Tools that return a job_id should be polled with poll_job or (for pipeline steps) get_project_status. Every image_url, video_url, audio / stem / export URL and published link comes back as a public https:// link on the ABCD domain (…/api/vibe/media/<file>) that your AI client can open directly — never a localhost address.
  5. Watch who connects. ABCD e-mails you and badges Connect the first time your token is used from a new IP or client. Press ✓ This is me on your own tools so they never alert again — even after you regenerate — and anything untrusted that reconnects on a regenerated token is flagged.

Session tokens & Reconnect

  • mcp_sess_… resolves server-side to your API key (same scopes and per-hour limits) and is the only thing your AI client stores. Tokens can auto-rotate on a schedule you choose (Advanced → Auto-rotate, with a countdown to the next rotation).
  • Live status pill — 🟢 Connected (shows the last call time) · 🟡 Idle · ⚪ Not connected yet.
  • ↻ Reconnect mints a fresh mcp_sess_ URL and invalidates the old one — paste the new URL into your client. Use it after a rotation, a revoked token, or whenever the pill stays ⚪ after a call.
  • Precise 401s — an expired or revoked session returns "MCP session expired — open Connect via MCP and tap Reconnect" rather than a generic error; if your ABCD sign-in itself expired, the Connect page says so and asks you to sign in first.
  • Stability — idempotency keys make retries of long tools safe for 24 h; a per-user lock prevents duplicate film projects on concurrent calls; the 10-task render gate queues extra animate_scenes clips instead of failing them.
Claude Desktop — claude_desktop_config.json
{
  "mcpServers": {
    "abcd": {
      "url": "https://abcdstudio.ai/api/mcp",
      "headers": {
        "X-ABCD-API-Key": "mcp_live_YOUR_KEY_HERE"
      }
    }
  }
}
Python — direct via fastmcp
# pip install anthropic openai fastmcp
import asyncio, os
from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession

BASE = "https://abcdstudio.ai/api/mcp"
HEADERS = {"X-ABCD-API-Key": os.environ["ABCD_MCP_KEY"]}

async def run():
    async with streamablehttp_client(BASE, headers=HEADERS) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()
            # 1. Pitch a film
            res = await session.call_tool("create_film_project", {
                "title": "The Last Signal",
                "genre": "sci-fi",
                "story_concept": ("A radio operator on Mars catches a "
                                   "signal from Earth long after contact "
                                   "was lost."),
                "film_length": "short",
                "aspect_ratio": "16:9",
                "resolution": "1080p",
            })
            print(res.content[0].text)

asyncio.run(run())
curl — raw JSON-RPC over Streamable HTTP
# 1. Initialize a session
curl -sN "https://abcdstudio.ai/api/mcp" \
  -H 'X-ABCD-API-Key: mcp_live_YOUR_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize",
       "params":{"protocolVersion":"2025-06-18",
                 "capabilities":{},
                 "clientInfo":{"name":"probe","version":"1"}}}'

# 2. List all tools (save session id from the response header
#    "mcp-session-id" and pass it as Mcp-Session-Id on subsequent calls)
curl -sN "…/api/mcp" \
  -H 'Mcp-Session-Id: SID_FROM_STEP_1' \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
🔍 Try it — Live tools/list
Fire an unauthenticated GET /api/mcp-public-toolsagainst this deployment. Returns the same 14-tool catalog an integrator sees after provisioning a key — no signup needed.
▶ Try a tool — live call
Fire a real MCP call from this page. 6 calls per hour per IP, whitelisted tools only. No credits deducted from your (nonexistent) account — image generation returns ajob_id so you can inspect the async shape without waiting for pixels.
Read-only. Free. Semantic search across characters + environments + scenes.

Tool reference

ToolParametersDescription
create_film_projecttitle, genre, story_concept, visual_style?, film_length, aspect_ratio, resolutionStart a new film project (session). Writer plans in the background.
add_charactersession_id, name, description, reference_image_url?Add a character; if no reference, a portrait is generated first.
generate_scriptsession_id, wait? = truePoll storyboard until the Writer produces the scene list.
generate_scenessession_id, scene_ids?Kick off frame generation for all scenes or a subset.
approve_scenesession_id, scene_id, approvedApprove or reject an individual scene's current frame.
animate_scenessession_id, scene_ids?, model?, duration?Run Seedance video generation on approved frames.
assemble_filmsession_id, export_format = "mp4", resolution?, wait?Approve assembly + finalize + optional 600s poll for the final export URL.
get_project_statussession_idFull state snapshot: stages, characters, scenes, render progress, export URL.
generate_imageprompt, aspect?, style?, model?, wait?One-off image. model: seedream (default, Seedream 4.5, 1 cr) · seedream-5 (Seedream 5.0 Pro, 2 cr) · gpt-image-1 (OpenAI GPT Image 1, 2 cr) · nano-banana (Gemini, 2 cr).
generate_videoprompt, image_url?, model?, duration?, aspect?, motion?One-off Seedance clip.
poll_jobjob_id, job_type = "image"|"video"Poll any async job by id.
search_vaultquery, kind?Semantic search over characters / environments / scenes.
publish_assetasset_id, title, kindPublish an asset to the user's public showcase.
get_characternameLook up a character asset by fuzzy name match.

Rate limits

Per-key, per-hour, sliding-window. ABCD staff can override any of these live via db.mcp_rate_limits without a restart. A rejected call returns {ok:false, error:'rate limit reached (…/h)'} — back off with exponential jitter.

ToolDefault cap
generate_image30 / h
generate_video10 / h
create_film_project20 / h
add_character60 / h
generate_script40 / h
generate_scenes60 / h
approve_scene200 / h
animate_scenes20 / h
assemble_film10 / h
get_project_status600 / h
poll_job600 / h
publish_asset20 / h
search_vault200 / h
get_character200 / h

Error envelope

Every tool call returns a JSON object whose top-level shape is stable:

Success
{
  "ok": true,
  "session_id": "…", "…": "…",
  "rate_limit": { "used": 3, "cap": 20, "remaining": 17 }
}
Failure
{
  "ok": false,
  "error": "backend rejected request (400)",
  "detail": "credit balance too low",
  "error_type": "insufficient_credits",  // when applicable
  "job_id": "…"                          // when a partial run exists
}

Content-flag envelope — when a Seedance render is refused for safety/copyright reasons, error_type is copyright_filter or safety_filter, and a request_id lets support trace the row in db.content_flags.

Video models

Any of these keys work as the model argument on generate_video and animate_scenes. Legacy identifiers auto-alias to the current lineup so old clients keep working:

  • seedance-2.0-mini (default · 720p · 24 fps · smart duration · sound on)
  • seedance-1.0-pro
  • seedance-1.5-pro
  • seedance-2.0-fast
  • seedance-2.0
  • seedance-2.5

End-to-end transcript

The scripted conversation below shows a user directing Claude through a full film project. Each turn shows exactly what tool was called and a compact excerpt of the response. Runnable — swap the story concept, keep the sequence.

👤 Director
“Let's make a short film — a sci-fi drama where a radio operator on Mars catches a signal from Earth long after contact was lost. 16:9, 1080p. Give the astronaut a character sheet, then walk me through the pipeline.”
🤖 Claude
On it — creating the project first.
tool_use: create_film_project
{
  "title": "The Last Signal",
  "genre": "sci-fi",
  "story_concept": "A radio operator on Mars catches a signal from Earth long after contact was lost — she has 90 minutes of oxygen to decide whether to reply.",
  "film_length": "short",
  "aspect_ratio": "16:9",
  "resolution": "1080p"
}
→ result
{
  "ok": true,
  "session_id": "d94a…c1e2",
  "project_id":  "d94a…c1e2",
  "title": "The Last Signal",
  "status": "planning",
  "pipeline_stage": "script"
}
🤖 Claude
Adding the astronaut. I'll let ABCD generate the portrait from her description.
tool_use: add_character
{
  "session_id": "d94a…c1e2",
  "name": "Commander Riya Vale",
  "description": "South-Asian woman, mid-30s, close-cropped black hair, weather-worn navy Mars-Corps flightsuit with Bengali unit patch, tired but resolute eyes."
}
→ result
{
  "ok": true,
  "character_id": "7b3f…9a11",
  "name": "Commander Riya Vale",
  "portrait_url": "data:image/jpeg;base64,/9j/4AA…",
  "description": "South-Asian woman, mid-30s, …",
  "session_id": "d94a…c1e2"
}
🤖 Claude
Waiting for the Writer to finish the storyboard…
tool_use: generate_script
{ "session_id": "d94a…c1e2", "wait": true }
→ result (truncated)
{
  "ok": true,
  "script_id": "d94a…c1e2",
  "scene_count": 7,
  "scenes": [
    { "id": "s01…", "order": 1, "title": "Silent radio room",
      "description": "Cold-open on Riya's static-hissing console...",
      "duration": 5 },
    { "id": "s02…", "order": 2, "title": "The signal", "…": "…" },
    …
  ],
  "status": "ready"
}
👤 Director
Scene 2's prompt reads too on-the-nose. Regenerate that one, leave the rest.
🤖 Claude
tool_use: generate_scenes
{ "session_id": "d94a…c1e2", "scene_ids": ["s02…"] }
→ result
{
  "ok": true,
  "session_id": "d94a…c1e2",
  "started": [{ "scene_id": "s02…", "order": 2, "status": "queued" }]
}
🤖 Claude
Polling for progress every few seconds…
tool_use: get_project_status
{ "session_id": "d94a…c1e2" }
→ result (truncated)
{
  "ok": true,
  "session_id": "d94a…c1e2",
  "pipeline_stage": "frames",
  "next_stage": "frames",
  "all_approved": false,
  "characters": [{ "id": "7b3f…", "name": "Commander Riya Vale", … }],
  "scenes": [
    { "id": "s01…", "frame_status": "ready", "approved": false, … },
    { "id": "s02…", "frame_status": "ready", "approved": false, … },
    …
  ],
  "render_progress": { "done": 0, "total": 7, "percent": 0 }
}
👤 Director
Approve all seven. Then animate everything with Seedance 2.5 at 6 seconds a shot.
🤖 Claude
tool_use: approve_scene (×7)
{ "session_id": "d94a…c1e2", "scene_id": "s01…", "approved": true }
{ "session_id": "d94a…c1e2", "scene_id": "s02…", "approved": true }
…
→ result (last call)
{
  "ok": true,
  "scene_id": "s07…",
  "approved": true,
  "session_id": "d94a…c1e2",
  "pipeline_stage": "assembly"
}
tool_use: animate_scenes
{
  "session_id": "d94a…c1e2",
  "model": "seedance-2.5",
  "duration": 6
}
→ result
{
  "ok": true,
  "session_id": "d94a…c1e2",
  "model": "2.5",
  "started": [
    { "scene_id": "s01…", "order": 1, "job_id": "vid_a1…" },
    { "scene_id": "s02…", "order": 2, "job_id": "vid_a2…" },
    …
  ],
  "skipped_orders": [],
  "errors": []
}
🤖 Claude
Kicking assembly. This one usually takes 3–5 minutes — I'll wait for the export.
tool_use: assemble_film
{
  "session_id": "d94a…c1e2",
  "export_format": "mp4",
  "wait": true
}
→ result
{
  "ok": true,
  "session_id": "d94a…c1e2",
  "status": "ready",
  "export_url": "https://abcdstudio.ai/api/vibe/media/d94a_export_1080p.mp4",
  "duration_secs": 42
}
🤖 Claude
Done — The Last Signal is rendered at 1080p, 42 seconds long, with your approved seven scenes assembled in order. Say the word if you want a re-cut, a poster, or a shortform reel from it.

Need help? Email hi@abcdstudio.ai or open the SuperAdmin Docs Console for the internal reference.