@appscreenshotstudio/mcp 0.1.2 → 0.1.4
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/README.md +24 -4
- package/dist/index.js +137 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,12 +63,13 @@ Create a complete set of App Store screenshots. One tool call = one full project
|
|
|
63
63
|
|
|
64
64
|
### `edit-screenshots`
|
|
65
65
|
|
|
66
|
-
Make changes to an existing project with natural language.
|
|
66
|
+
Make changes to an existing project with natural language. Optionally target specific cards.
|
|
67
67
|
|
|
68
68
|
| Parameter | Type | Required | Description |
|
|
69
69
|
|---|---|---|---|
|
|
70
70
|
| `project_id` | string | Yes | From a previous `generate-screenshots` call |
|
|
71
71
|
| `message` | string | Yes | What to change |
|
|
72
|
+
| `card_indices` | number[] | No | Target specific cards by index (0-based). Omit to edit all. |
|
|
72
73
|
|
|
73
74
|
**Costs 1 credit.**
|
|
74
75
|
|
|
@@ -82,6 +83,28 @@ Export to high-resolution PNGs. Returns download URLs.
|
|
|
82
83
|
|
|
83
84
|
**Free.**
|
|
84
85
|
|
|
86
|
+
### `get-project`
|
|
87
|
+
|
|
88
|
+
Retrieve a project's current state — cards, elements, backgrounds, and metadata.
|
|
89
|
+
|
|
90
|
+
| Parameter | Type | Required | Description |
|
|
91
|
+
|---|---|---|---|
|
|
92
|
+
| `project_id` | string | Yes | Project ID to retrieve |
|
|
93
|
+
|
|
94
|
+
**Free.**
|
|
95
|
+
|
|
96
|
+
### `generate-background`
|
|
97
|
+
|
|
98
|
+
Generate an AI background for a specific card. Uses project metadata (brand colors, mood, theme) for contextual results.
|
|
99
|
+
|
|
100
|
+
| Parameter | Type | Required | Description |
|
|
101
|
+
|---|---|---|---|
|
|
102
|
+
| `project_id` | string | Yes | Project containing the card |
|
|
103
|
+
| `card_index` | number | Yes | Which card (0-based) |
|
|
104
|
+
| `prompt` | string | Yes | Description of the background |
|
|
105
|
+
|
|
106
|
+
**Costs 1 credit.**
|
|
107
|
+
|
|
85
108
|
### `list-devices`
|
|
86
109
|
|
|
87
110
|
Show all supported device specs. No API call needed.
|
|
@@ -96,9 +119,6 @@ Show all supported device specs. No API call needed.
|
|
|
96
119
|
| `ipad-13` | iPad Pro 13" | 2064x2752 | App Store |
|
|
97
120
|
| `android-phone` | Android Phone | 1080x2340 | Play Store |
|
|
98
121
|
| `android-tablet-10` | Android Tablet 10" | 2560x1600 | Play Store |
|
|
99
|
-
| `iphone-5.5` | iPhone 8 Plus | 1242x2208 | Optional |
|
|
100
|
-
| `ipad-12.9` | iPad Pro 12.9" | 2048x2732 | Optional |
|
|
101
|
-
| `ipad-11` | iPad Pro 11" | 1668x2388 | Optional |
|
|
102
122
|
|
|
103
123
|
## Workflow
|
|
104
124
|
|
package/dist/index.js
CHANGED
|
@@ -7,10 +7,7 @@ const API_KEY = process.env.APPSCREENSHOTSTUDIO_API_KEY;
|
|
|
7
7
|
// ─── Devices (mirrors lib/device-specs.ts) ─────────────────────────────────────
|
|
8
8
|
const DEVICES = [
|
|
9
9
|
{ id: 'iphone-6.9', name: 'iPhone 16 Pro Max', width: 1260, height: 2736, category: 'iphone', required: true },
|
|
10
|
-
{ id: 'iphone-5.5', name: 'iPhone 8 Plus', width: 1242, height: 2208, category: 'iphone', required: false },
|
|
11
10
|
{ id: 'ipad-13', name: 'iPad Pro 13"', width: 2064, height: 2752, category: 'ipad', required: true },
|
|
12
|
-
{ id: 'ipad-12.9', name: 'iPad Pro 12.9"', width: 2048, height: 2732, category: 'ipad', required: false },
|
|
13
|
-
{ id: 'ipad-11', name: 'iPad Pro 11"', width: 1668, height: 2388, category: 'ipad', required: false },
|
|
14
11
|
{ id: 'android-phone', name: 'Android Phone', width: 1080, height: 2340, category: 'android-phone', required: true },
|
|
15
12
|
{ id: 'android-tablet-10', name: 'Android Tablet 10"', width: 2560, height: 1600, category: 'android-tablet', required: true },
|
|
16
13
|
];
|
|
@@ -79,7 +76,26 @@ const server = new McpServer({
|
|
|
79
76
|
// Tool 1: generate-screenshots
|
|
80
77
|
server.registerTool('generate-screenshots', {
|
|
81
78
|
title: 'Generate App Store Screenshots',
|
|
82
|
-
description:
|
|
79
|
+
description: `Create a complete set of App Store screenshot designs for an app. Returns a project URL where the developer can upload actual app screenshots into the device frames and export final PNGs.
|
|
80
|
+
|
|
81
|
+
Each card is a layered composition with: gradient background, decorative glow orbs, bold headline with colored accent words, device mockup (iPhone/iPad/Android with perspective tilts), and optional floating elements (badges, star ratings, UI snippets).
|
|
82
|
+
|
|
83
|
+
Available layouts per card:
|
|
84
|
+
- Layout A: "Text Top, Device Bottom Center" — default, device fills lower portion
|
|
85
|
+
- Layout B: "Text Top, Device Offset Right" — tilted phone with perspective
|
|
86
|
+
- Layout C: "Social Proof" — star rating + quote + badge + device
|
|
87
|
+
- Layout M1-M4: Marketing cards WITHOUT device (title cards, feature callouts, CTAs, testimonials)
|
|
88
|
+
|
|
89
|
+
Card types the system can generate:
|
|
90
|
+
- Hero card (value proposition + device)
|
|
91
|
+
- Feature spotlight (tilted phone + floating UI snippets)
|
|
92
|
+
- Social proof (stars, quotes, badges)
|
|
93
|
+
- Marketing/title card (no device, bold text + rich background)
|
|
94
|
+
- CTA/download card (no device, call to action)
|
|
95
|
+
|
|
96
|
+
App Store 60/40 rule: minimum 60% of cards must show a device mockup, maximum 40% can be marketing-only.
|
|
97
|
+
|
|
98
|
+
Costs 1 credit per generation.`,
|
|
83
99
|
inputSchema: z.object({
|
|
84
100
|
app_name: z.string().describe('Name of the app'),
|
|
85
101
|
app_description: z.string().describe('What the app does — 1-3 sentences'),
|
|
@@ -154,15 +170,37 @@ server.registerTool('generate-screenshots', {
|
|
|
154
170
|
// Tool 2: edit-screenshots
|
|
155
171
|
server.registerTool('edit-screenshots', {
|
|
156
172
|
title: 'Edit Screenshot Designs',
|
|
157
|
-
description:
|
|
173
|
+
description: `Make changes to an existing screenshot project. Use natural language to describe what you want to change. Costs 1 credit per edit.
|
|
174
|
+
|
|
175
|
+
What you can change:
|
|
176
|
+
- Text: headlines, subtitles, badge text, font size, font family (Inter, Poppins, Montserrat, DM Sans, Space Grotesk, etc.)
|
|
177
|
+
- Colors: brand palette, gradient backgrounds, accent colors, text colors
|
|
178
|
+
- Layout: reposition elements, switch between layouts (A/B/C/M1-M4), change device tilt
|
|
179
|
+
- Device mockups: perspective tilts (flat, left-15, right-15), resize, reposition
|
|
180
|
+
- Add/remove cards: add a social proof card, remove card 3, add a marketing title card
|
|
181
|
+
- Floating elements: add/edit badges, star ratings, floating UI snippets (rounded-rect + text overlays)
|
|
182
|
+
- Shapes: glow orbs, waves, blobs, rounded rectangles, circles, custom SVG paths
|
|
183
|
+
- Backgrounds: change gradient colors/angle, set a backgroundPrompt for AI-generated backgrounds
|
|
184
|
+
- Style: shadows, opacity, border radius, rotation, blur
|
|
185
|
+
|
|
186
|
+
Example edit messages:
|
|
187
|
+
- "Make the headlines larger and use Bebas Neue font"
|
|
188
|
+
- "Change the color scheme to blue (#2563EB) across all cards"
|
|
189
|
+
- "Add a social proof card with 5 stars and a testimonial quote"
|
|
190
|
+
- "Tilt the phone on card 2 to the left"
|
|
191
|
+
- "Add floating UI snippets around the device on card 1"
|
|
192
|
+
- "Replace card 3 with a marketing CTA card saying Download Free"
|
|
193
|
+
- "Add a wave shape flowing across all cards"`,
|
|
158
194
|
inputSchema: z.object({
|
|
159
195
|
project_id: z.string().describe('Project ID from a previous generate-screenshots call'),
|
|
160
196
|
message: z.string().describe('What to change — use natural language'),
|
|
197
|
+
card_indices: z.array(z.number()).optional()
|
|
198
|
+
.describe('Target specific cards by index (0-based). e.g. [0] for card 1, [2,3] for cards 3-4. Omit to apply changes to all cards.'),
|
|
161
199
|
}),
|
|
162
|
-
}, async ({ project_id, message }) => {
|
|
200
|
+
}, async ({ project_id, message, card_indices }) => {
|
|
163
201
|
const res = await apiCall('POST', `/api/v1/projects/${project_id}/chat`, {
|
|
164
202
|
message,
|
|
165
|
-
selected_card_indices: [],
|
|
203
|
+
selected_card_indices: card_indices || [],
|
|
166
204
|
});
|
|
167
205
|
if (!res.ok) {
|
|
168
206
|
return {
|
|
@@ -191,7 +229,7 @@ server.registerTool('edit-screenshots', {
|
|
|
191
229
|
// Tool 3: render-screenshots
|
|
192
230
|
server.registerTool('render-screenshots', {
|
|
193
231
|
title: 'Render Screenshots to PNG',
|
|
194
|
-
description: 'Export a screenshot project to high-resolution PNG files. Returns download URLs for each card. Note: device mockups will
|
|
232
|
+
description: 'Export a screenshot project to high-resolution PNG files at exact App Store dimensions. Returns download URLs for each card. Free — no credit cost. Note: device mockups will show empty frames unless app screenshots have been uploaded via the web app first.',
|
|
195
233
|
inputSchema: z.object({
|
|
196
234
|
project_id: z.string().describe('Project ID to render'),
|
|
197
235
|
}),
|
|
@@ -235,6 +273,97 @@ server.registerTool('list-devices', {
|
|
|
235
273
|
}],
|
|
236
274
|
};
|
|
237
275
|
});
|
|
276
|
+
// Tool 5: get-project
|
|
277
|
+
server.registerTool('get-project', {
|
|
278
|
+
title: 'Get Project Details',
|
|
279
|
+
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.
|
|
280
|
+
|
|
281
|
+
Returns the canvas state with:
|
|
282
|
+
- cards[]: each card has an id, elements array, and optional background settings
|
|
283
|
+
- Each element has: type (text, device-mockup, shape, badge, image, star-rating), position (x, y), size (width, height), zIndex, and type-specific properties
|
|
284
|
+
- Text elements: fontFamily, fontSize, fontWeight, color, segments (for multi-color text with highlights)
|
|
285
|
+
- Device mockups: perspectiveVariant (flat, left-15, right-15), screenshotImage (null if no upload)
|
|
286
|
+
- Shapes: shapeType (circle, rectangle, rounded-rect, blob, wave, etc.), fill, opacity
|
|
287
|
+
- projectMeta: globalVisualTheme, brandColors, mood, appCategory`,
|
|
288
|
+
inputSchema: z.object({
|
|
289
|
+
project_id: z.string().describe('Project ID to inspect'),
|
|
290
|
+
}),
|
|
291
|
+
}, async ({ project_id }) => {
|
|
292
|
+
const res = await apiCall('GET', `/api/v1/projects/${project_id}`);
|
|
293
|
+
if (!res.ok) {
|
|
294
|
+
return {
|
|
295
|
+
content: [{ type: 'text', text: `Failed to get project: ${JSON.stringify(res.data)}` }],
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
const project = res.data.data;
|
|
299
|
+
// Build a concise summary instead of dumping raw JSON
|
|
300
|
+
const cardSummaries = project.canvas_state?.cards?.map((card, i) => {
|
|
301
|
+
const elementTypes = card.elements.map(el => el.type);
|
|
302
|
+
const typeCounts = {};
|
|
303
|
+
for (const t of elementTypes) {
|
|
304
|
+
typeCounts[t] = (typeCounts[t] || 0) + 1;
|
|
305
|
+
}
|
|
306
|
+
const typeStr = Object.entries(typeCounts).map(([t, c]) => `${c} ${t}`).join(', ');
|
|
307
|
+
return ` Card ${i} (${card.id}): ${card.elements.length} elements — ${typeStr}`;
|
|
308
|
+
}) || [];
|
|
309
|
+
return {
|
|
310
|
+
content: [{
|
|
311
|
+
type: 'text',
|
|
312
|
+
text: [
|
|
313
|
+
`Project: ${project.name}`,
|
|
314
|
+
`ID: ${project.id}`,
|
|
315
|
+
`Device: ${project.device_id}`,
|
|
316
|
+
`Cards: ${project.canvas_state?.cards?.length || 0}`,
|
|
317
|
+
'',
|
|
318
|
+
...cardSummaries,
|
|
319
|
+
'',
|
|
320
|
+
`Project URL: ${API_BASE}/builder/${project.id}`,
|
|
321
|
+
'',
|
|
322
|
+
`Full canvas state:`,
|
|
323
|
+
JSON.stringify(project.canvas_state, null, 2),
|
|
324
|
+
].join('\n'),
|
|
325
|
+
}],
|
|
326
|
+
};
|
|
327
|
+
});
|
|
328
|
+
// Tool 6: generate-background
|
|
329
|
+
server.registerTool('generate-background', {
|
|
330
|
+
title: 'Generate AI Background',
|
|
331
|
+
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 1 credit.
|
|
332
|
+
|
|
333
|
+
Good prompts describe mood, lighting, and color — not objects or text:
|
|
334
|
+
- "Deep purple nebula with soft pink and blue light rays"
|
|
335
|
+
- "Warm sunset gradient with golden bokeh particles"
|
|
336
|
+
- "Dark moody atmosphere with teal and emerald glow"
|
|
337
|
+
- "Clean minimal white-to-light-gray gradient with subtle noise texture"
|
|
338
|
+
|
|
339
|
+
The generated image is cropped to exact device dimensions and set as the card's background.`,
|
|
340
|
+
inputSchema: z.object({
|
|
341
|
+
project_id: z.string().describe('Project ID'),
|
|
342
|
+
card_index: z.number().describe('Card index (0-based) to apply the background to'),
|
|
343
|
+
prompt: z.string().describe('Background description — describe mood, lighting, colors, textures. Do NOT include text, devices, or UI elements.'),
|
|
344
|
+
}),
|
|
345
|
+
}, async ({ project_id, card_index, prompt }) => {
|
|
346
|
+
const res = await apiCall('POST', `/api/v1/projects/${project_id}/generate-background`, {
|
|
347
|
+
card_index,
|
|
348
|
+
prompt,
|
|
349
|
+
});
|
|
350
|
+
if (!res.ok) {
|
|
351
|
+
return {
|
|
352
|
+
content: [{ type: 'text', text: `Background generation failed: ${JSON.stringify(res.data)}` }],
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
const creditsRemaining = res.data.credits_remaining;
|
|
356
|
+
return {
|
|
357
|
+
content: [{
|
|
358
|
+
type: 'text',
|
|
359
|
+
text: [
|
|
360
|
+
`AI background generated and applied to card ${card_index + 1}.`,
|
|
361
|
+
`Credits remaining: ${creditsRemaining}`,
|
|
362
|
+
`Project URL: ${API_BASE}/builder/${project_id}`,
|
|
363
|
+
].join('\n'),
|
|
364
|
+
}],
|
|
365
|
+
};
|
|
366
|
+
});
|
|
238
367
|
// ─── Start server ───────────────────────────────────────────────────────────────
|
|
239
368
|
async function main() {
|
|
240
369
|
if (!API_KEY) {
|