TrueIcon
TrueIcon is an MCP server for AI coding assistants to find exact, version-correct icon names, import paths, and ready-to-paste import statements from the icon packages a project uses.
search_icons: search the project's icon packages by query, with optional provider, version, style, set, and limit filters; returns ranked matches with import lines.get_icon: fetch the full record and exact import statement for a known icon name/import name from a given provider.list_providers: show the project directory, configured providers and resolved versions, and all supported providers.ping: health check.Supports 15 providers including lucide, heroicons, react-icons, phosphor, tabler, iconoir, fluentui, carbon, antdesign, mui, radix, remix, and Font Awesome solid/regular/brands; detects versions from package.json, .iconmcp.json, or node_modules and indexes them.
Provides exact, version-correct Lucide icon names, import paths, and ready-to-paste import statements for projects using the lucide-react package.
Provides exact, version-correct Phosphor icon names, import paths, and import statements for projects using the @phosphor-icons/react package, including weight variants.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@TrueIconWhat's the correct lucide-react import for a trash icon?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
TrueIcon
TrueIcon is an MCP server that gives AI coding assistants exact, version-correct icon references. Your assistant searches the icon packages your project actually uses (lucide-react, react-icons, @heroicons/react, @phosphor-icons/react, @tabler/icons-react, iconoir-react, @fluentui/react-icons, @carbon/icons-react, @ant-design/icons, @mui/icons-material, @radix-ui/react-icons, @remixicon/react and the Font Awesome Free packages) and gets back real icon names, import paths and a ready-to-paste import line.
Why
AI assistants often guess icon names. The guess can be an icon that never existed, one renamed a few releases ago, or one from a different library, and you only find out when the build fails. TrueIcon closes that gap:
It reads which icon packages and versions your project uses.
It downloads those exact versions from npm and indexes every icon once.
The assistant calls
search_iconsand gets results that are guaranteed to exist in that version, for exampleimport { Trash2 } from 'lucide-react';.
Related MCP server: Svg/icons MCP
Supported providers
Provider id | npm package | Icon naming |
|
| Lucide's file names, e.g. |
|
|
|
|
|
|
|
|
|
|
| Tabler's icon names, e.g. |
|
|
|
|
|
|
|
| Carbon's export names in kebab case, e.g. |
|
|
|
|
| MUI's export names in kebab case, e.g. |
|
| Radix's icon names, e.g. |
|
| Remix's icon names with the |
|
| Font Awesome's icon names, e.g. |
|
| Same as |
|
| Same as |
Tools accept either the provider id or the npm package name ("lucide" or "lucide-react"). Usage snippets are for React. Phosphor weights all share one component, so pass the record's style as the weight prop (e.g. <TrashIcon weight="bold" />); the usage snippet only shows the import. Font Awesome imports are icon definitions, not components: render them with @fortawesome/react-fontawesome, e.g. <FontAwesomeIcon icon={faTrashCan} />.
Install
TrueIcon needs Node.js 20 or newer.
# Run without installing (this is what the MCP configs below do)
npx -y trueicon
# Or install globally and run the `trueicon` binary
npm i -g trueicon
trueicontrueicon is a stdio MCP server. Your MCP client starts it; running it by hand only prints trueicon: v<version> running on stdio to stderr and waits for JSON-RPC on stdin.
Quick start
Register TrueIcon with your MCP client (Claude Code, Claude Desktop, or VS Code and Cursor).
Ask your assistant for an icon.
That's it for most projects. TrueIcon finds the icon packages your package.json lists and the versions installed in node_modules. The first search for each package downloads and indexes it, which takes a few seconds. Later searches use the local cache.
Configuration
Which icon packages are searched
By default, every supported package listed in
dependenciesordevDependenciesof yourpackage.json.With
.iconmcp.jsonin the project, exactly the packages it lists. Use it to search only some of your icon packages, to add one yourpackage.jsondoesn't list (for example one that comes in through a UI kit), or to pin a version.
{
"providers": [
{ "package": "lucide-react" },
{ "package": "react-icons", "version": "5.3.0" },
{ "package": "@heroicons/react", "version": "^2.1.0" }
]
}Field | Type | Required | Meaning |
| array | yes | Icon packages to search. When it lists any, |
| string | yes | npm package name: |
| string | no | Exact version or npm range. Overrides the installed version (see Versions). |
| bool | no | Opt-in semantic search (default |
Unsupported packages in
.iconmcp.jsonare skipped, andsearch_iconsreports them as a warning.Invalid JSON or a malformed entry makes the tools return an error that names the file and the bad field.
If neither file names a supported package,
search_iconsreturns an error that says which directory it looked in. You can still passproviderto a tool call.
Semantic search (opt-in)
Set "semantic": true in .iconmcp.json to add meaning-based ranking to search_icons. Each query is embedded with a small local model (all-MiniLM-L6-v2, ~90MB downloaded once to the transformers.js cache) and matched against per-icon vectors built at index time; those semantic candidates are merged with the keyword results using reciprocal rank fusion, so exact-name matches still win while conceptual queries like "remove background" can surface eraser.
{
"providers": [{ "package": "lucide-react" }],
"semantic": true
}Semantic search runs on @huggingface/transformers, which is an optional peer dependency and is not installed by default, so installs that never enable the flag stay lean. To enable semantic search, install it once (about 400MB) alongside trueicon:
npm install @huggingface/transformersIf the flag is on but the package is missing, search_icons and get_icon fall back to keyword-only indexes and return a one-line warning with the install command.
Toggling the flag rebuilds the indexes once (vectors are stored in index.json alongside each record, and meta.json records the embedding model). It stays fully local: no data leaves your machine. TRUEICON_SEMANTIC=1 (or 0) overrides the flag for one-off runs.
Which directory is the project
TrueIcon reads package.json, .iconmcp.json and node_modules from the project directory. It picks the first of:
$TRUEICON_PROJECT_DIR, when set.A folder your MCP client shares with the server (MCP roots) that contains a
package.jsonor.iconmcp.json. Clients that support roots, like VS Code, tell TrueIcon which folders you're working in, so it follows your open project without any setup.The server's working directory, when it contains one of those files. Claude Code starts servers in your project, so this is how it finds it.
The first shared folder, else the working directory.
list_providers shows the directory in use and which rule picked it, so you can check what your client does.
Environment variables
Variable | Default | Purpose |
| shared folder, else working directory | Project root holding |
|
| Where downloaded packages and indexes are stored |
|
|
|
Versions
Auto-detection
A provider's version is resolved in this order:
The
versionargument passed to the tool call, if any.The provider's
versionin.iconmcp.json.The version installed in
node_modules, looking in the project directory and then each parent directory, so packages hoisted to a monorepo root are found.The version range declared for the package in the project's
package.json, checkingdependenciesfirst and thendevDependencies.
If none of these is available, the tool asks you to pin the version or add the package to package.json. TrueIcon doesn't read your lockfile, and it downloads its own copy of the package from npm rather than using the files in node_modules. For a range, it indexes the range's base version: ^0.460.0 indexes lucide-react@0.460.0. For a || b ranges, only the first part counts. Before you run npm install, that base version can be older than what you'll get, so pin it in .iconmcp.json if the exact version matters.
Version policy
Indexes are keyed by major.minor:
Patch versions are ignored. One index serves all of
0.460.x. The index built from0.460.0answers requests for0.460.3.A minor change gets its own index. Bumping
lucide-reactfrom0.460to0.461builds a fresh index on the next search, with no manual step.Majors are strict. A different major is always a separate index and is never served from another major's index.
Cached indexes rebuild automatically when the bundled
synonyms.jsonchanges (detected by hash) or the index format changes.
Using it with Claude
Claude Code
Add TrueIcon from your project directory:
claude mcp add trueicon -- npx -y trueiconOr commit a .mcp.json at the project root to share it with your team:
{
"mcpServers": {
"trueicon": {
"command": "npx",
"args": ["-y", "trueicon"]
}
}
}Claude Code starts the server in your project directory, so it finds your package.json there with no setup. If it runs from somewhere else, add "env": { "TRUEICON_PROJECT_DIR": "/absolute/path/to/project" }.
Claude Desktop
Claude Desktop doesn't start servers in your project directory, so set TRUEICON_PROJECT_DIR. If your version of Claude Desktop shares folders with servers, TrueIcon uses those instead; list_providers shows which directory it picked. Edit claude_desktop_config.json: ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows.
{
"mcpServers": {
"trueicon": {
"command": "npx",
"args": ["-y", "trueicon"],
"env": {
"TRUEICON_PROJECT_DIR": "/absolute/path/to/your/project"
}
}
}
}Restart Claude Desktop after editing the file.
Using it in VS Code and Cursor
Use the install badges at the top of this README. They add TrueIcon with TRUEICON_PROJECT_DIR set to ${workspaceFolder}, so it searches the project you have open.
To add it by hand in VS Code, create .vscode/mcp.json in your project:
{
"servers": {
"trueicon": {
"command": "npx",
"args": ["-y", "trueicon"],
"env": {
"TRUEICON_PROJECT_DIR": "${workspaceFolder}"
}
}
}
}In Cursor, use the same entry under "mcpServers" in .cursor/mcp.json.
Tools
Every tool returns a single JSON text block. On failure, the block is {"error": "..."} and the MCP result is flagged with isError: true.
search_icons
Searches the index and returns ranked matches with import statements.
Argument | Type | Required | Description |
| string | yes | What the icon should depict, e.g. |
| string | no | Provider id or package. Default: every provider the project uses (see Configuration) |
| string | no | Version or range. Default: resolved as described in Versions |
| string | no | Exact style filter, e.g. |
| string | no | Exact set filter, e.g. |
| integer | no | Maximum results, 1 to 50, default 10 |
Example call:
{ "query": "trash", "provider": "lucide", "limit": 3 }Response:
{
"results": [
{ "name": "trash", "importName": "Trash", "importPath": "lucide-react", "package": "lucide-react",
"version": "0.460.0", "style": "outline", "set": "lucide",
"usage": "import { Trash } from 'lucide-react';", "score": 0 },
{ "name": "trash-2", "importName": "Trash2", "importPath": "lucide-react", "package": "lucide-react",
"version": "0.460.0", "style": "outline", "set": "lucide",
"usage": "import { Trash2 } from 'lucide-react';", "score": 0.02 },
{ "name": "delete", "importName": "Delete", "importPath": "lucide-react", "package": "lucide-react",
"version": "0.460.0", "style": "outline", "set": "lucide",
"usage": "import { Delete } from 'lucide-react';", "score": 0.6 }
]
}How search works:
provider,styleandsetare exact, case-insensitive filters. They are applied before ranking.Candidates come from Fuse.js fuzzy matching over the icon name, import name, keywords and tags. Small typos are tolerated:
"detele"findsDelete.Icons whose name answers the query rank first, compared on the name without its style suffix (
delete-bin-line→delete-bin):the name is the query:
deletefindsdelete,delete-outlined,DeleteRegularthe name starts with the query:
delete-bin-linethe query is a phrase inside the name:
"arrow right"findscircle-arrow-rightevery query word is in the name, a synonym or a tag:
trashfindsrestore-from-trash, anddeletethrough the trash → delete synonym
Within a level, shorter names come first, so the plain icon beats composites (
deletebeforerestore-from-trash), and each icon's styles stay together with the default style first. Variant numbers are ignored unless the query has one, sotrashrankstrashthentrash-2. Everything else, such as typos, follows the fuzzy score.scoreruns from0(perfect) to1, so lower is better. It encodes the ranking above, so results from several providers are merged and sorted by score without losing it.Multi-word queries are tokenized: each word is matched on its own, only icons that match every word are kept, and they are ranked by their average score. So
"trash can"findstrash-canicons. Short keyword queries ("trash","settings","beer") still cast the widest net.If one provider fails, for example because its version can't be resolved or the download fails, its results are skipped and a
warningsarray explains why. The other providers still return results.
list_providers
Takes no arguments. Returns the project directory TrueIcon reads and how it was found, the providers the project uses with their resolved versions, and every provider TrueIcon supports.
{
"project": { "dir": "/Users/you/code/my-app", "source": "roots" },
"providersFrom": "package.json",
"configured": [
{ "id": "lucide", "package": "lucide-react", "version": "1.47.0", "source": "node_modules" },
{ "id": "heroicons", "package": "@heroicons/react", "version": "^2.1.0", "source": "package.json" }
],
"registry": [
{ "id": "react-icons", "package": "react-icons", "description": "Aggregated icon sets (Font Awesome, Material, Feather, and more) as React components" },
{ "id": "lucide", "package": "lucide-react", "description": "Lucide icons as React components" },
{ "id": "heroicons", "package": "@heroicons/react", "description": "Heroicons by the Tailwind CSS team as React components" },
{ "id": "phosphor", "package": "@phosphor-icons/react", "description": "Phosphor icons in six weights (thin, light, regular, bold, fill, duotone) as React components" },
{ "id": "tabler", "package": "@tabler/icons-react", "description": "Tabler icons (outline and filled) as React components" },
{ "id": "iconoir", "package": "iconoir-react", "description": "Iconoir icons (regular and solid) as React components" },
{ "id": "fluentui", "package": "@fluentui/react-icons", "description": "Microsoft Fluent UI System icons (regular, filled and color) as React components" },
{ "id": "carbon", "package": "@carbon/icons-react", "description": "IBM Carbon Design System icons as React components" },
{ "id": "antdesign", "package": "@ant-design/icons", "description": "Ant Design icons (outlined, filled and two-tone) as React components" },
{ "id": "mui", "package": "@mui/icons-material", "description": "Material UI icons (filled, outlined, rounded, sharp and two-tone) as React components" },
{ "id": "radix", "package": "@radix-ui/react-icons", "description": "Radix UI icons (15x15) as React components" },
{ "id": "remix", "package": "@remixicon/react", "description": "Remix Icon (line and fill) as React components" },
{ "id": "fontawesome-solid", "package": "@fortawesome/free-solid-svg-icons", "description": "Font Awesome Free solid icons, rendered with @fortawesome/react-fontawesome" },
{ "id": "fontawesome-regular", "package": "@fortawesome/free-regular-svg-icons", "description": "Font Awesome Free regular icons, rendered with @fortawesome/react-fontawesome" },
{ "id": "fontawesome-brands", "package": "@fortawesome/free-brands-svg-icons", "description": "Font Awesome Free brand logos, rendered with @fortawesome/react-fontawesome" }
]
}project.sourceis"TRUEICON_PROJECT_DIR","roots"(a folder your MCP client shared) or"cwd"(the server's working directory). See Which directory is the project.providersFromis"iconmcp.json","package.json", ornullwhen neither names a supported package.Each provider's
sourcesays where its version came from:"iconmcp.json","node_modules"or"package.json".versionandsourcearenullwhen none provides a version.idisnullfor a package in.iconmcp.jsonthat TrueIcon doesn't support.
get_icon
Gets the full record and import statement for an icon whose name the assistant already knows.
Argument | Type | Required | Description |
| string | yes | Icon name ( |
| string | yes | Provider id or package |
| string | no | Version or range. Default: resolved as described in Versions |
Example call:
{ "name": "Trash2", "provider": "lucide" }Response:
{
"id": "lucide-react@0.460:trash-2",
"name": "trash-2",
"importName": "Trash2",
"importPath": "lucide-react",
"provider": "lucide",
"package": "lucide-react",
"version": "0.460.0",
"style": "outline",
"set": "lucide",
"categories": [],
"tags": [],
"keywords": ["trash", "2", "delete", "remove", "bin", "garbage", "rubbish"],
"svg": "<path d=\"M3 6h18\"/><path d=\"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\"/>…",
"usage": "import { Trash2 } from 'lucide-react';"
}svg is the icon's inner SVG markup, meaning the children of the root <svg> element. Heroicons uses the same import name in every size and style (TrashIcon). Pass the full variant name, such as "trash-24-outline", to get a specific one.
ping
A health check that returns {"status":"ok","server":"trueicon"}.
Indexing and caching
The first time a tool needs package@major.minor, TrueIcon does the following:
It downloads the package tarball from
https://registry.npmjs.org, verifies its sha512 integrity, and extracts it into the cache.It parses the package's shipped files with the provider's adapter. Nothing is executed. Icons are read from the compiled source.
It writes
index.json(one record per icon) andmeta.json(exact version, synonyms hash, index format, build time).
Later calls only read index.json. Package files are never touched at query time. From your node_modules, TrueIcon only reads each icon package's package.json to get the installed version, and it never modifies anything there. If several tool calls need the same index at once, they share one download.
The cache root is ~/.trueicon/cache, or $TRUEICON_CACHE if set:
~/.trueicon/cache/
├── lucide-react@0.460/ # extracted package + index.json + meta.json
├── react-icons@5.3/ # extracted package + index.json + meta.json
├── heroicons-react@2.1/ # extracted @heroicons/react package
└── @heroicons/react@2.1/ # index.json + meta.json for @heroicons/reactDownloads go to
<package>@<major.minor>, where scoped names are flattened:@heroicons/reactbecomesheroicons-react. A.download-completemarker is written last, and a directory without it is treated as partial and replaced.Indexes go to
<package>@<major.minor>/index.jsonandmeta.json. For unscoped packages this is the same directory as the download.The cache is safe to delete. It is rebuilt on demand, which needs network access.
Each record's keywords combine the name parts, the tags, and synonym expansions from the bundled synonyms.json. The expansions are added at index time, so "bin" finds Trash2 without any extra work at query time.
Contributing
git clone https://github.com/manikumarkv/trueicon.git
cd trueicon
npm ci
npm run build # compile to dist/
npm test # vitest
npm run lint # eslint
npm run typecheck # tsc --noEmitCI runs lint, typecheck and tests on Node 20 and 22 for every push and pull request.
Tests
Command | What it checks | Network |
| Adapter parsing and every tool ( | No |
| Every provider against the real npm packages: several pinned releases plus the current latest, checking the icon count and a few well-known icons | Yes |
The fixtures only change when someone edits them, so they can't catch a provider that changes its package format upstream. npm run smoke does. Run npm run smoke -- lucide tabler to check only some providers. CI runs it on pull requests that change src/providers/, src/indexer/ or src/cache/, and every Monday against the latest releases.
Testing and debugging locally
These scripts build the server and run it against playground/, a sample project that lists all 15 providers at their latest versions. They use a separate cache in .cache/dev/, so your real ~/.trueicon cache is untouched.
# Call one tool and print the result
npm run dev:call -- list_providers
npm run dev:call -- search_icons query="trash can" limit=5
npm run dev:call -- search_icons query=trash provider=lucide version=1.47.0
npm run dev:call -- get_icon name=Trash2 provider=lucide
# Open the MCP Inspector web UI on the local build
npm run dev:inspect
# Same, with the Node debugger on port 9229
npm run dev:debugArguments are
key=valuepairs. Numbers and booleans are parsed, solimit=5is sent as a number.Another project: set
TRUEICON_PROJECT_DIRto test against itspackage.jsonand.iconmcp.json, e.g.TRUEICON_PROJECT_DIR=~/code/my-app npm run dev:inspect.Rebuild indexes: add
--freshto delete the dev cache first, e.g.npm run dev:call -- --fresh search_icons query=trash. Use it after changing an adapter.Breakpoints: run
npm run dev:debug, then in VS Code use Debug: Attach to Node Process, or openchrome://inspectin Chrome. Source maps are on, so breakpoints work in the.tsfiles undersrc/. Set them, then call a tool from the Inspector.Logging: stdout carries the MCP protocol, so log with
console.error. It shows in the terminal fordev:calland in the Inspector's server log fordev:inspect.Manual test prompts:
playground/TEST-PROMPTS.mdis a checklist of prompts to run in an MCP client against the playground, with the expected tool calls and results. It covers every tool, all 15 providers, ranking, configuration errors and semantic search. Run it before a release.
Extending synonyms.json
src/synonyms/synonyms.json maps a term to extra search terms:
{
"trash": ["delete", "remove", "bin", "garbage", "rubbish"],
"logout": ["sign-out", "signout", "exit", "leave"]
}Keys are matched against an icon's name parts (the name split on
-) and its tags.trash-2matches the keytrash.Values are added to that icon's
keywords.Expansion is one-way. If
binshould also find icons nameddelete, add both"trash": ["bin"]and"delete": ["bin"], or add a reverse entry.Write keys and values in lowercase, and give every key a non-empty array of strings.
tests/synonyms.test.tschecks this.Changing the file changes its hash, so cached indexes rebuild automatically on the next search.
Adding a provider
Register it in
src/providers/registry.tswith a stableid, the npmpackageand a shortdescription.Write an adapter in
src/providers/adapters/<provider>.tsthat exportsparseIcons(packageDir: string): RawIcon[](seesrc/providers/adapter.ts). It gets the extracted package directory and returns oneRawIconper icon:name: kebab-case and unique within the package, because it becomes part of the record id. UsetoKebabCasefromadapter.ts. If the package has variants with clashing component names, add the variant to the name, as the heroicons, react-icons, phosphor and iconoir adapters do.importNameandimportPath: the exact export and module specifier a user would import.svg: the inner SVG markup.LiteralCursor(src/providers/jsLiteral.ts) parses JS object and array literals without executing code.toSvgAttrsandrenderSvg(src/providers/svg.ts) turn React props into SVG markup, andparseCreateElementreads compiledcreateElement(...)trees.Optional
style,set,categoriesandtags.Put a comment at the top of the adapter describing the package's file layout, as the existing adapters do.
Wire it up in
src/providers/adapters/index.tsby adding it toADAPTERSunder the provider id.Test it. Add a small pinned fixture under
tests/fixtures/<provider>/that mirrors the package layout, with a few real icon files plus any files the adapter must skip. Then addtests/adapters/<provider>.test.ts, covering name mapping, import paths, SVG output andbuildIndexrecord ids like the existing adapter tests.tests/adapters/common.test.tsfails if a registered provider has no adapter.Add it to the tool tests by adding a case to
CASESintests/providers-tools.test.ts: the fixture, a search query, one icon with its exact import line, and a deprecated alias if the package has them. The test fails if a registered provider has no case.Add smoke targets to
TARGETSinscripts/smoke.mjs: a few well-known import names and a minimum icon count well below the real one. Then runnpm run smoke -- <provider>to check it against the real published package.
License
MIT © 2026 manikumarkv
Available Tools
4 toolsget_iconA
Get the full record and exact import statement for an icon whose name is already known, e.g. Trash2 from lucide.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Icon name or import name, e.g. "trash-2" or "Trash2" | |
| version | No | Package version or range; defaults to the project's version | |
| provider | Yes | Provider id or npm package, e.g. "lucide" or "lucide-react" |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does disclose the output behavior ('full record and exact import statement'), which is the core behavioral trait for a getter. However, it does not mention failure behavior for unknown icons, provider-specific formatting, or any other side effects, leaving a moderate gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that front-loads the verb and resource, conveys the scoping constraint, and includes a clarifying example. Every word earns its place with zero redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple getter with 3 parameters, 100% schema coverage, and no output schema, the description adequately covers the return value and the tool's niche relative to siblings. The only minor gap is the lack of error/failure semantics for unknown icon names, which is low-stakes for a read-only lookup.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents name, version, and provider including examples and defaults. The description adds only an example mapping ('Trash2 from lucide') but no additional meaning beyond what the schema provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Get') with a specific resource ('full record and exact import statement') and adds a scoping constraint ('whose name is already known') that clearly differentiates it from the sibling search_icons. The concrete example 'Trash2 from lucide' makes the purpose unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Whose name is already known' gives clear context for when to use this tool versus searching, implicitly routing the agent away from search_icons and toward this tool when the name is known. However, it does not explicitly name the alternative or state when-not-to-use, so it falls short of the explicit-alternative bar.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_providersA
List the icon providers this project uses (from .iconmcp.json, else detected in package.json) with their versions, the project directory trueicon reads, and all providers trueicon supports.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It transparently states the data source (.iconmcp.json else package.json), what it returns (versions, directory, supported providers), and implies a read-only operation. It doesn't mention side effects or permissions, but for a list operation this is adequate. The level of detail about the input source and output contents exceeds the minimum.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence but somewhat lengthy with multiple clauses enumerating output elements. It is front-loaded with the main action 'List' and the primary resource, but the trailing details (versions, directory, supported providers) are necessary for clarity. It is not overly verbose, though it could be split into two sentences for better readability. Overall efficient and focused.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read-only tool with no output schema, the description is comprehensive. It specifies the exact information returned (providers with versions, project directory, all supported providers) and even notes the fallback source (package.json if .iconmcp.json absent). This gives an agent sufficient understanding to call the tool and interpret results without ambiguity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so parameter semantics are trivially satisfied. The rubric gives a baseline of 4 for zero parameters, and the description adds context about what the tool lists, which adds value even though no parameters exist. It doesn't repeat schema information since the schema is empty.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'List' with a clear resource 'the icon providers this project uses' and specifies additional output elements (versions, project directory, supported providers). It effectively distinguishes this tool from siblings like get_icon and search_icons by focusing on configuration and capability enumeration rather than icon retrieval or search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for inspecting the project's provider configuration and available providers. While it doesn't explicitly state when not to use it or name alternatives, the distinction from siblings (get_icon, search_icons, ping) is clear enough that an agent would know to call this when needing provider metadata. It lacks explicit when-to-use guidance, but the purpose is self-evident.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pingB
Health check
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. 'Health check' implies a read-only status verification but does not disclose any return format, potential delay, or what exactly is being checked. An agent gets minimal behavioral insight beyond the tool name.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely short—two words with no filler. For a tool with zero parameters and a clear single purpose, this is appropriately sized. It is not verbose or structured, but that is acceptable here.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the trivial nature of a health check with no parameters, the description is nearly sufficient. However, with no output schema or described return behavior, an agent does not know what the response will look like or how to interpret success vs. failure. Sibling separation is clear, but the missing response detail is a gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters approximating the schema, so 100% of parameters are documented. The description adds no parameter detail, but none is needed. Baseline for 0-param tools is 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description 'Health check' directly names the tool's function as a status probe, which is a specific enough resource scope. It distinguishes itself from the icon/provider siblings, which clearly serve different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit guidance on when to use this tool versus alternatives. While the sibling names make the distinction apparent, the description does not state any context, prerequisites, or conditions that would help an agent decide to call ping.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_iconsA
Search icons in the icon packages installed in the project. Returns ranked matches with ready-to-paste import statements.
| Name | Required | Description | Default |
|---|---|---|---|
| set | No | Icon set filter (react-icons), e.g. "fa6" | |
| limit | No | Maximum results (1-50, default 10) | |
| query | Yes | What the icon should depict, e.g. "trash can" | |
| style | No | Style filter, e.g. "outline" or "solid" | |
| version | No | Package version or range; defaults to the project's version | |
| provider | No | Provider id or npm package, e.g. "lucide" or "lucide-react" |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full disclosure burden. It usefully discloses that results are ranked and include ready-to-paste import statements, but it does not clarify read-only status, matching semantics, or what 'installed packages' means in practical terms.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler. The main verb and scope are front-loaded, and the second sentence adds the key output detail without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter tool with no annotations and no output schema, the description gives the essential purpose and output but leaves usage guidance and behavioral details to inference. The high schema coverage compensates for parameter semantics, so it is adequate but not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the input schema already documents all six parameters, including query, set, style, version, and provider. The description adds no parameter-specific meaning beyond the overall search scope, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific action ('search icons') and a clear scope ('icon packages installed in the project'), and signals the output ('ranked matches with ready-to-paste import statements'). It is distinguishable from siblings like get_icon and list_providers, though it does not explicitly name them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies use when an agent needs to locate an icon by concept, but it gives no explicit when-to-use or when-not-to-use guidance and does not mention alternatives such as get_icon for retrieving a specific icon. The sibling names help, but the description itself leaves the choice to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.1- First observed
get_icon - First observed
list_providers - First observed
ping - First observed
search_icons
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: listing providers, fetching an icon by exact name, searching icons, and health checking. No overlap exists between get_icon and search_icons since one requires a known name and the other performs fuzzy discovery.
All tools follow a consistent verb_noun pattern: list_providers, get_icon, search_icons. The exception 'ping' is a standard health-check convention and does not disrupt the overall pattern.
Four tools is a well-scoped set for an icon utility server. Each tool serves a necessary function without redundancy or bloat.
For the stated purpose of querying icon providers and retrieving icons, the surface is complete: it lists installed providers, searches icons, and retrieves exact import details. No obvious dead-ends or missing operations exist.
Maintenance
Related MCP Connectors
Multilingual semantic SVG icon search with previews for AI coding agents. 20,000+ icons.
Search and fetch SVG icons from 250,000+ icons across 200+ open-source icon sets.
Icons for agentic development: search & fetch 366,000+ open-source icons as SVG/PNG. No API key.
Search open SVG icon packs and fetch exact SVG markup from coding agents through MCP.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceProvides access to over 200,000 icons from 150+ collections with features for searching, recommendations, and direct file synchronization. It supports multiple frameworks and optimizes AI performance by writing icon code directly to project files.504 npm1,294MIT

Svg/icons MCPofficial
AlicenseNot gradedqualityCmaintenanceEnables AI coding tools to search, inspect, recommend, and export SVG icons from svgicons.com for use in design systems, frontend projects, and AI-assisted workflows.MIT- AlicenseAqualityBmaintenanceEnables AI agents to search, import, migrate, validate, and maintain official Google Material Symbols across various platforms and IDEs.11MIT
- AlicenseAqualityBmaintenanceEnables AI coding agents to search, retrieve, and add Lucide SVG icons to projects.524 npmMIT