nardoto-mcp-iconfinder 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/README.md +19 -0
- package/index.js +109 -0
- package/package.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# nardoto-mcp-iconfinder
|
|
2
|
+
|
|
3
|
+
MCP server para buscar e baixar **ícones (SVG/PNG) do Iconfinder** direto no chat.
|
|
4
|
+
|
|
5
|
+
## Configuração
|
|
6
|
+
- `ICONFINDER_API_KEY` — grátis no free tier em https://developer.iconfinder.com (header Bearer). O free tier dá ~500 req/dia.
|
|
7
|
+
|
|
8
|
+
## Tools
|
|
9
|
+
- `search_icons` — busca por texto. Por padrão traz só ícones **gratuitos** (`include_premium: false`) para não consumir crédito.
|
|
10
|
+
- `get_icon` — detalhes de um ícone (links SVG/PNG).
|
|
11
|
+
|
|
12
|
+
As `download_url` retornadas exigem o mesmo header `Authorization: Bearer <key>` para baixar de fato.
|
|
13
|
+
|
|
14
|
+
## Uso
|
|
15
|
+
```
|
|
16
|
+
npx -y nardoto-mcp-iconfinder
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
MIT · feito pelo Nardoto.
|
package/index.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* nardoto-mcp-iconfinder — MCP server pra buscar e baixar icones (SVG/PNG) do Iconfinder.
|
|
4
|
+
*
|
|
5
|
+
* Auth: ICONFINDER_API_KEY (Bearer, gratis no free tier em https://developer.iconfinder.com).
|
|
6
|
+
* Por padrao busca SO icones gratuitos (premium=0) pra nao consumir credito.
|
|
7
|
+
* As download_url do Iconfinder exigem o mesmo header Authorization: Bearer pra baixar de fato.
|
|
8
|
+
*/
|
|
9
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
|
|
10
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
11
|
+
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js'
|
|
12
|
+
|
|
13
|
+
const KEY = process.env.ICONFINDER_API_KEY
|
|
14
|
+
const BASE = 'https://api.iconfinder.com/v4'
|
|
15
|
+
|
|
16
|
+
async function iget(path, params) {
|
|
17
|
+
if (!KEY) throw new Error('Defina ICONFINDER_API_KEY (gratis em developer.iconfinder.com).')
|
|
18
|
+
const url = new URL(BASE + path)
|
|
19
|
+
for (const [k, v] of Object.entries(params || {})) {
|
|
20
|
+
if (v !== undefined && v !== null && v !== '') url.searchParams.set(k, String(v))
|
|
21
|
+
}
|
|
22
|
+
const res = await fetch(url, { headers: { Authorization: 'Bearer ' + KEY, 'User-Agent': 'nardoto-mcp-iconfinder' } })
|
|
23
|
+
if (!res.ok) throw new Error(`Iconfinder HTTP ${res.status}`)
|
|
24
|
+
return res.json()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Extrai a melhor URL SVG (vetor) e a maior PNG (raster) de um icone.
|
|
28
|
+
function fmtIcon(icon) {
|
|
29
|
+
let svg = null
|
|
30
|
+
for (const vs of icon.vector_sizes || []) {
|
|
31
|
+
for (const f of vs.formats || []) {
|
|
32
|
+
if ((f.format || '').toLowerCase() === 'svg' && f.download_url) { svg = f.download_url; break }
|
|
33
|
+
}
|
|
34
|
+
if (svg) break
|
|
35
|
+
}
|
|
36
|
+
let png = null
|
|
37
|
+
let bestSize = 0
|
|
38
|
+
for (const rs of icon.raster_sizes || []) {
|
|
39
|
+
const size = rs.size_width || rs.size || 0
|
|
40
|
+
for (const f of rs.formats || []) {
|
|
41
|
+
if ((f.format || '').toLowerCase() === 'png' && f.download_url && size >= bestSize) {
|
|
42
|
+
png = f.download_url; bestSize = size
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
icon_id: icon.icon_id,
|
|
48
|
+
tags: Array.isArray(icon.tags) ? icon.tags.slice(0, 12) : undefined,
|
|
49
|
+
is_premium: icon.is_premium,
|
|
50
|
+
svg_download_url: svg,
|
|
51
|
+
png_download_url: png,
|
|
52
|
+
png_size: bestSize || undefined,
|
|
53
|
+
nota_download: 'As download_url exigem o header Authorization: Bearer <sua key> pra baixar.',
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const TOOLS = [
|
|
58
|
+
{
|
|
59
|
+
name: 'search_icons',
|
|
60
|
+
description: 'Busca icones no Iconfinder por texto. Por padrao traz so icones gratuitos (nao consome credito). Retorna links de download SVG e PNG.',
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: 'object',
|
|
63
|
+
properties: {
|
|
64
|
+
query: { type: 'string', description: 'Termo de busca (ex: cross, sword, crown, map, scale, dove)' },
|
|
65
|
+
limit: { type: 'number', description: 'Maximo de resultados (1-50, padrao 12)' },
|
|
66
|
+
include_premium: { type: 'boolean', description: 'Incluir icones premium (consome credito). Padrao false.' },
|
|
67
|
+
},
|
|
68
|
+
required: ['query'],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'get_icon',
|
|
73
|
+
description: 'Detalhes de um icone pelo icon_id (tags, links de download SVG/PNG).',
|
|
74
|
+
inputSchema: { type: 'object', properties: { icon_id: { type: 'string', description: 'ID do icone' } }, required: ['icon_id'] },
|
|
75
|
+
},
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
const server = new Server({ name: 'nardoto-mcp-iconfinder', version: '1.0.0' }, { capabilities: { tools: {} } })
|
|
79
|
+
|
|
80
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }))
|
|
81
|
+
|
|
82
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
83
|
+
const { name, arguments: args = {} } = req.params
|
|
84
|
+
try {
|
|
85
|
+
if (name === 'search_icons') {
|
|
86
|
+
if (!args.query) throw new Error('query obrigatoria')
|
|
87
|
+
const params = {
|
|
88
|
+
query: args.query,
|
|
89
|
+
count: Math.min(Math.max(Number(args.limit) || 12, 1), 50),
|
|
90
|
+
premium: args.include_premium ? 'all' : '0',
|
|
91
|
+
vector: 1,
|
|
92
|
+
}
|
|
93
|
+
const data = await iget('/icons/search', params)
|
|
94
|
+
const icons = (data.icons || []).map(fmtIcon)
|
|
95
|
+
return { content: [{ type: 'text', text: JSON.stringify({ count: icons.length, total: data.total_count, icons }, null, 2) }] }
|
|
96
|
+
}
|
|
97
|
+
if (name === 'get_icon') {
|
|
98
|
+
if (!args.icon_id) throw new Error('icon_id obrigatorio')
|
|
99
|
+
const icon = await iget(`/icons/${encodeURIComponent(args.icon_id)}`, {})
|
|
100
|
+
return { content: [{ type: 'text', text: JSON.stringify(fmtIcon(icon), null, 2) }] }
|
|
101
|
+
}
|
|
102
|
+
return { content: [{ type: 'text', text: 'Tool desconhecida: ' + name }], isError: true }
|
|
103
|
+
} catch (e) {
|
|
104
|
+
return { content: [{ type: 'text', text: 'Erro: ' + (e?.message || String(e)) }], isError: true }
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
await server.connect(new StdioServerTransport())
|
|
109
|
+
console.error('[nardoto-mcp-iconfinder] pronto (stdio)')
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nardoto-mcp-iconfinder",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server para buscar e baixar icones (SVG/PNG) do Iconfinder",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"nardoto-mcp-iconfinder": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"index.js",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"model-context-protocol",
|
|
23
|
+
"iconfinder",
|
|
24
|
+
"icons",
|
|
25
|
+
"svg",
|
|
26
|
+
"nardoto"
|
|
27
|
+
],
|
|
28
|
+
"author": "Nardoto",
|
|
29
|
+
"license": "MIT"
|
|
30
|
+
}
|