Skip to main content
Glama
utils.ts5.59 kB
import { z } from "zod"; import * as outlineIcons from "@heroicons/react/24/outline"; import * as solidIcons from "@heroicons/react/24/solid"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; export const getAllIcons = () => { // Only keep keys ending with 'Icon' const solid = Object.keys(solidIcons).filter((k) => k.endsWith("Icon")); const outline = Object.keys(outlineIcons).filter((k) => k.endsWith("Icon")); return { solid, outline }; }; export const categorizeIcon = (iconName: string): string[] => { // Simple heuristic: categorize by substrings in the name const cats: string[] = []; const lower = iconName.toLowerCase(); if (lower.includes("arrow")) cats.push("arrows"); if ( lower.includes("user") || lower.includes("person") || lower.includes("group") ) cats.push("users"); if ( lower.includes("file") || lower.includes("document") || lower.includes("folder") || lower.includes("clipboard") ) cats.push("files"); if ( lower.includes("circle") || lower.includes("square") || lower.includes("star") || lower.includes("cube") || lower.includes("shape") ) cats.push("shapes"); if ( lower.includes("plus") || lower.includes("minus") || lower.includes("xmark") || lower.includes("check") || lower.includes("chevron") || lower.includes("menu") || lower.includes("list") || lower.includes("dot") || lower.includes("ellipsis") ) cats.push("interface"); if ( lower.includes("cart") || lower.includes("bag") || lower.includes("credit") || lower.includes("currency") || lower.includes("wallet") || lower.includes("receipt") || lower.includes("gift") ) cats.push("commerce"); if ( lower.includes("chat") || lower.includes("mail") || lower.includes("envelope") || lower.includes("phone") || lower.includes("message") || lower.includes("inbox") ) cats.push("communication"); if ( lower.includes("device") || lower.includes("computer") || lower.includes("phone") || lower.includes("tablet") || lower.includes("tv") || lower.includes("camera") ) cats.push("devices"); if ( lower.includes("sun") || lower.includes("moon") || lower.includes("cloud") || lower.includes("weather") ) cats.push("weather"); if (cats.length === 0) cats.push("misc"); return cats; }; const allIcons = getAllIcons(); export const iconMeta = [ ...allIcons.solid.map((name) => ({ name, style: "solid", categories: categorizeIcon(name) })), ...allIcons.outline.map((name) => ({ name, style: "outline", categories: categorizeIcon(name) })) ]; export function createMcpServer(): McpServer { const server = new McpServer({ name: "Heroicons MCP Server", version: "0.2.0" }); // Tool: search_icons server.tool( "search_icons", "Search for icons from heroicons by name or category", { query: z.string().describe("Search term for icon name or category"), style: z .enum(["solid", "outline"]) .optional() .describe("Icon style: solid or outline"), category: z .string() .optional() .describe("Category to filter by (optional)"), limit: z .number() .min(1) .max(100) .default(20) .optional() .describe("Max results to return") }, async ({ query, style, category, limit }) => { let results = iconMeta.filter((icon) => { const matchName = icon.name.toLowerCase().includes(query.toLowerCase()); const matchCat = category ? icon.categories.includes(category) : true; const matchStyle = style ? icon.style === style : true; return matchName && matchCat && matchStyle; }); if (limit) results = results.slice(0, limit); return { content: [ { type: "text", text: JSON.stringify(results, null, 2) } ] }; } ); // Tool: get_icon_usage_examples server.tool( "get_icon_usage_examples", "Get usage examples for an icon", { name: z.string().describe("Icon component name, e.g. BeakerIcon"), style: z .enum(["solid", "outline"]) .describe("Icon style: solid or outline") }, async ({ name, style }) => { const pkg = `@heroicons/react/24/${style}`; const importLine = `import { ${name} } from '${pkg}';`; const jsxLine = `<${name} className="w-6 h-6 text-blue-500" />`; const example = `${importLine}\n\nfunction Example() {\n return (\n <div>\n ${jsxLine}\n </div>\n );\n}`; return { content: [ { type: "text", text: example } ] }; } ); // Tool: list_all_icons server.tool( "list_all_icons", "List all icons from the heroicons library, optionally filtered by style", { style: z .enum(["solid", "outline"]) .optional() .describe("Icon style: solid or outline (optional)") }, async ({ style }) => { // Limit to 1000 icons for safety let results = iconMeta; if (style) { results = results.filter((icon) => icon.style === style); } const names = results.slice(0, 1000).map((icon) => icon.name); return { content: [ { type: "text", text: JSON.stringify(names, null, 2) } ] }; } ); return server; }

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/SeeYangZhi/heroicons-mcp'

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