search_components
Find Figma components by name across files or pages using partial matching, with filtering options to refine results and retrieve design assets efficiently.
Instructions
Search for components by name across the file.
HOW IT WORKS:
Searches entire file or specific page
Returns top 20 results with total count
If >20 results, suggests refinement options
Use 'continue: true' to get more results
TYPICAL WORKFLOW:
search_components(query) → find matches
If too many: refine with page_name or type filter
get_frame_info on specific result
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| file_key | Yes | Figma file key | |
| query | Yes | Search term (case-insensitive, partial match) | |
| page_name | No | Limit search to specific page | |
| type | No | Filter by type: COMPONENT, INSTANCE, FRAME, TEXT, VECTOR | |
| continue | No | Continue from last response for more results |
Implementation Reference
- src/tools/handlers/search.js:1-91 (handler)The core handler function that executes the search_components tool. Searches Figma file for nodes matching the query, handles pagination with continueFlag, and returns chunked results.export async function searchComponents(ctx, fileKey, query, pageName, type, continueFlag = false) { const { session, chunker, figmaClient } = ctx; const operationId = `search_components:${fileKey}:${query}:${pageName || "all"}:${type || "all"}`; if (continueFlag && session.hasPendingChunks(operationId)) { const chunk = session.getNextChunk(operationId); const response = chunker.wrapResponse( { query, results: chunk.items }, { step: `Showing results ${(chunk.chunkIndex - 1) * 20 + 1}-${Math.min(chunk.chunkIndex * 20, chunk.totalItems)}`, progress: `${chunk.chunkIndex}/${chunk.totalChunks}`, nextStep: chunk.chunkIndex < chunk.totalChunks ? "Call with continue=true for more" : "Use get_frame_info on specific result", operationId, } ); return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] }; } const file = await figmaClient.getFile(fileKey, 99); const lowerQuery = query.toLowerCase(); const results = []; const searchNode = (node, pageNameLocal, path) => { if (type && node.type !== type) { if (node.children) { node.children.forEach((child) => searchNode(child, pageNameLocal, [...path, node.name])); } return; } if (node.name.toLowerCase().includes(lowerQuery)) { results.push({ name: node.name, type: node.type, id: node.id, page: pageNameLocal, path: path.join(" > "), bounds: node.absoluteBoundingBox ? { width: Math.round(node.absoluteBoundingBox.width), height: Math.round(node.absoluteBoundingBox.height), } : null, }); } if (node.children) { node.children.forEach((child) => searchNode(child, pageNameLocal, [...path, node.name])); } }; const pages = pageName ? [figmaClient.findPageByName(file, pageName)].filter(Boolean) : file.document.children; pages.forEach((page) => { searchNode(page, page.name, []); }); if (results.length > 20) { const chunked = chunker.chunkArray(results, operationId, 20); const pageNames = [...new Set(results.map((r) => r.page))]; const types = [...new Set(results.map((r) => r.type))]; const response = chunker.wrapResponse( { query, resultCount: results.length, results: chunked.items }, { step: `Showing results 1-${chunked.items.length} of ${results.length}`, progress: `1/${chunked.totalChunks}`, nextStep: "Call with continue=true for more, or refine search", alert: `Found ${results.length} matches - showing first 20`, refinementOptions: [ pageNames.length > 1 ? `Filter by page: ${pageNames.slice(0, 3).join(", ")}` : null, types.length > 1 ? `Filter by type: ${types.join(", ")}` : null, "Use more specific search term", ].filter(Boolean), operationId, } ); return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] }; } const response = chunker.wrapResponse( { query, resultCount: results.length, results }, { step: "Search complete", progress: `${results.length} results`, nextStep: results.length > 0 ? "Use get_frame_info on a result for details" : "Try different search term", } ); return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] }; }
- src/tools/schemas.js:173-198 (schema)Input schema and description for the search_components tool, defining parameters and behavior.{ name: "search_components", description: `Search for components by name across the file. HOW IT WORKS: - Searches entire file or specific page - Returns top 20 results with total count - If >20 results, suggests refinement options - Use 'continue: true' to get more results TYPICAL WORKFLOW: 1. search_components(query) → find matches 2. If too many: refine with page_name or type filter 3. get_frame_info on specific result`, inputSchema: { type: "object", properties: { file_key: { type: "string", description: "Figma file key" }, query: { type: "string", description: "Search term (case-insensitive, partial match)" }, page_name: { type: "string", description: "Limit search to specific page" }, type: { type: "string", description: "Filter by type: COMPONENT, INSTANCE, FRAME, TEXT, VECTOR" }, continue: { type: "boolean", description: "Continue from last response for more results" }, }, required: ["file_key", "query"], }, },
- src/index.js:63-65 (registration)Dispatches calls to the search_components tool handler in the main MCP server switch statement.case "search_components": result = await handlers.searchComponents(this.ctx, args.file_key, args.query, args.page_name, args.type, args.continue); break;
- src/tools/handlers/index.js:6-6 (registration)Re-exports the searchComponents handler for use in the main index.js.export { searchComponents } from "./search.js";