@appscreenshotstudio/mcp
Advanced tools
+59
-10
@@ -95,3 +95,3 @@ #!/usr/bin/env node | ||
| }; | ||
| function buildDesignMessage(input) { | ||
| function buildDesignMessage(input, hasScreenshotImages = false) { | ||
| const parts = []; | ||
@@ -151,10 +151,48 @@ parts.push(`Create ${input.count} App Store screenshots for my app.`); | ||
| } | ||
| parts.push(`\nAll device mockups should have screenshotImage: null — the developer will upload actual app screenshots later.`); | ||
| if (hasScreenshotImages) { | ||
| parts.push(`\nMy app screenshots are attached — they are placed into the device frames automatically.`); | ||
| } | ||
| else { | ||
| parts.push(`\nAll device mockups should have screenshotImage: null — the developer will upload actual app screenshots later.`); | ||
| } | ||
| parts.push(`Please include projectMeta with brand colors, mood, appCategory, and a rich globalVisualTheme description.`); | ||
| return parts.join('\n'); | ||
| } | ||
| /** Read local image files into the chat API's images payload. Same file | ||
| * handling as upload-screenshots; kind rides through to server-side | ||
| * placement (screenshots fill the generated device frames, mascots get | ||
| * placed decoratively around the phones). */ | ||
| function readImagesForChat(images) { | ||
| const payload = []; | ||
| const errors = []; | ||
| for (const { file_path, kind } of images ?? []) { | ||
| try { | ||
| if (!existsSync(file_path)) { | ||
| errors.push(`File not found: ${file_path}`); | ||
| continue; | ||
| } | ||
| const buffer = readFileSync(file_path); | ||
| const ext = file_path.toLowerCase().split('.').pop(); | ||
| const mimeType = ext === 'jpg' || ext === 'jpeg' ? 'image/jpeg' | ||
| : ext === 'webp' ? 'image/webp' | ||
| : 'image/png'; | ||
| payload.push({ dataUrl: `data:${mimeType};base64,${buffer.toString('base64')}`, mediaType: mimeType, kind }); | ||
| } | ||
| catch (err) { | ||
| errors.push(`Failed to read ${file_path}: ${err instanceof Error ? err.message : String(err)}`); | ||
| } | ||
| } | ||
| return { payload, errors }; | ||
| } | ||
| /** Shared images param for generate-screenshots and edit-screenshots. */ | ||
| const chatImagesSchema = z.array(z.object({ | ||
| file_path: z.string().describe('Absolute path to an image file on the local filesystem (PNG, JPG, or WEBP)'), | ||
| kind: z.enum(['screenshot', 'mascot']).default('screenshot') | ||
| .describe("'screenshot' = real app UI, automatically placed inside the generated device frames (in attachment order). 'mascot' = the app's character/mascot, placed decoratively around the phones (peeking from behind the hook card's phone, beside or in a corner on the closing card). Use a transparent PNG for mascots."), | ||
| })).max(5).optional() | ||
| .describe('Images to attach to this generation. App screenshots land inside the device frames automatically; a mascot gets placed around the phones. Both survive later edits and regenerations.'); | ||
| // ─── MCP Server ───────────────────────────────────────────────────────────────── | ||
| const server = new McpServer({ | ||
| name: 'appscreenshotstudio', | ||
| version: '0.5.2', | ||
| version: '0.5.4', | ||
| }); | ||
@@ -164,3 +202,3 @@ // Tool 1: generate-screenshots | ||
| title: 'Generate App Store Screenshots', | ||
| 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. | ||
| 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. | ||
@@ -240,2 +278,3 @@ 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. | ||
| .describe('Context gathered from researching the app codebase. Dramatically improves screenshot quality — the more detail here, the better the output.'), | ||
| images: chatImagesSchema, | ||
| }), | ||
@@ -266,7 +305,11 @@ }, async (input) => { | ||
| const projectId = project.id; | ||
| // Step 2: Chat to generate all cards | ||
| const message = buildDesignMessage(input); | ||
| // Step 2: Chat to generate all cards (with attached images when provided: | ||
| // screenshots auto-fill the device frames, mascots decorate around them) | ||
| const { payload: chatImages, errors: imageErrors } = readImagesForChat(input.images); | ||
| const hasScreens = chatImages.some((img) => img.kind === 'screenshot'); | ||
| const message = buildDesignMessage(input, hasScreens); | ||
| const chatRes = await apiCall('POST', `/api/v1/projects/${projectId}/chat`, { | ||
| message, | ||
| selected_card_indices: [], | ||
| ...(chatImages.length > 0 ? { images: chatImages } : {}), | ||
| }); | ||
@@ -294,6 +337,9 @@ if (!chatRes.ok) { | ||
| 'Next steps:', | ||
| '1. Use upload-screenshots to add your app screenshots into the device frames', | ||
| hasScreens | ||
| ? '1. Your attached screenshots were placed into the device frames (upload-screenshots can swap any card later)' | ||
| : '1. Use upload-screenshots to add your app screenshots into the device frames', | ||
| '2. Use render-screenshots to export final PNGs', | ||
| '3. Or open the project URL in a browser to preview and adjust', | ||
| '', | ||
| imageErrors.length ? `Image read warnings:\n${imageErrors.join('\n')}` : '', | ||
| chatData.suggestions?.length | ||
@@ -309,3 +355,3 @@ ? `Suggestions: ${chatData.suggestions.join(', ')}` | ||
| title: 'Edit Screenshot Designs', | ||
| description: `Make changes to an existing screenshot project. Use natural language to describe what you want to change. Costs 5 credits per edit. | ||
| 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. | ||
@@ -367,4 +413,5 @@ What you can change: | ||
| .describe('App context from codebase research. Helps the AI make edits that match the actual app.'), | ||
| images: chatImagesSchema, | ||
| }), | ||
| }, async ({ project_id, message, card_indices, codebase_context }) => { | ||
| }, async ({ project_id, message, card_indices, codebase_context, images }) => { | ||
| let enrichedMessage = message; | ||
@@ -389,9 +436,11 @@ if (codebase_context) { | ||
| } | ||
| const { payload: chatImages, errors: imageErrors } = readImagesForChat(images); | ||
| const res = await apiCall('POST', `/api/v1/projects/${project_id}/chat`, { | ||
| message: enrichedMessage, | ||
| selected_card_indices: card_indices || [], | ||
| ...(chatImages.length > 0 ? { images: chatImages } : {}), | ||
| }); | ||
| if (!res.ok) { | ||
| return { | ||
| content: [{ type: 'text', text: `Edit failed: ${JSON.stringify(res.data)}` }], | ||
| content: [{ type: 'text', text: `Edit failed: ${JSON.stringify(res.data)}${imageErrors.length ? `\n\nImage read warnings:\n${imageErrors.join('\n')}` : ''}` }], | ||
| }; | ||
@@ -398,0 +447,0 @@ } |
+2
-2
@@ -1,4 +0,4 @@ | ||
| { | ||
| { | ||
| "name": "@appscreenshotstudio/mcp", | ||
| "version": "0.5.3", | ||
| "version": "0.5.4", | ||
| "description": "MCP server for generating App Store screenshots via AppScreenshotStudio", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -71,8 +71,9 @@ --- | ||
| - `codebase_context`: the full context object from Step 1 | ||
| - `images`: local file paths of real app screenshots (placed inside the device frames automatically, in order) and/or the app's mascot with `kind: "mascot"` (placed peeking from behind the hook card's phone and on the closing card; transparent PNG). If screenshots exist in the repo (fastlane/screenshots, store assets, README images), attach them here so the set comes back with real UI in the phones instead of empty frames. | ||
| ### Step 4: Upload App Screenshots | ||
| If the user has actual app screenshots (from Simulator, emulator, or screen captures), upload them into the device frames using `upload-screenshots`: | ||
| If screenshots were attached in Step 3 they are already in the frames — this step covers swaps and late additions. `upload-screenshots`: | ||
| - Takes local file paths and maps them to card indices | ||
| - Fills the empty device mockups with real app UI | ||
| - Fills or replaces the device mockups' app UI per card | ||
| - Free — no credit cost | ||
@@ -79,0 +80,0 @@ |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Invalid manifest file
QualityPackage has an invalid manifest file and can cause installation problems if you try to use it.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
73188
5.52%1009
5.32%1
-50%Yes
NaN2
Infinity%2
Infinity%1
Infinity%2
100%8
14.29%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added