Skip to main content
Glama
21st-dev

Magic Component Platform (MCP)

by 21st-dev

logo_search

Search for company logos and retrieve them as React components (JSX/TSX) or SVG markup for UI development projects.

Instructions

Search and return logos in specified format (JSX, TSX, SVG). Supports single and multiple logo searches with category filtering. Can return logos in different themes (light/dark) if available.

When to use this tool:

  1. When user types "/logo" command (e.g., "/logo GitHub")

  2. When user asks to add a company logo that's not in the local project

Example queries:

  • Single company: ["discord"]

  • Multiple companies: ["discord", "github", "slack"]

  • Specific brand: ["microsoft office"]

  • Command style: "/logo GitHub" -> ["github"]

  • Request style: "Add Discord logo to the project" -> ["discord"]

Format options:

  • TSX: Returns TypeScript React component

  • JSX: Returns JavaScript React component

  • SVG: Returns raw SVG markup

Each result includes:

  • Component name (e.g., DiscordIcon)

  • Component code

  • Import instructions

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queriesYesList of company names to search for logos
formatYesOutput format

Implementation Reference

  • The `execute` method: core handler that processes multiple logo queries, fetches SVGs from SVGL API, converts to JSX/TSX/SVG formats, generates component code, handles failures, saves test results, and returns JSON-structured response with icons, not-found suggestions, and usage setup instructions.
    async execute({ queries, format }: z.infer<typeof this.schema>) { console.log( `[${LOGO_TOOL_NAME}] Starting logo search for: ${queries.join( ", " )} in ${format} format` ); try { // Process all queries const results = await Promise.all( queries.map(async (query) => { try { console.log(`[${LOGO_TOOL_NAME}] Fetching logos for ${query}...`); const logos = await this.fetchLogos(query); if (logos.length === 0) { console.log(`[${LOGO_TOOL_NAME}] No logo found for ${query}`); return { query, success: false, message: `No logo found for: "${query}"`, }; } const logo = logos[0]; console.log( `[${LOGO_TOOL_NAME}] Processing logo for: ${logo.title}` ); const svgUrl = typeof logo.route === "string" ? logo.route : logo.route.light; console.log(`[${LOGO_TOOL_NAME}] Fetching SVG from: ${svgUrl}`); const svgContent = await this.fetchSVGContent(svgUrl); console.log(`[${LOGO_TOOL_NAME}] Converting to ${format} format`); const formattedContent = await this.convertToFormat( svgContent, format, logo.title + "Icon" ); console.log(`[${LOGO_TOOL_NAME}] Successfully processed ${query}`); return { query, success: true, content: `// ${logo.title} (${logo.url})\n${formattedContent}`, }; } catch (error) { console.error( `[${LOGO_TOOL_NAME}] Error processing ${query}:`, error ); return { query, success: false, message: error instanceof Error ? error.message : "Unknown error", }; } }) ); // Prepare summary const successful = results.filter((r) => r.success); const failed = results.filter((r) => !r.success); console.log(`[${LOGO_TOOL_NAME}] Results summary:`); console.log( `[${LOGO_TOOL_NAME}] Successfully processed: ${successful.length}` ); console.log(`[${LOGO_TOOL_NAME}] Failed to process: ${failed.length}`); // Save test results await this.saveTestResult({ queries, format, successful: successful .filter( (r): r is typeof r & { content: string } => r.content !== undefined ) .map((r) => ({ query: r.query, content: r.content, })), failed: failed .filter( (r): r is typeof r & { message: string } => r.message !== undefined ) .map((r) => ({ query: r.query, message: r.message, })), }); // Format response as component structure const foundIcons = successful.map((r) => { const title = r.content?.split("\n")[0].replace("// ", "").split(" (")[0] || ""; const componentName = title .split(" ") .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join("") .replace(/[^a-zA-Z0-9]/g, "") + "Icon"; return { icon: componentName, code: r.content?.split("\n").slice(1).join("\n") || "", }; }); const missingIcons = failed.map((f) => ({ icon: f.query, alternatives: [ "Search for SVG version on the official website", "Check other icon libraries (e.g., heroicons, lucide)", "Request SVG file from the user", ], })); const response = { icons: foundIcons, notFound: missingIcons, setup: [ "1. Add these icons to your project:", foundIcons .map((c) => ` ${c.icon}.${format.toLowerCase()}`) .join("\n"), "2. Import and use like this:", "```tsx", "import { " + foundIcons.map((c) => c.icon).join(", ") + " } from '@/icons';", "```", ].join("\n"), }; // Log results return { content: [ { type: "text" as const, text: JSON.stringify(response, null, 2), }, ], }; } catch (error) { // Log error console.error(`[${LOGO_TOOL_NAME}] Error:`, error); throw error; } }
  • LogoSearchTool class definition including name='logo_search', multi-line description, and Zod schema for inputs: queries (string array), format (enum: JSX/TSX/SVG).
    export class LogoSearchTool extends BaseTool { name = LOGO_TOOL_NAME; description = LOGO_TOOL_DESCRIPTION; schema = z.object({ queries: z .array(z.string()) .describe("List of company names to search for logos"), format: z.enum(["JSX", "TSX", "SVG"]).describe("Output format"), });
  • src/index.ts:22-25 (registration)
    Registration of LogoSearchTool (and other tools) to the MCP server instance via .register(server) method.
    new CreateUiTool().register(server); new LogoSearchTool().register(server); new FetchUiTool().register(server); new RefineUiTool().register(server);
  • src/index.ts:10-10 (registration)
    Import statement for LogoSearchTool from the implementation file.
    import { LogoSearchTool } from "./tools/logo-search.js";
  • Helper method to fetch logo metadata from SVGL API.
    private async fetchLogos(query: string): Promise<SVGLogo[]> { const baseUrl = "https://api.svgl.app"; const url = `${baseUrl}?search=${encodeURIComponent(query)}`; try { const response = await fetch(url); if (!response.ok) { if (response.status === 404) { return []; // Return empty array for not found instead of throwing } throw new Error(`SVGL API error: ${response.statusText}`); } const data = await response.json(); return Array.isArray(data) ? data : []; } catch (error) { console.error( `[${LOGO_TOOL_NAME}] Error fetching logos for ${query}:`, error ); return []; // Return empty array on error } }

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/21st-dev/magic-mcp'

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