The MCP server
Run Compose as an MCP tool server so an AI agent can build a course start to finish — and take a real screenshot to check what it made.
Compose can run as an MCP server instead of opening a window, which lets an AI agent author a course the same way a person does.
MauvelyCompose --mcp
Register that command with any MCP client as a stdio server. No arguments, no configuration.
Setting it up
- 1Find the binary
Wherever Compose is installed. On Linux that is inside the AppImage; on Windows, next to the installed
MauvelyCompose.exe. - 2Add it to your client's config
{ "mcpServers": { "mauvely-compose": { "command": "/path/to/MauvelyCompose", "args": ["--mcp"] } } } - 3Check the tools loaded
Your client should report 25 tools. If it reports none, run the command by hand — anything it prints to stderr is the reason.
What an agent can do
| Group | Tools |
|---|---|
| Project | new_course · open_course · save_course · get_course · set_course |
| Design | set_theme · list_fonts |
| Lessons | list_lessons · add_lesson · rename_lesson · remove_lesson · move_lesson |
| Blocks | list_block_kinds · list_blocks · add_block · get_block · update_block · remove_block · move_block · duplicate_block |
| Landing page | set_overview · set_resources |
| Media | add_asset |
| Output | export_course · preview_course |
Every block type is reachable, including quizzes, flashcards, branching scenarios and custom code.
Writing a good prompt
Two things trip agents up, both worth saying explicitly in your instructions.
A new course is not empty
new_course gives you one lesson that already contains a Welcome block — the same thing you
get opening the app, so a person has something to edit rather than a blank page.
If you want exact control over what the course contains, tell the agent to pass empty: true,
or ask it to remove the Welcome block. Otherwise “make a course with one block” produces two.
Newlines must be real newlines
Text fields take actual line breaks. An agent that sends the two characters \ and n gets
them rendered literally in the finished course, which looks like \n\n sitting in the middle
of a paragraph.
Smaller models get this wrong fairly often. If you see it, the fix is in the prompt rather than the course.
Point it at list_block_kinds first
Blocks carry every type’s fields at once, so setting the wrong ones is not an error — it just produces an empty block.
list_block_kinds returns each type’s field list, and an agent that reads it first makes far fewer silent mistakes.
Checking the result
preview_course renders the real exported course and returns a PNG. This matters: it is the
same runtime a learner gets, not a sketch of it, so an agent looking at the picture is looking at
what you would actually ship.
preview_course { "width": 1200, "height": 900, "path": "/tmp/check.png" }
Ask the agent to call it after building something and describe what it sees. It catches empty blocks, broken media and theme choices that read badly far faster than reading the JSON does.
On a server
Rendering needs a graphics backend. On a headless machine, run the whole thing under a virtual framebuffer:
xvfb-run -a --server-args="-screen 0 1400x1000x24" MauvelyCompose --mcp
Without one, every other tool still works — only preview_course returns an error, and it says
why.
A worked prompt
Using Mauvely Compose, make a course called “Onboarding” with exactly two lessons. Call
new_coursewithempty: trueso there is no starter content. Readlist_block_kindsbefore adding anything. Lesson one gets a rich text introduction and a multiple-choice question with three answers; lesson two gets a flashcard set. Use real newlines in any text. Then callpreview_courseand tell me whether it looks right before saving to~/onboarding.course.
Limits
Worth knowing
- The server holds one course at a time.
new_courseandopen_coursediscard what is in memory. - There is no undo across tool calls — an agent that removes the wrong block has to add it back. - Media has to exist on disk foradd_asset; the agent cannot generate an image. - Nothing here talks to Mauvely Cloud. Courses are saved and exported locally.