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.
Files changed (3) hide show
  1. package/README.md +19 -0
  2. package/index.js +109 -0
  3. 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
+ }