@appscreenshotstudio/mcp 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -32,20 +32,27 @@ const API_KEY = process.env.APPSCREENSHOTSTUDIO_API_KEY;
32
32
  // mcp-server/skills/appscreenshotstudio/SKILL.md (ships in the npm package, so it drifts unseen),
33
33
  // public/api-docs.md (served raw at /api-docs.md, linked from nowhere, so it drifts unseen too)
34
34
  // Enforced by `npm run test:device-specs`, which reads all six files.
35
+ // Hand-copied from lib/device-specs.ts because this package ships standalone.
36
+ // `required` means required to PUBLISH, and it is emitted to agents as
37
+ // "required for store submission", so a wrong flag here is a wrong instruction
38
+ // rather than a cosmetic slip. Keep it in step with the source file.
35
39
  const DEVICES = [
36
40
  { id: 'iphone-6.9', name: 'iPhone 16 Pro Max', width: 1260, height: 2736, category: 'iphone', required: true },
37
41
  { id: 'iphone-6.3', name: 'iPhone 17 Pro', width: 1206, height: 2622, category: 'iphone', required: false },
38
42
  { id: 'ipad-13', name: 'iPad Pro 13"', width: 2064, height: 2752, category: 'ipad', required: true },
39
43
  { id: 'android-phone', name: 'Android Phone', width: 1080, height: 2340, category: 'android-phone', required: true },
40
44
  { id: 'pixel-11-pro', name: 'Google Pixel 11 Pro', width: 1280, height: 2856, category: 'android-phone', required: false },
41
- { id: 'android-tablet-10', name: 'Android Tablet 7"', width: 1200, height: 1920, category: 'android-tablet', required: true },
45
+ { id: 'galaxy-s26-ultra', name: 'Samsung Galaxy S26 Ultra', width: 1440, height: 3120, category: 'android-phone', required: false },
46
+ // Play Console requires 2 screenshots to publish; tablets are "can add", not
47
+ // "must provide". Was `true` until 2026-09-07. See lib/device-specs.ts.
48
+ { id: 'android-tablet-10', name: 'Android Tablet 7"', width: 1200, height: 1920, category: 'android-tablet', required: false },
42
49
  { id: 'android-tablet-large', name: 'Android Tablet 10"', width: 1600, height: 2560, category: 'android-tablet', required: false },
43
50
  { id: 'apple-watch-ultra', name: 'Apple Watch Ultra 2', width: 410, height: 502, category: 'apple-watch', required: true },
44
51
  ];
45
52
  const VALID_DEVICE_IDS = DEVICES.map(d => d.id);
46
53
  // Aliases callers commonly pass instead of the canonical id: display-name
47
54
  // derivations ("iPhone 16 Pro Max" -> iphone-16-pro-max) and legacy slugs.
48
- // Mirrors MARKETING_TO_SPEC in lib/device-specs.ts keep the two in sync.
55
+ // Mirrors MARKETING_TO_SPEC in lib/device-specs.ts. Keep the two in sync.
49
56
  const DEVICE_ALIASES = {
50
57
  'iphone-16-pro': 'iphone-6.9',
51
58
  'iphone-16-pro-max': 'iphone-6.9',
@@ -153,10 +160,10 @@ function buildDesignMessage(input, hasScreenshotImages = false) {
153
160
  parts.push('\nUse the research context above to create screenshots that accurately represent this specific app. Headlines, features, and visual style should reflect what the app actually does and looks like.');
154
161
  }
155
162
  if (hasScreenshotImages) {
156
- parts.push(`\nMy app screenshots are attached they are placed into the device frames automatically.`);
163
+ parts.push(`\nMy app screenshots are attached, and they are placed into the device frames automatically.`);
157
164
  }
158
165
  else {
159
- parts.push(`\nAll device mockups should have screenshotImage: null the developer will upload actual app screenshots later.`);
166
+ parts.push(`\nAll device mockups should have screenshotImage: null. The developer will upload actual app screenshots later.`);
160
167
  }
161
168
  parts.push(`Please include projectMeta with brand colors, mood, appCategory, and a rich globalVisualTheme description.`);
162
169
  return parts.join('\n');
@@ -191,49 +198,58 @@ const chatImagesSchema = z.array(z.object({
191
198
  })).max(5).optional()
192
199
  .describe('Images to attach to this generation. App screenshots land inside the device frames automatically; a mascot gets placed around the phones; a reference only informs the design. All survive later edits and regenerations.');
193
200
  // ─── MCP Server ─────────────────────────────────────────────────────────────────
201
+ // Read from package.json rather than a literal. This is the version a client
202
+ // sees in the MCP handshake, and a hand-synced literal silently sat at 0.6.1
203
+ // through the 0.6.2 release, then at 0.6.3 through 0.7.0 and 0.8.0. A comment
204
+ // asking the next person to remember has now failed twice, so stop asking.
205
+ const PKG_VERSION = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf-8')).version;
194
206
  const server = new McpServer({
195
207
  name: 'appscreenshotstudio',
196
- // Keep in step with package.json: this is the version a client sees in the
197
- // MCP handshake, and it silently sat at 0.6.1 through the 0.6.2 release.
198
- version: '0.6.3',
208
+ version: PKG_VERSION,
199
209
  });
200
210
  // Tool 1: generate-screenshots
201
211
  server.registerTool('generate-screenshots', {
202
212
  title: 'Generate App Store Screenshots',
203
- description: `Create a complete set of App Store screenshot designs for an app. Attach real app screenshots via the images param and they are placed inside the device frames automatically; attach a mascot/character image (kind: "mascot", transparent PNG) and it gets placed around the phones. Returns a project URL where the developer can preview, refine, and export final PNGs.
204
-
205
- IMPORTANT: Before calling this tool, research the user's codebase to populate the codebase_context parameter. Search for: package.json/README (app name & description), theme/color config files (brand colors), route definitions (key screens), marketing copy (value proposition), and App Store metadata. The more context you provide, the better the screenshots will be. Call prepare-screenshot-brief first if you need a research checklist.
206
-
207
- The AI picks a narrative arc that fits the app's sell angle (trust-first for finance/health, visual-first for creative/lifestyle, problem-first for pain-relief apps, numbers-led for SaaS/analytics, community-first for social, feature-forward for multi-mode apps) and assigns a job to each card: HOOK → EDUCATE → PROVE → CONVERT.
208
-
209
- 10 layout types available per card:
210
- - text-top-device-bottom: headline top, flat device bottom (feature/educate)
211
- - text-top-device-tilted: headline left, tilted device right (or mirrored)
212
- - device-hero: headline + large centered device, product-forward
213
- - social-proof: stars + quote + laurel stat, no device (testimonial-led)
214
- - review-clip: rating-statement headline + stars + quote + bottom-clipped device
215
- - screen-hero: top-clipped device + centered headline + optional trust stat
216
- - lifestyle-hero: full-bleed photo background + text overlay (no device)
217
- - stats-hero: giant centered stat(s), no device, numbers-led
218
- - metric-badge: centered device + chunky "achievement card" floating over its screen
219
- - annotated-feature: tilted device + side callout chip linked by a connector line
220
-
221
- Each card can carry auto-positioned compound fields: statRow, laurelStat, pressBanner, starRating, quote, credential ("FDIC insured"-style trust pills), guarantee ("Cancel anytime"-style risk-reversal pills). Trust signals are opt-in: supply the real number, quote or press name, or the card ships clean rather than inventing one.
222
-
223
- Panoramic backgrounds slice one wide AI-generated or Pexels image across multiple cards for cohesion. Panoramic element spans stretch a foreground image or device across adjacent cards. Note: if the design comes back with a panoramic background, the chat only tags the cards; call generate-panoramic-background afterwards to actually create and slice the wide image.
224
-
225
- Design features:
226
- - Rich text with per-word color, weight, italic, underline, highlight pills, gradient fills, stroke outlines, and emoji
227
- - Device perspective variants: flat, left-15/30, right-15/30, isometric, top-down, landscape
228
- - 77 decorative shapes across 13 categories (nature, weather, celebration, social, tech, health, food, travel, abstract, finance, education, pets, emoji), plus 17 core geometric shapes
229
- - Laurel stats: wing-left + wing-right shapes flanking a hero number
230
-
231
- App Store 60/40 rule enforced: minimum 60% of cards must show a device mockup, maximum 40% can be marketing-only.
232
-
213
+ annotations: {
214
+ // Creates a new project; never overwrites an existing one.
215
+ readOnlyHint: false,
216
+ destructiveHint: false,
217
+ openWorldHint: false,
218
+ },
219
+ description: `Create a complete set of App Store screenshot designs for an app. Attach real app screenshots via the images param and they are placed inside the device frames automatically; attach a mascot/character image (kind: "mascot", transparent PNG) and it gets placed around the phones. Returns a project URL where the developer can preview, refine, and export final PNGs.
220
+
221
+ IMPORTANT: Before calling this tool, research the user's codebase to populate the codebase_context parameter. Search for: package.json/README (app name & description), theme/color config files (brand colors), route definitions (key screens), marketing copy (value proposition), and App Store metadata. The more context you provide, the better the screenshots will be. Call prepare-screenshot-brief first if you need a research checklist.
222
+
223
+ The AI picks a narrative arc that fits the app's sell angle (trust-first for finance/health, visual-first for creative/lifestyle, problem-first for pain-relief apps, numbers-led for SaaS/analytics, community-first for social, feature-forward for multi-mode apps) and assigns a job to each card: HOOK → EDUCATE → PROVE → CONVERT.
224
+
225
+ 10 layout types available per card:
226
+ - text-top-device-bottom: headline top, flat device bottom (feature/educate)
227
+ - text-top-device-tilted: headline left, tilted device right (or mirrored)
228
+ - device-hero: headline + large centered device, product-forward
229
+ - social-proof: stars + quote + laurel stat, no device (testimonial-led)
230
+ - review-clip: rating-statement headline + stars + quote + bottom-clipped device
231
+ - screen-hero: top-clipped device + centered headline + optional trust stat
232
+ - lifestyle-hero: full-bleed photo background + text overlay (no device)
233
+ - stats-hero: giant centered stat(s), no device, numbers-led
234
+ - metric-badge: centered device + chunky "achievement card" floating over its screen
235
+ - annotated-feature: tilted device + side callout chip linked by a connector line
236
+
237
+ Each card can carry auto-positioned compound fields: statRow, laurelStat, pressBanner, starRating, quote, credential ("FDIC insured"-style trust pills), guarantee ("Cancel anytime"-style risk-reversal pills). Trust signals are opt-in: supply the real number, quote or press name, or the card ships clean rather than inventing one.
238
+
239
+ Panoramic backgrounds slice one wide AI-generated or Pexels image across multiple cards for cohesion. Panoramic element spans stretch a foreground image or device across adjacent cards. Note: if the design comes back with a panoramic background, the chat only tags the cards; call generate-panoramic-background afterwards to actually create and slice the wide image.
240
+
241
+ Design features:
242
+ - Rich text with per-word color, weight, italic, underline, highlight pills, gradient fills, stroke outlines, and emoji
243
+ - Device perspective variants: flat, left-15/30, right-15/30, isometric, top-down, landscape
244
+ - 77 decorative shapes across 13 categories (nature, weather, celebration, social, tech, health, food, travel, abstract, finance, education, pets, emoji), plus 17 core geometric shapes
245
+ - Laurel stats: wing-left + wing-right shapes flanking a hero number
246
+
247
+ App Store 60/40 rule enforced: minimum 60% of cards must show a device mockup, maximum 40% can be marketing-only.
248
+
233
249
  Costs 5 credits per generation.`,
234
250
  inputSchema: z.object({
235
251
  app_name: z.string().describe('Name of the app'),
236
- app_description: z.string().describe('What the app does 1-3 sentences'),
252
+ app_description: z.string().describe('What the app does, in 1-3 sentences'),
237
253
  features: z.array(z.string()).max(10).optional()
238
254
  .describe('Key features in order of importance. The first 2-3 will be highlighted most prominently.'),
239
255
  brand_colors: z.object({
@@ -242,7 +258,7 @@ Costs 5 credits per generation.`,
242
258
  accent: z.string().optional().describe('Accent color as hex'),
243
259
  }).optional().describe('Brand colors to use in the design'),
244
260
  mood: z.string().optional()
245
- .describe('Design mood e.g. "energetic", "calm", "minimal", "bold", "professional", "playful"'),
261
+ .describe('Design mood, e.g. "energetic", "calm", "minimal", "bold", "professional", "playful"'),
246
262
  device_id: z.string().default('iphone-6.9')
247
263
  .describe(`Target device. Options: ${VALID_DEVICE_IDS.join(', ')}. Default: iphone-6.9 (iPhone 16 Pro Max)`),
248
264
  count: z.number().min(3).max(10).default(5)
@@ -251,27 +267,27 @@ Costs 5 credits per generation.`,
251
267
  .describe('Narrative structure for the screenshots. "auto" lets the AI choose the best flow.'),
252
268
  codebase_context: z.object({
253
269
  readme_summary: z.string().optional()
254
- .describe('Summary of the app from README or docs what does it do and why?'),
270
+ .describe('Summary of the app from README or docs: what does it do and why?'),
255
271
  key_screens: z.array(z.string()).max(15).optional()
256
- .describe('Main screens/views in the app e.g. "Dashboard with activity feed", "Settings with theme toggle"'),
272
+ .describe('Main screens/views in the app, e.g. "Dashboard with activity feed", "Settings with theme toggle"'),
257
273
  color_tokens: z.record(z.string()).optional()
258
- .describe('Brand/theme colors found in code e.g. {"primary": "#7C3AED", "background": "#0F172A"}'),
274
+ .describe('Brand/theme colors found in code, e.g. {"primary": "#7C3AED", "background": "#0F172A"}'),
259
275
  target_audience: z.string().optional()
260
- .describe('Who the app is for e.g. "busy professionals who want to track habits"'),
276
+ .describe('Who the app is for, e.g. "busy professionals who want to track habits"'),
261
277
  app_category: z.string().optional()
262
- .describe('App category e.g. fitness, finance, social, productivity, food, travel, health, education'),
278
+ .describe('App category, e.g. fitness, finance, social, productivity, food, travel, health, education'),
263
279
  competitive_edge: z.string().optional()
264
280
  .describe('What makes this app unique vs competitors'),
265
281
  app_store_description: z.string().optional()
266
282
  .describe('Existing App Store/Play Store description if found in the codebase'),
267
283
  tech_stack: z.string().optional()
268
- .describe('Tech stack e.g. "React Native", "SwiftUI", "Flutter". Useful for developer-tool apps.'),
284
+ .describe('Tech stack, e.g. "React Native", "SwiftUI", "Flutter". Useful for developer-tool apps.'),
269
285
  ui_style: z.string().optional()
270
- .describe('UI style observations e.g. "dark mode with neon accents", "clean minimal with lots of whitespace"'),
286
+ .describe('UI style observations, e.g. "dark mode with neon accents", "clean minimal with lots of whitespace"'),
271
287
  primary_user_flow: z.string().optional()
272
- .describe('The main user journey e.g. "Sign up → Create project → Invite team → Track progress"'),
288
+ .describe('The main user journey, e.g. "Sign up → Create project → Invite team → Track progress"'),
273
289
  }).optional()
274
- .describe('Context gathered from researching the app codebase. Dramatically improves screenshot quality the more detail here, the better the output.'),
290
+ .describe('Context gathered from researching the app codebase. Dramatically improves screenshot quality. The more detail here, the better the output.'),
275
291
  images: chatImagesSchema,
276
292
  }),
277
293
  }, async (input) => {
@@ -346,48 +362,54 @@ Costs 5 credits per generation.`,
346
362
  // Tool 2: edit-screenshots
347
363
  server.registerTool('edit-screenshots', {
348
364
  title: 'Edit Screenshot Designs',
349
- description: `Make changes to an existing screenshot project. Use natural language to describe what you want to change. Costs 5 credits per edit. You can also attach images: app screenshots fill the device frames of regenerated cards, a mascot (kind: "mascot") gets placed around the phones.
350
-
351
- What you can change:
352
- - Text: headlines, subtitles, badge text, font size, font family (Inter, Poppins, Montserrat, DM Sans, Space Grotesk, etc.)
353
- - Text styling: per-word color, bold, italic, underline, highlight pills (colored background behind words), gradient text, text stroke outlines
354
- - Colors: brand palette, gradient backgrounds, accent colors, text colors. A set can rotate MULTIPLE accents card by card ("pink, then coral, then brick") and each card keeps its own highlight colour.
355
- - Background textures (ask for one explicitly, they are never added on their own): diagonal-stripe, crosshatch, checkerboard, zigzag, hairline-grid, dot-grid, waves, grain, radial-rays, concentric-circles. Kept subtle by design so they cannot affect headline contrast. Tiled textures run continuously across the whole set; radial-rays and concentric-circles can be centred on the middle of the set so the pattern fans out across every card.
356
- - Layouts (10 types): text-top-device-bottom, text-top-device-tilted, device-hero, social-proof, review-clip, screen-hero, lifestyle-hero, stats-hero, metric-badge, annotated-feature. The AI picks a narrative arc (HOOK → EDUCATE → PROVE → CONVERT) across the set.
357
- - Layout params: deviceScale (small/medium/large), deviceSide (left/right), textPosition (above/below), textAlign (left/center)
358
- - Device mockups: perspective variants (flat, left-15, right-15, left-30, right-30, isometric, top-down, landscape-left, landscape-right), 2D rotation, resize, reposition
359
- - Frame color: recolor the device frame — "natural" (default), "black", "white", "gold". Examples: "make the iPhone gold", "black titanium finish", "white iPhone". Requires Growth plan or higher.
360
- - Switch devices: "make this for Apple Watch" / "duplicate for Android tablet" clones the project at the target device's canvas size
361
- - Add/remove cards: add a social proof card, remove card 3, add a marketing title card
362
- - Compound fields (auto-positioned): statRow, laurelStat, pressBanner, starRating, quote, credential, guarantee
363
- - Panoramic backgrounds: one wide AI or Pexels image sliced across multiple cards ("pano the background across cards 1-3"). The edit only tags the cards; call generate-panoramic-background afterwards to create and slice the wide image.
364
- - Panoramic element spans: stretch a foreground image, device-mockup, or shape across adjacent cards ("pano the device across cards 1-2")
365
- - Floating elements: add/edit badges, star ratings
366
- - Shapes: glow orbs, waves, blobs, rounded rectangles, circles, custom SVG paths
367
- - Decorative shapes: 77 library shapes leaf, flower, cloud, sparkle, heart, rocket, trophy, crown, coffee-cup, airplane, dollar-sign, paw-print, wing-left/wing-right (for laurels), and many more
368
- - Backgrounds: solid, subtle-gradient, rich-gradient, photo (Pexels), or ai-generated; change gradient colors/angle; set a backgroundPrompt for AI-generated
369
- - Style: shadows, opacity, border radius, rotation, blur
370
-
371
- What isn't supported (the AI will flag these in unsupportedAsks):
372
- - Multiple devices side-by-side in a single card (e.g. iPhone + Watch in one scene) — each card renders one device. Use the duplicate-for-device workflow instead, or split across cards.
373
- - Uploading a specific user-supplied screenshot into a mockup use upload-screenshots tool first, then reference the uploaded project.
374
-
375
- Example edit messages:
376
- - "Make the headlines larger and use Bebas Neue font"
377
- - "Change the color scheme to blue (#2563EB) across all cards"
378
- - "Add a social proof card with 5 stars and a testimonial quote"
379
- - "Tilt the phone on card 2 to the left"
380
- - "Pano the background photo across cards 1-3"
381
- - "Stretch the device on card 1 across into card 2"
382
- - "Make this project for Apple Watch"
383
- - "Recolor the iPhone frame to gold across all cards"
384
- - "Replace card 3 with a CTA card saying Download Free"
385
- - "Switch card 2 to device-hero layout with statRow showing our three key metrics"
386
- - "Add decorative leaf and sparkle shapes scattered in the background"
365
+ annotations: {
366
+ // Rewrites cards in place, so a bad edit costs the previous design.
367
+ readOnlyHint: false,
368
+ destructiveHint: true,
369
+ openWorldHint: false,
370
+ },
371
+ description: `Make changes to an existing screenshot project. Use natural language to describe what you want to change. Costs 5 credits per edit. You can also attach images: app screenshots fill the device frames of regenerated cards, a mascot (kind: "mascot") gets placed around the phones.
372
+
373
+ What you can change:
374
+ - Text: headlines, subtitles, badge text, font size, font family (Inter, Poppins, Montserrat, DM Sans, Space Grotesk, etc.)
375
+ - Text styling: per-word color, bold, italic, underline, highlight pills (colored background behind words), gradient text, text stroke outlines
376
+ - Colors: brand palette, gradient backgrounds, accent colors, text colors. A set can rotate MULTIPLE accents card by card ("pink, then coral, then brick") and each card keeps its own highlight colour.
377
+ - Background textures (ask for one explicitly, they are never added on their own): diagonal-stripe, crosshatch, checkerboard, zigzag, hairline-grid, dot-grid, waves, grain, radial-rays, concentric-circles. Kept subtle by design so they cannot affect headline contrast. Tiled textures run continuously across the whole set; radial-rays and concentric-circles can be centred on the middle of the set so the pattern fans out across every card.
378
+ - Layouts (10 types): text-top-device-bottom, text-top-device-tilted, device-hero, social-proof, review-clip, screen-hero, lifestyle-hero, stats-hero, metric-badge, annotated-feature. The AI picks a narrative arc (HOOK → EDUCATE → PROVE → CONVERT) across the set.
379
+ - Layout params: deviceScale (small/medium/large), deviceSide (left/right), textPosition (above/below), textAlign (left/center)
380
+ - Device mockups: perspective variants (flat, left-15, right-15, left-30, right-30, isometric, top-down, landscape-left, landscape-right), 2D rotation, resize, reposition
381
+ - Frame color: recolor the device frame: "natural" (default), "black", "white", "gold". Examples: "make the iPhone gold", "black titanium finish", "white iPhone". Requires Growth plan or higher.
382
+ - Switch devices: "make this for Apple Watch" / "duplicate for Android tablet" clones the project at the target device's canvas size
383
+ - Add/remove cards: add a social proof card, remove card 3, add a marketing title card
384
+ - Compound fields (auto-positioned): statRow, laurelStat, pressBanner, starRating, quote, credential, guarantee
385
+ - Panoramic backgrounds: one wide AI or Pexels image sliced across multiple cards ("pano the background across cards 1-3"). The edit only tags the cards; call generate-panoramic-background afterwards to create and slice the wide image.
386
+ - Panoramic element spans: stretch a foreground image, device-mockup, or shape across adjacent cards ("pano the device across cards 1-2")
387
+ - Floating elements: add/edit badges, star ratings
388
+ - Shapes: glow orbs, waves, blobs, rounded rectangles, circles, custom SVG paths
389
+ - Decorative shapes: 77 library shapes: leaf, flower, cloud, sparkle, heart, rocket, trophy, crown, coffee-cup, airplane, dollar-sign, paw-print, wing-left/wing-right (for laurels), and many more
390
+ - Backgrounds: solid, subtle-gradient, rich-gradient, photo (Pexels), or ai-generated; change gradient colors/angle; set a backgroundPrompt for AI-generated
391
+ - Style: shadows, opacity, border radius, rotation, blur
392
+
393
+ What isn't supported (the AI will flag these in unsupportedAsks):
394
+ - Multiple devices side-by-side in a single card (e.g. iPhone + Watch in one scene). Each card renders one device. Use the duplicate-for-device workflow instead, or split across cards.
395
+ - Uploading a specific user-supplied screenshot into a mockup: use upload-screenshots tool first, then reference the uploaded project.
396
+
397
+ Example edit messages:
398
+ - "Make the headlines larger and use Bebas Neue font"
399
+ - "Change the color scheme to blue (#2563EB) across all cards"
400
+ - "Add a social proof card with 5 stars and a testimonial quote"
401
+ - "Tilt the phone on card 2 to the left"
402
+ - "Pano the background photo across cards 1-3"
403
+ - "Stretch the device on card 1 across into card 2"
404
+ - "Make this project for Apple Watch"
405
+ - "Recolor the iPhone frame to gold across all cards"
406
+ - "Replace card 3 with a CTA card saying Download Free"
407
+ - "Switch card 2 to device-hero layout with statRow showing our three key metrics"
408
+ - "Add decorative leaf and sparkle shapes scattered in the background"
387
409
  - "Make 'Every' underlined and italic in the headline"`,
388
410
  inputSchema: z.object({
389
411
  project_id: z.string().describe('Project ID from a previous generate-screenshots call'),
390
- message: z.string().describe('What to change use natural language'),
412
+ message: z.string().describe('What to change, in natural language'),
391
413
  card_indices: z.array(z.number().int().min(0)).max(10).optional()
392
414
  .describe('Target specific cards by index (0-based). e.g. [0] for card 1, [2,3] for cards 3-4. Max 10 indices. Omit to apply changes to all cards.'),
393
415
  codebase_context: z.object({
@@ -464,6 +486,13 @@ Example edit messages:
464
486
  // Tool 3: render-screenshots
465
487
  server.registerTool('render-screenshots', {
466
488
  title: 'Render Screenshots to PNG',
489
+ annotations: {
490
+ // Re-rendering the same project state yields the same PNGs.
491
+ readOnlyHint: false,
492
+ destructiveHint: false,
493
+ idempotentHint: true,
494
+ openWorldHint: false,
495
+ },
467
496
  description: 'Export a screenshot project to high-resolution PNG files at exact App Store dimensions. Returns download URLs for each card; URLs stay valid for 7 days, so save the PNGs to disk promptly (re-rendering is free if a URL has expired). Free (no credit cost). Rendering blocks until the PNGs are ready: expect roughly 20-40s for iPhone sets and 60-120s for iPad (the larger canvas renders slower), so allow up to ~2 minutes before treating it as failed. Note: device mockups will show empty frames unless app screenshots have been uploaded via upload-screenshots first.',
468
497
  inputSchema: z.object({
469
498
  project_id: z.string().describe('Project ID to render'),
@@ -511,10 +540,15 @@ server.registerTool('render-screenshots', {
511
540
  // Tool 4: list-devices
512
541
  server.registerTool('list-devices', {
513
542
  title: 'List Supported Devices',
543
+ annotations: {
544
+ // Reads a local constant; makes no API call at all.
545
+ readOnlyHint: true,
546
+ openWorldHint: false,
547
+ },
514
548
  description: 'Show all supported device specs for App Store and Play Store screenshots. Use the device ID when generating screenshots.',
515
549
  inputSchema: z.object({}),
516
550
  }, async () => {
517
- const lines = DEVICES.map(d => `${d.id} ${d.name} (${d.width}×${d.height}, ${d.category}${d.required ? ', required for store submission' : ''})`);
551
+ const lines = DEVICES.map(d => `${d.id}: ${d.name} (${d.width}×${d.height}, ${d.category}${d.required ? ', required for store submission' : ''})`);
518
552
  return {
519
553
  content: [{
520
554
  type: 'text',
@@ -532,14 +566,18 @@ server.registerTool('list-devices', {
532
566
  // Tool 5: get-project
533
567
  server.registerTool('get-project', {
534
568
  title: 'Get Project Details',
535
- description: `Retrieve the full state of a screenshot project, including all cards and their elements. Use this to inspect what was generated before making edits. Free — no credit cost.
536
-
537
- Returns the canvas state with:
538
- - cards[]: each card has an id, elements array, and optional background settings
539
- - Each element has: type (text, device-mockup, shape, badge, image, star-rating), position (x, y), size (width, height), zIndex, and type-specific properties
540
- - Text elements: fontFamily, fontSize, fontWeight, color, segments (for multi-color text with per-word color, bold, italic, underline, highlightColor)
541
- - Device mockups: perspectiveVariant (flat, left-15, right-15, left-30, right-30, isometric, top-down, landscape-left, landscape-right), screenshotImage (null if no upload), frameStyle (realistic | none), showIsland (false hides the Dynamic Island pill; Apple accepts screenshots either way)
542
- - Shapes: 94 shape types (17 core + 77 decorative across 13 categories) — core shapes (circle, rectangle, rounded-rect, blob, wave, triangle, diamond, hexagon, ring, star, wing-left, wing-right, etc.) plus decorative library shapes (leaf, flower, cloud, sparkle, heart, rocket, trophy, crown, coffee-cup, airplane, dollar-sign, paw-print, and many more)
569
+ annotations: {
570
+ readOnlyHint: true,
571
+ openWorldHint: false,
572
+ },
573
+ description: `Retrieve the full state of a screenshot project, including all cards and their elements. Use this to inspect what was generated before making edits. Free: no credit cost.
574
+
575
+ Returns the canvas state with:
576
+ - cards[]: each card has an id, elements array, and optional background settings
577
+ - Each element has: type (text, device-mockup, shape, badge, image, star-rating), position (x, y), size (width, height), zIndex, and type-specific properties
578
+ - Text elements: fontFamily, fontSize, fontWeight, color, segments (for multi-color text with per-word color, bold, italic, underline, highlightColor)
579
+ - Device mockups: perspectiveVariant (flat, left-15, right-15, left-30, right-30, isometric, top-down, landscape-left, landscape-right), screenshotImage (null if no upload), frameStyle (realistic | none), showIsland (false hides the Dynamic Island pill; Apple accepts screenshots either way)
580
+ - Shapes: 94 shape types (17 core + 77 decorative across 13 categories): core shapes (circle, rectangle, rounded-rect, blob, wave, triangle, diamond, hexagon, ring, star, wing-left, wing-right, etc.) plus decorative library shapes (leaf, flower, cloud, sparkle, heart, rocket, trophy, crown, coffee-cup, airplane, dollar-sign, paw-print, and many more)
543
581
  - projectMeta: globalVisualTheme, brandColors, mood, appCategory`,
544
582
  inputSchema: z.object({
545
583
  project_id: z.string().describe('Project ID to inspect'),
@@ -560,7 +598,7 @@ Returns the canvas state with:
560
598
  typeCounts[t] = (typeCounts[t] || 0) + 1;
561
599
  }
562
600
  const typeStr = Object.entries(typeCounts).map(([t, c]) => `${c} ${t}`).join(', ');
563
- return ` Card ${i} (${card.id}): ${card.elements.length} elements ${typeStr}`;
601
+ return ` Card ${i} (${card.id}): ${card.elements.length} elements: ${typeStr}`;
564
602
  }) || [];
565
603
  return {
566
604
  content: [{
@@ -584,19 +622,25 @@ Returns the canvas state with:
584
622
  // Tool 6: generate-background
585
623
  server.registerTool('generate-background', {
586
624
  title: 'Generate AI Background',
587
- description: `Generate an AI background image for a specific card using Gemini. The background is generated based on a text prompt and applied directly to the card. Costs 6 credits.
588
-
589
- Good prompts describe mood, lighting, and color — not objects or text:
590
- - "Deep purple nebula with soft pink and blue light rays"
591
- - "Warm sunset gradient with golden bokeh particles"
592
- - "Dark moody atmosphere with teal and emerald glow"
593
- - "Clean minimal white-to-light-gray gradient with subtle noise texture"
594
-
625
+ annotations: {
626
+ // Replaces the card's existing background.
627
+ readOnlyHint: false,
628
+ destructiveHint: true,
629
+ openWorldHint: false,
630
+ },
631
+ description: `Generate an AI background image for a specific card using Gemini. The background is generated based on a text prompt and applied directly to the card. Costs 6 credits.
632
+
633
+ Good prompts describe mood, lighting, and color, not objects or text:
634
+ - "Deep purple nebula with soft pink and blue light rays"
635
+ - "Warm sunset gradient with golden bokeh particles"
636
+ - "Dark moody atmosphere with teal and emerald glow"
637
+ - "Clean minimal white-to-light-gray gradient with subtle noise texture"
638
+
595
639
  The generated image is cropped to exact device dimensions and set as the card's background.`,
596
640
  inputSchema: z.object({
597
641
  project_id: z.string().describe('Project ID'),
598
642
  card_index: z.number().describe('Card index (0-based) to apply the background to'),
599
- prompt: z.string().describe('Background description describe mood, lighting, colors, textures. Do NOT include text, devices, or UI elements.'),
643
+ prompt: z.string().describe('Background description: describe mood, lighting, colors, textures. Do NOT include text, devices, or UI elements.'),
600
644
  }),
601
645
  }, async ({ project_id, card_index, prompt }) => {
602
646
  const res = await apiCall('POST', `/api/v1/projects/${project_id}/generate-background`, {
@@ -623,17 +667,23 @@ The generated image is cropped to exact device dimensions and set as the card's
623
667
  // Tool 7: generate-panoramic-background
624
668
  server.registerTool('generate-panoramic-background', {
625
669
  title: 'Generate Panoramic Background',
626
- description: `Generate one wide background image and slice it across multiple cards so they read as a continuous scene when the App Store gallery scrolls. The store gallery gap is accounted for, so slices line up after Apple's gutter.
627
-
628
- Two image sources:
629
- - prompt: AI-generated via Gemini. Costs 6 credits.
630
- - pexels_query: stock landscape photo from Pexels. Free.
631
-
632
- If you omit both, the tool fulfills a panoramic the chat already set up: when generate-screenshots or edit-screenshots returns a design with a panoramic background (e.g. after "pano the background across cards 1-3"), the cards are tagged but the wide image isn't created yet. Calling this tool with just the project_id picks up that pending panoramic and generates it.
633
-
634
- Good prompts describe a continuous scene, not objects or text:
635
- - "Misty mountain range at dawn, soft pink-to-blue gradient sky"
636
- - "Calm ocean horizon at golden hour with gentle waves"
670
+ annotations: {
671
+ // Replaces the background on every card in the span.
672
+ readOnlyHint: false,
673
+ destructiveHint: true,
674
+ openWorldHint: false,
675
+ },
676
+ description: `Generate one wide background image and slice it across multiple cards so they read as a continuous scene when the App Store gallery scrolls. The store gallery gap is accounted for, so slices line up after Apple's gutter.
677
+
678
+ Two image sources:
679
+ - prompt: AI-generated via Gemini. Costs 6 credits.
680
+ - pexels_query: stock landscape photo from Pexels. Free.
681
+
682
+ If you omit both, the tool fulfills a panoramic the chat already set up: when generate-screenshots or edit-screenshots returns a design with a panoramic background (e.g. after "pano the background across cards 1-3"), the cards are tagged but the wide image isn't created yet. Calling this tool with just the project_id picks up that pending panoramic and generates it.
683
+
684
+ Good prompts describe a continuous scene, not objects or text:
685
+ - "Misty mountain range at dawn, soft pink-to-blue gradient sky"
686
+ - "Calm ocean horizon at golden hour with gentle waves"
637
687
  - "Abstract flowing emerald and teal silk waves"`,
638
688
  inputSchema: z.object({
639
689
  project_id: z.string().describe('Project ID'),
@@ -671,16 +721,20 @@ Good prompts describe a continuous scene, not objects or text:
671
721
  // Tool 8: prepare-screenshot-brief
672
722
  server.registerTool('prepare-screenshot-brief', {
673
723
  title: 'Prepare Screenshot Brief',
674
- description: `Get a category playbook and repo-research checklist to prepare for screenshot generation. Call this BEFORE generate-screenshots. Free (no credits).
675
-
676
- Pass app_category to get category-specific guidance pulled live from AppScreenshotStudio: the frame-1 hook playbook (default layout, what to avoid, caption patterns), the recommended story_flow and mood, and the exact facts to dig out of THIS app's repo for its category (e.g. security and compliance signals for finance, real gameplay art for games, the outcome for fitness).
677
-
678
- Returns:
679
- - A category playbook (frame-1 hooks + layout + arc + mood) for the app_category
680
- - A category-specific repo research focus (what to grep this app for)
681
- - A generic codebase research checklist (file patterns per tech stack)
682
- - Headline tips + the codebase_context schema to fill in
683
-
724
+ annotations: {
725
+ readOnlyHint: true,
726
+ openWorldHint: false,
727
+ },
728
+ description: `Get a category playbook and repo-research checklist to prepare for screenshot generation. Call this BEFORE generate-screenshots. Free (no credits).
729
+
730
+ Pass app_category to get category-specific guidance pulled live from AppScreenshotStudio: the frame-1 hook playbook (default layout, what to avoid, caption patterns), the recommended story_flow and mood, and the exact facts to dig out of THIS app's repo for its category (e.g. security and compliance signals for finance, real gameplay art for games, the outcome for fitness).
731
+
732
+ Returns:
733
+ - A category playbook (frame-1 hooks + layout + arc + mood) for the app_category
734
+ - A category-specific repo research focus (what to grep this app for)
735
+ - A generic codebase research checklist (file patterns per tech stack)
736
+ - Headline tips + the codebase_context schema to fill in
737
+
684
738
  The more you gather here, the better generate-screenshots does on the first try.`,
685
739
  inputSchema: z.object({
686
740
  app_category: z.string().optional()
@@ -690,7 +744,7 @@ The more you gather here, the better generate-screenshots does on the first try.
690
744
  }),
691
745
  }, async ({ app_category, platform }) => {
692
746
  const checklist = [
693
- '# Screenshot Brief Research Checklist',
747
+ '# Screenshot Brief: Research Checklist',
694
748
  '',
695
749
  'Search the codebase for each of these before calling generate-screenshots.',
696
750
  'The more you find, the better the screenshots will be.',
@@ -796,7 +850,7 @@ The more you gather here, the better generate-screenshots does on the first try.
796
850
  '- Lead with USER BENEFIT, not feature name: "Never forget a task" > "Task Management"',
797
851
  '- Use power words: Track, Save, Build, Discover, Master, Simplify, Automate',
798
852
  '- Include numbers when possible: "3x faster", "10K+ recipes", "Save 2hrs/week"',
799
- '- First 3 screenshots matter most App Store shows them in search results',
853
+ '- First 3 screenshots matter most: App Store shows them in search results',
800
854
  '- Hero card headline = your one-sentence pitch. Make it count.',
801
855
  '- Keep headlines under 6 words. Subtitle can add detail.',
802
856
  ];
@@ -810,15 +864,15 @@ The more you gather here, the better generate-screenshots does on the first try.
810
864
  ];
811
865
  if (platform === 'ios' || platform === 'both') {
812
866
  deviceTips.push('**iOS (required for App Store):**');
813
- deviceTips.push('- iPhone 16 Pro Max (iphone-6.9): 1260×2736 REQUIRED');
814
- deviceTips.push('- iPad Pro 13" (ipad-13): 2064×2752 REQUIRED');
867
+ deviceTips.push('- iPhone 16 Pro Max (iphone-6.9): 1260×2736: REQUIRED');
868
+ deviceTips.push('- iPad Pro 13" (ipad-13): 2064×2752: REQUIRED');
815
869
  deviceTips.push('');
816
870
  }
817
871
  if (platform === 'android' || platform === 'both') {
818
872
  deviceTips.push('**Android (required for Play Store):**');
819
- deviceTips.push('- Android Phone (android-phone): 1080×2340 REQUIRED');
820
- deviceTips.push('- Android Tablet 7" (android-tablet-10): 1200×1920 REQUIRED');
821
- deviceTips.push('- Android Tablet 10" (android-tablet-large): 1600×2560 second large-screen slot');
873
+ deviceTips.push('- Android Phone (android-phone): 1080×2340: REQUIRED');
874
+ deviceTips.push('- Android Tablet 7" (android-tablet-10): 1200×1920: REQUIRED');
875
+ deviceTips.push('- Android Tablet 10" (android-tablet-large): 1600×2560: second large-screen slot');
822
876
  deviceTips.push('');
823
877
  }
824
878
  // Schema reminder
@@ -861,21 +915,27 @@ The more you gather here, the better generate-screenshots does on the first try.
861
915
  // Tool 9: upload-screenshots
862
916
  server.registerTool('upload-screenshots', {
863
917
  title: 'Upload App Screenshots',
864
- description: `Upload local app screenshots (from Simulator, emulator, or screen captures) into the device mockups of an existing project. This lets you add real app UI into the device frames without leaving the terminal.
865
-
866
- Reads files from your local filesystem, converts them to base64, and sets them on the device mockup elements in the specified cards.
867
-
868
- Free — no credit cost. The screenshots are placed into the device frames that were created by generate-screenshots.
869
-
870
- Workflow:
871
- 1. generate-screenshots → creates project with empty device frames
872
- 2. upload-screenshots fills the device frames with your actual app UI
873
- 3. render-screenshots → exports final PNGs at App Store dimensions
874
-
875
- Tips:
876
- - Take screenshots from the iOS Simulator (Cmd+S) or Android emulator
877
- - Use PNG format for best quality
878
- - Screenshots are automatically fitted into the device frame
918
+ annotations: {
919
+ // Overwrites whatever image the device frames already held.
920
+ readOnlyHint: false,
921
+ destructiveHint: true,
922
+ openWorldHint: false,
923
+ },
924
+ description: `Upload local app screenshots (from Simulator, emulator, or screen captures) into the device mockups of an existing project. This lets you add real app UI into the device frames without leaving the terminal.
925
+
926
+ Reads files from your local filesystem, converts them to base64, and sets them on the device mockup elements in the specified cards.
927
+
928
+ Free: no credit cost. The screenshots are placed into the device frames that were created by generate-screenshots.
929
+
930
+ Workflow:
931
+ 1. generate-screenshots creates project with empty device frames
932
+ 2. upload-screenshots fills the device frames with your actual app UI
933
+ 3. render-screenshots → exports final PNGs at App Store dimensions
934
+
935
+ Tips:
936
+ - Take screenshots from the iOS Simulator (Cmd+S) or Android emulator
937
+ - Use PNG format for best quality
938
+ - Screenshots are automatically fitted into the device frame
879
939
  - You can upload different screenshots to different cards`,
880
940
  inputSchema: z.object({
881
941
  project_id: z.string().describe('Project ID from a previous generate-screenshots call'),
@@ -959,7 +1019,7 @@ function autoInstallSkill() {
959
1019
  copyFileSync(src, dest);
960
1020
  }
961
1021
  catch {
962
- // Silent fail skill install is optional
1022
+ // Silent fail: skill install is optional
963
1023
  }
964
1024
  }
965
1025
  async function main() {