@supericons/mcp 0.4.8 → 0.4.9
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/generated/motion-lab-baseline.json +1 -1
- package/hosted-search-client.js +42 -16
- package/package.json +1 -1
- package/recommend-icons.js +50 -8
- package/server.json +2 -2
package/hosted-search-client.js
CHANGED
|
@@ -51,6 +51,18 @@ function hasSearchResults(payload) {
|
|
|
51
51
|
return Array.isArray(payload?.results) && payload.results.length > 0;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
function sleep(ms) {
|
|
55
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getRetryDelayMs(response, attempt) {
|
|
59
|
+
const retryAfter = Number(response.headers.get('retry-after'));
|
|
60
|
+
if (Number.isFinite(retryAfter) && retryAfter > 0) {
|
|
61
|
+
return Math.min(retryAfter * 1000, 5000);
|
|
62
|
+
}
|
|
63
|
+
return Math.min(500 * 2 ** attempt, 2500);
|
|
64
|
+
}
|
|
65
|
+
|
|
54
66
|
function buildLocalizedRetryQueries(query, locale) {
|
|
55
67
|
if (!locale || multilingualExpansionTerms.length === 0) return [];
|
|
56
68
|
|
|
@@ -73,31 +85,45 @@ function buildLocalizedRetryQueries(query, locale) {
|
|
|
73
85
|
}
|
|
74
86
|
|
|
75
87
|
async function postHostedSearch(url, headers, body) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
let lastStatus = 0;
|
|
89
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
90
|
+
const response = await fetch(url, {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
headers,
|
|
93
|
+
body: JSON.stringify(body),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (response.ok) {
|
|
97
|
+
return response.json();
|
|
98
|
+
}
|
|
81
99
|
|
|
82
|
-
|
|
83
|
-
|
|
100
|
+
lastStatus = response.status;
|
|
101
|
+
if (response.status !== 429 && response.status < 500) break;
|
|
102
|
+
await sleep(getRetryDelayMs(response, attempt));
|
|
84
103
|
}
|
|
85
104
|
|
|
86
|
-
|
|
105
|
+
throw new Error(`hosted MCP search failed (${lastStatus})`);
|
|
87
106
|
}
|
|
88
107
|
|
|
89
108
|
async function postPublicSearch(url, headers, body) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
109
|
+
let lastStatus = 0;
|
|
110
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
111
|
+
const response = await fetch(url, {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
headers,
|
|
114
|
+
body: JSON.stringify(body),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (response.ok) {
|
|
118
|
+
return response.json();
|
|
119
|
+
}
|
|
95
120
|
|
|
96
|
-
|
|
97
|
-
|
|
121
|
+
lastStatus = response.status;
|
|
122
|
+
if (response.status !== 429 && response.status < 500) break;
|
|
123
|
+
await sleep(getRetryDelayMs(response, attempt));
|
|
98
124
|
}
|
|
99
125
|
|
|
100
|
-
|
|
126
|
+
throw new Error(`public MCP search failed (${lastStatus})`);
|
|
101
127
|
}
|
|
102
128
|
|
|
103
129
|
async function retryLocalizedHostedSearch({ postSearch, url, headers, body, locale }) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supericons/mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.9",
|
|
4
4
|
"mcpName": "io.github.curlymolelabs/supericons",
|
|
5
5
|
"description": "MCP server for Supericons: multilingual semantic SVG icon search and recommendations for AI coding agents.",
|
|
6
6
|
"type": "module",
|
package/recommend-icons.js
CHANGED
|
@@ -26,6 +26,8 @@ const multilingualSearchAliases = existsSync(multilingualAliasesPath)
|
|
|
26
26
|
? JSON.parse(readFileSync(multilingualAliasesPath, 'utf8')).aliases || []
|
|
27
27
|
: [];
|
|
28
28
|
const multilingualExpansionTerms = [...cjkSearchTerms, ...multilingualSearchAliases];
|
|
29
|
+
const SLOT_SEARCH_CONCURRENCY = 2;
|
|
30
|
+
const SLOT_QUERY_CONCURRENCY = 1;
|
|
29
31
|
|
|
30
32
|
const GENERIC_SLOT_WORDS = new Set([
|
|
31
33
|
'action',
|
|
@@ -478,6 +480,17 @@ const COMMON_SLOT_PREFERENCE_RULES = Object.freeze([
|
|
|
478
480
|
{ pattern: /fork|knife|git|branch|merge|forklift|grill|cancel|\bx\b|off|discount|heart|exclamation|minus|plus|search|share|star|question|bolt|code|copy|dollar|down|up|pin|pause/i, bonus: -140 },
|
|
479
481
|
],
|
|
480
482
|
},
|
|
483
|
+
{
|
|
484
|
+
priority: 120,
|
|
485
|
+
slotPatterns: [/^cart$/i, /shopping cart/i, /\bbasket\b/i],
|
|
486
|
+
queryVariants: ['shopping cart', 'cart', 'basket'],
|
|
487
|
+
iconPreferences: [
|
|
488
|
+
{ pattern: /^shopping[_-]?cart$|^basket$/i, bonus: 220 },
|
|
489
|
+
{ pattern: /shopping-cart-(cog|x|off|discount|dollar|exclamation|heart|minus|pause|plus|question|share|star|bolt|copy|down|up|search|pin)/i, bonus: -260 },
|
|
490
|
+
{ pattern: /basket-(cog|x|off|discount|dollar|exclamation|heart|minus|pause|plus|question|share|star|bolt|copy|down|up|search|pin)/i, bonus: -180 },
|
|
491
|
+
{ pattern: /garden-cart/i, bonus: -180 },
|
|
492
|
+
],
|
|
493
|
+
},
|
|
481
494
|
{
|
|
482
495
|
priority: 90,
|
|
483
496
|
slotPatterns: [/customers?/i, /shoppers?/i, /buyers?/i],
|
|
@@ -514,6 +527,26 @@ const COMMON_SLOT_PREFERENCE_RULES = Object.freeze([
|
|
|
514
527
|
{ pattern: /border|sort|align|cancel|\bx\b|off|discount|heart|exclamation|minus|plus|search|share|star|question|bolt|code|copy|dollar|down|up|pin|pause/i, bonus: -130 },
|
|
515
528
|
],
|
|
516
529
|
},
|
|
530
|
+
{
|
|
531
|
+
priority: 120,
|
|
532
|
+
slotPatterns: [/shipping/i, /delivery/i, /fulfillment/i, /dispatch/i],
|
|
533
|
+
queryVariants: ['truck delivery', 'delivery', 'shipping', 'package delivery'],
|
|
534
|
+
iconPreferences: [
|
|
535
|
+
{ pattern: /^truck[_-]?delivery$/i, bonus: 260 },
|
|
536
|
+
{ pattern: /^truck$|package[_-]?export|package[_-]?import/i, bonus: 180 },
|
|
537
|
+
{ pattern: /^truck[_-]?return$/i, bonus: -120 },
|
|
538
|
+
{ pattern: /cloud-upload|upload|ship-off|cloud|arrow-up/i, bonus: -220 },
|
|
539
|
+
],
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
priority: 120,
|
|
543
|
+
slotPatterns: [/returns?/i, /refunds?/i, /reverse logistics/i],
|
|
544
|
+
queryVariants: ['return', 'refund', 'truck return', 'receipt refund'],
|
|
545
|
+
iconPreferences: [
|
|
546
|
+
{ pattern: /^truck[_-]?return$|receipt[_-]?refund|credit-card[_-]?refund|arrow-back|cash.*move.*back/i, bonus: 220 },
|
|
547
|
+
{ pattern: /player|chevron|stack|upload|cloud|ship-off/i, bonus: -160 },
|
|
548
|
+
],
|
|
549
|
+
},
|
|
517
550
|
{
|
|
518
551
|
priority: 90,
|
|
519
552
|
slotPatterns: [/products?/i, /catalog/i, /inventory/i],
|
|
@@ -523,14 +556,23 @@ const COMMON_SLOT_PREFERENCE_RULES = Object.freeze([
|
|
|
523
556
|
{ pattern: /brand-producthunt|brand-stocktwits|border|sort|cancel|\bx\b|off|discount|heart|exclamation|minus|plus|search|share|star|question|bolt|code|copy|dollar|down|up|pin|pause/i, bonus: -130 },
|
|
524
557
|
],
|
|
525
558
|
},
|
|
526
|
-
{
|
|
527
|
-
slotPatterns: [/reports?/i, /analytics/i, /insights?/i],
|
|
528
|
-
queryVariants: ['bar chart', 'file chart', 'analytics chart', 'report document'],
|
|
559
|
+
{
|
|
560
|
+
slotPatterns: [/reports?/i, /analytics/i, /insights?/i],
|
|
561
|
+
queryVariants: ['bar chart', 'file chart', 'analytics chart', 'report document'],
|
|
529
562
|
iconPreferences: [
|
|
530
563
|
{ pattern: /file-.*chart|chart-bar|bar-chart-3|bar-chart|chart-line|line-chart/i, bonus: 40 },
|
|
531
|
-
{ pattern: /chart|report|analytics/i, bonus: 16 },
|
|
532
|
-
],
|
|
533
|
-
},
|
|
564
|
+
{ pattern: /chart|report|analytics/i, bonus: 16 },
|
|
565
|
+
],
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
priority: 100,
|
|
569
|
+
slotPatterns: [/^quotes?$/i, /blockquote/i, /quotation/i, /citation/i],
|
|
570
|
+
queryVariants: ['quotes', 'quotation', 'quote', 'blockquote'],
|
|
571
|
+
iconPreferences: [
|
|
572
|
+
{ pattern: /^quotes?$|quotation|blockquote/i, bonus: 180 },
|
|
573
|
+
{ pattern: /indent|text-align|receipt|ticket/i, bonus: -120 },
|
|
574
|
+
],
|
|
575
|
+
},
|
|
534
576
|
{
|
|
535
577
|
slotPatterns: [/settings?/i, /preferences?/i, /configure/i],
|
|
536
578
|
queryVariants: ['settings', 'cog', 'sliders'],
|
|
@@ -1278,7 +1320,7 @@ export async function recommendIconsForTask({
|
|
|
1278
1320
|
semanticMap,
|
|
1279
1321
|
}) {
|
|
1280
1322
|
const normalizedResponseMode = normalizeResponseMode(responseMode);
|
|
1281
|
-
const scoredSlotResults = await mapWithConcurrency(slots,
|
|
1323
|
+
const scoredSlotResults = await mapWithConcurrency(slots, SLOT_SEARCH_CONCURRENCY, async (slotLabel) => {
|
|
1282
1324
|
const intentTerms = buildSlotIntentTerms(task, slotLabel, locale);
|
|
1283
1325
|
const requestedVariantTerms = dedupe([
|
|
1284
1326
|
...tokenizeText(slotLabel),
|
|
@@ -1289,7 +1331,7 @@ export async function recommendIconsForTask({
|
|
|
1289
1331
|
const pooledIcons = [];
|
|
1290
1332
|
const seen = new Set();
|
|
1291
1333
|
|
|
1292
|
-
const resultGroups = await mapWithConcurrency(queryVariants,
|
|
1334
|
+
const resultGroups = await mapWithConcurrency(queryVariants, SLOT_QUERY_CONCURRENCY, async (queryVariant) => {
|
|
1293
1335
|
try {
|
|
1294
1336
|
return await searchIconsForQuery({
|
|
1295
1337
|
query: queryVariant,
|
package/server.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"url": "https://github.com/curlymolelabs/supericons",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.4.
|
|
10
|
+
"version": "0.4.9",
|
|
11
11
|
"remotes": [
|
|
12
12
|
{
|
|
13
13
|
"type": "streamable-http",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
{
|
|
19
19
|
"registryType": "npm",
|
|
20
20
|
"identifier": "@supericons/mcp",
|
|
21
|
-
"version": "0.4.
|
|
21
|
+
"version": "0.4.9",
|
|
22
22
|
"transport": {
|
|
23
23
|
"type": "stdio"
|
|
24
24
|
}
|