Skip to content

Murzav/appshots-mcp

Repository files navigation

appshots-mcp

CI Coverage Crates.io Downloads MSRV License MCP

MCP server for generating ASO-optimized App Store screenshots. Generates up to 780 final images per app (39 locales x 5-10 screenshots x 1-2 devices).

AI logic lives in Claude Code; the server provides tools, rendering, and validation.

Why appshots-mcp?

Current solution Problem
Manual Figma Days of work, repeat on every update
AppScreens / Screenshots.pro Paid, vendor lock-in
fastlane frameit + ImageMagick Flat PNG frames, ~10% layout accuracy, RTL/emoji breaks

Core problem: screenshot captions are disconnected from ASO keywords. Captions must reinforce keyword coverage, not be random marketing text. appshots-mcp solves this by integrating ASO keyword analysis directly into the screenshot generation pipeline.

Features

  • 24 MCP tools for the complete screenshot pipeline
  • 3 MCP prompts guiding app preparation, template design, and batch generation
  • Simulator state management — pre-warm, seed UserDefaults, scroll/tap before capture
  • Clean capture + Typst compositing — framebuffer screenshots with device frames added in templates
  • Typst rendering — native RTL/CJK support, exact layout, sub-second renders
  • OKLCH color space exclusively — perceptually uniform, no hex/RGB
  • 39 ASO locales with fallback chains
  • Granular regeneration — fix one screenshot without re-rendering all 780
  • Keyword-aware captions — AI incorporates ASO keywords into every locale's captions
  • Parallel rendering with configurable concurrency (4 concurrent by default)
  • Auto font discovery from appshots/fonts/ directory
  • Compilation timeout (30s) prevents infinite-loop templates
  • Atomic file writes with advisory locking
  • Path containment prevents symlink escape attacks

Quick Start

Installation

Homebrew (macOS/Linux):

brew install Murzav/tap/appshots-mcp

Cargo:

cargo install appshots-mcp

cargo-binstall (prebuilt binary):

cargo binstall appshots-mcp

Configuration

Claude Code:

claude mcp add appshots-mcp -- appshots-mcp --project-dir /path/to/your/app

Generic MCP client (stdio):

{
  "mcpServers": {
    "appshots-mcp": {
      "command": "appshots-mcp",
      "args": ["--project-dir", "/path/to/your/app"]
    }
  }
}

CLI Options

Flag Default Description
--project-dir . Path to the app project root
--glossary-path glossary.json Path to shared glossary file
--config-path appshots.json Path to screenshot config

Usage

Typical Workflow

  1. Prepare your app — use the prepare-app prompt to create ScreenshotMode enum in Swift
  2. Design templates — use the design-template prompt to create Typst templates with preview_design
  3. Generate all screenshots — use the generate-screenshots prompt for the full pipeline:
scan_project → analyze_keywords → plan_screens → save_captions (en-US)
→ translate captions (38 locales) → validate_layout
→ warm_simulator → seed_defaults → capture_screenshots
→ compose_screenshots → run_deliver

Tools

Capture & Setup

Tool Description
list_simulators List available iOS simulators (UDID, runtime, state)
warm_simulator Pre-boot simulator, grant permissions, set Apple canonical status bar (9:41)
seed_defaults Seed UserDefaults via plist import (run after install, before launch)
interact_simulator Scroll or tap in iOS Simulator via CGEvent mouse drag simulation
capture_screenshots Capture clean screenshots from simulator framebuffer (no device bezels)

Discovery & Analysis

Tool Description
scan_project Parse fastlane/metadata/ across all 39 locales
analyze_keywords Find keyword coverage gaps for a locale
get_project_status Check config, templates, captions, captures readiness

Strategy

Tool Description
plan_screens Save mode -> keyword -> messaging mapping
get_plans Retrieve current screen plans
save_captions Save captions for a locale (upsert by mode)
get_captions Get captions with locale/mode filters
get_locale_keywords Read keywords.txt for a locale
get_caption_coverage Coverage matrix: locale x mode
review_captions Keyword coverage analysis per caption

Design & Rendering

Tool Description
save_template Save Typst template source
get_template Read template with resolution chain
preview_design Render a single design preview
validate_layout Check all templates for errors/warnings
suggest_font Suggest system font for a locale's script
compose_screenshots Render final PNGs via Typst

Pipeline & Glossary

Tool Description
run_deliver Run fastlane deliver to upload screenshots
get_glossary Get glossary entries (shared with xcstrings-mcp)
update_glossary Update glossary entries

Prompts

Prompt Description
prepare-app Guide: create ScreenshotMode enum + ScreenshotDataProvider in Swift; documents defaults import for seeding mock data
design-template Guide: design Typst template with OKLCH colors, auto-scaling text, RTL support; includes device frame compositing approaches
generate-screenshots Guide: full 10-step pipeline from scan to deliver; covers warm/seed/interact prep steps and compose internals

Granular Regeneration

All rendering tools accept optional modes and locales filters. Omitting = process all.

"Fix screenshot 3"         → compose_screenshots(modes: [3])
"Fix German text on #5"    → compose_screenshots(modes: [5], locales: ["de-DE"])
"Re-capture stats screen"  → capture_screenshots(modes: [4])

Key Rules

  • OKLCH Only: All colors use oklch(L%, C, Hdeg). No hex, RGB, or HSL.
  • Template Resolution: templates/template-{mode}.typ -> templates/template.typ -> template.typ
  • Locale Fallback: es-MX->es-ES, fr-CA->fr-FR, en-AU/CA/GB->en-US, pt-PT->pt-BR, zh-Hant->zh-Hans
  • Required Sizes: iPhone 6.9" (1320x2868), iPad 13" (2064x2752). Max 10 per locale.

How Screenshot Modes Work

Each app screen is assigned a numeric mode (1-10). The app's ScreenshotMode Swift enum maps modes to specific UI states:

  1. The app is launched with xcrun simctl launch --screenshot-N <udid> <bundle_id> where N is the mode number
  2. ScreenshotDataProvider in the app checks ProcessInfo.processInfo.arguments for --screenshot-N and configures mock data accordingly
  3. For complex state (e.g., streak counts, pro status), use seed_defaults to write UserDefaults before launching the app
  4. capture_screenshots captures a clean framebuffer image per mode — no device bezels
  5. compose_screenshots renders the final PNG via Typst, overlaying captions and optionally adding device frames

Project Directory Structure

project-root/
├── fastlane/
│   ├── metadata/{locale}/    ← keywords.txt, name.txt, subtitle.txt
│   └── screenshots/{locale}/ ← final output
├── appshots.json             ← project config (plan, captions, template)
├── appshots/
│   ├── template.typ          ← single template
│   ├── templates/            ← per-screen templates
│   ├── fonts/                ← custom fonts (.ttf, .otf, .woff2)
│   ├── captures/             ← simulator captures (clean framebuffer)
│   ├── previews/             ← design iteration previews
│   └── .seed-defaults.plist  ← temporary plist for defaults import
├── examples/                 ← reference Typst templates
└── glossary.json             ← shared with xcstrings-mcp

Device Frame Compositing

capture_screenshots produces clean framebuffer images without device bezels. Device frames are added during compose_screenshots via Typst templates. Three approaches:

  1. Raw screenshot — no frame, just the capture with captions overlay
  2. Rounded card — Typst rect(radius: ...) with clip: true to simulate device corners
  3. PNG overlay — place a transparent device frame PNG on top of the screenshot (pixel-perfect Apple bezels)

See examples/template-with-frame.typ for a reference template demonstrating approach #2 with RTL support, auto-scaling text, and OKLCH colors.

Architecture

main.rs     → CLI (clap), tokio current_thread, stdio transport
server.rs   → #[tool_router] (24 tools) + #[prompt_router] (3 prompts)
tools/      → capture, scan, analyze, plan, captions, design, render,
              deliver, validate, glossary — all I/O via FileStore trait
service/    → metadata_parser, locale, keyword_matcher, font_resolver,
              template_resolver, typst_renderer, typst_world, validator,
              config_parser — pure functions, NO I/O
model/      → ProjectConfig, Caption, OklchColor, AsoLocale, Device,
              TemplateConfig — data types with serde + JsonSchema
io/         → FileStore trait + FsFileStore (atomic writes, flock)
error.rs    → AppShotsError enum (thiserror)
prompts.rs  → prompt content generators

Layer rule: server -> tools -> service -> model. Services have NO I/O.

Performance

Operation Target
scan_project (39 locales) < 50ms
compose_screenshots (1) < 100ms
compose_screenshots (all, parallel) < 20s
capture_screenshots (1x1) ~3s

Related

  • MCP Protocol — Model Context Protocol specification
  • xcstrings-mcp — Sister project for .xcstrings localization
  • Typst — The typesetting system used for rendering
  • fastlane — App Store automation

License

Licensed under either of:

at your option.

Contributing

Contributions are welcome! Please open an issue or submit a PR.

About

MCP server for generating ASO-optimized App Store screenshots

Topics

Resources

License

Unknown, MIT licenses found

Licenses found

Unknown
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages