An AI comic generator delivered as an A2MCP Agent Service Provider on OKX.AI. A requesting agent sends a prompt, genre, page count, and style — BoredComic writes the story, draws every panel, letters the speech balloons and sound effects, builds a cover, and returns a complete PDF + CBZ plus decision-grade metadata the agent can evaluate without ever looking at the comic.
Beyond one-shot generation, BoredComic is stateful: register characters once and reuse them across comics with a consistent design (create_character), run ongoing series where each episode continues from the previous ending (create_series), and revise a single page of a delivered comic without regenerating the rest (revise_page). Every delivery ships with SHA-256 integrity hashes, a signed receipt, and an explicit commercial-use license.
| Type | A2MCP — pay-per-call via x402 |
| Agent ID | #6006 |
| Endpoint | https://boredcomic.web.id/mcp |
| Transport | MCP Streamable HTTP (POST /mcp) |
| Price | Tiered by page count (see Pricing) · no free calls |
Everything below was produced by a single generate_comic call:
prompt: "a young inventor and her clumsy robot race to deliver a package across a bright futuristic city" ·genre: action ·pages: 2 ·style: manga
Notice what the renderer adds on top of the AI art: a cream narration caption ("In a city that never stops moving…"), black ink panel frames, shout balloons ("COME ON, BOB! WE CAN'T BE LATE!"), and sound-effect word art ("VROOM", "WHOOPS!") — all lettered in real comic fonts.
The tool returns structured JSON. This is the delivery payload for the comic above, trimmed — see examples/example-delivery.json for the full shape (the PNG hashes there are real and verifiable against the example images):
The summary, characters, perPage, and evidence fields let a calling agent judge the result programmatically — panel counts, story beats, generation time, and cost — without rendering the images.
An autonomous agent working with creative requests constantly hits things it cannot do itself: a user wants a comic, but the agent cannot draw, cannot lay out panels, cannot keep characters consistent across pages. BoredComic is the primitive that answers:
"I have a story idea — make it into a comic I can share."
It returns structured data the agent can compose — not a web app it has to navigate. Pay-per-call via x402. And because the service is stateful, an agent can build on past calls instead of starting over: a registered cast, a running series, a paid revision of one page instead of a full regeneration.
Generates a complete comic from a natural-language prompt.
| Input | Type | Description |
|---|---|---|
prompt |
string | What the comic is about (min 3 chars) — required |
pages |
integer | Number of pages, 1–10 — required |
genre |
enum | horror · romance · action · comedy · manga · fantasy · sci-fi · slice-of-life |
style |
enum | manga · western · semi-realistic · chibi (default: manga) |
aspectRatio |
enum | 3:4 · 9:16 · 1:1 (default: 3:4; ignored in webtoon mode) |
language |
string | BCP-47 dialogue language, e.g. en, id, ja, zh (default: en) |
colorMode |
enum | color · bw (default: color) |
layoutMode |
enum | page · webtoon (default: page) — webtoon renders full-width panels stacked vertically plus a single tall strip.png |
characterIds |
string[] | Registered characters (from create_character) that must star in the comic |
seriesId |
string | Series (from create_series) — the story continues from the previous episode's ending |
Returns the delivery payload shown above, extended with per-panel images + alt text (perPage[].panelDetails), cbzUrl, stripUrl (webtoon), integrity (SHA-256 of every file), receipt (signed proof of delivery), and license (commercial-use grant + provenance).
Register a character once, reuse it forever. Stores a canonical appearance description and a stable generation seed, and renders a reference character sheet. Comics generated with this character reuse both, so its design stays consistent across every comic and series episode. Inputs: name, appearance (detailed visual description, min 20 chars), optional role, style.
create_series starts a series container with optional defaults (genre, style, language, colorMode) and a fixed cast of registered characterIds. Every generate_comic call carrying the seriesId becomes the next episode: the writer receives each previous episode's title and ending summary as context and continues the story. get_series returns the episode history.
Revise one page of a delivered comic without regenerating the rest: { jobId, page, instruction } — e.g. "make panel 2 a dramatic close-up" or "rewrite the dialogue to be funnier". The page spec is rewritten by the LLM, re-rendered with the job's original seed and cast, and the PDF/CBZ are rebuilt when the other pages are still on disk. Jobs stay revisable for 7 days (JOB_TTL_MS).
Re-fetch the full delivery payload of a previously generated comic by jobId — the recovery path when a paid generate_comic response was lost to a connection drop or timeout. You paid once; the result stays fetchable for 7 days. The payload reports filesAvailable since comic files expire from disk on a shorter TTL (24h) than the metadata.
Look up a registered character: canonical appearance, style, seed, reference sheet URL.
Given a partial or vague request, returns structured clarification questions (missing fields, genre/style options, defaults). Use it before generate_comic when the user's request is incomplete. Always free.
Returns current per-tool x402 pricing, payment address, and whether the gate is enabled. Always free.
Every delivery carries three trust artifacts:
integrity— SHA-256 of every delivered file (cover, pages, panels, PDF, CBZ, strip). The payer can verify the bytes they downloaded are the bytes they paid for.receipt—payloadSha256over the job's file hashes plus an HMAC-SHA256 signature (whenRECEIPT_SECRETis configured): portable proof of what was delivered for which job.license— explicit commercial-use grant, attribution status, AI disclosure, and provenance (image model, seed, prompt hash) so a commercial agent knows exactly what it may do with the output before publishing.
Agent → POST /mcp (MCP Streamable HTTP)
│
┌────▼────┐ x402 gate: discovery, clarify_comic, get_quota, get_character,
│ x402.ts │ create_series, get_series are free. generate_comic is priced by
└────┬────┘ page count; revise_page + create_character cost the base rate.
│ Deterministic failures are rejected before payment.
┌────▼─────────┐
│ pipeline.ts │ one-shot orchestrator
└────┬─────────┘
┌─────────┼───────────────────────┐
▼ ▼ ▼
writer.ts illustrator.ts assembler.ts
(LLM → (Cloudflare Workers (pdf-lib →
storyboard) AI → panel images) combined PDF)
│
▼
pipeline.ts assembly (sharp): panel frames · smart crop ·
speech/shout/thought balloons · SFX word art · narration
caption · cover · B&W grayscale
- Writer (
writer.ts) — Sumopod LLM turns the prompt into a storyboard: title, synopsis, characters (with detailed visual appearance), and per-page panel descriptions including dialogue,dialogueType,sfx, and camera angle. Dialogue is generated in the requested language. - Illustrator (
illustrator.ts) — each panel is rendered by Cloudflare Workers AI (@cf/black-forest-labs/flux-1-schnell, free tier). A shared per-job seed keeps panels visually coherent. Requests time out after 60s and fall back across multiple Cloudflare accounts on quota exhaustion. - Assembly (
pipeline.ts) — sharp composites each page: a layout template chosen per page (the final page favours a hero/splash panel), attention-based smart cropping, panel frames, balloons whose shape varies by type, SFX word art, and a narration caption box. B&W mode applies a grayscale pass. - Cover — a hero key-art image with the title, genre badge, and synopsis, prepended to the pages and the PDF.
- PDF (
assembler.ts) — every page PNG is embedded into a single PDF via pdf-lib.
- Panel frames — black ink borders around every panel.
- Smart crop — sharp
attentionstrategy keeps faces and action in frame. - Balloon variety — rounded speech, jagged shout balloons (auto-applied to exclamations), and puffy thought clouds.
- Sound effects — the writer emits onomatopoeia on action panels, rendered as angled, outlined word art.
- Real comic lettering — bundled OFL fonts (Bangers for display/SFX, Comic Neue for balloons) are converted to vector outlines with
opentype.js, because sharp's bundled librsvg ignores system fonts. - Dynamic layouts — layout templates for 1–4 panels, varied per page, with a climax splash on the last page.
Charged per tool call via x402 v2 on X Layer (USDT0). No free quota. generate_comic scales with page count; single-generation tools cost the base rate:
| Tool | Multiplier | Price (at 0.5 base) |
|---|---|---|
generate_comic 1–3 pages |
1× | 0.50 USDT |
generate_comic 4–6 pages |
2× | 1.00 USDT |
generate_comic 7–10 pages |
3× | 1.50 USDT |
revise_page |
1× | 0.50 USDT |
create_character |
1× | 0.50 USDT |
The base price is set by X402_PRICE_USD; multipliers are applied automatically. Discovery calls (initialize, tools/list), clarify_comic, get_quota, get_job, get_character, create_series, and get_series are always free. Deterministic failures (bad input, unknown characterIds/jobId, missing image provider) are rejected before payment.
Abuse guards: /mcp is rate-limited to 120 requests/minute per IP, create_series (free but disk-writing) to 20/hour per IP, and the persistent store caps each collection at 5000 records.
Our own cost per generation is roughly $0.01 (LLM storyboard ~$0.005 + free-tier image generation + assembly), so the fee reflects real cost with margin.
cd backend
npm install
cp .env.example .env # fill in the keys below
npm run dev # starts on PORT (default 3001)Point an MCP client at http://localhost:3001/mcp. With X402_MODE=off (the default) the payment gate is disabled, so generate_comic runs without payment — useful for local testing.
| Variable | Purpose |
|---|---|
SUMOPOD_API_KEY |
LLM API key (Sumopod) — required |
SUMOPOD_BASE_URL / SUMOPOD_MODEL |
LLM endpoint and model (default deepseek-v4-flash) |
CLOUDFLARE_ACCOUNT_ID / CLOUDFLARE_API_TOKEN |
Cloudflare Workers AI for image generation — required |
CLOUDFLARE_ACCOUNT_ID_2 / _3 … up to _8 |
Optional extra accounts for quota fallback |
FLUX_STEPS |
Diffusion steps per panel (default 8) |
XLAYER_API_KEY / XLAYER_SECRET_KEY / XLAYER_PASSPHRASE |
OKX facilitator credentials for x402 settlement |
X402_MODE |
off · demo · on (default off) |
X402_PAY_TO |
Payment recipient address (required when the gate is enabled) |
X402_PRICE_USD |
Base price; multiplied by the page tier |
COMIC_DIR / COMIC_TTL_MS |
Output directory and cleanup TTL (default 24h) |
DATA_DIR |
Persistent store for characters, series, and revisable jobs (default ./data) |
JOB_TTL_MS |
How long a job stays revisable via revise_page (default 7 days) |
RECEIPT_SECRET |
HMAC key for signed delivery receipts (unset → receipts unsigned) |
PORT / NODE_ENV |
Server port and environment |
npm run dev # dev server with reload (tsx watch)
npm run build # compile TypeScript to dist/
npm start # run compiled server
npm test # run the test suite (node:test)
npm run typecheck # tsc --noEmitbored-comic/
├── README.md
├── examples/ # sample cover, pages, and delivery JSON (this README)
└── backend/
├── assets/fonts/ # bundled OFL comic fonts (Bangers, Comic Neue)
└── src/
├── index.ts # Express + MCP + x402 + static files
├── config.ts # env configuration
├── types.ts # types, layout templates, pickLayout()
├── mcp.ts # MCP server: all 9 tools
├── x402.ts # x402 payment gate + per-tool pricing + preflight
├── pipeline.ts # orchestrator, page/webtoon assembly, revise_page
├── writer.ts # LLM → storyboard, series context, page revision
├── illustrator.ts # Cloudflare Workers AI → panel images
├── assembler.ts # pdf-lib → combined PDF
├── cbz.ts # dependency-free CBZ (zip) writer
├── character.ts # character registration + reference sheets
├── store.ts # persistent store: characters, series, jobs
├── receipt.ts # integrity hashes, signed receipts, license
├── fonts.ts # opentype.js glyph-path lettering
├── storage.ts # temp file serving + TTL cleanup
└── *.test.ts # tests
- Evidence travels with every comic — model, panel count, generation time, cost, and a caveat.
- Counts are real — reported pages and panels reflect what was actually generated, not what the LLM claimed.
- No fabricated characters — every character in the output is explicitly defined in the storyboard.
- The fee matches reality — pricing reflects actual LLM + image-generation cost.
- Character consistency is heuristic. Faces can drift between panels. The image model (
flux-1-schnell) has no reference-image conditioning, so consistency relies on prompt detail and seeds. Registered characters (create_character) narrow the drift — canonical appearance text plus a stable per-character seed reused across jobs — but do not eliminate it. Fully solving this requires a model with reference-image conditioning. - Image quality is capped by
flux-1-schnell(a fast, free-tier turbo model). A higher-fidelity model would improve raw art at the cost of leaving the free tier. - Safety filter — Cloudflare blocks NSFW prompts; some innocuous words ("haunted", "magical") can occasionally trip it. There is no 18+ support.
Bundled fonts are used under the SIL Open Font License; see backend/assets/fonts/OFL-Bangers.txt and OFL-ComicNeue.txt.


{ "jobId": "cg_example", "summary": "2-page action manga 'Package Dash': 8 panels, 3 characters. Generated in 41s. Language: en. Color mode: color.", "title": "Package Dash", "pages": 2, "totalPanels": 8, "style": "manga", "genre": "action", "language": "en", "colorMode": "color", "characters": [ { "name": "Mia", "role": "Young inventor", "appearance": "16 years old, short messy pink hair, goggles on forehead, blue jumpsuit with patches..." }, { "name": "Bob (B-0B)", "role": "Clumsy robot", "appearance": "Tall, boxy body with mismatched parts, oversized blue eyes, one wheel instead of a left leg..." } ], "coverUrl": "/comics/cg_example/cover.png", "pageUrls": ["/comics/cg_example/cover.png", "/comics/cg_example/page-1.png", "/comics/cg_example/page-2.png"], "pdfUrl": "/comics/cg_example/comic.pdf", "cbzUrl": "/comics/cg_example/comic.cbz", "perPage": [ { "page": 1, "panels": 4, "storyBeat": "In a city that never stops moving, every second counts...", "imageUrl": "/comics/cg_example/page-1.png", "panelDetails": [ { "panel": 2, "imageUrl": "/comics/cg_example/panel-1-1.png", "altText": "Mia straps a glowing package onto Bob's back... Dialogue: \"COME ON, BOB! WE CAN'T BE LATE!\"", "dialogue": "COME ON, BOB! WE CAN'T BE LATE!" } // one panel shown; every panel is exported ], "evidence": { "model": "@cf/black-forest-labs/flux-1-schnell", "promptChars": 2773, "layout": "4p" } } ], "integrity": { "algorithm": "sha256", "files": { "cover.png": "cfb38666...", "page-1.png": "7893e01f...", /* every file */ } }, "receipt": { "payloadSha256": "...", "algorithm": "HMAC-SHA256", "signature": "..." }, "license": { "usage": "...full commercial rights...", "provenance": { "imageModel": "...", "seed": 483920175, "promptSha256": "c137036b..." } }, "evidence": { "model": "@cf/black-forest-labs/flux-1-schnell", "pagesGenerated": 2, "panelsGenerated": 8, "generationTimeSec": 41, "costEstimateUsd": 0.01, "caveat": "Comic is AI-generated. Story coherence and visual consistency are heuristic, not guaranteed." } }