trueicon 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -32
- package/dist/config/loadConfig.d.ts +11 -0
- package/dist/config/loadConfig.js +51 -6
- package/dist/config/loadConfig.js.map +1 -1
- package/dist/providers/adapters/lucide.js +67 -20
- package/dist/providers/adapters/lucide.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +8 -4
- package/dist/server.js.map +1 -1
- package/dist/tools/context.d.ts +30 -5
- package/dist/tools/context.js +39 -6
- package/dist/tools/context.js.map +1 -1
- package/dist/tools/getIcon.d.ts +2 -1
- package/dist/tools/getIcon.js +10 -3
- package/dist/tools/getIcon.js.map +1 -1
- package/dist/tools/listProviders.d.ts +15 -3
- package/dist/tools/listProviders.js +12 -8
- package/dist/tools/listProviders.js.map +1 -1
- package/dist/tools/projectLocator.d.ts +6 -0
- package/dist/tools/projectLocator.js +40 -0
- package/dist/tools/projectLocator.js.map +1 -0
- package/dist/tools/searchIcons.d.ts +6 -2
- package/dist/tools/searchIcons.js +12 -11
- package/dist/tools/searchIcons.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -44,27 +44,21 @@ npm i -g trueicon
|
|
|
44
44
|
trueicon
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
`trueicon` is a stdio MCP server. Your MCP client starts it; running it by hand only prints `trueicon:
|
|
47
|
+
`trueicon` 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.
|
|
48
48
|
|
|
49
49
|
## Quick start
|
|
50
50
|
|
|
51
|
-
1.
|
|
51
|
+
1. Register TrueIcon with your MCP client ([Claude Code](#claude-code), [Claude Desktop](#claude-desktop), or [VS Code and Cursor](#using-it-in-vs-code-and-cursor)).
|
|
52
|
+
2. Ask your assistant for an icon.
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
{
|
|
55
|
-
"providers": [
|
|
56
|
-
{ "package": "lucide-react" },
|
|
57
|
-
{ "package": "@heroicons/react", "version": "2.1.5" }
|
|
58
|
-
]
|
|
59
|
-
}
|
|
60
|
-
```
|
|
54
|
+
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.
|
|
61
55
|
|
|
62
|
-
|
|
63
|
-
3. Ask your assistant for an icon. The first search for each package downloads and indexes it, which takes a few seconds. Later searches use the local cache.
|
|
56
|
+
## Configuration
|
|
64
57
|
|
|
65
|
-
|
|
58
|
+
### Which icon packages are searched
|
|
66
59
|
|
|
67
|
-
|
|
60
|
+
- **By default**, every supported package listed in `dependencies` or `devDependencies` of your `package.json`.
|
|
61
|
+
- **With `.iconmcp.json`** in the project, exactly the packages it lists. Use it to search only some of your icon packages, to add one your `package.json` doesn't list (for example one that comes in through a UI kit), or to pin a version.
|
|
68
62
|
|
|
69
63
|
```json
|
|
70
64
|
{
|
|
@@ -78,20 +72,31 @@ TrueIcon looks for `.iconmcp.json` in the project directory. That is `$TRUEICON_
|
|
|
78
72
|
|
|
79
73
|
| Field | Type | Required | Meaning |
|
|
80
74
|
| ----------------------- | ------ | -------- | ---------------------------------------------------------------------------------------- |
|
|
81
|
-
| `providers` | array | yes | Icon packages
|
|
75
|
+
| `providers` | array | yes | Icon packages to search. When it lists any, `package.json` is not used to pick packages. |
|
|
82
76
|
| `providers[].package` | string | yes | npm package name: `lucide-react`, `react-icons`, `@heroicons/react`, `@phosphor-icons/react`, `@tabler/icons-react`, `iconoir-react`, `@fluentui/react-icons`, `@carbon/icons-react` or `@ant-design/icons`. |
|
|
83
|
-
| `providers[].version` | string | no | Exact version or npm range.
|
|
77
|
+
| `providers[].version` | string | no | Exact version or npm range. Overrides the installed version (see [Versions](#versions)). |
|
|
84
78
|
|
|
85
|
-
-
|
|
86
|
-
- Unsupported packages in the list are skipped, and `search_icons` reports them as a warning.
|
|
79
|
+
- Unsupported packages in `.iconmcp.json` are skipped, and `search_icons` reports them as a warning.
|
|
87
80
|
- Invalid JSON or a malformed entry makes the tools return an error that names the file and the bad field.
|
|
81
|
+
- If neither file names a supported package, `search_icons` returns an error that says which directory it looked in. You can still pass `provider` to a tool call.
|
|
82
|
+
|
|
83
|
+
### Which directory is the project
|
|
84
|
+
|
|
85
|
+
TrueIcon reads `package.json`, `.iconmcp.json` and `node_modules` from the project directory. It picks the first of:
|
|
86
|
+
|
|
87
|
+
1. `$TRUEICON_PROJECT_DIR`, when set.
|
|
88
|
+
2. A folder your MCP client shares with the server (MCP [roots](https://modelcontextprotocol.io/docs/concepts/roots)) that contains a `package.json` or `.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.
|
|
89
|
+
3. 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.
|
|
90
|
+
4. The first shared folder, else the working directory.
|
|
91
|
+
|
|
92
|
+
`list_providers` shows the directory in use and which rule picked it, so you can check what your client does.
|
|
88
93
|
|
|
89
94
|
### Environment variables
|
|
90
95
|
|
|
91
|
-
| Variable | Default
|
|
92
|
-
| ---------------------- |
|
|
93
|
-
| `TRUEICON_PROJECT_DIR` | working directory
|
|
94
|
-
| `TRUEICON_CACHE` | `~/.trueicon/cache`
|
|
96
|
+
| Variable | Default | Purpose |
|
|
97
|
+
| ---------------------- | ------------------------------------ | ---------------------------------------------------- |
|
|
98
|
+
| `TRUEICON_PROJECT_DIR` | shared folder, else working directory | Project root holding `package.json` and `.iconmcp.json` |
|
|
99
|
+
| `TRUEICON_CACHE` | `~/.trueicon/cache` | Where downloaded packages and indexes are stored |
|
|
95
100
|
|
|
96
101
|
## Versions
|
|
97
102
|
|
|
@@ -101,9 +106,10 @@ A provider's version is resolved in this order:
|
|
|
101
106
|
|
|
102
107
|
1. The `version` argument passed to the tool call, if any.
|
|
103
108
|
2. The provider's `version` in `.iconmcp.json`.
|
|
104
|
-
3. The version
|
|
109
|
+
3. 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.
|
|
110
|
+
4. The version range declared for the package in the project's `package.json`, checking `dependencies` first and then `devDependencies`.
|
|
105
111
|
|
|
106
|
-
If none of these is available, the tool asks you to pin the version or add the package to `package.json`. TrueIcon
|
|
112
|
+
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.
|
|
107
113
|
|
|
108
114
|
### Version policy
|
|
109
115
|
|
|
@@ -137,11 +143,11 @@ Or commit a `.mcp.json` at the project root to share it with your team:
|
|
|
137
143
|
}
|
|
138
144
|
```
|
|
139
145
|
|
|
140
|
-
Claude Code starts the server in your project directory, so it finds
|
|
146
|
+
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" }`.
|
|
141
147
|
|
|
142
148
|
### Claude Desktop
|
|
143
149
|
|
|
144
|
-
Claude Desktop doesn't start servers in your project directory, so set `TRUEICON_PROJECT_DIR`. Edit `claude_desktop_config.json`: `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows.
|
|
150
|
+
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.
|
|
145
151
|
|
|
146
152
|
```json
|
|
147
153
|
{
|
|
@@ -192,7 +198,7 @@ Searches the index and returns ranked matches with import statements.
|
|
|
192
198
|
| Argument | Type | Required | Description |
|
|
193
199
|
| ---------- | ------- | -------- | ------------------------------------------------------------------------------------ |
|
|
194
200
|
| `query` | string | yes | What the icon should depict, e.g. `"trash"` |
|
|
195
|
-
| `provider` | string | no | Provider id or package. Default: every provider
|
|
201
|
+
| `provider` | string | no | Provider id or package. Default: every provider the project uses ([see Configuration](#which-icon-packages-are-searched)) |
|
|
196
202
|
| `version` | string | no | Version or range. Default: resolved as described in [Versions](#versions) |
|
|
197
203
|
| `style` | string | no | Exact style filter, e.g. `"outline"`, `"solid"`, `"filled"` (tabler), `"regular"` (fluentui), `"two-tone"` (antdesign) or a phosphor weight such as `"bold"`. Lucide icons are all `outline`; base carbon icons have no style |
|
|
198
204
|
| `set` | string | no | Exact set filter, e.g. `"fa6"` or `"md"` for react-icons |
|
|
@@ -232,13 +238,15 @@ How search works:
|
|
|
232
238
|
|
|
233
239
|
### `list_providers`
|
|
234
240
|
|
|
235
|
-
Takes no arguments. Returns the providers
|
|
241
|
+
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.
|
|
236
242
|
|
|
237
243
|
```json
|
|
238
244
|
{
|
|
245
|
+
"project": { "dir": "/Users/you/code/my-app", "source": "roots" },
|
|
246
|
+
"providersFrom": "package.json",
|
|
239
247
|
"configured": [
|
|
240
|
-
{ "id": "lucide", "package": "lucide-react", "version": "
|
|
241
|
-
{ "id": "heroicons", "package": "@heroicons/react", "version": "2.1.
|
|
248
|
+
{ "id": "lucide", "package": "lucide-react", "version": "1.47.0", "source": "node_modules" },
|
|
249
|
+
{ "id": "heroicons", "package": "@heroicons/react", "version": "^2.1.0", "source": "package.json" }
|
|
242
250
|
],
|
|
243
251
|
"registry": [
|
|
244
252
|
{ "id": "react-icons", "package": "react-icons", "description": "Aggregated icon sets (Font Awesome, Material, Feather, and more) as React components" },
|
|
@@ -254,7 +262,9 @@ Takes no arguments. Returns the providers configured in `.iconmcp.json` with the
|
|
|
254
262
|
}
|
|
255
263
|
```
|
|
256
264
|
|
|
257
|
-
`source` is `"
|
|
265
|
+
- `project.source` is `"TRUEICON_PROJECT_DIR"`, `"roots"` (a folder your MCP client shared) or `"cwd"` (the server's working directory). See [Which directory is the project](#which-directory-is-the-project).
|
|
266
|
+
- `providersFrom` is `"iconmcp.json"`, `"package.json"`, or `null` when neither names a supported package.
|
|
267
|
+
- Each provider's `source` says where its version came from: `"iconmcp.json"`, `"node_modules"` or `"package.json"`. `version` and `source` are `null` when none provides a version. `id` is `null` for a package in `.iconmcp.json` that TrueIcon doesn't support.
|
|
258
268
|
|
|
259
269
|
### `get_icon`
|
|
260
270
|
|
|
@@ -307,7 +317,7 @@ The first time a tool needs `package@major.minor`, TrueIcon does the following:
|
|
|
307
317
|
2. It parses the package's shipped files with the provider's adapter. Nothing is executed. Icons are read from the compiled source.
|
|
308
318
|
3. It writes `index.json` (one record per icon) and `meta.json` (exact version, synonyms hash, index format, build time).
|
|
309
319
|
|
|
310
|
-
Later calls only read `index.json`. Package files are never touched at query time
|
|
320
|
+
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.
|
|
311
321
|
|
|
312
322
|
The cache root is `~/.trueicon/cache`, or `$TRUEICON_CACHE` if set:
|
|
313
323
|
|
|
@@ -339,6 +349,39 @@ npm run typecheck # tsc --noEmit
|
|
|
339
349
|
|
|
340
350
|
CI runs lint, typecheck and tests on Node 20 and 22 for every push and pull request.
|
|
341
351
|
|
|
352
|
+
### Tests
|
|
353
|
+
|
|
354
|
+
| Command | What it checks | Network |
|
|
355
|
+
| --- | --- | --- |
|
|
356
|
+
| `npm test` | Adapter parsing and every tool (`search_icons`, `get_icon`, `list_providers`) for all 9 providers, using the small fixtures in `tests/fixtures/` | No |
|
|
357
|
+
| `npm run smoke` | 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 |
|
|
358
|
+
|
|
359
|
+
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.
|
|
360
|
+
|
|
361
|
+
### Testing and debugging locally
|
|
362
|
+
|
|
363
|
+
These scripts build the server and run it against `playground/`, a sample project that lists all 9 providers at their latest versions. They use a separate cache in `.cache/dev/`, so your real `~/.trueicon` cache is untouched.
|
|
364
|
+
|
|
365
|
+
```sh
|
|
366
|
+
# Call one tool and print the result
|
|
367
|
+
npm run dev:call -- list_providers
|
|
368
|
+
npm run dev:call -- search_icons query="trash can" limit=5
|
|
369
|
+
npm run dev:call -- search_icons query=trash provider=lucide version=1.47.0
|
|
370
|
+
npm run dev:call -- get_icon name=Trash2 provider=lucide
|
|
371
|
+
|
|
372
|
+
# Open the MCP Inspector web UI on the local build
|
|
373
|
+
npm run dev:inspect
|
|
374
|
+
|
|
375
|
+
# Same, with the Node debugger on port 9229
|
|
376
|
+
npm run dev:debug
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
- **Arguments** are `key=value` pairs. Numbers and booleans are parsed, so `limit=5` is sent as a number.
|
|
380
|
+
- **Another project:** set `TRUEICON_PROJECT_DIR` to test against its `package.json` and `.iconmcp.json`, e.g. `TRUEICON_PROJECT_DIR=~/code/my-app npm run dev:inspect`.
|
|
381
|
+
- **Rebuild indexes:** add `--fresh` to delete the dev cache first, e.g. `npm run dev:call -- --fresh search_icons query=trash`. Use it after changing an adapter.
|
|
382
|
+
- **Breakpoints:** run `npm run dev:debug`, then in VS Code use **Debug: Attach to Node Process**, or open `chrome://inspect` in Chrome. Source maps are on, so breakpoints work in the `.ts` files under `src/`. Set them, then call a tool from the Inspector.
|
|
383
|
+
- **Logging:** stdout carries the MCP protocol, so log with `console.error`. It shows in the terminal for `dev:call` and in the Inspector's server log for `dev:inspect`.
|
|
384
|
+
|
|
342
385
|
### Extending `synonyms.json`
|
|
343
386
|
|
|
344
387
|
`src/synonyms/synonyms.json` maps a term to extra search terms:
|
|
@@ -367,6 +410,8 @@ CI runs lint, typecheck and tests on Node 20 and 22 for every push and pull requ
|
|
|
367
410
|
- Put a comment at the top of the adapter describing the package's file layout, as the existing adapters do.
|
|
368
411
|
3. **Wire it up** in `src/providers/adapters/index.ts` by adding it to `ADAPTERS` under the provider id.
|
|
369
412
|
4. **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 add `tests/adapters/<provider>.test.ts`, covering name mapping, import paths, SVG output and `buildIndex` record ids like the existing adapter tests. `tests/adapters/common.test.ts` fails if a registered provider has no adapter.
|
|
413
|
+
5. **Add it to the tool tests** by adding a case to `CASES` in `tests/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.
|
|
414
|
+
6. **Add smoke targets** to `TARGETS` in `scripts/smoke.mjs`: a few well-known import names and a minimum icon count well below the real one. Then run `npm run smoke -- <provider>` to check it against the real published package.
|
|
370
415
|
|
|
371
416
|
## License
|
|
372
417
|
|
|
@@ -10,3 +10,14 @@ export interface ProjectConfig {
|
|
|
10
10
|
export declare function loadProjectConfig(projectDir: string): ProjectConfig;
|
|
11
11
|
/** Returns the version range declared for packageName in <projectDir>/package.json. */
|
|
12
12
|
export declare function detectVersion(projectDir: string, packageName: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Returns the packages from `candidates` that <projectDir>/package.json lists in dependencies or
|
|
15
|
+
* devDependencies, in candidate order. A missing package.json lists nothing.
|
|
16
|
+
*/
|
|
17
|
+
export declare function detectListedPackages(projectDir: string, candidates: readonly string[]): string[];
|
|
18
|
+
/**
|
|
19
|
+
* Returns the version of packageName installed in node_modules, looking in <projectDir> and then
|
|
20
|
+
* each parent directory, as Node's module resolution does (this covers hoisted monorepo installs).
|
|
21
|
+
* Returns null when it is not installed or its package.json has no version.
|
|
22
|
+
*/
|
|
23
|
+
export declare function detectInstalledVersion(projectDir: string, packageName: string): string | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
3
|
export const CONFIG_FILE = ".iconmcp.json";
|
|
4
4
|
function isObject(value) {
|
|
5
5
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -46,8 +46,8 @@ export function loadProjectConfig(projectDir) {
|
|
|
46
46
|
});
|
|
47
47
|
return { providers };
|
|
48
48
|
}
|
|
49
|
-
/**
|
|
50
|
-
|
|
49
|
+
/** Reads <projectDir>/package.json, or returns null when there is none. */
|
|
50
|
+
function readPackageJson(projectDir) {
|
|
51
51
|
const path = join(projectDir, "package.json");
|
|
52
52
|
let raw;
|
|
53
53
|
try {
|
|
@@ -55,17 +55,62 @@ export function detectVersion(projectDir, packageName) {
|
|
|
55
55
|
}
|
|
56
56
|
catch (error) {
|
|
57
57
|
if (isMissing(error))
|
|
58
|
-
|
|
58
|
+
return null;
|
|
59
59
|
throw error;
|
|
60
60
|
}
|
|
61
61
|
if (!isObject(raw))
|
|
62
62
|
throw new Error(`Invalid ${path}: expected a JSON object`);
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
return raw;
|
|
64
|
+
}
|
|
65
|
+
const DEPENDENCY_FIELDS = ["dependencies", "devDependencies"];
|
|
66
|
+
/** Returns the version range declared for packageName in <projectDir>/package.json. */
|
|
67
|
+
export function detectVersion(projectDir, packageName) {
|
|
68
|
+
const pkg = readPackageJson(projectDir);
|
|
69
|
+
const path = join(projectDir, "package.json");
|
|
70
|
+
if (!pkg)
|
|
71
|
+
throw new Error(`No package.json found at ${path}`);
|
|
72
|
+
for (const field of DEPENDENCY_FIELDS) {
|
|
73
|
+
const deps = pkg[field];
|
|
65
74
|
const version = isObject(deps) ? deps[packageName] : undefined;
|
|
66
75
|
if (typeof version === "string" && version.trim() !== "")
|
|
67
76
|
return version;
|
|
68
77
|
}
|
|
69
78
|
throw new Error(`${packageName} is not listed in dependencies or devDependencies of ${path}`);
|
|
70
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Returns the packages from `candidates` that <projectDir>/package.json lists in dependencies or
|
|
82
|
+
* devDependencies, in candidate order. A missing package.json lists nothing.
|
|
83
|
+
*/
|
|
84
|
+
export function detectListedPackages(projectDir, candidates) {
|
|
85
|
+
const pkg = readPackageJson(projectDir);
|
|
86
|
+
if (!pkg)
|
|
87
|
+
return [];
|
|
88
|
+
const listed = new Set();
|
|
89
|
+
for (const field of DEPENDENCY_FIELDS) {
|
|
90
|
+
const deps = pkg[field];
|
|
91
|
+
if (isObject(deps))
|
|
92
|
+
for (const name of Object.keys(deps))
|
|
93
|
+
listed.add(name);
|
|
94
|
+
}
|
|
95
|
+
return candidates.filter((name) => listed.has(name));
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Returns the version of packageName installed in node_modules, looking in <projectDir> and then
|
|
99
|
+
* each parent directory, as Node's module resolution does (this covers hoisted monorepo installs).
|
|
100
|
+
* Returns null when it is not installed or its package.json has no version.
|
|
101
|
+
*/
|
|
102
|
+
export function detectInstalledVersion(projectDir, packageName) {
|
|
103
|
+
for (let dir = projectDir;; dir = dirname(dir)) {
|
|
104
|
+
try {
|
|
105
|
+
const raw = readJson(join(dir, "node_modules", packageName, "package.json"));
|
|
106
|
+
if (isObject(raw) && typeof raw.version === "string" && raw.version.trim() !== "")
|
|
107
|
+
return raw.version;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Not installed here, or unreadable: keep looking further up.
|
|
111
|
+
}
|
|
112
|
+
if (dirname(dir) === dir)
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
71
116
|
//# sourceMappingURL=loadConfig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadConfig.js","sourceRoot":"","sources":["../../src/config/loadConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"loadConfig.js","sourceRoot":"","sources":["../../src/config/loadConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,55 +3,102 @@ import { join } from "node:path";
|
|
|
3
3
|
import { LiteralCursor } from "../jsLiteral.js";
|
|
4
4
|
import { renderSvg, toSvgAttrs } from "../svg.js";
|
|
5
5
|
/*
|
|
6
|
-
* lucide-react layout: dist/esm/icons/<kebab-name>.js, one ESM module per icon
|
|
6
|
+
* lucide-react layout: dist/esm/icons/<kebab-name>.js (.mjs from 1.x), one ESM module per icon.
|
|
7
|
+
* The module body has changed across releases; all three shapes are supported:
|
|
7
8
|
*
|
|
8
|
-
* const Trash2 = createLucideIcon("Trash2", [["path", { d: "...", key: "..." }], ...]);
|
|
9
|
+
* older 0.x: const Trash2 = createLucideIcon("Trash2", [["path", { d: "...", key: "..." }], ...]);
|
|
10
|
+
* later 0.x - 1.46: const __iconNode = [["path", { ... }], ...];
|
|
11
|
+
* const Trash2 = createLucideIcon("trash-2", __iconNode);
|
|
12
|
+
* 1.47+: const __iconData = { name: "trash-2", size: 24, node: [...], aliases: ["..."] };
|
|
13
|
+
* const Trash2 = createLucideIcon(__iconData);
|
|
9
14
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
15
|
+
* The import name always comes from the `const <Name> = createLucideIcon(` binding, because the
|
|
16
|
+
* string argument is the component name in older releases but the kebab name in later ones.
|
|
17
|
+
*
|
|
18
|
+
* Deprecated alias names ship as re-export modules (`export { default } from './target.js'`), and
|
|
19
|
+
* from 1.47 also in __iconData.aliases. They are not indexed separately but added to the target
|
|
20
|
+
* icon's tags so old names still match. lucide-react ships no categories or tags of its own.
|
|
13
21
|
*/
|
|
14
22
|
const ICONS_DIR = join("dist", "esm", "icons");
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
const MODULE_FILE = /^(?<name>[\w-]+)\.m?js$/;
|
|
24
|
+
const CREATE_CALL = /const\s+(?<importName>[\w$]+)\s*=\s*createLucideIcon\(\s*/;
|
|
25
|
+
const ICON_NODE = /const\s+__iconNode\s*=\s*/;
|
|
26
|
+
const ICON_DATA = /const\s+__iconData\s*=\s*/;
|
|
27
|
+
const ALIAS_EXPORT = /export\s*\{\s*default\s*\}\s*from\s*['"]\.\/([\w-]+)\.m?js['"]/;
|
|
28
|
+
function toNodes(cursor, nodes) {
|
|
29
|
+
if (!Array.isArray(nodes))
|
|
30
|
+
cursor.fail("expected an array of [tag, attrs]");
|
|
19
31
|
return nodes.map((node) => {
|
|
20
32
|
if (!Array.isArray(node) || typeof node[0] !== "string")
|
|
21
33
|
cursor.fail("expected [tag, attrs]");
|
|
22
34
|
return { tag: node[0], attr: toSvgAttrs(node[1]), child: [] };
|
|
23
35
|
});
|
|
24
36
|
}
|
|
37
|
+
/** Reads the value assigned by `const <binding> = ` in src. */
|
|
38
|
+
function readBinding(src, binding) {
|
|
39
|
+
const match = binding.exec(src);
|
|
40
|
+
if (!match)
|
|
41
|
+
return undefined;
|
|
42
|
+
const cursor = new LiteralCursor(src, match.index + match[0].length);
|
|
43
|
+
return { cursor, value: cursor.value() };
|
|
44
|
+
}
|
|
45
|
+
function parseModule(src) {
|
|
46
|
+
const call = CREATE_CALL.exec(src);
|
|
47
|
+
if (!call)
|
|
48
|
+
return undefined;
|
|
49
|
+
const importName = call.groups.importName;
|
|
50
|
+
const data = readBinding(src, ICON_DATA);
|
|
51
|
+
if (data) {
|
|
52
|
+
const { value } = data;
|
|
53
|
+
const cursor = data.cursor;
|
|
54
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
55
|
+
cursor.fail("expected __iconData object");
|
|
56
|
+
const aliases = Array.isArray(value.aliases) ? value.aliases.filter((a) => typeof a === "string") : [];
|
|
57
|
+
return { importName, nodes: toNodes(cursor, value.node ?? null), aliases };
|
|
58
|
+
}
|
|
59
|
+
const iconNode = readBinding(src, ICON_NODE);
|
|
60
|
+
if (iconNode)
|
|
61
|
+
return { importName, nodes: toNodes(iconNode.cursor, iconNode.value), aliases: [] };
|
|
62
|
+
// Older 0.x: createLucideIcon("<Name>", [...nodes]).
|
|
63
|
+
const cursor = new LiteralCursor(src, call.index + call[0].length);
|
|
64
|
+
cursor.string();
|
|
65
|
+
cursor.expect(",");
|
|
66
|
+
return { importName, nodes: toNodes(cursor, cursor.array()), aliases: [] };
|
|
67
|
+
}
|
|
25
68
|
export function parseIcons(packageDir) {
|
|
26
69
|
const dir = join(packageDir, ICONS_DIR);
|
|
27
70
|
const icons = new Map();
|
|
28
71
|
const aliases = [];
|
|
29
|
-
for (const file of readdirSync(dir).
|
|
30
|
-
const name =
|
|
72
|
+
for (const file of readdirSync(dir).sort()) {
|
|
73
|
+
const name = MODULE_FILE.exec(file)?.groups?.name;
|
|
74
|
+
if (!name)
|
|
75
|
+
continue;
|
|
31
76
|
const src = readFileSync(join(dir, file), "utf8");
|
|
32
|
-
const
|
|
33
|
-
if (!
|
|
77
|
+
const icon = parseModule(src);
|
|
78
|
+
if (!icon) {
|
|
34
79
|
const alias = ALIAS_EXPORT.exec(src);
|
|
35
80
|
if (alias)
|
|
36
81
|
aliases.push([name, alias[1]]);
|
|
37
82
|
continue;
|
|
38
83
|
}
|
|
39
|
-
const cursor = new LiteralCursor(src, call.index + call[0].length);
|
|
40
|
-
const importName = cursor.string();
|
|
41
|
-
cursor.expect(",");
|
|
42
84
|
icons.set(name, {
|
|
43
85
|
name,
|
|
44
|
-
importName,
|
|
86
|
+
importName: icon.importName,
|
|
45
87
|
importPath: "lucide-react",
|
|
46
88
|
style: "outline",
|
|
47
89
|
set: "lucide",
|
|
48
90
|
categories: [],
|
|
49
91
|
tags: [],
|
|
50
|
-
svg: renderSvg(
|
|
92
|
+
svg: renderSvg(icon.nodes),
|
|
51
93
|
});
|
|
94
|
+
for (const alias of icon.aliases)
|
|
95
|
+
aliases.push([alias, name]);
|
|
96
|
+
}
|
|
97
|
+
for (const [alias, target] of aliases) {
|
|
98
|
+
const tags = icons.get(target)?.tags;
|
|
99
|
+
if (tags && !tags.includes(alias))
|
|
100
|
+
tags.push(alias);
|
|
52
101
|
}
|
|
53
|
-
for (const [alias, target] of aliases)
|
|
54
|
-
icons.get(target)?.tags?.push(alias);
|
|
55
102
|
return [...icons.values()];
|
|
56
103
|
}
|
|
57
104
|
//# sourceMappingURL=lucide.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lucide.js","sourceRoot":"","sources":["../../../src/providers/adapters/lucide.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"lucide.js","sourceRoot":"","sources":["../../../src/providers/adapters/lucide.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
package/dist/server.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
3
|
import { registerGetIconTool } from "./tools/getIcon.js";
|
|
3
4
|
import { registerListProvidersTool } from "./tools/listProviders.js";
|
|
4
5
|
import { registerPingTool } from "./tools/ping.js";
|
|
6
|
+
import { createProjectLocator } from "./tools/projectLocator.js";
|
|
5
7
|
import { registerSearchIconsTool } from "./tools/searchIcons.js";
|
|
6
8
|
export const SERVER_NAME = "trueicon";
|
|
7
|
-
|
|
9
|
+
// Read from package.json (one level up from both src/ and dist/) so it can't drift from the release.
|
|
10
|
+
export const SERVER_VERSION = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
8
11
|
// Builds the MCP server with all tools registered. Transport wiring lives in index.ts.
|
|
9
12
|
export function createServer() {
|
|
10
13
|
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
14
|
+
const locateProject = createProjectLocator(server.server);
|
|
11
15
|
registerPingTool(server);
|
|
12
|
-
registerSearchIconsTool(server);
|
|
13
|
-
registerListProvidersTool(server);
|
|
14
|
-
registerGetIconTool(server);
|
|
16
|
+
registerSearchIconsTool(server, locateProject);
|
|
17
|
+
registerListProvidersTool(server, locateProject);
|
|
18
|
+
registerGetIconTool(server, locateProject);
|
|
15
19
|
return server;
|
|
16
20
|
}
|
|
17
21
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;AACtC,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;AACtC,qGAAqG;AACrG,MAAM,CAAC,MAAM,cAAc,GACzB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC7E,CAAC,OAAO,CAAC;AAEV,uFAAuF;AACvF,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;IAE7E,MAAM,aAAa,GAAG,oBAAoB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAE1D,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,uBAAuB,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC/C,yBAAyB,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACjD,mBAAmB,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAE3C,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/tools/context.d.ts
CHANGED
|
@@ -1,26 +1,51 @@
|
|
|
1
1
|
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import { type ProjectConfig } from "../config/loadConfig.js";
|
|
3
3
|
import type { IconRecord, Synonyms } from "../indexer/types.js";
|
|
4
|
+
/** Where the project directory came from: the env var, a root shared by the MCP client, or cwd. */
|
|
5
|
+
export type ProjectSource = "TRUEICON_PROJECT_DIR" | "roots" | "cwd";
|
|
6
|
+
export interface ProjectLocation {
|
|
7
|
+
dir: string;
|
|
8
|
+
source: ProjectSource;
|
|
9
|
+
}
|
|
4
10
|
/** Everything the icon tools need from their environment. */
|
|
5
11
|
export interface ToolContext {
|
|
6
12
|
projectDir: string;
|
|
13
|
+
projectSource: ProjectSource;
|
|
7
14
|
cacheRoot: string;
|
|
8
15
|
synonyms: Synonyms;
|
|
9
16
|
}
|
|
10
|
-
|
|
17
|
+
/** Where a provider's version came from, in precedence order after an explicit tool argument. */
|
|
18
|
+
export type VersionSource = "iconmcp.json" | "node_modules" | "package.json";
|
|
11
19
|
export interface ResolvedVersion {
|
|
12
20
|
version: string;
|
|
13
21
|
source: VersionSource;
|
|
14
22
|
}
|
|
15
|
-
/**
|
|
16
|
-
export declare function
|
|
23
|
+
/** The project directory from $TRUEICON_PROJECT_DIR, else cwd. The server also consults client roots. */
|
|
24
|
+
export declare function defaultProjectLocation(): ProjectLocation;
|
|
25
|
+
/** Resolves the context: the project location (default: env var, else cwd), cache root and synonyms. */
|
|
26
|
+
export declare function resolveContext(project?: ProjectLocation): ToolContext;
|
|
17
27
|
/** The import statement for an icon, e.g. "import { Trash2 } from 'lucide-react';". */
|
|
18
28
|
export declare function usageSnippet(record: IconRecord): string;
|
|
19
29
|
/**
|
|
20
|
-
* Version for packageName: the .iconmcp.json pin, else the
|
|
21
|
-
* Returns null when
|
|
30
|
+
* Version for packageName: the .iconmcp.json pin, else the version installed in node_modules,
|
|
31
|
+
* else the range in package.json. Returns null when none is available.
|
|
22
32
|
*/
|
|
23
33
|
export declare function resolveVersion(projectDir: string, config: ProjectConfig, packageName: string): ResolvedVersion | null;
|
|
34
|
+
/** Which file named the project's providers. */
|
|
35
|
+
export type ProvidersSource = "iconmcp.json" | "package.json";
|
|
36
|
+
export interface ProjectProviders {
|
|
37
|
+
config: ProjectConfig;
|
|
38
|
+
/** Packages to search, in order. May include unsupported packages listed in .iconmcp.json. */
|
|
39
|
+
packages: string[];
|
|
40
|
+
source: ProvidersSource | null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The icon packages this project uses: the providers listed in .iconmcp.json, else every supported
|
|
44
|
+
* provider listed in package.json. `source` is null when neither names any.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveProjectProviders(projectDir: string): ProjectProviders;
|
|
47
|
+
/** Error for a project that names no icon packages, saying where trueicon looked and how to fix it. */
|
|
48
|
+
export declare function noProvidersError(ctx: ToolContext): Error;
|
|
24
49
|
export declare function errorMessage(error: unknown): string;
|
|
25
50
|
/** Runs a tool body and wraps its result (or error) as MCP JSON text content. */
|
|
26
51
|
export declare function jsonToolResult(run: () => unknown): Promise<CallToolResult>;
|
package/dist/tools/context.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { resolveCacheRoot } from "../cache/downloader.js";
|
|
2
|
-
import { detectVersion } from "../config/loadConfig.js";
|
|
2
|
+
import { CONFIG_FILE, detectInstalledVersion, detectListedPackages, detectVersion, loadProjectConfig, } from "../config/loadConfig.js";
|
|
3
|
+
import { PROVIDERS } from "../providers/registry.js";
|
|
3
4
|
import { loadSynonyms } from "../synonyms/loadSynonyms.js";
|
|
4
|
-
/**
|
|
5
|
-
export function
|
|
5
|
+
/** The project directory from $TRUEICON_PROJECT_DIR, else cwd. The server also consults client roots. */
|
|
6
|
+
export function defaultProjectLocation() {
|
|
7
|
+
const fromEnv = process.env.TRUEICON_PROJECT_DIR;
|
|
8
|
+
return fromEnv ? { dir: fromEnv, source: "TRUEICON_PROJECT_DIR" } : { dir: process.cwd(), source: "cwd" };
|
|
9
|
+
}
|
|
10
|
+
/** Resolves the context: the project location (default: env var, else cwd), cache root and synonyms. */
|
|
11
|
+
export function resolveContext(project = defaultProjectLocation()) {
|
|
6
12
|
return {
|
|
7
|
-
projectDir:
|
|
13
|
+
projectDir: project.dir,
|
|
14
|
+
projectSource: project.source,
|
|
8
15
|
cacheRoot: resolveCacheRoot({}),
|
|
9
16
|
synonyms: loadSynonyms(),
|
|
10
17
|
};
|
|
@@ -14,13 +21,16 @@ export function usageSnippet(record) {
|
|
|
14
21
|
return `import { ${record.importName} } from '${record.importPath}';`;
|
|
15
22
|
}
|
|
16
23
|
/**
|
|
17
|
-
* Version for packageName: the .iconmcp.json pin, else the
|
|
18
|
-
* Returns null when
|
|
24
|
+
* Version for packageName: the .iconmcp.json pin, else the version installed in node_modules,
|
|
25
|
+
* else the range in package.json. Returns null when none is available.
|
|
19
26
|
*/
|
|
20
27
|
export function resolveVersion(projectDir, config, packageName) {
|
|
21
28
|
const pinned = config.providers.find((p) => p.package === packageName)?.version;
|
|
22
29
|
if (pinned !== undefined)
|
|
23
30
|
return { version: pinned, source: "iconmcp.json" };
|
|
31
|
+
const installed = detectInstalledVersion(projectDir, packageName);
|
|
32
|
+
if (installed !== null)
|
|
33
|
+
return { version: installed, source: "node_modules" };
|
|
24
34
|
try {
|
|
25
35
|
return { version: detectVersion(projectDir, packageName), source: "package.json" };
|
|
26
36
|
}
|
|
@@ -28,6 +38,29 @@ export function resolveVersion(projectDir, config, packageName) {
|
|
|
28
38
|
return null;
|
|
29
39
|
}
|
|
30
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The icon packages this project uses: the providers listed in .iconmcp.json, else every supported
|
|
43
|
+
* provider listed in package.json. `source` is null when neither names any.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveProjectProviders(projectDir) {
|
|
46
|
+
const config = loadProjectConfig(projectDir);
|
|
47
|
+
if (config.providers.length > 0) {
|
|
48
|
+
return { config, packages: config.providers.map((p) => p.package), source: "iconmcp.json" };
|
|
49
|
+
}
|
|
50
|
+
const detected = detectListedPackages(projectDir, PROVIDERS.map((p) => p.package));
|
|
51
|
+
return { config, packages: detected, source: detected.length > 0 ? "package.json" : null };
|
|
52
|
+
}
|
|
53
|
+
/** Error for a project that names no icon packages, saying where trueicon looked and how to fix it. */
|
|
54
|
+
export function noProvidersError(ctx) {
|
|
55
|
+
const where = ctx.projectSource === "cwd"
|
|
56
|
+
? ` (the server's working directory; set TRUEICON_PROJECT_DIR if your project is elsewhere)`
|
|
57
|
+
: ctx.projectSource === "roots"
|
|
58
|
+
? " (from the folders your MCP client shared)"
|
|
59
|
+
: " (from TRUEICON_PROJECT_DIR)";
|
|
60
|
+
return new Error(`No icon packages found in ${ctx.projectDir}${where}. Add a supported package to package.json (` +
|
|
61
|
+
PROVIDERS.map((p) => p.package).join(", ") +
|
|
62
|
+
`), list providers in ${CONFIG_FILE}, or pass "provider".`);
|
|
63
|
+
}
|
|
31
64
|
export function errorMessage(error) {
|
|
32
65
|
return error instanceof Error ? error.message : String(error);
|
|
33
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/tools/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/tools/context.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/getIcon.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import type { IconRecord } from "../indexer/types.js";
|
|
3
3
|
import { type ToolContext } from "./context.js";
|
|
4
|
+
import type { ProjectLocator } from "./projectLocator.js";
|
|
4
5
|
export interface GetIconInput {
|
|
5
6
|
/** Icon name ("trash-2") or import name ("Trash2"). */
|
|
6
7
|
name: string;
|
|
@@ -13,4 +14,4 @@ export type GetIconOutput = IconRecord & {
|
|
|
13
14
|
};
|
|
14
15
|
/** Looks up one icon by name or import name and returns its full record plus an import snippet. */
|
|
15
16
|
export declare function getIconTool(input: GetIconInput, ctx: ToolContext): Promise<GetIconOutput>;
|
|
16
|
-
export declare function registerGetIconTool(server: McpServer): void;
|
|
17
|
+
export declare function registerGetIconTool(server: McpServer, locateProject: ProjectLocator): void;
|
package/dist/tools/getIcon.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { ensureIndex } from "../config/ensureIndex.js";
|
|
3
3
|
import { CONFIG_FILE, loadProjectConfig } from "../config/loadConfig.js";
|
|
4
|
+
import { toKebabCase } from "../providers/adapter.js";
|
|
4
5
|
import { getProvider } from "../providers/registry.js";
|
|
5
6
|
import { loadIndex } from "../search/search.js";
|
|
6
7
|
import { jsonToolResult, resolveContext, resolveVersion, usageSnippet } from "./context.js";
|
|
@@ -9,7 +10,13 @@ function findRecord(records, name) {
|
|
|
9
10
|
if (exact)
|
|
10
11
|
return exact;
|
|
11
12
|
const lower = name.toLowerCase();
|
|
12
|
-
|
|
13
|
+
const caseInsensitive = records.find((r) => r.name.toLowerCase() === lower || r.importName.toLowerCase() === lower);
|
|
14
|
+
if (caseInsensitive)
|
|
15
|
+
return caseInsensitive;
|
|
16
|
+
// Deprecated or renamed icons are kept as alias tags on the current icon, e.g. lucide 1.47
|
|
17
|
+
// renamed trash-2 to trash, so "Trash2" resolves to the Trash record.
|
|
18
|
+
const kebab = toKebabCase(name);
|
|
19
|
+
return records.find((r) => r.tags.some((tag) => tag === lower || tag === kebab));
|
|
13
20
|
}
|
|
14
21
|
/** Looks up one icon by name or import name and returns its full record plus an import snippet. */
|
|
15
22
|
export async function getIconTool(input, ctx) {
|
|
@@ -37,7 +44,7 @@ export async function getIconTool(input, ctx) {
|
|
|
37
44
|
throw new Error(`Icon "${name}" not found in ${provider.id} (${provider.package}@${version})`);
|
|
38
45
|
return { ...record, usage: usageSnippet(record) };
|
|
39
46
|
}
|
|
40
|
-
export function registerGetIconTool(server) {
|
|
47
|
+
export function registerGetIconTool(server, locateProject) {
|
|
41
48
|
server.registerTool("get_icon", {
|
|
42
49
|
description: "Get the full record and exact import statement for an icon whose name is already known, e.g. Trash2 from lucide.",
|
|
43
50
|
inputSchema: {
|
|
@@ -45,6 +52,6 @@ export function registerGetIconTool(server) {
|
|
|
45
52
|
provider: z.string().min(1).describe('Provider id or npm package, e.g. "lucide" or "lucide-react"'),
|
|
46
53
|
version: z.string().optional().describe("Package version or range; defaults to the project's version"),
|
|
47
54
|
},
|
|
48
|
-
}, (input) => jsonToolResult(() => getIconTool(input, resolveContext())));
|
|
55
|
+
}, (input) => jsonToolResult(async () => getIconTool(input, resolveContext(await locateProject()))));
|
|
49
56
|
}
|
|
50
57
|
//# sourceMappingURL=getIcon.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getIcon.js","sourceRoot":"","sources":["../../src/tools/getIcon.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAoB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"getIcon.js","sourceRoot":"","sources":["../../src/tools/getIcon.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { type ToolContext, type VersionSource } from "./context.js";
|
|
2
|
+
import { type ProjectSource, type ProvidersSource, type ToolContext, type VersionSource } from "./context.js";
|
|
3
|
+
import type { ProjectLocator } from "./projectLocator.js";
|
|
3
4
|
export interface ConfiguredProvider {
|
|
4
5
|
/** Registry id, or null when the package is not a supported provider. */
|
|
5
6
|
id: string | null;
|
|
6
7
|
package: string;
|
|
7
8
|
version: string | null;
|
|
9
|
+
/** Where the version came from. */
|
|
8
10
|
source: VersionSource | null;
|
|
9
11
|
}
|
|
10
12
|
export interface ListProvidersOutput {
|
|
13
|
+
/** The project directory the tools read, and how it was found. */
|
|
14
|
+
project: {
|
|
15
|
+
dir: string;
|
|
16
|
+
source: ProjectSource;
|
|
17
|
+
};
|
|
18
|
+
/** Which file named the configured providers, or null when neither names any. */
|
|
19
|
+
providersFrom: ProvidersSource | null;
|
|
11
20
|
configured: ConfiguredProvider[];
|
|
12
21
|
registry: {
|
|
13
22
|
id: string;
|
|
@@ -15,6 +24,9 @@ export interface ListProvidersOutput {
|
|
|
15
24
|
description: string;
|
|
16
25
|
}[];
|
|
17
26
|
}
|
|
18
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Lists the providers the project uses (from .iconmcp.json, else detected in package.json) with
|
|
29
|
+
* their resolved versions, and every supported provider.
|
|
30
|
+
*/
|
|
19
31
|
export declare function listProvidersTool(ctx: ToolContext): ListProvidersOutput;
|
|
20
|
-
export declare function registerListProvidersTool(server: McpServer): void;
|
|
32
|
+
export declare function registerListProvidersTool(server: McpServer, locateProject: ProjectLocator): void;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { loadProjectConfig } from "../config/loadConfig.js";
|
|
2
1
|
import { getProvider, PROVIDERS } from "../providers/registry.js";
|
|
3
|
-
import { jsonToolResult, resolveContext, resolveVersion } from "./context.js";
|
|
4
|
-
/**
|
|
2
|
+
import { jsonToolResult, resolveContext, resolveProjectProviders, resolveVersion, } from "./context.js";
|
|
3
|
+
/**
|
|
4
|
+
* Lists the providers the project uses (from .iconmcp.json, else detected in package.json) with
|
|
5
|
+
* their resolved versions, and every supported provider.
|
|
6
|
+
*/
|
|
5
7
|
export function listProvidersTool(ctx) {
|
|
6
|
-
const config =
|
|
7
|
-
const configured =
|
|
8
|
+
const { config, packages, source: providersFrom } = resolveProjectProviders(ctx.projectDir);
|
|
9
|
+
const configured = packages.map((pkg) => {
|
|
8
10
|
const resolved = resolveVersion(ctx.projectDir, config, pkg);
|
|
9
11
|
return {
|
|
10
12
|
id: getProvider(pkg)?.id ?? null,
|
|
@@ -14,9 +16,11 @@ export function listProvidersTool(ctx) {
|
|
|
14
16
|
};
|
|
15
17
|
});
|
|
16
18
|
const registry = PROVIDERS.map(({ id, package: pkg, description }) => ({ id, package: pkg, description }));
|
|
17
|
-
return { configured, registry };
|
|
19
|
+
return { project: { dir: ctx.projectDir, source: ctx.projectSource }, providersFrom, configured, registry };
|
|
18
20
|
}
|
|
19
|
-
export function registerListProvidersTool(server) {
|
|
20
|
-
server.registerTool("list_providers", {
|
|
21
|
+
export function registerListProvidersTool(server, locateProject) {
|
|
22
|
+
server.registerTool("list_providers", {
|
|
23
|
+
description: "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.",
|
|
24
|
+
}, () => jsonToolResult(async () => listProvidersTool(resolveContext(await locateProject()))));
|
|
21
25
|
}
|
|
22
26
|
//# sourceMappingURL=listProviders.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listProviders.js","sourceRoot":"","sources":["../../src/tools/listProviders.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"listProviders.js","sourceRoot":"","sources":["../../src/tools/listProviders.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACL,cAAc,EACd,cAAc,EACd,uBAAuB,EACvB,cAAc,GAKf,MAAM,cAAc,CAAC;AAqBtB;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAgB;IAChD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,uBAAuB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC5F,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAsB,EAAE;QAC1D,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7D,OAAO;YACL,EAAE,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,IAAI;YAChC,OAAO,EAAE,GAAG;YACZ,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,IAAI;YAClC,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,IAAI;SACjC,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;IAC3G,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,aAAa,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAC9G,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,MAAiB,EAAE,aAA6B;IACxF,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,WAAW,EACT,+LAA+L;KAClM,EACD,GAAG,EAAE,CAAC,cAAc,CAAC,KAAK,IAAI,EAAE,CAAC,iBAAiB,CAAC,cAAc,CAAC,MAAM,aAAa,EAAE,CAAC,CAAC,CAAC,CAC3F,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { type ProjectLocation } from "./context.js";
|
|
3
|
+
/** The parts of the SDK Server the locator needs, so tests can pass a fake. */
|
|
4
|
+
export type RootsClient = Pick<Server, "getClientCapabilities" | "listRoots" | "setNotificationHandler">;
|
|
5
|
+
export type ProjectLocator = () => Promise<ProjectLocation>;
|
|
6
|
+
export declare function createProjectLocator(client: RootsClient, fallback?: () => ProjectLocation): ProjectLocator;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { RootsListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { CONFIG_FILE } from "../config/loadConfig.js";
|
|
6
|
+
import { defaultProjectLocation } from "./context.js";
|
|
7
|
+
// A client that advertises roots but never answers should not stall every tool call for the
|
|
8
|
+
// SDK's default 60s request timeout.
|
|
9
|
+
const LIST_ROOTS_TIMEOUT_MS = 5_000;
|
|
10
|
+
function isProjectDir(dir) {
|
|
11
|
+
return existsSync(join(dir, "package.json")) || existsSync(join(dir, CONFIG_FILE));
|
|
12
|
+
}
|
|
13
|
+
export function createProjectLocator(client, fallback = defaultProjectLocation) {
|
|
14
|
+
let roots;
|
|
15
|
+
client.setNotificationHandler(RootsListChangedNotificationSchema, () => {
|
|
16
|
+
roots = undefined;
|
|
17
|
+
});
|
|
18
|
+
function rootDirs() {
|
|
19
|
+
if (!client.getClientCapabilities()?.roots)
|
|
20
|
+
return Promise.resolve([]);
|
|
21
|
+
roots ??= client.listRoots(undefined, { timeout: LIST_ROOTS_TIMEOUT_MS }).then(({ roots: list }) => list.filter((r) => r.uri.startsWith("file://")).map((r) => fileURLToPath(r.uri)), () => {
|
|
22
|
+
roots = undefined; // retry on the next call
|
|
23
|
+
return [];
|
|
24
|
+
});
|
|
25
|
+
return roots;
|
|
26
|
+
}
|
|
27
|
+
return async () => {
|
|
28
|
+
const location = fallback();
|
|
29
|
+
if (location.source === "TRUEICON_PROJECT_DIR")
|
|
30
|
+
return location;
|
|
31
|
+
const dirs = await rootDirs();
|
|
32
|
+
const project = dirs.find(isProjectDir);
|
|
33
|
+
if (project)
|
|
34
|
+
return { dir: project, source: "roots" };
|
|
35
|
+
if (dirs.length === 0 || isProjectDir(location.dir))
|
|
36
|
+
return location;
|
|
37
|
+
return { dir: dirs[0], source: "roots" };
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=projectLocator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectLocator.js","sourceRoot":"","sources":["../../src/tools/projectLocator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,kCAAkC,EAAE,MAAM,oCAAoC,CAAC;AACxF,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAwB,MAAM,cAAc,CAAC;AAoB5E,4FAA4F;AAC5F,qCAAqC;AACrC,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAEpC,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAmB,EACnB,WAAkC,sBAAsB;IAExD,IAAI,KAAoC,CAAC;IACzC,MAAM,CAAC,sBAAsB,CAAC,kCAAkC,EAAE,GAAG,EAAE;QACrE,KAAK,GAAG,SAAS,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,SAAS,QAAQ;QACf,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE,EAAE,KAAK;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACvE,KAAK,KAAK,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAC5E,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EACrG,GAAG,EAAE;YACH,KAAK,GAAG,SAAS,CAAC,CAAC,yBAAyB;YAC5C,OAAO,EAAE,CAAC;QACZ,CAAC,CACF,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,KAAK,IAAI,EAAE;QAChB,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAAC;QAC5B,IAAI,QAAQ,CAAC,MAAM,KAAK,sBAAsB;YAAE,OAAO,QAAQ,CAAC;QAChE,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACxC,IAAI,OAAO;YAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QACtD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,QAAQ,CAAC;QACrE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC5C,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { type ToolContext } from "./context.js";
|
|
3
|
+
import type { ProjectLocator } from "./projectLocator.js";
|
|
3
4
|
export declare const DEFAULT_LIMIT = 10;
|
|
4
5
|
export declare const MAX_LIMIT = 50;
|
|
5
6
|
export interface SearchIconsInput {
|
|
@@ -26,6 +27,9 @@ export interface SearchIconsOutput {
|
|
|
26
27
|
results: SearchIconsHit[];
|
|
27
28
|
warnings?: string[];
|
|
28
29
|
}
|
|
29
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Searches the indexes of the requested provider, or of every provider the project uses (from
|
|
32
|
+
* .iconmcp.json, else detected in package.json), and merges the ranked hits.
|
|
33
|
+
*/
|
|
30
34
|
export declare function searchIconsTool(input: SearchIconsInput, ctx: ToolContext): Promise<SearchIconsOutput>;
|
|
31
|
-
export declare function registerSearchIconsTool(server: McpServer): void;
|
|
35
|
+
export declare function registerSearchIconsTool(server: McpServer, locateProject: ProjectLocator): void;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { ensureIndex } from "../config/ensureIndex.js";
|
|
3
|
-
import { CONFIG_FILE
|
|
3
|
+
import { CONFIG_FILE } from "../config/loadConfig.js";
|
|
4
4
|
import { getProvider } from "../providers/registry.js";
|
|
5
5
|
import { loadIndex, searchIcons } from "../search/search.js";
|
|
6
|
-
import { errorMessage, jsonToolResult, resolveContext, resolveVersion, usageSnippet } from "./context.js";
|
|
6
|
+
import { errorMessage, jsonToolResult, noProvidersError, resolveContext, resolveProjectProviders, resolveVersion, usageSnippet, } from "./context.js";
|
|
7
7
|
export const DEFAULT_LIMIT = 10;
|
|
8
8
|
export const MAX_LIMIT = 50;
|
|
9
9
|
function clampLimit(limit) {
|
|
@@ -24,12 +24,15 @@ function toHit({ record, score }) {
|
|
|
24
24
|
score,
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Searches the indexes of the requested provider, or of every provider the project uses (from
|
|
29
|
+
* .iconmcp.json, else detected in package.json), and merges the ranked hits.
|
|
30
|
+
*/
|
|
28
31
|
export async function searchIconsTool(input, ctx) {
|
|
29
32
|
const query = input.query?.trim() ?? "";
|
|
30
33
|
if (!query)
|
|
31
34
|
throw new Error("query must be a non-empty string");
|
|
32
|
-
const config =
|
|
35
|
+
const { config, packages } = resolveProjectProviders(ctx.projectDir);
|
|
33
36
|
const warnings = [];
|
|
34
37
|
let candidates;
|
|
35
38
|
if (input.provider !== undefined) {
|
|
@@ -39,12 +42,10 @@ export async function searchIconsTool(input, ctx) {
|
|
|
39
42
|
candidates = [provider];
|
|
40
43
|
}
|
|
41
44
|
else {
|
|
42
|
-
if (
|
|
43
|
-
throw
|
|
44
|
-
`e.g. {"providers":[{"package":"lucide-react"}]}, or pass "provider".`);
|
|
45
|
-
}
|
|
45
|
+
if (packages.length === 0)
|
|
46
|
+
throw noProvidersError(ctx);
|
|
46
47
|
candidates = [];
|
|
47
|
-
for (const
|
|
48
|
+
for (const pkg of packages) {
|
|
48
49
|
const provider = getProvider(pkg);
|
|
49
50
|
if (provider)
|
|
50
51
|
candidates.push(provider);
|
|
@@ -81,7 +82,7 @@ export async function searchIconsTool(input, ctx) {
|
|
|
81
82
|
const results = hits.sort((a, b) => a.score - b.score).slice(0, clampLimit(input.limit)).map(toHit);
|
|
82
83
|
return warnings.length > 0 ? { results, warnings } : { results };
|
|
83
84
|
}
|
|
84
|
-
export function registerSearchIconsTool(server) {
|
|
85
|
+
export function registerSearchIconsTool(server, locateProject) {
|
|
85
86
|
server.registerTool("search_icons", {
|
|
86
87
|
description: "Search icons in the icon packages installed in the project. Returns ranked matches with ready-to-paste import statements.",
|
|
87
88
|
inputSchema: {
|
|
@@ -92,6 +93,6 @@ export function registerSearchIconsTool(server) {
|
|
|
92
93
|
set: z.string().optional().describe('Icon set filter (react-icons), e.g. "fa6"'),
|
|
93
94
|
limit: z.number().int().optional().describe(`Maximum results (1-${MAX_LIMIT}, default ${DEFAULT_LIMIT})`),
|
|
94
95
|
},
|
|
95
|
-
}, (input) => jsonToolResult(() => searchIconsTool(input, resolveContext())));
|
|
96
|
+
}, (input) => jsonToolResult(async () => searchIconsTool(input, resolveContext(await locateProject()))));
|
|
96
97
|
}
|
|
97
98
|
//# sourceMappingURL=searchIcons.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"searchIcons.js","sourceRoot":"","sources":["../../src/tools/searchIcons.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"searchIcons.js","sourceRoot":"","sources":["../../src/tools/searchIcons.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trueicon",
|
|
3
3
|
"mcpName": "io.github.manikumarkv/trueicon",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"description": "MCP server that lets AI coding assistants search the icon packages actually installed in your project.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "manikumarkv",
|
|
@@ -43,7 +43,11 @@
|
|
|
43
43
|
"typecheck": "tsc --noEmit",
|
|
44
44
|
"test": "vitest run",
|
|
45
45
|
"lint": "eslint",
|
|
46
|
-
"prepublishOnly": "npm run build"
|
|
46
|
+
"prepublishOnly": "npm run build",
|
|
47
|
+
"dev:call": "npm run build --silent && node scripts/dev.mjs call",
|
|
48
|
+
"dev:inspect": "npm run build --silent && node scripts/dev.mjs inspect",
|
|
49
|
+
"dev:debug": "npm run build --silent && node scripts/dev.mjs inspect --debug",
|
|
50
|
+
"smoke": "npm run build --silent && node scripts/smoke.mjs"
|
|
47
51
|
},
|
|
48
52
|
"dependencies": {
|
|
49
53
|
"@modelcontextprotocol/sdk": "^1.30.1",
|