flashstory-mcp
v0.1.2
Published
MCP server + local bridge that lets CLI agents drive the FlashStory shot editor running in your browser.
Downloads
440
Maintainers
Readme
flashstory-mcp
Let a command-line AI (Claude Code, or any MCP client) drive the FlashStory shot editor running in your browser: read the scene, block movement, pose characters, look at screenshots, and export the guide video to disk.
Everything it does goes through the editor's own reducer — the same validation path as clicking in the UI — so the six-colour cap, joint limits and keyframe ranges all still apply, and a rejected edit comes back with the reason.
Install
npm install -g flashstory-mcp
claude mcp add -s user flashstory -- npx -y flashstory-mcpDo not drop -s user. claude mcp add defaults to local scope, which files
the server under whatever directory you happened to run it in — start Claude Code
from anywhere else and FlashStory is not there, which looks exactly like the
install failed. -s user registers it once for every project on the machine.
(Disabling a server from /mcp does not delete it either — the name just goes on
a disabled list — so "it vanished" is almost always scope, not deletion.)
The global install is separate from that: it is what puts the flashstory-bridge
command on your PATH. See Daemon control for why you want it.
Then, in the FlashStory editor: 设置 → CLI / MCP 桥接 → 允许 CLI 控制 (Settings → CLI / MCP bridge → Allow CLI control). It is off by default; nothing can touch your scene until you turn it on.
That's it to get going — the bridge daemon starts by itself on the first tool call.
How it fits together
Claude Code ──stdio──► flashstory-mcp ──ws──► flashstory-bridge ◄──ws── editor tab
(per session) (one daemon, port 18787)The editor tab dials out to the daemon because an extension page cannot listen on a port. The daemon is separate from the MCP process so that CLI sessions can come and go without the editor's connection flapping — and so two terminals can work at once. It exits on its own after 10 idle minutes.
Requirements
- Node ≥ 20
- The FlashStory extension, ≥ 0.5.2, with an editor tab open
- Keep that tab visible while exporting or taking screenshots — WebGL and WebCodecs get throttled in background tabs
Daemon control
The daemon exits after ten idle minutes, so it will usually be gone when you
come back to a project. The next tool call spawns it again and the editor tab
redials on its own, but that redial backs off to once every 30 seconds — so the
first call after a long gap can land before the tab is back and fail with no
editor connected. Starting it yourself when you sit down avoids the wait;
start is idempotent.
flashstory-bridge start # idempotent; do this when you sit down
flashstory-bridge status # is it running, on which port, who is attached
flashstory-bridge stop
flashstory-bridge set-port 19001 # persist a new port, restart if running
flashstory-bridge logs --tail 40
flashstory-bridge prune-exports --keep 10
curl http://127.0.0.1:18787/health # raw self-checkWithout the global install these need npx -y -p flashstory-mcp flashstory-bridge
<cmd> every time: the command is flashstory-bridge but the package is
flashstory-mcp, so a bare npx flashstory-bridge looks up a package by that
name and 404s. That is the one thing npm install -g buys you.
Config lives in ~/.flashstory/config.json (port, outputDir,
allowedExtensionIds, logLevel); the lock file, logs and exports sit beside it.
If you change the port, change it in the editor too — the two must match. The daemon never silently moves to another port, because the browser would then be dialling nowhere.
The tools
Reading and editing the scene:
| Tool | What it does |
| --- | --- |
| get_scene | The whole scene as JSON, including the rev you pass back as expectRev |
| add_entity / remove_entity / update_entity | Characters, primitives, image boards, models |
| place_entity / set_transform_keys / upsert_transform_key | Position and orientation over time |
| set_pose_keys / list_poses / get_pose / define_pose / delete_pose | The pose library |
| get_character_joints / set_character_joints / adjust_character_joints / promote_pose | Joint angles in degrees at a given time |
| set_camera_keys / add_camera / set_camera_switches | Camera work, including multi-camera cuts |
| add_dialogue_track / add_dialogue_cue | Dialogue lanes |
| add_marker / update_marker / delete_marker | Timeline markers |
| set_settings | fps / aspect / duration / project name |
| screenshot / pose_screenshot | Look at the scene (with grid/label/path overlays) |
| undo / redo | History |
| begin_batch / commit_batch | Group several calls into one undo entry |
| list_editors / select_editor | Pick which editor tab to act on |
Exporting (submit, poll, collect):
| Tool | What it does |
| --- | --- |
| export_video | Start an export, returns an exportId right away |
| get_export_status | running / done / error, with progress |
| get_export_result | Writes the files to disk, returns absolute paths |
| cancel_export | Stop a running export |
A typical session
get_scene → what is here, and the current rev
add_entity {id:"c_red", name:"老张", kind:"character"}
set_transform_keys {id:"c_red", keys:[…]} → walk from the bar to the window
get_character_joints {id:"c_red", t:1} → read the angles first
adjust_character_joints {id:"c_red", t:1, deltas:{shoulderR:30}}
screenshot {overlays:["grid","labels"]} → check it looks right
export_video {} → {exportId}
get_export_status {exportId} → poll until done
get_export_result {exportId} → absolute paths to
guide_video.mp4, prompt_suggestion.md, …From there the mp4 and prompt_suggestion.md go to whatever renders the final
video — no manual download or upload in between.
Notes on behaviour
- Joint angles are degrees. Models are markedly worse at radians. Pass
unit: "rad"if you prefer them. - One call is one undo entry unless you wrap calls in
begin_batch/commit_batch. An abandoned batch is rolled back after two minutes, and while it is open another agent's writes are refused. - Errors are readable, not fatal. A rejected edit returns the reducer's own
wording as an
isErrorresult so you can correct and retry. expectRevis optional optimistic concurrency. Useful when two sessions share one editor.
Security
The daemon binds 127.0.0.1 only, and it refuses WebSocket handshakes whose
Origin is not a browser extension — which shuts out any web page you happen to
have open, since a page cannot forge that header. Beyond that, the editor's
toggle is the authorisation: while it is off the channel does not exist, and the
top bar shows what is attached with a log of every call. Exports are written only
under the configured outputDir, and no tool accepts a destination path.
License
UNLICENSED — proprietary, all rights reserved. Installing and running it is fine; modification and redistribution are not granted.
