trueicon 0.2.1 → 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 +42 -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/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 +2 -2
- 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 +1 -1
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
|
|
|
@@ -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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"}
|
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
|
@@ -44,7 +44,7 @@ export async function getIconTool(input, ctx) {
|
|
|
44
44
|
throw new Error(`Icon "${name}" not found in ${provider.id} (${provider.package}@${version})`);
|
|
45
45
|
return { ...record, usage: usageSnippet(record) };
|
|
46
46
|
}
|
|
47
|
-
export function registerGetIconTool(server) {
|
|
47
|
+
export function registerGetIconTool(server, locateProject) {
|
|
48
48
|
server.registerTool("get_icon", {
|
|
49
49
|
description: "Get the full record and exact import statement for an icon whose name is already known, e.g. Trash2 from lucide.",
|
|
50
50
|
inputSchema: {
|
|
@@ -52,6 +52,6 @@ export function registerGetIconTool(server) {
|
|
|
52
52
|
provider: z.string().min(1).describe('Provider id or npm package, e.g. "lucide" or "lucide-react"'),
|
|
53
53
|
version: z.string().optional().describe("Package version or range; defaults to the project's version"),
|
|
54
54
|
},
|
|
55
|
-
}, (input) => jsonToolResult(() => getIconTool(input, resolveContext())));
|
|
55
|
+
}, (input) => jsonToolResult(async () => getIconTool(input, resolveContext(await locateProject()))));
|
|
56
56
|
}
|
|
57
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,yBAAyB,CAAC;AACtD,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",
|