opentoonz-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| OPENTOONZ_RUNTIME | No | Path to the OpenToonz runtime (e.g. the extracted AppImage's squashfs-root directory) containing the OpenToonz CLI binary and `tcomposer` headless renderer. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| logging | {} |
| prompts | {
"listChanged": true
} |
| resources | {
"subscribe": false,
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| opentoonz_healthA | Quick availability check for the runtime, tcomposer, and ffmpeg. |
| opentoonz_doctorA | Full diagnostic: resolved paths, versions, and prepared state. smoke=true also runs a trivial script through OpenToonz, which proves the runtime actually executes — not merely that the binaries exist. That launches OpenToonz, so it costs a few seconds and is off by default. |
| opentoonz_create_workspaceA | Create a self-contained workspace folder (idempotent). A workspace holds drawings/, render/, and scripts/. The shared OpenToonz 'stuff' tree is not copied per workspace (it lives once in the data home). |
| opentoonz_list_workspacesB | List workspaces with their scenes and rendered videos. |
| opentoonz_cleanA | Delete a workspace's generated files to reclaim disk space. what selects drawings, render, scripts, orphans (drawings no scene references), or all (the default). Only the contents are removed — the workspace itself is kept, so it can be reused. This is irreversible. When the client supports it, the user is asked to confirm through an elicitation prompt; otherwise pass confirm=true explicitly (which is also how automation and tests proceed). |
| opentoonz_delete_workspaceA | Delete a whole workspace, including its scenes and renders. This is the blunt instrument: opentoonz_clean empties a workspace but keeps it usable, while this removes it entirely. Irreversible: when the client supports it, the user is asked to confirm through an elicitation prompt; otherwise pass confirm=true explicitly. |
| opentoonz_scene_newB | Create (or overwrite) an empty scene, optionally setting its resolution. The default camera is 1920x1080. Levels composite 1:1 and centred, so draw your art at the scene's size for full-frame output. |
| opentoonz_set_scene_settingsA | Change a scene's camera resolution and/or frame rate (e.g. 1080p -> 720p). OpenToonz's scripting API has no setters for these, so the scene file's XML
is patched directly; later edits to the scene keep the new settings. |
| opentoonz_import_images_as_levelA | Import an ordered image sequence as a raster level and place it on the xsheet. Additive: an existing scene is loaded first, so you can call this repeatedly with different level_name/column to build a multi-level scene. Images are converted to RGBA PNG named <level_name>.%04d.png, and levels composite 1:1 and centred — draw at the scene's size (1920x1080 by default) for full-frame output. Re-importing the same level_name reuses that level and overwrites its drawings, so you can iterate on art without the level being duplicated. |
| opentoonz_extract_framesA | Extract a video's frames into drawings/<level_name>.%04d.png, as a level. How outside footage joins a scene: extract, then pass the returned paths to opentoonz_import_images_as_level. fps resamples (default keeps the source rate), start/end are seconds, and max_width downscales so a large source does not fill the workspace. max_frames caps the extraction (default 5000) so a long clip cannot fill the disk; raise it, or use start/end/fps, for more. Previous drawings for the same level are cleared first, so a shorter extract cannot leave orphaned frames. |
| opentoonz_scene_infoB | Report a scene's frame/column counts, its levels, and its cell map. The cell map is scanned row by row and stops at max_rows (default 1000); the output says so explicitly when a scene is taller than that. |
| opentoonz_set_cellsA | Place/replace cells on a scene's xsheet. placements: list of {"row": int, "col": int, "level": str, "fid": int|str}. Levels must already exist in the scene (see opentoonz_import_images_as_level). For the common animation task of holding each drawing for N frames, use opentoonz_exposure instead of computing rows yourself. |
| opentoonz_exposureA | Time a level's drawings on the xsheet by holding each one for N frames. exposures is either a single hold for every drawing ([3] = hold all on 3s) or one hold per drawing in order ([2, 4, 1]). Rows are contiguous, and the scene's frame count follows what is placed. The level must already be in the scene (see opentoonz_import_images_as_level). |
| opentoonz_camera_moveA | Move the scene's camera over the shot — pan, zoom, and rotate. keyframes: list of {"frame": int, "x": px, "y": px, "zoom": factor, "rotation": degrees, "ease": bool}. Only "frame" is required; the rest default to no movement (x=0, y=0, zoom=1, rotation=0, ease=false). "frame" is a 1-based shot frame — the same numbering as opentoonz_render_frame. x/y are the camera's position in scene pixels: +x pans the view right and +y pans it up, so the artwork moves the opposite way. zoom is a magnification (2 renders the art twice as large), and rotation is in degrees, clockwise on screen, about the frame centre. ease=true makes the camera glide out of that keyframe and into the next instead of moving at a constant speed — it eases the segment starting there, symmetrically, across every channel. Each segment eases on its own, so a run of eased keyframes settles at each pose; ease only the segments you want softened. The flag on the last keyframe does nothing, so adding ease=true to every keyframe eases the whole move. The move is stored in the scene file as the camera's animation channels, so it survives later edits and stays editable in OpenToonz's Function Editor. Re-render to see it. |
| opentoonz_draw_frameA | Draw one RGBA frame with PIL primitives and save it as a level drawing. ops: list of {"op": "rect|ellipse|line|polygon|polyline|text|image", ...} — see docs/tools.md. The "image" op composites an existing PNG, so art made elsewhere can join a drawn frame. Saved to /drawings/<level_name>..png, ready for opentoonz_import_images_as_level. |
| opentoonz_draw_framesA | Draw a whole sequence of frames, one op-list per frame. frames: list where each item is a list of ops for that frame (frame 1 first). Saves /drawings/<level_name>.%04d.png and returns the paths. |
| opentoonz_tween_framesA | Tween one drawing from a start pose to an end pose, saving the sequence. OpenToonz's auto-inbetweening is GUI-only, so the in-betweens are rendered here and saved as /drawings/<level_name>.%04d.png, ready for opentoonz_import_images_as_level. start/end each describe the drawing: {"path": "/abs/sprite.png", "xy": [x, y], "scale": 1.0, "rotation": 0, "opacity": 1.0}. xy is the drawing's CENTRE, so motion and rotation share one anchor; omitted fields stay neutral. ease=true leaves and arrives gently instead of at a constant speed. |
| opentoonz_render_frameA | Render a single frame to a PNG — the agent's 'look' at the result. The image is returned inline as well as on disk, so looking at a frame costs no extra round-trip. It is downscaled to 768px wide by default, so a large scene costs far fewer image tokens; pass max_width to change that, or max_width=0 for the full-resolution frame. Only the returned preview is affected — the scene's resolution is unchanged, and opentoonz_render / opentoonz_render_video output is never downscaled. |
| opentoonz_renderA | Render a scene to PNG frames under /render/ with tcomposer. By default the whole scene renders. Give start and end together to render an inclusive frame range instead — e.g. start=1, end=3 for frames 1-3 — which is much cheaper when you only need a section. |
| opentoonz_render_videoB | Render a scene and mux the frames into an MP4 with ffmpeg. audio (optional) is a path to an external soundtrack (mp3, wav, ...). It is encoded as AAC and cut to the video's length. OpenToonz's own audio columns cannot be reached from the scripting API, so audio always comes from a file. crf (0-51, lower is better) trades quality for file size, and scale (a positive factor, e.g. 0.5) resizes the video. |
| opentoonz_render_gifA | Render a scene to a looping GIF — the shareable form of a short move. fps sets playback speed (12–15 reads well for hand-drawn work), max_width downscales the GIF, and colors caps the palette (2–256). Frames come from the same tcomposer pass as opentoonz_render_video; use that for anything with audio or that must stay full resolution. |
| opentoonz_render_batchA | Render several scenes in one call, reporting each scene's own result. scenes defaults to every scene in the workspace. kind is frames, video or gif; fps applies to video/gif, start/end (frames only) limit an inclusive range, and crf/scale (video only) control the encode. Each output is named after its scene, so one batch produces one deliverable per scene. One scene failing does not stop the rest: every outcome is reported, so a long batch is never lost to a single bad scene. The reply lists each scene as OK or FAILED, and the structured payload carries the same per-scene detail. |
| opentoonz_run_scriptA | Run arbitrary OpenToonz JavaScript headlessly (the full-power escape hatch). The script can use the OpenToonz API: new Scene(path?), scene.newLevel(type, name), scene.loadLevel(name, "path/..png"), scene.setCell(row, col, level, fid), scene.getCell(row, col), scene.getLevels(), scene.save(path), new Image(path), image.save(path), level.setFrame(fid, image). Use print() for output; stdout is returned. Do NOT use new Renderer() — renderFrame deadlocks in CLI mode; use opentoonz_render instead. Use absolute paths. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| workspaces_resource | Every workspace with its scenes, videos and size, as JSON. |
TDQS
Scored across 23 tools
Each tool targets a distinct resource or operation: workspace management, scene creation/settings, drawing/import, xsheet timing, camera movemen, rendering, diagnostics, and scripting are all clearly separated. Overlaps like clean vs. delete_workspace and render vs. render_frame are explicitly contrasted in their descriptions, so an agent can tell them apart.
All tools share the opentoonz_ prefix and use snake_case consistently. The verbs and nouns are predictable (e.g., create/list/delete workspace, draw/render/tween frame), with only minor stylistic variation like scene_info or exposure that remains readable and consistent.
23 tools is on the high side but each maps to a distinct operation in a complex animation domain. The five render tools differ by output format or batching, and the surface does not feel bloated with redundant tools, though a few could theoretically be consolidated.
The set covers workspace lifecycle, scene creation/configuration, drawing/import/extraction, xsheet timing, camera moves, multiple render outputs, diagnostics, and a full scripting escape hatch. Minor gaps exist such as direct scene deletion or level deletion, but run_script and clean provide workarounds.