Skip to main content
Glama
alucardeht
by alucardeht

extract_assets

Extract all assets from a Figma frame, including icons, images, and composite groups, with automatic categorization and progress tracking.

Instructions

Extract all assets from a frame with progress tracking.

HOW IT WORKS:

  • Detects "composite groups" (image + decorative shapes) and exports them as single PNG

  • For composite groups, the ENTIRE group is exported as one image, preserving layout

  • Automatically categorizes into icons/, images/, and images/composites/

  • Uses smart naming based on component hierarchy

  • Shows progress: "Processing batch 1/5 - found 8 icons, 3 images, 2 composites"

  • Final summary with all file paths

  • Look for "isCompositeAsset: true" in the frame tree to identify composite groups

TYPICAL WORKFLOW:

  1. get_frame_info → see what assets exist and identify composite groups

  2. extract_assets → download all

  3. Check summary for file paths

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
file_keyYesFigma file key
page_nameYesPage name (partial match)
frame_nameYesFrame name (partial match)
output_dirNoOutput directory (default: ./figma-assets)./figma-assets

Implementation Reference

  • Core implementation: Extracts icons (SVG), images (PNG), and composite groups (PNG) from Figma frame. Batches API calls, smart categorization, saves to outputDir/icons|images|composites/, returns paths and summary.
    export async function extractAssets(ctx, fileKey, pageName, frameName, outputDir) { const { chunker, figmaClient } = ctx; const file = await figmaClient.getFile(fileKey, 2); const page = figmaClient.findPageByName(file, pageName); if (!page) throw new Error(`Page "${pageName}" not found`); const frameRef = figmaClient.findFrameByName(page, frameName); if (!frameRef) throw new Error(`Frame "${frameName}" not found`); const frame = await figmaClient.getNode(fileKey, frameRef.id); const assets = findAssets(frame, { collectBounds: true }); const iconsDir = join(outputDir, "icons"); const imagesDir = join(outputDir, "images"); const compositeDir = join(imagesDir, "composites"); await mkdir(iconsDir, { recursive: true }); await mkdir(imagesDir, { recursive: true }); await mkdir(compositeDir, { recursive: true }); const results = { icons: [], images: [], composites: [], failed: [] }; const assetMap = {}; const batchSize = 10; for (let i = 0; i < assets.length; i += batchSize) { const batch = assets.slice(i, i + batchSize); const ids = batch.map((a) => a.id).join(","); try { const svgData = await figmaClient.getImage(fileKey, ids, "svg"); const pngData = await figmaClient.getImage(fileKey, ids, "png", 2); for (const asset of batch) { try { if (asset.isComposite) { if (pngData.images[asset.id]) { const pngResponse = await axios.get(pngData.images[asset.id], { responseType: "arraybuffer" }); const filePath = join(compositeDir, `${asset.name}.png`); await writeFile(filePath, Buffer.from(pngResponse.data)); results.composites.push({ path: filePath, uniqueName: asset.name, originalName: asset.originalName, section: getSectionFromPath(asset.path), bounds: asset.bounds, isComposite: true, }); assetMap[asset.name] = filePath; } } else if (asset.category === "icon" && svgData.images[asset.id]) { const svgResponse = await axios.get(svgData.images[asset.id]); const filePath = join(iconsDir, `${asset.name}.svg`); await writeFile(filePath, svgResponse.data); results.icons.push({ path: filePath, uniqueName: asset.name, originalName: asset.originalName, section: getSectionFromPath(asset.path), bounds: asset.bounds, }); assetMap[asset.name] = filePath; } else if (pngData.images[asset.id]) { const pngResponse = await axios.get(pngData.images[asset.id], { responseType: "arraybuffer" }); const filePath = join(imagesDir, `${asset.name}.png`); await writeFile(filePath, Buffer.from(pngResponse.data)); results.images.push({ path: filePath, uniqueName: asset.name, originalName: asset.originalName, section: getSectionFromPath(asset.path), bounds: asset.bounds, }); assetMap[asset.name] = filePath; } } catch (err) { results.failed.push({ name: asset.name, originalName: asset.originalName, error: err.message, }); } } } catch (err) { batch.forEach((a) => results.failed.push({ name: a.name, originalName: a.originalName, error: err.message, })); } } const response = chunker.wrapResponse( { frame: frame.name, outputDir, summary: { icons: results.icons.length, images: results.images.length, composites: results.composites.length, failed: results.failed.length, }, icons: results.icons, images: results.images, composites: results.composites, assetMap, failed: results.failed, }, { step: "Asset extraction complete", progress: `${results.icons.length} icons, ${results.images.length} images, ${results.composites.length} composite groups`, nextStep: "Assets saved to disk. Use extract_styles for design tokens.", } ); return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] }; }
  • Tool schema defining name, description, and input parameters (file_key, page_name, frame_name, output_dir). Part of toolSchemas array exported for MCP server.
    name: "extract_assets", description: `Extract all assets from a frame with progress tracking. HOW IT WORKS: - Detects "composite groups" (image + decorative shapes) and exports them as single PNG - For composite groups, the ENTIRE group is exported as one image, preserving layout - Automatically categorizes into icons/, images/, and images/composites/ - Uses smart naming based on component hierarchy - Shows progress: "Processing batch 1/5 - found 8 icons, 3 images, 2 composites" - Final summary with all file paths - Look for "isCompositeAsset: true" in the frame tree to identify composite groups TYPICAL WORKFLOW: 1. get_frame_info → see what assets exist and identify composite groups 2. extract_assets → download all 3. Check summary for file paths`, inputSchema: { type: "object", properties: { file_key: { type: "string", description: "Figma file key" }, page_name: { type: "string", description: "Page name (partial match)" }, frame_name: { type: "string", description: "Frame name (partial match)" }, output_dir: { type: "string", description: "Output directory (default: ./figma-assets)", default: "./figma-assets" }, }, required: ["file_key", "page_name", "frame_name"], }, },
  • src/index.js:60-62 (registration)
    Registration in main server switch statement: maps 'extract_assets' tool call to handlers.extractAssets with parsed arguments. handlers imported from './tools/handlers/index.js'.
    case "extract_assets": result = await handlers.extractAssets(this.ctx, args.file_key, args.page_name, args.frame_name, args.output_dir || "./figma-assets"); break;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/alucardeht/figma-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server