mcp-icon 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hustcc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,175 @@
1
+ <div align="center">
2
+
3
+ # ๐ŸŽจ mcp-icon
4
+
5
+ **A Model Context Protocol (MCP) server for semantic SVG icon search.**
6
+
7
+ Generate infographic SVG icons by keyword โ€” over **100,000 icons** with semantic search support, powered by [AntV Infographic](https://infographic.antv.vision/icon).
8
+
9
+ [![npm version](https://img.shields.io/npm/v/mcp-icon.svg)](https://www.npmjs.com/package/mcp-icon)
10
+ [![Build](https://github.com/hustcc/mcp-icon/actions/workflows/build.yml/badge.svg)](https://github.com/hustcc/mcp-icon/actions/workflows/build.yml)
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
12
+
13
+ </div>
14
+
15
+ ---
16
+
17
+ ## ๐Ÿ“‹ Table of Contents
18
+
19
+ - [โœจ Features](#-features)
20
+ - [๐Ÿค– Usage](#-usage)
21
+ - [๐Ÿšฐ Transport Modes](#-transport-modes)
22
+ - [๐ŸŽฎ CLI Options](#-cli-options)
23
+ - [๐Ÿ”จ Development](#-development)
24
+ - [๐Ÿ“„ License](#-license)
25
+
26
+ ---
27
+
28
+ ## โœจ Features
29
+
30
+ - ๐Ÿ” **Semantic search** โ€” Find icons by meaning, not just exact names
31
+ - ๐Ÿ–ผ๏ธ **100,000+ SVG icons** โ€” A massive library of high-quality infographic icons
32
+ - โšก **Three transport modes** โ€” `stdio`, `sse`, and `streamable-http`
33
+ - ๐Ÿชถ **Minimal dependencies** โ€” Clean, focused implementation
34
+ - ๐Ÿงช **Fully tested** โ€” Unit tests with Vitest
35
+
36
+ ### Available Tool
37
+
38
+ | Tool | Description |
39
+ |------|-------------|
40
+ | `search_icons` | Search for SVG icons by keyword. Returns a list of SVG URLs matching the semantic query. |
41
+
42
+ **`search_icons` parameters:**
43
+
44
+ | Parameter | Type | Required | Default | Description |
45
+ |-----------|------|----------|---------|-------------|
46
+ | `keyword` | string | โœ… | โ€” | Search keyword or phrase (e.g. `"data analysis"`, `"cloud"`) |
47
+ | `topK` | number | โŒ | `3` | Number of icons to return (1โ€“20) |
48
+
49
+ ---
50
+
51
+ ## ๐Ÿค– Usage
52
+
53
+ Add to your MCP client configuration (e.g. Claude Desktop, VS Code, Cursor):
54
+
55
+ **macOS / Linux:**
56
+
57
+ ```json
58
+ {
59
+ "mcpServers": {
60
+ "mcp-icon": {
61
+ "command": "npx",
62
+ "args": ["-y", "mcp-icon"]
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ **Windows:**
69
+
70
+ ```json
71
+ {
72
+ "mcpServers": {
73
+ "mcp-icon": {
74
+ "command": "cmd",
75
+ "args": ["/c", "npx", "-y", "mcp-icon"]
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ ---
82
+
83
+ ## ๐Ÿšฐ Transport Modes
84
+
85
+ `mcp-icon` supports three standard MCP transport protocols.
86
+
87
+ ### stdio (default)
88
+
89
+ Used by desktop MCP clients (Claude Desktop, Cursor, etc.):
90
+
91
+ ```bash
92
+ npx mcp-icon
93
+ # or explicitly:
94
+ npx mcp-icon --transport stdio
95
+ ```
96
+
97
+ ### SSE (Server-Sent Events)
98
+
99
+ ```bash
100
+ npx mcp-icon --transport sse --port 3456
101
+ # Server available at: http://localhost:3456/sse
102
+ ```
103
+
104
+ ### Streamable HTTP
105
+
106
+ ```bash
107
+ npx mcp-icon --transport streamable --port 3456
108
+ # Server available at: http://localhost:3456/mcp
109
+ ```
110
+
111
+ ---
112
+
113
+ ## ๐ŸŽฎ CLI Options
114
+
115
+ ```
116
+ mcp-icon CLI
117
+
118
+ Options:
119
+ --transport, -t Transport protocol: "stdio", "sse", or "streamable" (default: "stdio")
120
+ --host, -h Host for SSE or streamable transport (default: localhost)
121
+ --port, -p Port for SSE or streamable transport (default: 3456)
122
+ --endpoint, -e Endpoint path:
123
+ - For SSE: default is "/sse"
124
+ - For streamable: default is "/mcp"
125
+ --help, -H Show this help message
126
+ ```
127
+
128
+ ---
129
+
130
+ ## ๐Ÿ”จ Development
131
+
132
+ ```bash
133
+ # Clone the repository
134
+ git clone https://github.com/hustcc/mcp-icon.git
135
+ cd mcp-icon
136
+
137
+ # Install dependencies
138
+ npm install
139
+
140
+ # Build
141
+ npm run build
142
+
143
+ # Run tests
144
+ npm test
145
+
146
+ # Start with MCP inspector (for local debugging)
147
+ npm start
148
+ ```
149
+
150
+ ### Project Structure
151
+
152
+ ```
153
+ src/
154
+ โ”œโ”€โ”€ index.ts # CLI entry point
155
+ โ”œโ”€โ”€ server.ts # MCP server + tool handlers
156
+ โ”œโ”€โ”€ services/
157
+ โ”‚ โ”œโ”€โ”€ stdio.ts # Stdio transport
158
+ โ”‚ โ”œโ”€โ”€ sse.ts # SSE transport
159
+ โ”‚ โ””โ”€โ”€ streamable.ts # Streamable HTTP transport
160
+ โ”œโ”€โ”€ tools/
161
+ โ”‚ โ””โ”€โ”€ search-icons.ts # Tool definition
162
+ โ””โ”€โ”€ utils/
163
+ โ”œโ”€โ”€ api.ts # Icon search API client
164
+ โ””โ”€โ”€ logger.ts # Logger utility
165
+ tests/
166
+ โ”œโ”€โ”€ api.test.ts # API client unit tests
167
+ โ””โ”€โ”€ server.test.ts # MCP server integration tests
168
+ ```
169
+
170
+ ---
171
+
172
+ ## ๐Ÿ“„ License
173
+
174
+ MIT ยฉ [hustcc](https://github.com/hustcc)
175
+
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/build/index.js ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const node_util_1 = require("node:util");
5
+ const logger_1 = require("./utils/logger.js");
6
+ const server_1 = require("./server.js");
7
+ const { values } = (0, node_util_1.parseArgs)({
8
+ options: {
9
+ transport: { type: "string", short: "t", default: "stdio" },
10
+ host: { type: "string", short: "h", default: "localhost" },
11
+ port: { type: "string", short: "p", default: "3456" },
12
+ endpoint: { type: "string", short: "e", default: "" },
13
+ help: { type: "boolean", short: "H" },
14
+ },
15
+ });
16
+ if (values.help) {
17
+ console.log(`
18
+ mcp-icon CLI
19
+
20
+ Options:
21
+ --transport, -t Transport protocol: "stdio", "sse", or "streamable" (default: "stdio")
22
+ --host, -h Host for SSE or streamable transport (default: localhost)
23
+ --port, -p Port for SSE or streamable transport (default: 3456)
24
+ --endpoint, -e Endpoint path:
25
+ - For SSE: default is "/sse"
26
+ - For streamable: default is "/mcp"
27
+ --help, -H Show this help message
28
+ `);
29
+ process.exit(0);
30
+ }
31
+ const transport = values.transport.toLowerCase();
32
+ const port = Number.parseInt(values.port, 10);
33
+ const host = values.host;
34
+ if (transport === "sse") {
35
+ logger_1.logger.setIsStdio(false);
36
+ const endpoint = values.endpoint || "/sse";
37
+ (0, server_1.runSSEServer)(host, port, endpoint).catch(console.error);
38
+ }
39
+ else if (transport === "streamable") {
40
+ logger_1.logger.setIsStdio(false);
41
+ const endpoint = values.endpoint || "/mcp";
42
+ (0, server_1.runStreamableServer)(host, port, endpoint).catch(console.error);
43
+ }
44
+ else {
45
+ logger_1.logger.setIsStdio(true);
46
+ (0, server_1.runStdioServer)().catch(console.error);
47
+ }
@@ -0,0 +1,7 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { startSSEServer, startStdioServer, startStreamableServer } from "./services/index";
3
+ export { startSSEServer, startStdioServer, startStreamableServer };
4
+ export declare function createServer(): Server;
5
+ export declare function runStdioServer(): Promise<void>;
6
+ export declare function runSSEServer(host?: string, port?: number, endpoint?: string): Promise<void>;
7
+ export declare function runStreamableServer(host?: string, port?: number, endpoint?: string): Promise<void>;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startStreamableServer = exports.startStdioServer = exports.startSSEServer = void 0;
4
+ exports.createServer = createServer;
5
+ exports.runStdioServer = runStdioServer;
6
+ exports.runSSEServer = runSSEServer;
7
+ exports.runStreamableServer = runStreamableServer;
8
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
9
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
10
+ const search_icons_1 = require("./tools/search-icons.js");
11
+ const api_1 = require("./utils/api.js");
12
+ const logger_1 = require("./utils/logger.js");
13
+ const index_1 = require("./services/index.js");
14
+ Object.defineProperty(exports, "startSSEServer", { enumerable: true, get: function () { return index_1.startSSEServer; } });
15
+ Object.defineProperty(exports, "startStdioServer", { enumerable: true, get: function () { return index_1.startStdioServer; } });
16
+ Object.defineProperty(exports, "startStreamableServer", { enumerable: true, get: function () { return index_1.startStreamableServer; } });
17
+ function createServer() {
18
+ const server = new index_js_1.Server({ name: "mcp-icon", version: "1.0.0" }, { capabilities: { tools: {} } });
19
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
20
+ tools: [search_icons_1.searchIconsTool],
21
+ }));
22
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
23
+ const { name, arguments: args = {} } = request.params;
24
+ if (name !== "search_icons") {
25
+ throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
26
+ }
27
+ const { keyword, topK = 3 } = args;
28
+ if (!keyword || typeof keyword !== "string") {
29
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, "The 'keyword' parameter is required and must be a string.");
30
+ }
31
+ const clampedTopK = Math.min(20, Math.max(1, Math.round(topK)));
32
+ logger_1.logger.info(`Searching icons: keyword="${keyword}", topK=${clampedTopK}`);
33
+ try {
34
+ const { urls } = await (0, api_1.searchIcons)(keyword, clampedTopK);
35
+ return {
36
+ content: urls.map((url) => ({
37
+ type: "text",
38
+ text: url,
39
+ })),
40
+ _meta: {
41
+ description: "SVG icon URLs matching the search keyword. Each URL points to an SVG file that can be embedded using an <img> tag or rendered inline.",
42
+ urls,
43
+ keyword,
44
+ topK: clampedTopK,
45
+ },
46
+ };
47
+ }
48
+ catch (err) {
49
+ const message = err instanceof Error ? err.message : "Unknown error";
50
+ logger_1.logger.error(`Failed to search icons: ${message}`);
51
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to search icons: ${message}`);
52
+ }
53
+ });
54
+ server.onerror = (err) => {
55
+ logger_1.logger.error("Server error", err);
56
+ };
57
+ process.on("SIGINT", async () => {
58
+ await server.close();
59
+ process.exit(0);
60
+ });
61
+ return server;
62
+ }
63
+ async function runStdioServer() {
64
+ const server = createServer();
65
+ await (0, index_1.startStdioServer)(server);
66
+ }
67
+ async function runSSEServer(host = "localhost", port = 3456, endpoint = "/sse") {
68
+ await (0, index_1.startSSEServer)(createServer, endpoint, port, host);
69
+ }
70
+ async function runStreamableServer(host = "localhost", port = 3456, endpoint = "/mcp") {
71
+ await (0, index_1.startStreamableServer)(createServer, endpoint, port, host);
72
+ }
@@ -0,0 +1,3 @@
1
+ export { startStdioServer } from "./stdio";
2
+ export { startSSEServer } from "./sse";
3
+ export { startStreamableServer } from "./streamable";
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startStreamableServer = exports.startSSEServer = exports.startStdioServer = void 0;
4
+ var stdio_1 = require("./stdio.js");
5
+ Object.defineProperty(exports, "startStdioServer", { enumerable: true, get: function () { return stdio_1.startStdioServer; } });
6
+ var sse_1 = require("./sse.js");
7
+ Object.defineProperty(exports, "startSSEServer", { enumerable: true, get: function () { return sse_1.startSSEServer; } });
8
+ var streamable_1 = require("./streamable.js");
9
+ Object.defineProperty(exports, "startStreamableServer", { enumerable: true, get: function () { return streamable_1.startStreamableServer; } });
@@ -0,0 +1,2 @@
1
+ import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ export declare function startSSEServer(createServer: () => Server, endpoint?: string, port?: number, host?: string): Promise<void>;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startSSEServer = startSSEServer;
7
+ const sse_js_1 = require("@modelcontextprotocol/sdk/server/sse.js");
8
+ const express_1 = __importDefault(require("express"));
9
+ const logger_1 = require("../utils/logger.js");
10
+ async function startSSEServer(createServer, endpoint = "/sse", port = 3456, host = "localhost") {
11
+ const app = (0, express_1.default)();
12
+ app.use(express_1.default.json());
13
+ const connections = {};
14
+ app.get(endpoint, async (_req, res) => {
15
+ const server = createServer();
16
+ const transport = new sse_js_1.SSEServerTransport("/messages", res);
17
+ connections[transport.sessionId] = transport;
18
+ transport.onclose = () => {
19
+ delete connections[transport.sessionId];
20
+ logger_1.logger.info(`SSE connection closed: sessionId=${transport.sessionId}`);
21
+ };
22
+ await server.connect(transport);
23
+ logger_1.logger.info(`SSE connection opened: sessionId=${transport.sessionId}`);
24
+ });
25
+ app.post("/messages", async (req, res) => {
26
+ const sessionId = req.query.sessionId;
27
+ if (!sessionId) {
28
+ res.status(400).send("Missing sessionId parameter");
29
+ return;
30
+ }
31
+ const transport = connections[sessionId];
32
+ if (!transport) {
33
+ res.status(404).send("Session not found");
34
+ return;
35
+ }
36
+ try {
37
+ await transport.handlePostMessage(req, res, req.body);
38
+ }
39
+ catch (e) {
40
+ logger_1.logger.error("SSE error handling message", e);
41
+ if (!res.headersSent)
42
+ res.status(500).send("Error handling request");
43
+ }
44
+ });
45
+ app.listen(port, host, () => {
46
+ logger_1.logger.success(`SSE server listening on http://${host}:${port}${endpoint}`);
47
+ });
48
+ }
@@ -0,0 +1,2 @@
1
+ import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ export declare function startStdioServer(server: Server): Promise<void>;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startStdioServer = startStdioServer;
4
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
5
+ const logger_1 = require("../utils/logger.js");
6
+ async function startStdioServer(server) {
7
+ const transport = new stdio_js_1.StdioServerTransport();
8
+ await server.connect(transport);
9
+ logger_1.logger.success("Stdio MCP server started");
10
+ }
@@ -0,0 +1,2 @@
1
+ import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ export declare function startStreamableServer(createServer: () => Server, endpoint?: string, port?: number, host?: string): Promise<void>;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startStreamableServer = startStreamableServer;
7
+ const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
8
+ const cors_1 = __importDefault(require("cors"));
9
+ const express_1 = __importDefault(require("express"));
10
+ const logger_1 = require("../utils/logger.js");
11
+ async function startStreamableServer(createServer, endpoint = "/mcp", port = 3456, host = "localhost") {
12
+ const app = (0, express_1.default)();
13
+ app.use(express_1.default.json());
14
+ app.use((0, cors_1.default)({ origin: "*", exposedHeaders: ["Mcp-Session-Id"] }));
15
+ app.post(endpoint, async (req, res) => {
16
+ try {
17
+ const server = createServer();
18
+ const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
19
+ sessionIdGenerator: undefined,
20
+ enableJsonResponse: true,
21
+ });
22
+ res.on("close", () => {
23
+ transport.close();
24
+ });
25
+ await server.connect(transport);
26
+ await transport.handleRequest(req, res, req.body);
27
+ }
28
+ catch (e) {
29
+ logger_1.logger.error("Streamable HTTP error", e);
30
+ if (!res.headersSent) {
31
+ res.status(500).json({
32
+ jsonrpc: "2.0",
33
+ error: { code: -32603, message: "Internal server error" },
34
+ id: null,
35
+ });
36
+ }
37
+ }
38
+ });
39
+ app.listen(port, host, () => {
40
+ logger_1.logger.success(`Streamable HTTP server listening on http://${host}:${port}${endpoint}`);
41
+ });
42
+ }
@@ -0,0 +1,2 @@
1
+ import type { Tool } from "@modelcontextprotocol/sdk/types.js";
2
+ export declare const searchIconsTool: Tool;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.searchIconsTool = void 0;
4
+ exports.searchIconsTool = {
5
+ name: "search_icons",
6
+ description: "Search for SVG icons by keyword using semantic search. Returns URLs of matching SVG icons from a library of over 100,000 infographic icons.",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ keyword: {
11
+ type: "string",
12
+ description: 'The search keyword or phrase to find relevant icons (e.g. "data analysis", "cloud computing", "security").',
13
+ },
14
+ topK: {
15
+ type: "number",
16
+ description: "The number of icons to return. Must be between 1 and 20. Defaults to 3.",
17
+ default: 3,
18
+ minimum: 1,
19
+ maximum: 20,
20
+ },
21
+ },
22
+ required: ["keyword"],
23
+ },
24
+ };
@@ -0,0 +1,9 @@
1
+ export interface IconSearchResult {
2
+ urls: string[];
3
+ }
4
+ /**
5
+ * Search for icons by keyword using the Infographic icon API.
6
+ * @param text - The search keyword (e.g. "data analysis")
7
+ * @param topK - Number of icons to return (1-20, default 3)
8
+ */
9
+ export declare function searchIcons(text: string, topK?: number): Promise<IconSearchResult>;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.searchIcons = searchIcons;
4
+ const ICON_API_BASE = "https://www.weavefox.cn/api/open/v1/icon";
5
+ /**
6
+ * Search for icons by keyword using the Infographic icon API.
7
+ * @param text - The search keyword (e.g. "data analysis")
8
+ * @param topK - Number of icons to return (1-20, default 3)
9
+ */
10
+ async function searchIcons(text, topK = 3) {
11
+ const url = `${ICON_API_BASE}?text=${encodeURIComponent(text)}&topK=${topK}`;
12
+ const response = await fetch(url, {
13
+ headers: { "Content-Type": "application/json" },
14
+ });
15
+ if (!response.ok) {
16
+ throw new Error(`Icon API request failed: ${response.status} ${response.statusText}`);
17
+ }
18
+ const json = (await response.json());
19
+ if (!json.status || !json.data?.success) {
20
+ throw new Error(`Icon API returned an error: ${json.message}`);
21
+ }
22
+ return { urls: json.data.data };
23
+ }
@@ -0,0 +1,13 @@
1
+ declare function setIsStdio(isStdio: boolean): void;
2
+ declare function info(message: string, ...args: unknown[]): void;
3
+ declare function warn(message: string, ...args: unknown[]): void;
4
+ declare function error(message: string, err?: unknown): void;
5
+ declare function success(message: string, ...args: unknown[]): void;
6
+ export declare const logger: {
7
+ info: typeof info;
8
+ warn: typeof warn;
9
+ error: typeof error;
10
+ success: typeof success;
11
+ setIsStdio: typeof setIsStdio;
12
+ };
13
+ export {};
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logger = void 0;
4
+ const PREFIX = "[mcp-icon]";
5
+ let IS_STDIO = true;
6
+ function setIsStdio(isStdio) {
7
+ IS_STDIO = isStdio;
8
+ }
9
+ function getTimestamp() {
10
+ return new Date().toISOString();
11
+ }
12
+ function info(message, ...args) {
13
+ const fn = IS_STDIO ? console.error : console.log;
14
+ fn(`${PREFIX} ${getTimestamp()} โ„น๏ธ ${message}`, ...args);
15
+ }
16
+ function warn(message, ...args) {
17
+ const fn = IS_STDIO ? console.warn : console.log;
18
+ fn(`${PREFIX} ${getTimestamp()} โš ๏ธ ${message}`, ...args);
19
+ }
20
+ function error(message, err) {
21
+ console.error(`${PREFIX} ${getTimestamp()} โŒ ${message}`, err ?? "");
22
+ }
23
+ function success(message, ...args) {
24
+ const fn = IS_STDIO ? console.error : console.log;
25
+ fn(`${PREFIX} ${getTimestamp()} โœ… ${message}`, ...args);
26
+ }
27
+ exports.logger = { info, warn, error, success, setIsStdio };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "mcp-icon",
3
+ "description": "A Model Context Protocol server for semantic icon search. Generate infographic SVG icons by keyword, with over 100,000 icons and semantic search support.",
4
+ "version": "1.0.0",
5
+ "main": "build/index.js",
6
+ "scripts": {
7
+ "start": "npx @modelcontextprotocol/inspector node build/index.js",
8
+ "prebuild": "rm -rf build/*",
9
+ "build": "tsc && tsc-alias -p tsconfig.json",
10
+ "postbuild": "chmod +x build/index.js",
11
+ "prepublishOnly": "npm run build",
12
+ "test": "vitest run",
13
+ "test:watch": "vitest"
14
+ },
15
+ "bin": {
16
+ "mcp-icon": "./build/index.js"
17
+ },
18
+ "publishConfig": {
19
+ "registry": "https://registry.npmjs.org/",
20
+ "access": "public"
21
+ },
22
+ "files": ["build"],
23
+ "keywords": ["antv", "mcp", "icon", "svg", "search", "infographic"],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/hustcc/mcp-icon"
27
+ },
28
+ "author": {
29
+ "name": "hustcc"
30
+ },
31
+ "license": "MIT",
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "dependencies": {
36
+ "@modelcontextprotocol/sdk": "^1.12.0",
37
+ "cors": "^2.8.5",
38
+ "express": "^5.1.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/cors": "^2.8.19",
42
+ "@types/express": "^5.0.3",
43
+ "@types/node": "^22.0.0",
44
+ "@vitest/coverage-v8": "^3.0.0",
45
+ "tsc-alias": "^1.8.0",
46
+ "typescript": "^5.8.0",
47
+ "vitest": "^3.0.0"
48
+ }
49
+ }