# Make Me a Movie > Make Me a Movie runs an MCP server that turns a written brief into a short film — storyboard, cast, keyframes, voices, clips, music and a final cut — and seals every shot with a provenance manifest anyone can verify. It uses the same account, prices and refunds as the website. - MCP endpoint: https://api.makemeamovie.app/mcp (Streamable HTTP, OAuth 2.1) - Documentation for people: https://makemeamovie.app/developers ## Connect Add the address to your assistant, then sign in on makemeamovie.app. - **Claude** (claude.ai or Claude Desktop): Add a custom connector and paste the address, or use the one-click link. Connect it, then sign in to Make Me a Movie when Claude asks. One-click link: . Connectors added on claude.ai also appear in Claude Code when you sign in to Claude Code with your Claude subscription. For the make-a-film skill and the `film` command as well (in Cowork, run it as `/makemeamovie:film`), add the plugin instead: open Customize > Plugins, choose Add > Add marketplace, enter `mark24680617/makemeamovie-plugin`, add the Make Me a Movie plugin, then add and connect its connector from the plugin's Connectors tab. Source: [github.com/mark24680617/makemeamovie-plugin](https://github.com/mark24680617/makemeamovie-plugin). - **ChatGPT** (Developer mode): Turn on developer mode in ChatGPT. Add a server with the address above, then sign in when ChatGPT asks. The server speaks Streamable HTTP and signs you in with OAuth; there is no API key to paste. - **Claude Code** (In your terminal): Add the server, then sign in. Run `claude mcp add --transport http --scope user makemeamovie https://api.makemeamovie.app/mcp`, then `claude mcp login makemeamovie`. `--scope user` makes the server available in every project. `claude mcp login` signs you in on makemeamovie.app in your browser. For the make-a-film skill and the `/makemeamovie:film` command as well, install the plugin instead of adding the server: `claude plugin marketplace add mark24680617/makemeamovie-plugin`, then `claude plugin install makemeamovie@makemeamovie`, then sign in from `/mcp`. - **Any MCP client**: Any other MCP client connects to `https://api.makemeamovie.app/mcp` over Streamable HTTP from a server, desktop app or command line. Its first request without a token gets a 401 whose challenge points at the resource metadata; OAuth starts from there. Browser-based clients are refused: a request carrying an `Origin` header gets a 403 before any sign-in. Your assistant sends you to makemeamovie.app. Sign in, or create an account, and approve the connection. The approval page names the app and where it will send you back. Every film is quoted first. The server starts one only when the credits approved in the chat cover the estimate, and never charges past the approved figure: a film that would pass it pauses for a fresh approval. ## Authentication - **Grant**: OAuth 2.1 authorization code with PKCE. The only challenge method is `S256`; clients are public, with no client secret. - **Discovery**: Protected-resource metadata at `https://api.makemeamovie.app/.well-known/oauth-protected-resource/mcp`; authorization-server metadata at `https://api.makemeamovie.app/.well-known/oauth-authorization-server`. - **Clients**: Client ID metadata documents are accepted from `https://claude.ai` and `https://chatgpt.com`. Any other client registers once with dynamic client registration at `https://api.makemeamovie.app/oauth/register`: a public client, `application_type` `web` or `native`, redirect URIs on https, or on http at a loopback address. - **Scope**: `films` is the only scope. `offline_access` is accepted and has no further effect. - **Resource**: Every token is bound to the endpoint, `https://api.makemeamovie.app/mcp`, and is refused anywhere else, including the website. - **Tokens**: Access tokens last an hour. Refresh tokens rotate on every use and lapse after 30 idle days; presenting a used refresh token again revokes the connection. - **Revoking**: Revoke any connection on your profile under [Connected apps](https://makemeamovie.app/profile/connections), or through `https://api.makemeamovie.app/oauth/revoke`. Changing your password revokes every connection. A film the app is making stops before its next scene: what is already generating finishes and is kept, and the film waits, paused, to be resumed in the studio. ## The film flow 1. `get_account` — the balance, the options on offer, how much of the account's daily limit for AI apps is left today, and which account is connected. 2. `create_project` with a title and a brief — a draft. Nothing is generated or charged. 3. `quote_film` — the estimate, `approve_credits` (the figure to ask for, with room for spoken lines that run long), the time, and every reason it would refuse. Show the user both and get their approval of `approve_credits` in the chat. 4. `start_film` with `approved_credits` set to the approved figure; the `approved_credits` in its answer is the ceiling the run charges against. The run is charged at actual, scene by scene, and never past the approval: if the next charge would pass it, the film pauses and `get_film_status` says why. Never call it again while the phase is `running`. 5. `get_film_status` with `wait_seconds` up to 45, called again as soon as it answers: the server does the waiting, so there is no need to sleep between calls. `poll_after_seconds` says how long to wait between calls made without `wait_seconds` — about 20 s while a film is being made. When `poll_after_seconds` is null the film has settled: read `phase` and `next_action`. 6. `get_film` when the phase is `done` — the mp4, the manifest and the provenance summary. 7. `share_film` only when the user asks for a public link, with `confirm_public=true` after telling them the link is permanent. `phase` is one of `not_started`, `idle`, `running`, `paused`, `failed` or `done`. A film takes about 8 to 20 minutes. What `next_action` asks for: - `wait`: The film is being made; call `get_film_status` again with `wait_seconds`. - `get_film`: There is a finished cut to collect — either the film is done, or a stage failed and an earlier cut is ready anyway. - `start_film`: Act on it only when `poll_after_seconds` is null. A paused film says why in `pause_reason`: `approval_used` (its approval is used up; `approval` gives `approved_credits`, `charged_credits`, `remaining_credits`, and `rest_credits`, the rest of the film at today's estimate), `disconnected` (the app that started it was disconnected) or `user` (the account owner paused it). Quote, ask the user, then `start_film`; nothing already paid for is regenerated. - `fix_then_start_film`: A stage failed and there is no finished cut. Read the error, fix the storyboard or settings, quote, ask, then resume. - `none`: The balance cannot cover the rest and there is no finished cut. Tell the user the shortfall and stop. For control stage by stage: `write_storyboard`, `edit_storyboard`, `add_character`, `update_character_voice`, `generate_stage` for one stage on one scene or all of them, `cancel_job`, `stop_film` and `update_project_settings`. Each charging tool states its price in any refusal. ## Tools All 18, in the order `tools/list` returns them. Read-only tools change nothing. Tools that charge credits need `approved_credits`. Destructive tools replace, discard or publish something that cannot be taken back. ### get_account Account, balance and options (read-only). The connected account's email and balance, prices per stage and each clip model's price per second, the lengths, aspects, models on offer, the voice models with their voices, the features this server has, and how much of the account's daily limit for AI apps is left today. Parameters: - none ### list_projects List film projects (read-only). The account's projects, newest first, with each one's run state, whether it has a share link, and whether it is a read-only showcase. Parameters: - `limit` (integer, 1 to 50, optional): Defaults to 20. ### get_project Read a film project (read-only). Everything about one project: brief, settings, the full storyboard, the cast, each scene's stage status and clip price, the run state and the finished film. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. ### get_film_status Film status and progress (read-only). Where a film is: phase, next stage, scenes done, active jobs, credits charged and refunded so far, why a paused film paused and what its approval has left, and what to do next. With `wait_seconds` it blocks until something changes. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. - `wait_seconds` (integer, 0 to 45, optional): 0 answers at once. ### quote_film Quote a film (read-only). What `start_film` would cost and take from here, the figure to ask the user to approve (`approve_credits`), the balance, what is left of today's daily limit for AI apps, and every reason it would refuse. The cost is an estimate. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. ### get_film Get the finished film (read-only). The finished cut: mp4 and manifest URLs, duration, the provenance summary and the share link if there is one. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. ### verify_film Verify a film's provenance (read-only). Verify a film manifest and every source it was cut from, by manifest URL, project id or share id. Parameters: - `manifest_url` (string, optional): Pass exactly one of these three. - `project_id` (string, optional): From `create_project` or `list_projects`. - `share_id` (string, optional) ### create_project Create a film project. A new draft from a title and a brief. Nothing is generated or charged; returns the project and its quote. Parameters: - `title` (string, up to 80 characters, required) - `brief` (string, up to 2,000 characters, required): The story the film is made from. - `target_sec` (integer: 15, 30, 60, 90 or 120, optional) - `aspect` (string: 16:9, 9:16 or 1:1, optional) - `speech_mode` (string: narration or dialogue, optional) - `script_model` (string, optional): `auto` or a name from `get_account`. - `keyframe_model` (string, optional): `auto` or a name from `get_account`. - `clip_model` (string, optional): `auto` or a name from `get_account`. - `voice_model` (string: gpt-4o-mini-tts, cosyvoice-v3-plus or cosyvoice-v3-flash, optional): Which TTS model speaks the whole film; gpt-4o-mini-tts when never chosen. Locks with the other models; changing it re-casts the characters and narrator. - `narrator_voice` (string, optional): A voice from `get_account`'s `voice_models`, for the project's voice model. ### update_project_settings Change a project's settings. Change the brief, length, aspect, speech mode, models, voice model, narrator voice or who speaks on-screen lines. Length and aspect lock once a storyboard exists, models and the voice model once anything is generated. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. - `brief` (string, up to 2,000 characters, optional): Replaces the project's stored brief. - `target_sec` (integer: 15, 30, 60, 90 or 120, optional) - `aspect` (string: 16:9, 9:16 or 1:1, optional) - `speech_mode` (string: narration or dialogue, optional) - `script_model` (string, optional): `auto` or a name from `get_account`. - `keyframe_model` (string, optional): `auto` or a name from `get_account`. - `clip_model` (string, optional): `auto` or a name from `get_account`. - `voice_model` (string: gpt-4o-mini-tts, cosyvoice-v3-plus or cosyvoice-v3-flash, optional): Which TTS model speaks the whole film; gpt-4o-mini-tts when never chosen. Locks with the other models; changing it re-casts the characters and narrator. - `narrator_voice` (string, optional): A voice from `get_account`'s `voice_models`, for the project's voice model. - `voice_source` (string: model or cast, optional) ### write_storyboard Write the storyboard (charges credits, destructive). Have the script model write the storyboard from the brief. The model is asked to write the title, the captions and the spoken lines in the brief's own language, and to keep the prompts behind the pictures and the music in English. An existing storyboard comes back unchanged and free unless `replace_existing` is true. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. - `approved_credits` (integer, required): What the user approved; must cover the price computed now. For `start_film`, the film never charges past it. - `brief` (string, up to 2,000 characters, optional): Replaces the project's stored brief. - `replace_existing` (boolean, optional): Defaults to false. ### edit_storyboard Edit the storyboard (destructive). Replace the storyboard with an edited copy of the one `get_project` returns, free. The first problem is named. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. - `storyboard` (object, required): The whole storyboard, edited. ### add_character Add a cast member (charges credits). Generate a sealed reference portrait for a named character so their face stays the same in every scene. A name already in the cast comes back free. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. - `name` (string, up to 40 characters, required) - `description` (string, up to 400 characters, required): What they look like. - `approved_credits` (integer, required): What the user approved; must cover the price computed now. For `start_film`, the film never charges past it. - `voice_register` (string: low, mid or high, optional) - `voice_timbre` (string: feminine, masculine or neutral, optional) - `voice_instructions` (string, optional): How lines are delivered, up to 90 characters. ### update_character_voice Change a cast member's voice. Set which voice a character speaks in, with an optional register, timbre and delivery note, free. A voice another cast member holds is refused. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. - `character_id` (string, required): From the cast in `get_project`. - `voice` (string, required): A voice from `get_account`'s `voice_models`, for the project's voice model. - `voice_register` (string: low, mid or high, optional) - `voice_timbre` (string: feminine, masculine or neutral, optional) - `voice_instructions` (string, optional): How lines are delivered, up to 90 characters. ### start_film Start or resume the film (charges credits). Make the whole film from wherever it is, charged at actual and never past the approval; a film that would pass it pauses. Nothing already made is regenerated. Calling it while the film is running changes nothing. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. - `approved_credits` (integer, required): What the user approved; must cover the price computed now. For `start_film`, the film never charges past it. - `brief` (string, up to 2,000 characters, optional): Replaces the project's stored brief. ### stop_film Stop the film (destructive). End the run. Queued jobs are cancelled and refunded; running jobs were billed by the provider and their output is discarded. Finished stages are kept. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. ### generate_stage Generate one stage (charges credits). Run one stage by hand: keyframe, narration, dialogue or clip for one scene or all of them, or the music bed or final cut for the film. Finished scenes are regenerated and the answer says what is replaced. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. - `stage` (string: keyframe, narration, dialogue, clip, music or compose, required) - `approved_credits` (integer, required): What the user approved; must cover the price computed now. For `start_film`, the film never charges past it. - `scene_index` (integer, 0 or more, optional): One scene, counted from 0; omit for every scene. ### cancel_job Cancel a job (destructive). Cancel one queued or running stage job. A job that has not started is refunded; a running one was billed by the provider and its output is discarded. A finished or failed job is refused. Parameters: - `job_id` (string, required): From `get_film_status` or `generate_stage`. ### share_film Publish a share link (destructive). Mint the permanent public link for a finished film, or return the one it has, with its covering line. Sharing cannot be undone. Parameters: - `project_id` (string, required): From `create_project` or `list_projects`. - `confirm_public` (boolean, required): True only after the user was told the link is permanent and agreed. - `note` (string, up to 280 characters, optional): The line sent with the link. ## Credits and limits Prices, in credits: - Storyboard: 2 - Keyframe, per scene: 12 - Cast portrait: 5 - Video clip, per second: Seedance 2.5 (speaks) (doubao-seedance-2-5-260628): 32 - Video clip, per second: Seedance 2.0 (speaks) (doubao-seedance-2-0-260128): 24 - Video clip, per second: Seedance 2.0 fast (speaks) (doubao-seedance-2-0-fast-260128): 20 - Video clip, per second: Seedance 2.0 mini (speaks) (doubao-seedance-2-0-mini-260615): 20 - Video clip, per second: HappyHorse 1.1 (silent) (happyhorse-1.1-i2v): 20 - Video clip, per second: Wan 3.0 Video Prime (silent) (wan3.0-video-prime): 20 - Video clip, per second: Seedance Lite (silent) (bytedance/seedance-1-lite): 20 - Video clip, per second: Kling 2.1 (silent, films 5 s or 10 s) (kwaivgi/kling-v2.1): 20 - Narration, per scene: 2 - Dialogue, per scene: 6 - Music bed: 10 - Final-cut compose: 5 How credits are charged and refunded: - A quote is an estimate. Clips are billed per ordered second, at the clip model's price, and a scene whose line runs long is ordered longer than planned, up to 15 s per scene. A line our voice has not recorded yet is priced from its words, and its clip is charged for the length the recording needs. So `quote_film` also returns `approve_credits`: the estimate plus about a quarter of the price of each scene still priced from words, with that extra trimmed to what today's limit and the balance leave. Ask the user to approve that. A film is charged at actual, unused approval is never charged, and a film never charges past the figure approved: when the next charge would pass it, the film pauses and `get_film_status` says why. - Each clip model has its own price per second, in the table above. With `clip_model` set to `auto`, a scene goes to the default silent or speaking model, whichever it needs, at that model's price, and `get_project` gives each scene's clip price before anything is charged. A clip that falls back to another model keeps the price it was charged at. - Every charging tool takes `approved_credits`. The price is recomputed at the call; a figure short of it is refused with `[quote_changed]` and the new figure, and nothing is charged. - Spending from AI apps is limited per account per day. The account owner sets the limit on their profile under [Connected apps](https://makemeamovie.app/profile/connections), from 0, which turns it off, up to the server's maximum, currently 3,000 credits; no app can raise it, and it cannot be changed from chat. In `get_account`, `daily_limit` is the account's limit, `daily_cap` the most it can be, and `daily_cap_remaining` what is left today. Each approval holds its figure against the day it was given; when the film or call settles, what it did not spend, and any refund, goes back to that day. The limit resets at 00:00 UTC. The balance is always the hard stop. A lower limit applies to approvals given after it is saved. - A stage started from chat is refunded in full, automatically, whenever it fails: an outage, a timeout, a rejected key, a model that withholds the video it made. The one exception to refunds applies only to stages started on the website after the author accepted a photoreal-people warning there; chat never sends that acceptance. - Cancelling a job that has not started refunds it. A job that is already running was billed by the provider, so `cancel_job` and `stop_film` discard its output and refund nothing. `cancel_job` refuses a finished or failed job. - Credits are bought on the website. No tool sells them. Limits: - 120 calls per minute per account. - 60 charging calls per hour per account. - 20 `verify_film` calls per 5 minutes per account. - The charging tools are `write_storyboard`, `add_character`, `start_film` and `generate_stage`. - At most two films being made at once per account. - `get_film_status` waits at most 45 s. `write_storyboard` and `add_character` wait up to 40 s, then answer busy and keep working; `get_film_status` reports when they land. - A charging call, or `create_project`, repeated with the same arguments within 120 s returns the first answer instead of acting twice; while the first is still running it answers `[conflict]`. ## Errors Every refusal is one line that starts with a bracketed code, then the figure, then what to do. `quote_film` reports the codes that would stop `start_film` as blockers without failing. A stage that fails during a run is not a tool error: the status shows phase `failed` with the error and the refund — and the finished film beside them when an earlier cut landed. `next_action` reads `get_film` then, unless the run was cut short by a restart and can simply resume. - `[insufficient_credits]`: The balance is short of the price; the message names the shortfall. Nothing was charged, unless `generate_stage` says it stopped partway, when the submissions it names were charged. Tell the user; credits are bought on the website. - `[quote_changed]`: `approved_credits` is below the price computed now; for `start_film`, below the estimate computed now. Show the user the new figure, ask again, and call with it. - `[daily_cap_reached]`: This account's daily limit for AI apps cannot hold this, or spending from AI apps is turned off on this account. When the limit is above 0, the message names it and what is left. Tell the user; it resets at 00:00 UTC. Only they can change the limit, on their profile, never in chat. - `[rate_limited]`: Too many calls for this account. Wait the `retry_after_seconds` it names. - `[too_many_runs]`: Two films are already being made on this account. Wait for one to finish, or `stop_film`. - `[already_running]`: A quote blocker: this film is already being made. Poll `get_film_status`; do not call `start_film`. - `[not_found]`: No such project, job, character or share on this account. Other accounts' ids read the same way. Check the id with `list_projects` or `get_project`. - `[invalid_input]`: An argument is wrong; the message names it. Fix that argument and call again. - `[empty_brief]`: There is no brief to make the film from. Pass `brief` to `start_film` or `update_project_settings`. - `[no_storyboard]`: `generate_stage` needs a storyboard first. Run `write_storyboard`, or `start_film` for the whole film. - `[missing_prerequisite]`: A stage needs an earlier one: a clip needs its keyframe, the final cut needs a visual for every scene. Generate what it names first. - `[locked]`: A setting can no longer change; the message says what it is locked to. Keep it, or start a new project. - `[conflict]`: The request clashes with the current state, such as the same request still being processed, `cancel_job` on a job that has already finished, `generate_stage` on a film `start_film` is making, or a charge refused because the app was disconnected. Read the message; poll `get_film_status` rather than repeating the call. - `[not_finished]`: There is no finished cut yet. Poll `get_film_status` until the phase is `done`. - `[feature_unavailable]`: This server does not offer that feature, such as video or dialogue. Check `get_account` and choose another option. - `[read_only_project]`: A shared showcase project cannot be changed. Create a project of your own. - `[confirmation_required]`: `share_film` was called without `confirm_public=true`. Tell the user the link is permanent; pass true only if they agree. - `[upstream_failed]`: A provider failed the request. Nothing was charged, unless `generate_stage` says it stopped partway, when the submissions it names were charged. Try again later. - `[internal]`: Something failed on the server's side. Nothing more was charged than the status shows. Try again in a minute. ## Provenance Every shot and the final cut carry a manifest: the providers, models, prompts and parameters that made them, and a SHA-256 hash of each asset, sealed under one canonical hash. `verify_film` takes a manifest URL, a project id or a share id, recomputes the film's manifest and every source manifest it was cut from, and reports which verify. `verified` means the manifests are hash-consistent and carry the recorded asset digests; the media bytes are not fetched again. Anyone can check a manifest by hand on the [verify page](https://makemeamovie.app/verify).