@appscreenshotstudio/mcp 0.8.0 → 0.8.1

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
@@ -38,6 +38,7 @@ const DEVICES = [
38
38
  { id: 'ipad-13', name: 'iPad Pro 13"', width: 2064, height: 2752, category: 'ipad', required: true },
39
39
  { id: 'android-phone', name: 'Android Phone', width: 1080, height: 2340, category: 'android-phone', required: true },
40
40
  { id: 'pixel-11-pro', name: 'Google Pixel 11 Pro', width: 1280, height: 2856, category: 'android-phone', required: false },
41
+ { id: 'galaxy-s26-ultra', name: 'Samsung Galaxy S26 Ultra', width: 1440, height: 3120, category: 'android-phone', required: false },
41
42
  { id: 'android-tablet-10', name: 'Android Tablet 7"', width: 1200, height: 1920, category: 'android-tablet', required: true },
42
43
  { id: 'android-tablet-large', name: 'Android Tablet 10"', width: 1600, height: 2560, category: 'android-tablet', required: false },
43
44
  { id: 'apple-watch-ultra', name: 'Apple Watch Ultra 2', width: 410, height: 502, category: 'apple-watch', required: true },
@@ -45,7 +46,7 @@ const DEVICES = [
45
46
  const VALID_DEVICE_IDS = DEVICES.map(d => d.id);
46
47
  // Aliases callers commonly pass instead of the canonical id: display-name
47
48
  // 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.
49
+ // Mirrors MARKETING_TO_SPEC in lib/device-specs.ts. Keep the two in sync.
49
50
  const DEVICE_ALIASES = {
50
51
  'iphone-16-pro': 'iphone-6.9',
51
52
  'iphone-16-pro-max': 'iphone-6.9',
@@ -153,10 +154,10 @@ function buildDesignMessage(input, hasScreenshotImages = false) {
153
154
  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
155
  }
155
156
  if (hasScreenshotImages) {
156
- parts.push(`\nMy app screenshots are attached they are placed into the device frames automatically.`);
157
+ parts.push(`\nMy app screenshots are attached, and they are placed into the device frames automatically.`);
157
158
  }
158
159
  else {
159
- parts.push(`\nAll device mockups should have screenshotImage: null the developer will upload actual app screenshots later.`);
160
+ parts.push(`\nAll device mockups should have screenshotImage: null. The developer will upload actual app screenshots later.`);
160
161
  }
161
162
  parts.push(`Please include projectMeta with brand colors, mood, appCategory, and a rich globalVisualTheme description.`);
162
163
  return parts.join('\n');
@@ -191,49 +192,58 @@ const chatImagesSchema = z.array(z.object({
191
192
  })).max(5).optional()
192
193
  .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
194
  // ─── MCP Server ─────────────────────────────────────────────────────────────────
195
+ // Read from package.json rather than a literal. This is the version a client
196
+ // sees in the MCP handshake, and a hand-synced literal silently sat at 0.6.1
197
+ // through the 0.6.2 release, then at 0.6.3 through 0.7.0 and 0.8.0. A comment
198
+ // asking the next person to remember has now failed twice, so stop asking.
199
+ const PKG_VERSION = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf-8')).version;
194
200
  const server = new McpServer({
195
201
  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',
202
+ version: PKG_VERSION,
199
203
  });
200
204
  // Tool 1: generate-screenshots
201
205
  server.registerTool('generate-screenshots', {
202
206
  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
-
207
+ annotations: {
208
+ // Creates a new project; never overwrites an existing one.
209
+ readOnlyHint: false,
210
+ destructiveHint: false,
211
+ openWorldHint: false,
212
+ },
213
+ 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.
214
+
215
+ 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.
216
+
217
+ 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.
218
+
219
+ 10 layout types available per card:
220
+ - text-top-device-bottom: headline top, flat device bottom (feature/educate)
221
+ - text-top-device-tilted: headline left, tilted device right (or mirrored)
222
+ - device-hero: headline + large centered device, product-forward
223
+ - social-proof: stars + quote + laurel stat, no device (testimonial-led)
224
+ - review-clip: rating-statement headline + stars + quote + bottom-clipped device
225
+ - screen-hero: top-clipped device + centered headline + optional trust stat
226
+ - lifestyle-hero: full-bleed photo background + text overlay (no device)
227
+ - stats-hero: giant centered stat(s), no device, numbers-led
228
+ - metric-badge: centered device + chunky "achievement card" floating over its screen
229
+ - annotated-feature: tilted device + side callout chip linked by a connector line
230
+
231
+ 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.
232
+
233
+ 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.
234
+
235
+ Design features:
236
+ - Rich text with per-word color, weight, italic, underline, highlight pills, gradient fills, stroke outlines, and emoji
237
+ - Device perspective variants: flat, left-15/30, right-15/30, isometric, top-down, landscape
238
+ - 77 decorative shapes across 13 categories (nature, weather, celebration, social, tech, health, food, travel, abstract, finance, education, pets, emoji), plus 17 core geometric shapes
239
+ - Laurel stats: wing-left + wing-right shapes flanking a hero number
240
+
241
+ App Store 60/40 rule enforced: minimum 60% of cards must show a device mockup, maximum 40% can be marketing-only.
242
+
233
243
  Costs 5 credits per generation.`,
234
244
  inputSchema: z.object({
235
245
  app_name: z.string().describe('Name of the app'),
236
- app_description: z.string().describe('What the app does 1-3 sentences'),
246
+ app_description: z.string().describe('What the app does, in 1-3 sentences'),
237
247
  features: z.array(z.string()).max(10).optional()
238
248
  .describe('Key features in order of importance. The first 2-3 will be highlighted most prominently.'),
239
249
  brand_colors: z.object({
@@ -242,7 +252,7 @@ Costs 5 credits per generation.`,
242
252
  accent: z.string().optional().describe('Accent color as hex'),
243
253
  }).optional().describe('Brand colors to use in the design'),
244
254
  mood: z.string().optional()
245
- .describe('Design mood e.g. "energetic", "calm", "minimal", "bold", "professional", "playful"'),
255
+ .describe('Design mood, e.g. "energetic", "calm", "minimal", "bold", "professional", "playful"'),
246
256
  device_id: z.string().default('iphone-6.9')
247
257
  .describe(`Target device. Options: ${VALID_DEVICE_IDS.join(', ')}. Default: iphone-6.9 (iPhone 16 Pro Max)`),
248
258
  count: z.number().min(3).max(10).default(5)
@@ -251,27 +261,27 @@ Costs 5 credits per generation.`,
251
261
  .describe('Narrative structure for the screenshots. "auto" lets the AI choose the best flow.'),
252
262
  codebase_context: z.object({
253
263
  readme_summary: z.string().optional()
254
- .describe('Summary of the app from README or docs what does it do and why?'),
264
+ .describe('Summary of the app from README or docs: what does it do and why?'),
255
265
  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"'),
266
+ .describe('Main screens/views in the app, e.g. "Dashboard with activity feed", "Settings with theme toggle"'),
257
267
  color_tokens: z.record(z.string()).optional()
258
- .describe('Brand/theme colors found in code e.g. {"primary": "#7C3AED", "background": "#0F172A"}'),
268
+ .describe('Brand/theme colors found in code, e.g. {"primary": "#7C3AED", "background": "#0F172A"}'),
259
269
  target_audience: z.string().optional()
260
- .describe('Who the app is for e.g. "busy professionals who want to track habits"'),
270
+ .describe('Who the app is for, e.g. "busy professionals who want to track habits"'),
261
271
  app_category: z.string().optional()
262
- .describe('App category e.g. fitness, finance, social, productivity, food, travel, health, education'),
272
+ .describe('App category, e.g. fitness, finance, social, productivity, food, travel, health, education'),
263
273
  competitive_edge: z.string().optional()
264
274
  .describe('What makes this app unique vs competitors'),
265
275
  app_store_description: z.string().optional()
266
276
  .describe('Existing App Store/Play Store description if found in the codebase'),
267
277
  tech_stack: z.string().optional()
268
- .describe('Tech stack e.g. "React Native", "SwiftUI", "Flutter". Useful for developer-tool apps.'),
278
+ .describe('Tech stack, e.g. "React Native", "SwiftUI", "Flutter". Useful for developer-tool apps.'),
269
279
  ui_style: z.string().optional()
270
- .describe('UI style observations e.g. "dark mode with neon accents", "clean minimal with lots of whitespace"'),
280
+ .describe('UI style observations, e.g. "dark mode with neon accents", "clean minimal with lots of whitespace"'),
271
281
  primary_user_flow: z.string().optional()
272
- .describe('The main user journey e.g. "Sign up → Create project → Invite team → Track progress"'),
282
+ .describe('The main user journey, e.g. "Sign up → Create project → Invite team → Track progress"'),
273
283
  }).optional()
274
- .describe('Context gathered from researching the app codebase. Dramatically improves screenshot quality the more detail here, the better the output.'),
284
+ .describe('Context gathered from researching the app codebase. Dramatically improves screenshot quality. The more detail here, the better the output.'),
275
285
  images: chatImagesSchema,
276
286
  }),
277
287
  }, async (input) => {
@@ -346,48 +356,54 @@ Costs 5 credits per generation.`,
346
356
  // Tool 2: edit-screenshots
347
357
  server.registerTool('edit-screenshots', {
348
358
  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"
359
+ annotations: {
360
+ // Rewrites cards in place, so a bad edit costs the previous design.
361
+ readOnlyHint: false,
362
+ destructiveHint: true,
363
+ openWorldHint: false,
364
+ },
365
+ 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.
366
+
367
+ What you can change:
368
+ - Text: headlines, subtitles, badge text, font size, font family (Inter, Poppins, Montserrat, DM Sans, Space Grotesk, etc.)
369
+ - Text styling: per-word color, bold, italic, underline, highlight pills (colored background behind words), gradient text, text stroke outlines
370
+ - 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.
371
+ - 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.
372
+ - 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.
373
+ - Layout params: deviceScale (small/medium/large), deviceSide (left/right), textPosition (above/below), textAlign (left/center)
374
+ - Device mockups: perspective variants (flat, left-15, right-15, left-30, right-30, isometric, top-down, landscape-left, landscape-right), 2D rotation, resize, reposition
375
+ - 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.
376
+ - Switch devices: "make this for Apple Watch" / "duplicate for Android tablet" clones the project at the target device's canvas size
377
+ - Add/remove cards: add a social proof card, remove card 3, add a marketing title card
378
+ - Compound fields (auto-positioned): statRow, laurelStat, pressBanner, starRating, quote, credential, guarantee
379
+ - 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.
380
+ - Panoramic element spans: stretch a foreground image, device-mockup, or shape across adjacent cards ("pano the device across cards 1-2")
381
+ - Floating elements: add/edit badges, star ratings
382
+ - Shapes: glow orbs, waves, blobs, rounded rectangles, circles, custom SVG paths
383
+ - 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
384
+ - Backgrounds: solid, subtle-gradient, rich-gradient, photo (Pexels), or ai-generated; change gradient colors/angle; set a backgroundPrompt for AI-generated
385
+ - Style: shadows, opacity, border radius, rotation, blur
386
+
387
+ What isn't supported (the AI will flag these in unsupportedAsks):
388
+ - 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.
389
+ - Uploading a specific user-supplied screenshot into a mockup: use upload-screenshots tool first, then reference the uploaded project.
390
+
391
+ Example edit messages:
392
+ - "Make the headlines larger and use Bebas Neue font"
393
+ - "Change the color scheme to blue (#2563EB) across all cards"
394
+ - "Add a social proof card with 5 stars and a testimonial quote"
395
+ - "Tilt the phone on card 2 to the left"
396
+ - "Pano the background photo across cards 1-3"
397
+ - "Stretch the device on card 1 across into card 2"
398
+ - "Make this project for Apple Watch"
399
+ - "Recolor the iPhone frame to gold across all cards"
400
+ - "Replace card 3 with a CTA card saying Download Free"
401
+ - "Switch card 2 to device-hero layout with statRow showing our three key metrics"
402
+ - "Add decorative leaf and sparkle shapes scattered in the background"
387
403
  - "Make 'Every' underlined and italic in the headline"`,
388
404
  inputSchema: z.object({
389
405
  project_id: z.string().describe('Project ID from a previous generate-screenshots call'),
390
- message: z.string().describe('What to change use natural language'),
406
+ message: z.string().describe('What to change, in natural language'),
391
407
  card_indices: z.array(z.number().int().min(0)).max(10).optional()
392
408
  .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
409
  codebase_context: z.object({
@@ -464,6 +480,13 @@ Example edit messages:
464
480
  // Tool 3: render-screenshots
465
481
  server.registerTool('render-screenshots', {
466
482
  title: 'Render Screenshots to PNG',
483
+ annotations: {
484
+ // Re-rendering the same project state yields the same PNGs.
485
+ readOnlyHint: false,
486
+ destructiveHint: false,
487
+ idempotentHint: true,
488
+ openWorldHint: false,
489
+ },
467
490
  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
491
  inputSchema: z.object({
469
492
  project_id: z.string().describe('Project ID to render'),
@@ -511,10 +534,15 @@ server.registerTool('render-screenshots', {
511
534
  // Tool 4: list-devices
512
535
  server.registerTool('list-devices', {
513
536
  title: 'List Supported Devices',
537
+ annotations: {
538
+ // Reads a local constant; makes no API call at all.
539
+ readOnlyHint: true,
540
+ openWorldHint: false,
541
+ },
514
542
  description: 'Show all supported device specs for App Store and Play Store screenshots. Use the device ID when generating screenshots.',
515
543
  inputSchema: z.object({}),
516
544
  }, async () => {
517
- const lines = DEVICES.map(d => `${d.id} ${d.name} (${d.width}×${d.height}, ${d.category}${d.required ? ', required for store submission' : ''})`);
545
+ const lines = DEVICES.map(d => `${d.id}: ${d.name} (${d.width}×${d.height}, ${d.category}${d.required ? ', required for store submission' : ''})`);
518
546
  return {
519
547
  content: [{
520
548
  type: 'text',
@@ -532,14 +560,18 @@ server.registerTool('list-devices', {
532
560
  // Tool 5: get-project
533
561
  server.registerTool('get-project', {
534
562
  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)
563
+ annotations: {
564
+ readOnlyHint: true,
565
+ openWorldHint: false,
566
+ },
567
+ 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.
568
+
569
+ Returns the canvas state with:
570
+ - cards[]: each card has an id, elements array, and optional background settings
571
+ - Each element has: type (text, device-mockup, shape, badge, image, star-rating), position (x, y), size (width, height), zIndex, and type-specific properties
572
+ - Text elements: fontFamily, fontSize, fontWeight, color, segments (for multi-color text with per-word color, bold, italic, underline, highlightColor)
573
+ - 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)
574
+ - 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
575
  - projectMeta: globalVisualTheme, brandColors, mood, appCategory`,
544
576
  inputSchema: z.object({
545
577
  project_id: z.string().describe('Project ID to inspect'),
@@ -560,7 +592,7 @@ Returns the canvas state with:
560
592
  typeCounts[t] = (typeCounts[t] || 0) + 1;
561
593
  }
562
594
  const typeStr = Object.entries(typeCounts).map(([t, c]) => `${c} ${t}`).join(', ');
563
- return ` Card ${i} (${card.id}): ${card.elements.length} elements ${typeStr}`;
595
+ return ` Card ${i} (${card.id}): ${card.elements.length} elements: ${typeStr}`;
564
596
  }) || [];
565
597
  return {
566
598
  content: [{
@@ -584,19 +616,25 @@ Returns the canvas state with:
584
616
  // Tool 6: generate-background
585
617
  server.registerTool('generate-background', {
586
618
  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
-
619
+ annotations: {
620
+ // Replaces the card's existing background.
621
+ readOnlyHint: false,
622
+ destructiveHint: true,
623
+ openWorldHint: false,
624
+ },
625
+ 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.
626
+
627
+ Good prompts describe mood, lighting, and color, not objects or text:
628
+ - "Deep purple nebula with soft pink and blue light rays"
629
+ - "Warm sunset gradient with golden bokeh particles"
630
+ - "Dark moody atmosphere with teal and emerald glow"
631
+ - "Clean minimal white-to-light-gray gradient with subtle noise texture"
632
+
595
633
  The generated image is cropped to exact device dimensions and set as the card's background.`,
596
634
  inputSchema: z.object({
597
635
  project_id: z.string().describe('Project ID'),
598
636
  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.'),
637
+ prompt: z.string().describe('Background description: describe mood, lighting, colors, textures. Do NOT include text, devices, or UI elements.'),
600
638
  }),
601
639
  }, async ({ project_id, card_index, prompt }) => {
602
640
  const res = await apiCall('POST', `/api/v1/projects/${project_id}/generate-background`, {
@@ -623,17 +661,23 @@ The generated image is cropped to exact device dimensions and set as the card's
623
661
  // Tool 7: generate-panoramic-background
624
662
  server.registerTool('generate-panoramic-background', {
625
663
  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"
664
+ annotations: {
665
+ // Replaces the background on every card in the span.
666
+ readOnlyHint: false,
667
+ destructiveHint: true,
668
+ openWorldHint: false,
669
+ },
670
+ 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.
671
+
672
+ Two image sources:
673
+ - prompt: AI-generated via Gemini. Costs 6 credits.
674
+ - pexels_query: stock landscape photo from Pexels. Free.
675
+
676
+ 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.
677
+
678
+ Good prompts describe a continuous scene, not objects or text:
679
+ - "Misty mountain range at dawn, soft pink-to-blue gradient sky"
680
+ - "Calm ocean horizon at golden hour with gentle waves"
637
681
  - "Abstract flowing emerald and teal silk waves"`,
638
682
  inputSchema: z.object({
639
683
  project_id: z.string().describe('Project ID'),
@@ -671,16 +715,20 @@ Good prompts describe a continuous scene, not objects or text:
671
715
  // Tool 8: prepare-screenshot-brief
672
716
  server.registerTool('prepare-screenshot-brief', {
673
717
  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
-
718
+ annotations: {
719
+ readOnlyHint: true,
720
+ openWorldHint: false,
721
+ },
722
+ description: `Get a category playbook and repo-research checklist to prepare for screenshot generation. Call this BEFORE generate-screenshots. Free (no credits).
723
+
724
+ 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).
725
+
726
+ Returns:
727
+ - A category playbook (frame-1 hooks + layout + arc + mood) for the app_category
728
+ - A category-specific repo research focus (what to grep this app for)
729
+ - A generic codebase research checklist (file patterns per tech stack)
730
+ - Headline tips + the codebase_context schema to fill in
731
+
684
732
  The more you gather here, the better generate-screenshots does on the first try.`,
685
733
  inputSchema: z.object({
686
734
  app_category: z.string().optional()
@@ -690,7 +738,7 @@ The more you gather here, the better generate-screenshots does on the first try.
690
738
  }),
691
739
  }, async ({ app_category, platform }) => {
692
740
  const checklist = [
693
- '# Screenshot Brief Research Checklist',
741
+ '# Screenshot Brief: Research Checklist',
694
742
  '',
695
743
  'Search the codebase for each of these before calling generate-screenshots.',
696
744
  'The more you find, the better the screenshots will be.',
@@ -796,7 +844,7 @@ The more you gather here, the better generate-screenshots does on the first try.
796
844
  '- Lead with USER BENEFIT, not feature name: "Never forget a task" > "Task Management"',
797
845
  '- Use power words: Track, Save, Build, Discover, Master, Simplify, Automate',
798
846
  '- Include numbers when possible: "3x faster", "10K+ recipes", "Save 2hrs/week"',
799
- '- First 3 screenshots matter most App Store shows them in search results',
847
+ '- First 3 screenshots matter most: App Store shows them in search results',
800
848
  '- Hero card headline = your one-sentence pitch. Make it count.',
801
849
  '- Keep headlines under 6 words. Subtitle can add detail.',
802
850
  ];
@@ -810,15 +858,15 @@ The more you gather here, the better generate-screenshots does on the first try.
810
858
  ];
811
859
  if (platform === 'ios' || platform === 'both') {
812
860
  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');
861
+ deviceTips.push('- iPhone 16 Pro Max (iphone-6.9): 1260×2736: REQUIRED');
862
+ deviceTips.push('- iPad Pro 13" (ipad-13): 2064×2752: REQUIRED');
815
863
  deviceTips.push('');
816
864
  }
817
865
  if (platform === 'android' || platform === 'both') {
818
866
  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');
867
+ deviceTips.push('- Android Phone (android-phone): 1080×2340: REQUIRED');
868
+ deviceTips.push('- Android Tablet 7" (android-tablet-10): 1200×1920: REQUIRED');
869
+ deviceTips.push('- Android Tablet 10" (android-tablet-large): 1600×2560: second large-screen slot');
822
870
  deviceTips.push('');
823
871
  }
824
872
  // Schema reminder
@@ -861,21 +909,27 @@ The more you gather here, the better generate-screenshots does on the first try.
861
909
  // Tool 9: upload-screenshots
862
910
  server.registerTool('upload-screenshots', {
863
911
  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
912
+ annotations: {
913
+ // Overwrites whatever image the device frames already held.
914
+ readOnlyHint: false,
915
+ destructiveHint: true,
916
+ openWorldHint: false,
917
+ },
918
+ 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.
919
+
920
+ Reads files from your local filesystem, converts them to base64, and sets them on the device mockup elements in the specified cards.
921
+
922
+ Free: no credit cost. The screenshots are placed into the device frames that were created by generate-screenshots.
923
+
924
+ Workflow:
925
+ 1. generate-screenshots creates project with empty device frames
926
+ 2. upload-screenshots fills the device frames with your actual app UI
927
+ 3. render-screenshots → exports final PNGs at App Store dimensions
928
+
929
+ Tips:
930
+ - Take screenshots from the iOS Simulator (Cmd+S) or Android emulator
931
+ - Use PNG format for best quality
932
+ - Screenshots are automatically fitted into the device frame
879
933
  - You can upload different screenshots to different cards`,
880
934
  inputSchema: z.object({
881
935
  project_id: z.string().describe('Project ID from a previous generate-screenshots call'),
@@ -959,7 +1013,7 @@ function autoInstallSkill() {
959
1013
  copyFileSync(src, dest);
960
1014
  }
961
1015
  catch {
962
- // Silent fail skill install is optional
1016
+ // Silent fail: skill install is optional
963
1017
  }
964
1018
  }
965
1019
  async function main() {