Skip to main content
Glama
utils.ts6.29 kB
import Fuse from "fuse.js"; import { z } from "zod"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { categories, getAllCategories, getIconsByCategory, iconMetadata } from "./data/icons.js"; // Common response helper const createTextResponse = (data: any) => ({ content: [ { type: "text" as const, text: JSON.stringify(data, null, 2) } ] }); // Common schemas const limitSchema = (max: number, defaultValue: number) => z.number().min(1).max(max).default(defaultValue).optional(); const searchSchemas = { iconLimit: limitSchema(300, 20), categoryLimit: limitSchema(50, 10), listLimit: limitSchema(300, 20) }; // Search utilities class SearchService { static filterIconsByName(icons: typeof iconMetadata, name: string) { return icons.filter((icon) => icon.name.toLowerCase().includes(name.toLowerCase()) ); } static filterIconsByCategory(icons: typeof iconMetadata, category: string) { return icons.filter((icon) => icon.categories.some((cat) => cat.toLowerCase().includes(category.toLowerCase()) ) ); } static filterCategories(categoryName: string) { return categories.filter((category) => category.name.toLowerCase().includes(categoryName.toLowerCase()) ); } static createFuseSearch<T>(data: T[], keys: string[]) { return new Fuse(data, { keys, isCaseSensitive: false }); } static applyLimit<T>(results: T[], limit?: number): T[] { return limit ? results.slice(0, limit) : results; } } // Icon usage example generator class IconUsageGenerator { static generate(iconName: string) { const componentName = iconName; const importLine = `import { ${componentName} } from 'lucide-react';`; const basicExample = `<${componentName} />`; const propsExample = `<${componentName} size={24} color="#3b82f6" strokeWidth={1.5} />`; return `${importLine}\n\nfunction Example() {\n return (\n <div>\n {/* Basic usage */}\n ${basicExample}\n \n {/* With props */}\n ${propsExample}\n </div>\n );\n}`; } } export function createMcpServer(): McpServer { const server = new McpServer({ name: "Lucide Icons MCP Server", version: "0.1.5" }); // Tool: search_icons server.tool( "search_icons", "Search for icons from lucide by name or category using partial matching", { query: z.string().describe("Search term for icon name"), category: z .string() .optional() .describe("category to filter by (optional)"), limit: searchSchemas.iconLimit.describe("Max results to return") }, async ({ query, category, limit }) => { let results = SearchService.filterIconsByName(iconMetadata, query); if (category) { results = SearchService.filterIconsByCategory(results, category); } results = SearchService.applyLimit(results, limit); return createTextResponse(results); } ); // Tool: search_categories server.tool( "search_categories", "Search for icon categories by category name using partial matching", { query: z.string().describe("Search term for category name"), limit: searchSchemas.categoryLimit.describe("Max results to return") }, async ({ query, limit }) => { let results = SearchService.filterCategories(query); results = SearchService.applyLimit(results, limit); return createTextResponse(results); } ); // Tool: fuzzy_search_icons server.tool( "fuzzy_search_icons", "Fuzzy Search for icons from lucide by icon name", { query: z.string().describe("Search term for icon name"), limit: searchSchemas.iconLimit.describe("Max results to return") }, async ({ query, limit }) => { const fuse = SearchService.createFuseSearch(iconMetadata, ["name"]); let results = fuse.search(query); results = SearchService.applyLimit(results, limit); return createTextResponse(results); } ); // Tool: fuzzy_search_categories server.tool( "fuzzy_search_categories", "Fuzzy Search for icon categories by category name", { query: z.string().describe("Search term for category name"), limit: searchSchemas.categoryLimit.describe("Max results to return") }, async ({ query, limit }) => { const fuse = SearchService.createFuseSearch(categories, ["name"]); let results = fuse.search(query); results = SearchService.applyLimit(results, limit); return createTextResponse(results); } ); // Tool: get_icon_usage_examples server.tool( "get_icon_usage_examples", "Get usage examples for a Lucide React icon", { name: z.string().describe("Icon name, e.g. 'home' or 'user'") }, async ({ name }) => { const icon = iconMetadata.find( (i) => i.name.toLowerCase() === name.toLowerCase() ); if (!icon) { return createTextResponse( `Icon "${name}" not found. Use search_icons to find available icons.` ); } const example = IconUsageGenerator.generate(icon.name); return { content: [ { type: "text" as const, text: example } ] }; } ); // Tool: list_icons_by_category server.tool( "list_all_icons_by_category", "List all icons in a specific category", { category: z.string().describe("Category name to list icons for"), limit: searchSchemas.listLimit.describe( "Max results to return (optional)" ) }, async ({ category, limit }) => { let results = getIconsByCategory(category); if (results.length === 0) { const availableCategories = getAllCategories(); return createTextResponse( `No icons found in category "${category}". Available categories: ${availableCategories.join(", ")}` ); } results = SearchService.applyLimit(results, limit); return createTextResponse(results); } ); // Tool: list_all_categories server.tool( "list_all_categories", "List all available icon categories with their icon counts", {}, async () => createTextResponse(categories) ); return server; }

Implementation Reference

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/lucide-icons-mcp'

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