Miraiclip SDK
AI

MCP server

Let Claude, Codex or any MCP client edit video.

@miraiclip/mcp serves one project file over MCP (stdio). An agent can read the project, apply commands, undo, look at rendered frames, and export. Every successful edit is saved to the file.

npx @miraiclip/mcp --project ./video.json --assets ./media

The project file is created if it doesn't exist. Previews and exports run in headless Chrome through @miraiclip/server-export.

Flags

FlagDefaultWhat it does
--project <path>miraiclip-project.jsonThe project JSON file. Created if missing
--assets <dir>the project file's folderBase folder for relative asset src paths
--width <px>1920Composition width, for a new project file only
--height <px>1080Composition height, for a new project file only
--fps <n>30Frame rate, for a new project file only
--browser <path>MIRAICLIP_BROWSER, then installed ChromeChrome or Chromium binary for previews and exports
--helpPrint the flags to stderr and exit

MP4 export needs Google Chrome. WebM works with any Chromium. See The browser.

Connect a client

Claude Desktop

Add the server to claude_desktop_config.json, then restart Claude Desktop. Use absolute paths.

{
  "mcpServers": {
    "miraiclip": {
      "command": "npx",
      "args": ["-y", "@miraiclip/mcp", "--project", "/path/to/video.json", "--assets", "/path/to/media"]
    }
  }
}

Claude Code

claude mcp add miraiclip -- npx -y @miraiclip/mcp --project ./video.json --assets ./media

Everything after -- is the server command.

Other clients

Any client that launches stdio MCP servers works the same way: command npx, arguments -y @miraiclip/mcp --project …. For example, Codex (~/.codex/config.toml):

[mcp_servers.miraiclip]
command = "npx"
args = ["-y", "@miraiclip/mcp", "--project", "/path/to/video.json"]

Tools

ToolInputWhat it does
get_stateinclude_json?The describeProject summary: settings, assets, tracks, clips, transitions
list_commandsnoneEvery command type with a one-line description
get_command_schematypeOne command's payload JSON Schema
dispatchtype, payloadApply one command
apply_commandscommands, label?Apply a batch as one transaction and one undo step
undo / redononeStep the history. Returns the new summary
preview_frametimeUs, width?, height?Render a frame and return it as a PNG image the model can see
exportout, format, quality?, fps?, width?, height?, rangeStartUs?, rangeEndUs?Encode to a file
get_project_jsonnoneThe full project document

All times are integer microseconds. The tool descriptions tell the model so.

Errors

A failed dispatch or apply_commands changes nothing and returns isError: true. dispatch returns the failure from tryDispatch:

{
  "kind": "rejected",
  "commandType": "clip/move",
  "code": "clip-not-found",
  "message": "Command \"clip/move\" rejected (clip-not-found): no clip \"nope\""
}

apply_commands returns the applyCommands result, { ok: false, applied: 0, failedIndex, error }, so the model knows which command to fix.

Previews

preview_frame renders through the export pipeline, so the frame matches the exported file. Without width and height, the longest side is capped at 768 px. The first call starts headless Chrome; later calls reuse it.

Export

InputDefaultNotes
outrequiredRelative paths are resolved against the project file's folder
formatrequired"mp4" or "webm"
quality"standard""draft", "standard" or "high"
fps, width, heightproject settings
rangeStartUs, rangeEndUswhole compositionGive both, or the range is ignored

The file streams to disk. The tool returns { ok, filePath, bytesWritten }.

A typical session

  1. get_state: read the composition and its ids.
  2. apply_commands: make the edit as one batch, for example asset/add, track/add, clip/add.
  3. preview_frame at the moments that matter, to check the result.
  4. undo if it's wrong, or export when it's right.

Notes

TopicDetail
SavingEach successful edit writes the project file (via a temporary file and rename)
Undo historyKept in memory while the server runs. Restarting the server clears it; the file stays
Asset pathsRelative src values resolve against --assets. Use absolute paths or http(s): URLs otherwise
Custom clip kindsNot rendered: previews and exports support built-in kinds only

Embed it

The package exports the pieces for your own server. To run it over MCP yourself, also install @modelcontextprotocol/sdk.

import { ProjectSession, callTool, createMcpServer, listTools } from "@miraiclip/mcp";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const session = await ProjectSession.open({ projectPath: "./video.json", assetsDir: "./media" });

// As an MCP server
const server = createMcpServer(session);
await server.connect(new StdioServerTransport());

// Or call the tools directly
listTools(session).map((tool) => tool.name);
const result = await callTool(session, "get_state", {});
ExportWhat it does
ProjectSession.open({ projectPath, assetsDir?, defaults?, browser? })Loads or creates the project file. session.project is a normal Project
session.preview({ timeUs, width?, height? })A PNG as Uint8Array
session.export(options)Same options as the export tool, with range: { startUs, endUs }
session.close()Closes the browser
createMcpServer(session, version?)An MCP Server with the tools registered
listTools(session) / callTool(session, name, args)The tool list and dispatcher without MCP

On this page