# Inkroost — Full AI Agent Documentation > Inkroost is a premium manga publishing platform where independent creators publish original manga series, and readers discover, read, and support the artists behind them. ## Platform Overview Inkroost is a full-stack manga publishing platform. Creators register accounts, build manga series (title, description, genres, maturity rating, reading direction), create character sheets with appearance and personality notes, generate AI cover and banner art using credits, write and publish chapters, and submit them for moderation review. Readers browse the catalogue, read free chapters, and purchase credits to unlock premium content. ## MCP Server Inkroost exposes a single MCP (Model Context Protocol) server that covers every domain — story, characters, art, publishing, credits. The server speaks the MCP 2025-03-26 specification over HTTPS (Streamable HTTP transport). ### Endpoint ``` POST https://inkroost.com/mcp ``` Every tool and resource lives behind that one URL. Tool discovery via `tools/list` returns the full catalog in a single page. ### Connecting Two paths, both backed by the same authorization layer. **Option 1 — Custom Connector via OAuth (Claude.ai)** Claude.ai (Pro / Team / Enterprise) authorizes once and gets full access. No bearer-token plumbing. 1. In Claude, open the left sidebar → **Customize** → **Connectors** 2. Click the **+** button → **Add custom connector** 3. Paste `https://inkroost.com/mcp` and click **Add** 4. Sign in to Inkroost when prompted, then click **Allow** Under the hood, Claude.ai performs RFC 7591 Dynamic Client Registration, then the standard OAuth 2.1 authorization-code flow (PKCE required). The resulting access token carries the umbrella `mcp:use` scope, which authorizes every tool. OAuth discovery documents live at `/.well-known/oauth-authorization-server` and `/.well-known/oauth-protected-resource`. **Option 2 — Bearer token (Claude Code, Cursor, Windsurf, OpenAI Agents, scripts)** For clients that don't speak the OAuth Custom Connector flow, generate a manual token with the granular abilities you need: 1. Log in at https://inkroost.com/login 2. Visit https://inkroost.com/settings/api-tokens 3. Create a token with the abilities your agent requires 4. Copy the token value — it is shown only once 5. Send it as a Bearer credential: ``` Authorization: Bearer ``` Example configs: ``` # Claude Code CLI claude mcp add --transport http inkroost https://inkroost.com/mcp \ --header "Authorization: Bearer YOUR_TOKEN_HERE" # Cursor / Windsurf (mcp.json) { "mcpServers": { "inkroost": { "url": "https://inkroost.com/mcp", "headers": { "Authorization": "Bearer YOUR_TOKEN_HERE" } } } } # OpenAI Agents SDK { "tools": [{ "type": "mcp", "server_label": "inkroost", "server_url": "https://inkroost.com/mcp", "headers": { "Authorization": "Bearer YOUR_TOKEN_HERE" }, "require_approval": "never" }] } ``` ### Token Abilities (manual tokens) Manual tokens are scoped. Pick the abilities your agent actually needs. | Ability | What it unlocks | |---------|-----------------| | `story:read` | Read series, story state, characters, consistency context | | `story:write` | Create / update series, characters, chapters, style profiles | | `art:generate` | Generate AI art (charges credits per generation) | | `publish:write` | Publish chapters and submit for review | | `credits:read` | Check balance, estimate generation costs, list packages | | `credits:purchase` | Initiate credit purchases (returns a checkout URL the user opens) | OAuth tokens (Option 1) hold the umbrella `mcp:use` scope, which counts as every ability. --- ## Tool Catalog 26 tools total. The server registers all of them under one endpoint; tools the calling token isn't authorized for are filtered out of `tools/list`. ### Story #### Tool: `create-series-tool` Create a new manga series. Required ability: `story:write`. **Input:** ```json { "title": "string (required) — Series title", "description": "string (required) — Short synopsis, max 5000 chars", "genre_ids": "array (optional) — Genre IDs to attach", "maturity_rating": "string (optional) — one of: all_ages, teen, mature", "reading_direction": "string (optional) — one of: ltr, rtl", "default_style_profile": "object (optional) — Prefer set-series-style-profile-tool after creation for a guided structured shape" } ``` **Output:** ```json { "series_id": 42, "slug": "my-series-title", "title": "My Series Title", "status": "ongoing", "approval_status": "draft" } ``` #### Tool: `set-series-style-profile-tool` Set the series-wide default visual style profile. Call this immediately after `create-series-tool` and before any page generation — the profile is auto-injected into every generation prompt and is the single biggest lever for visual consistency across a manga. Required ability: `story:write`. **Input:** ```json { "series_id": "integer (required)", "subject": { "name": "string", "age": "integer", "gender": "string", "hair": "string", "eyes": "string", "distinguishing_marks": "string", "typical_outfit": "string", "build": "string" }, "photography": { "style": "string", "shading": "string", "linework": "string", "panel_framing": "string" }, "background": { "setting": "string", "atmosphere": "string", "time_of_day": "string" }, "constraints": { "no_text": "boolean", "no_logos": "boolean", "aspect_ratio": "string", "color_palette": "string" } } ``` Fill in every sub-field. Vague entries ("cool hair", "manga style") produce inconsistent art across pages — write detail the image model can actually render. The call replaces the existing profile (not a merge). **Output:** ```json { "series_id": 42, "default_style_profile": { "subject": { "...": "..." }, "photography": { "...": "..." }, "background": { "...": "..." }, "constraints": { "...": "..." } }, "completeness": { "score": 17, "max": 19, "percentage": 89, "is_complete": true, "missing": ["subject.distinguishing_marks", "background.atmosphere"] } } ``` #### Tool: `get-story-state-tool` Retrieve the current state of a series including chapters, characters, and the series style profile. Required ability: `story:read`. **Input:** ```json { "series_id": "integer (required)" } ``` **Output:** ```json { "id": 42, "title": "Shadow Realm", "slug": "shadow-realm", "description": "...", "status": "ongoing", "maturity_rating": "teen", "reading_direction": "ltr", "is_published": false, "approval_status": "draft", "default_style_profile": { "...": "..." }, "chapter_count": 3, "character_count": 2, "chapters": [ { "chapter_id": 1, "title": "Chapter One", "position": 1, "status": "draft" } ], "characters": [ { "character_id": 7, "name": "Kira", "appearance_notes": "Silver hair, blue almond eyes, warm golden skin.", "personality_notes": "Calm under pressure, dry wit.", "style_profile": { "...": "..." } } ] } ``` #### Tool: `get-consistency-context-tool` Retrieve the consistency context that will be auto-injected into generation prompts — series style profile, character sheets, and completeness scores. Use this before planning or generating pages so you can self-correct any gaps first. Required ability: `story:read`. **Input:** ```json { "series_id": "integer (required)" } ``` **Output:** ```json { "series_id": 42, "title": "Shadow Realm", "default_style_profile": { "...": "..." }, "series_style_profile_completeness": { "score": 17, "max": 19, "percentage": 89, "is_complete": true, "missing": ["background.atmosphere"] }, "character_count": 2, "characters": [ { "character_id": 7, "name": "Kira", "appearance_notes": "Silver hair, blue almond eyes.", "personality_notes": "Calm under pressure.", "style_profile": { "...": "..." }, "completeness_score": { "score": 6, "max": 8, "percentage": 75, "is_complete": true, "missing": ["appearance:build", "appearance:outfit"] }, "style_profile_completeness": { "score": 12, "max": 19, "percentage": 63, "is_complete": false, "missing": ["subject.distinguishing_marks", "photography.linework", "background.atmosphere", "constraints.color_palette"] } } ] } ``` The `completeness_score` block reflects keyword coverage of `appearance_notes`. The `style_profile_completeness` block reflects how many leaf fields of the structured style profile are filled in (70% threshold for `is_complete`). Below-threshold characters may produce inconsistent images — fill them in via `set-character-style-profile-tool` before generating. #### Tool: `create-chapter-tool` Create a new chapter shell within an existing series. A chapter is the container for sequential pages — never a single page. Required ability: `story:write`. **Input:** ```json { "series_id": "integer (required)", "title": "string (required) — Chapter title", "content": "string (optional) — Chapter synopsis or description", "summary": "string (optional) — Short summary (alias for content)", "position": "number (optional) — Chapter number (e.g. 1, 1.5, 2). Auto-increments if omitted", "status": "string (optional) — one of: draft (default), published", "tags": "array (optional) — Tags for the chapter" } ``` **Output:** ```json { "chapter_id": 12, "series_id": 42, "title": "Chapter One: The Beginning", "position": 1, "status": "draft", "approval_status": "draft" } ``` Next steps: call `generate-pages-tool` (or `generate-pages-batch-tool`) multiple times to produce 8-24 pages, approve the best variants with `approve-pages-tool` / `batch-approve-pages-tool`, then publish with `publish-chapter-tool`. #### Tool: `update-page-tool` Update an existing chapter's title, description, status, or position. (The parameter is named `page_id` for legacy reasons but the entity is a Chapter.) Required ability: `story:write`. **Input:** ```json { "page_id": "integer (required) — The chapter to update", "title": "string (optional)", "content": "string (optional) — Updated synopsis", "summary": "string (optional)", "status": "string (optional) — one of: draft, published", "position": "number (optional)" } ``` **Output:** Updated chapter object with `chapter_id`, `series_id`, `title`, `position`, `status`, `approval_status`, `updated: true`. --- ### Characters #### Tool: `create-character-tool` Create a new character sheet for a series. Required ability: `story:write`. **Input:** ```json { "series_id": "integer (required)", "name": "string (required)", "description": "string (optional)", "appearance_notes": "string (optional)", "personality_notes": "string (optional)", "style_profile": "object (optional) — Prefer set-character-style-profile-tool after creation for the guided structured shape" } ``` **Output:** ```json { "character_id": 7, "series_id": 42, "name": "Kira Tanaka" } ``` After creating, **immediately call `set-character-style-profile-tool`** to fix the character's visual identity. Without a structured style profile the character will drift visually across pages. #### Tool: `update-character-tool` Update an existing character sheet (name, description, narrative notes). For visual style updates use `set-character-style-profile-tool`. Required ability: `story:write`. **Input:** Same shape as `create-character-tool`, plus `character_id` (required). #### Tool: `set-character-style-profile-tool` Fix the character's visual identity so they render consistently across every page they appear in. When `character_ids` are passed to `generate-pages-tool`, this profile overrides the series default. Required ability: `story:write`. **Input:** ```json { "character_id": "integer (required)", "subject": { "name": "string (required) — Character's display name; anchors the profile", "age": "integer", "gender": "string", "hair": "string", "eyes": "string", "distinguishing_marks": "string", "typical_outfit": "string", "build": "string" }, "photography": { "...": "optional, see set-series-style-profile-tool" }, "background": { "...": "optional" }, "constraints": { "...": "optional" } } ``` The call replaces the existing `style_profile` (not a merge). **Output:** ```json { "character_id": 7, "series_id": 42, "name": "Kira Tanaka", "style_profile": { "...": "..." }, "completeness": { "score": 15, "max": 19, "percentage": 79, "is_complete": true, "missing": ["background.atmosphere"] } } ``` #### Tool: `get-character-sheet-tool` Retrieve a character sheet by ID. Required ability: `story:read`. **Input:** `{ "character_id": "integer (required)" }` #### Character Definition Best Practices The quality and consistency of AI-generated art depends heavily on how precisely each character is described. Vague descriptions produce inconsistent characters; detailed descriptions anchor the model. **Appearance notes and style profiles must be hyper-specific.** Include every visual attribute that matters: | Attribute | Bad (vague) | Good (specific) | |-----------|-------------|-----------------| | Hair | "dark hair" | "jet-black straight hair, cut bluntly at the jaw, with a single short fringe swept left across the forehead" | | Eyes | "blue eyes" | "pale ice-blue irises, almond-shaped, with a thin dark limbal ring and slightly upturned outer corners" | | Build | "athletic" | "lean mesomorphic build, 175 cm, wide shoulders tapering to a narrow waist, visible forearm musculature" | | Skin | "tan" | "warm golden-brown skin tone, no visible blemishes, light scar on the left chin 1 cm long" | | Clothing | "casual outfit" | "worn dark navy bomber jacket over a white ribbed tank top, fitted charcoal joggers, white low-top canvas sneakers" | | Distinctive features | — | "high cheekbones, a slightly prominent aquiline nose, and a thin vertical scar through the left eyebrow" | Personality notes should also capture mannerisms that translate to visual storytelling: posture (slouched vs. rigid), typical facial expressions (default scowl, warm grin), and habitual gestures. > **Why this matters:** Inkroost auto-injects each referenced character's style profile and appearance notes directly into the image prompt. The more precise your description, the more consistent characters appear across different panels and pages. --- ### Art Art generation charges credits from the authenticated user's wallet. Check balance with `check-balance-tool` and remaining daily capacity with `get-daily-limit-status-tool` before queuing large batches. #### Tool: `generate-cover-tool` Generate an AI cover image for a series. Required ability: `art:generate`. **Input:** ```json { "series_id": "integer (required)", "prompt": "string (required) — Descriptive prompt, min 5, max 2000 chars", "style_profile": "object (optional) — Style overrides for this generation" } ``` **Output:** ```json { "series_id": 42, "status": "queued", "message": "Cover generation has been queued. Check back shortly for results.", "credits_charged": 1 } ``` #### Tool: `generate-banner-tool` Generate an AI banner image for a series. Uses a 16:9 landscape aspect ratio. Same input/output shape as `generate-cover-tool`. #### Tool: `generate-pages-tool` Generate AI manga page image variants for a chapter. Credits are charged per variant. Required ability: `art:generate`. The series `default_style_profile` and every referenced character `style_profile` are auto-injected into the prompt for visual consistency — set them first via `set-series-style-profile-tool` and `set-character-style-profile-tool`. A manga chapter is multiple sequential pages telling one sub-story. Call this once per beat (or use `generate-pages-batch-tool` for multiple beats in one call) — never settle for a single page per chapter. **Input:** ```json { "series_id": "integer (required)", "chapter_id": "integer (optional) — attach to an existing chapter; if omitted, a chapter is created after approval", "prompt": "string (required) — scene description, min 10, max 1000 chars", "style_prompt": "string (optional) — art style instructions; defaults to manga style, black and white ink", "variant_count": "integer (optional) — number of variants 1-4. Defaults to 2", "style_profile": "object (optional) — override/patch the series default_style_profile for this page only", "chapter_title": "string (optional) — title for the new chapter created at approval", "chapter_number": "number (optional) — chapter number for the new chapter", "character_ids": "array (optional) — IDs of characters appearing in this scene; their style profiles get injected automatically", "location": "string (optional) — e.g. 'Tokyo rooftop at dusk', 'underground cavern'", "time_of_day": "string (optional) — one of: dawn, morning, noon, afternoon, dusk, night, midnight", "camera_angle": "string (optional) — e.g. 'low-angle', 'over-the-shoulder', 'birds-eye', 'dutch-angle'", "framing": "string (optional) — e.g. 'extreme close-up', 'medium shot', 'wide establishing shot', 'two-shot'", "mood": "string (optional) — emotional tone, e.g. 'tense', 'hopeful', 'melancholic', 'action-packed'", "continuity_notes": "string (optional) — visual facts that must remain unchanged, e.g. 'Kira still wears the bandage on her left arm from Chapter 2'", "allow_text": "boolean (optional, default false) — by default no text, dialog, speech bubbles, or captions are rendered in images. Set to true only when you need the image model to handle in-image text (see guidance below)" } ``` **Output:** ```json { "job_id": 123, "series_id": 42, "chapter_id": null, "status": "queued", "variant_count": 2, "credits_charged": 2, "message": "Page generation has been queued. Use get-art-status-tool with this job_id to poll for results." } ``` #### `allow_text` — When and How to Use It **Only enable `allow_text: true` when you want the image model to handle speech bubbles and in-image text.** This trades layout control for contextual placement — the model can place dialog near the speaker, but results vary by model. **When you set `allow_text: true`, your `prompt` must include a precise script. Use the format below — speaker prefixes are stripped automatically so only the quoted text is rendered inside the bubbles:** ``` DIALOG SCRIPT (in reading order): Panel 1 — Kira: "I found it." Panel 2 — Ren: "Impossible. That vault has been sealed for a hundred years." Panel 3 — Kira: "Not anymore." Caption (top of page): Three days before the heist. ``` > **Format rule:** write each line as `Panel N — Speaker: "dialog text"`. **Do NOT write** `Speaker (position): "text"` — the parenthetical position info would render literally inside the bubble. **Requirements for `allow_text: true`:** - Name every speaker by their character name in `Panel N — Speaker: "text"` format - Write the exact dialog text — do not paraphrase - Specify reading order (panel 1 → 2 → 3); the model places bubbles contextually - Include caption or narration text with its position and type (caption, narration) **When NOT to use `allow_text`:** - Leave `allow_text: false` (default) for action scenes, establishing shots, or any page where dialog is not needed - For precise, reliable dialog control, generate clean art first and use `annotate-page-tool` afterwards > **Quality note:** in-image text quality varies by underlying model. If text is garbled, misspelled, or misplaced, discard the job and either retry with a refined prompt or switch to `annotate-page-tool` for post-generation annotation. #### Tool: `generate-pages-batch-tool` Queue multiple AI page generation jobs in one call. Each entry in the `pages` array creates one generation job. Credits are charged per variant per job. Returns an array of job IDs. Maximum 20 entries per batch. Required ability: `art:generate`. Each entry counts as one AI generation toward your **daily limit of 500/day**. Check remaining capacity with `get-daily-limit-status-tool` before queuing. **Input:** ```json { "series_id": "integer (required)", "chapter_id": "integer (optional) — attach all jobs to an existing chapter", "pages": [ { "prompt": "string (required) — scene description, min 10, max 1000 chars", "chapter_title": "string (optional)", "chapter_number": "number (optional)", "character_ids": "array (optional) — overrides batch-level character_ids for this page", "location": "string (optional)", "time_of_day": "string (optional)", "camera_angle": "string (optional)", "framing": "string (optional)", "mood": "string (optional)", "continuity_notes": "string (optional)" } ], "style_prompt": "string (optional) — shared art style for all jobs", "variant_count": "integer (optional) — variants per job, 1-4. Defaults to 2", "style_profile": "object (optional) — shared style profile override; falls back to series default_style_profile when omitted", "chapter_title": "string (optional) — default chapter title for all jobs", "chapter_number": "number (optional) — starting chapter number (auto-increments per job)", "character_ids": "array (optional) — default character IDs for all pages", "location": "string (optional)", "time_of_day": "string (optional)", "camera_angle": "string (optional)", "framing": "string (optional)", "mood": "string (optional)", "continuity_notes": "string (optional)", "allow_text": "boolean (optional, default false)" } ``` **Output:** ```json { "series_id": 42, "chapter_id": null, "jobs_queued": 5, "total_credits_charged": 10, "variant_count": 2, "jobs": [ { "job_id": 123, "prompt_preview": "A hero stands at the cliff...", "chapter_number": 1.0, "credits_charged": 2, "status": "queued" } ], "message": "5 generation job(s) queued. Use get-art-status-tool with each job_id to poll for results, then use batch-approve-pages-tool to approve all at once." } ``` #### Tool: `get-art-status-tool` Poll the status of an AI art generation job. Returns result URLs when the job is ready for review. Required ability: `art:generate`. **Input:** ```json { "job_id": "integer (optional) — the job ID to check", "series_id": "integer (optional) — return current cover and banner URLs for this series" } ``` **Output:** ```json { "job_id": 123, "status": "review", "result_urls": ["https://..."], "error_message": null, "completed_at": "2026-04-30T12:00:00+00:00" } ``` Status values: `pending`, `processing`, `review` (ready to approve), `completed`, `failed`. When status is `failed`, `error_message` contains the reason. #### Tool: `get-daily-limit-status-tool` Check your current AI generation usage for today. **Call this before queuing large batches** to avoid hitting the daily cap mid-way through. Required ability: `art:generate`. **Daily limit: 500 AI generations per user per day, resets at midnight UTC.** No input required. **Output:** ```json { "used_today": 12, "daily_limit": 500, "remaining": 488, "resets_at": "2026-05-03T00:00:01+00:00", "message": "You have used 12 of your 500 daily AI generations. 488 remaining today." } ``` #### Tool: `approve-pages-tool` Approve AI-generated page variants and create Page records without the browser review UI. The job must have status `review`. Required ability: `art:generate`. **Input:** ```json { "job_id": "integer (required) — the generation job to approve", "variant_indices": "array (optional) — zero-based positions of variants to approve, e.g. [0] for first only. Defaults to all variants.", "discard": "boolean (optional) — set to true to discard all variants without creating pages. Credits are not refunded." } ``` **Output (pages approved):** ```json { "job_id": 123, "action": "approved", "chapter_id": 99, "series_id": 42, "pages_created": 2, "page_ids": [301, 302], "message": "Chapter \"Chapter 1\" created with 2 page(s)." } ``` #### Tool: `batch-approve-pages-tool` Approve multiple AI generation jobs at once. Accepts up to 50 job IDs per call and processes each atomically. Supports partial success — if one job fails, the others continue. Required ability: `art:generate`. **Input:** ```json { "job_ids": [123, 124, 125], "variant_indices": "array (optional) — zero-based variant indices applied uniformly to every job", "discard": "boolean (optional) — discard all variants in every job without creating pages" } ``` **Output:** ```json { "total": 3, "approved": 2, "failed": 1, "summary": "2 of 3 job(s) approved. 1 failed — see results for details.", "results": [ { "job_id": 123, "action": "approved", "chapter_id": 99, "pages_created": 2 }, { "job_id": 124, "action": "approved", "chapter_id": 100, "pages_created": 2 }, { "job_id": 125, "error": "Job 125 not found or you do not own it." } ] } ``` #### Tool: `annotate-page-tool` Composite text, dialog bubbles, captions, or narration boxes onto an approved page image. A reliable way to add readable dialog to manga pages when in-image text is needed. Required ability: `art:generate`. > **TEXT OVERLAP WARNING:** Agents have no visibility into image composition. Fixed-position annotations frequently overlap with generated art because manga pages are centre-focused and the agent cannot see where characters, panels, or backgrounds are placed. **Preferred approach:** use `generate-pages-tool` with `style_prompt` describing where dialog should appear and `allow_text=true` so the image generator can place text context-aware. **If `annotate-page-tool` must be used:** omit `position` to let the server choose a type-based default (speech/thought → `bottom-center`, caption → `top-center`, narration → `bottom-left`), or explicitly use `bottom-*` positions for dialog and `top-*` positions for captions to minimise overlap with centre-focused art. **Input:** ```json { "page_id": "integer (required)", "annotations": [ { "type": "speech | thought | caption | narration (required)", "text": "string (required) — the text content to render", "position": "top-left | top-center | top-right | center | bottom-left | bottom-center | bottom-right (optional)", "speaker": "string (optional) — character name prepended to speech/thought text" } ] } ``` **Output:** ```json { "page_id": 301, "chapter_id": 99, "new_image_path": "/storage/pages/annotated_ann_abc123.png", "annotations_applied": 2, "message": "2 annotation(s) applied successfully. The page image has been updated." } ``` **Annotation types:** - `speech` — white background bubble, dark text (dialog spoken aloud) - `thought` — light-blue background, dark text (internal monologue) - `caption` — dark semi-transparent bar, white text (scene description) - `narration` — dark navy bar, white text (narrator voice-over) --- ### Publish #### Tool: `publish-chapter-tool` Publish a chapter for a series — makes it publicly visible. Required ability: `publish:write`. Manga chapters typically contain 8-24 sequential pages telling one complete sub-story. Generate every page with `generate-pages-tool`, approve them with `approve-pages-tool` / `batch-approve-pages-tool`, then publish once. Publishing a one-page chapter is almost always a mistake (omake and splash chapters are the exception). **Input:** ```json { "series_id": "integer (required)", "number": "number (required) — Chapter number, e.g. 1, 1.5, 2", "title": "string (required) — Chapter title", "description": "string (optional)", "is_locked": "boolean (optional) — Whether credits are required to unlock", "credit_price": "integer (optional)" } ``` **Output:** ```json { "chapter_id": 99, "series_id": 42, "number": 1.0, "title": "The Beginning", "approval_status": "approved", "is_published": true, "page_count": 12, "warnings": [] } ``` The response includes a `warnings` array. If the chapter has fewer than 5 pages, the warning explains that manga chapters typically contain 8-24 sequential pages and suggests adding more pages before publishing — or ignoring the warning if it's a splash or omake. #### Tool: `submit-for-review-tool` Submit a chapter for moderation review. Required ability: `publish:write`. **Input:** `{ "chapter_id": "integer (required)" }` **Output:** ```json { "chapter_id": 99, "approval_status": "pending_review", "submitted": true } ``` #### Tool: `check-approval-status-tool` Check the current approval status of a chapter. Required ability: `publish:write`. **Input:** `{ "chapter_id": "integer (required)" }` **Output:** Chapter ID and current approval status. --- ### Credits #### Tool: `check-balance-tool` Returns the current credit balance for the authenticated user. No input required. Required ability: `credits:read`. **Output:** ```json { "balance": 50, "currency": "credits" } ``` #### Tool: `estimate-generation-cost-tool` Estimate the credit cost for an AI generation operation before committing. Required ability: `credits:read`. **Input:** ```json { "page_count": "integer (required, 1-1000) — Number of pages to estimate the cost for" } ``` **Output:** ```json { "page_count": 5, "cost_per_page": 10, "total_cost": 50, "currency": "credits" } ``` #### Tool: `list-credit-packages-tool` List all available credit packages with their prices and IDs. Call this first to discover the `package_id` needed for `purchase-credits-tool`. Required ability: `credits:read`. No input required. **Output:** ```json { "packages": [ { "id": 1, "name": "Starter", "credits": 100, "bonus_credits": 0, "total_credits": 100, "price_formatted": "$4.99", "price_cents": 499 }, { "id": 2, "name": "Creator", "credits": 500, "bonus_credits": 50, "total_credits": 550, "price_formatted": "$19.99", "price_cents": 1999 } ], "currency": "usd" } ``` #### Tool: `purchase-credits-tool` Initiate a Stripe Checkout session for the user to purchase credits. Returns a checkout URL that the user must open in a browser — the agent cannot complete the payment autonomously. Credits are added to the user's wallet automatically after successful payment. Required ability: `credits:purchase`. **Input:** ```json { "package_id": "integer (required) — ID from list-credit-packages-tool" } ``` **Output:** ```json { "checkout_url": "https://checkout.stripe.com/pay/...", "package_name": "Creator", "credits": 500, "bonus_credits": 50, "total_credits": 550, "price_formatted": "$19.99", "currency": "usd", "instructions": "Open the checkout_url in a browser to complete payment. Credits will be added to your account automatically after successful checkout." } ``` **Agent workflow for low-credit scenario:** ``` 1. check-balance-tool → balance too low 2. list-credit-packages-tool → pick best package for user's needs 3. purchase-credits-tool → returns checkout_url 4. Present checkout_url to the user: "You need more credits. Open this link to purchase: " 5. User completes payment in browser 6. Credits appear in wallet automatically (webhook-driven) 7. check-balance-tool → confirm balance updated 8. Resume the original task ``` --- ## Typical Agent Workflow A complete agent workflow for creating and publishing a manga chapter: 1. **Check balance** (`credits:read`) — Verify sufficient credits before generating art. If balance is too low, call `list-credit-packages-tool` and then `purchase-credits-tool` to surface a checkout URL for the user. 2. **Check daily limit** (`art:generate`) — Call `get-daily-limit-status-tool` to confirm you have enough remaining generations for your planned batch. Daily limit: 500/day, resets at midnight UTC. 3. **Create series** (`story:write`) — Call `create-series-tool` with title and metadata. 4. **Set the series style profile** (`story:write`) — Immediately call `set-series-style-profile-tool` with a detailed default profile (subject, photography, background, constraints). This is the single biggest lever for visual consistency across pages. 5. **Create characters** (`story:write`) — For each named character: `create-character-tool` → `set-character-style-profile-tool` with detailed visual anchors (hair length + colour + parting, eye colour + shape, distinguishing marks, default outfit, build). 6. **Inspect consistency context** (`story:read`) — Call `get-consistency-context-tool` to review the series style profile, character IDs, and completeness scores. Fill any gaps before generating. 7. **Create a chapter shell** (`story:write`) — Call `create-chapter-tool`. A chapter is the container for multiple sequential pages. 8. **Plan the chapter** — A manga chapter typically runs 8-24 sequential pages telling one complete sub-story. Plan the beats before generating. 9. **Generate pages** (`art:generate`) — For a single beat use `generate-pages-tool`; for multiple beats at once use `generate-pages-batch-tool` (up to 20 prompts per call). Pass `character_ids` so the server injects the right style profiles automatically. Leave `allow_text=false` (default) for clean art; add dialog in step 12 instead. 10. **Poll status** (`art:generate`) — Use `get-art-status-tool` until each job's status is `review`. For failed jobs, `error_message` contains the reason. 11. **Analyse generated images** — When the job reaches `review` status, `get-art-status-tool` returns `result_urls`. **Fetch each URL and visually analyse the image before approving:** - Are all characters recognisable and consistent with their style profiles? - Does the scene match the intended composition and action? - Is the panel layout, lighting, and mood correct? - If `allow_text=true` was used, is the dialog readable, correctly attributed, and free of spelling errors? **If the image does not meet expectations**, call `approve-pages-tool` with `discard: true` to reject it (credits are not refunded), then regenerate with a refined prompt. Common refinements: - Add more specific physical descriptors to the prompt - Reference the character's style profile fields explicitly in the scene description - Add composition hints: "close-up on face", "wide shot from above", "three-quarter profile" - Simplify complex multi-character scenes into separate single-character pages 12. **Approve pages** (`art:generate`) — Once satisfied with the image, use `approve-pages-tool` for a single job or `batch-approve-pages-tool` for multiple jobs at once. Both create Page records autonomously. Use `variant_indices` to select specific variants or omit to approve all. 13. **Annotate (optional)** (`art:generate`) — For in-image text, prefer re-generating with `generate-pages-tool` using `style_prompt` and `allow_text=true` so the model places text context-aware. If post-generation annotation is needed, use `annotate-page-tool`. 14. **Publish** (`publish:write`) — Once every page is approved, call `publish-chapter-tool`. The response's `warnings` field flags chapters with fewer than 5 pages. 15. **Submit for review** (`publish:write`) — Submit the chapter to moderation with `submit-for-review-tool`. 16. **Check approval** (`publish:write`) — Poll `check-approval-status-tool` until the chapter is approved. --- ## Prompting Best Practices ### Character Consistency AI image models have no persistent memory between jobs. The server helps by auto-injecting consistency context into every generation prompt: - **Series default style profile** — when `style_profile` is omitted from `generate-pages-tool` or `generate-pages-batch-tool`, the series `default_style_profile` is used automatically. - **Character injection** — when you pass `character_ids`, the server merges each character's `appearance_notes` and `style_profile` into the prompt in a stable order before your scene description. **Always pass `character_ids`** for scenes with named characters — this is the most reliable way to keep characters consistent across pages without repeating their descriptions manually. Call `get-consistency-context-tool` before generating to preview what will be injected and to check completeness scores. Characters below 70% completeness may produce inconsistent results; fill in missing fields with `set-character-style-profile-tool` first. For scenes where a character has critical visual details not yet in their profile, you can still embed them inline in `prompt` or `continuity_notes`: ``` continuity_notes: "Kira still has the bandage on her left arm from Chapter 2. The amulet glows red, not blue." ``` Never rely on a character's name alone to anchor appearance — image models do not know your characters, only what is described in the prompt. ### Iterative Refinement Loop High-quality manga pages rarely emerge from a single generation. Treat generation as a loop: ``` 1. generate-pages-tool / generate-pages-batch-tool → job queued 2. get-art-status-tool (poll until status = "review") 3. Fetch result_urls → analyse each image 4a. Image OK → approve-pages-tool → continue 4b. Image not OK → approve-pages-tool (discard: true) → refine prompt → go to step 1 ``` Common reasons to discard and retry: - Character appearance doesn't match the style profile (wrong hair, eye colour, etc.) - Wrong number of characters in the scene - Composition is too cluttered or key action is unclear - Dialog text (when `allow_text=true`) is garbled or unreadable Each retry consumes credits, so invest in precise style profiles and prompts upfront to reduce iteration cycles. ### Scene Prompting Tips - **One idea per panel** — describe one action, emotion, or moment per page generation; complex multi-event scenes almost never render well - **Foreground vs. background** — explicitly separate foreground subjects from background: "Ren stands in the foreground, sword raised; behind him, burning ruins and scattered soldiers" - **Camera angle and framing** — name it: "extreme close-up on eyes", "low-angle wide shot", "over-the-shoulder from behind Kira" - **Lighting and mood** — specify: "harsh neon back-lighting", "soft dawn light", "dim torch-lit cave" - **Panel context** — if the page follows a specific moment in the story, briefly name it: "aftermath of the fight — Kira kneels beside the fallen enemy, exhausted" --- ## Daily AI Generation Limit Each user account may generate up to **500 AI images per day**. This counter is shared across all generation tools (`generate-pages-tool`, `generate-pages-batch-tool`, `generate-cover-tool`, `generate-banner-tool`). The counter resets at midnight UTC. - Use `get-daily-limit-status-tool` to check `used_today`, `remaining`, and `resets_at` before queuing batches. - When the limit is reached, generation tools return: `"Daily AI generation limit reached (500/day). Your limit resets at midnight UTC."` - For very large projects (e.g. 1000+ pages), spread generation across multiple days. All AI generation consumes Inkroost Credits — top up with `purchase-credits-tool` when your balance runs low. ## Rate Limiting All MCP endpoints are rate-limited to 60 requests per minute. Credits-consuming operations (art generation) require a sufficient wallet balance — insufficient credits return an error response. --- ## Resources - Machine-readable summary: https://inkroost.com/llms.txt - AI Agent Access: https://inkroost.com/settings/api-tokens - Pricing & Credits: https://inkroost.com/pricing - Support: https://inkroost.com