MCP icon verify

July 31, 2026 · View on GitHub

Date: 2026-07-31 Outcome: Client limitation (server correct) per D-05

Variant tested

V1 (baseline) — data URI 192×192 first, then jsDelivr favicon-32.png (32×32), then mcp-icon-192.png (192×192). Implemented in buildMcpServerIcons() (src/mcp/server-icons.ts).

V2–V4 not required: server emits correct icons[]; Cursor UI shows letter "A" fallback on both paths (client limitation per D-05).

Path A: local dist/

.cursor/mcp.json config:

{
  "mcpServers": {
    "awesome-coolify-mcp": {
      "command": "node",
      "args": ["dist/index.js"],
      "cwd": "<repo-root>"
    }
  }
}

Prerequisite: npm run build

UI observation (Path A)

  • Server name: awesome-coolify-mcp (connected — green)
  • Tools listed: visible (action-based tools load)
  • Icon: generic letter "A" only — no custom icon rendered (client limitation)

Initialize JSON excerpt (Path A)

Verified via stdio dump (node dist/index.js):

{
  "serverInfo": {
    "name": "awesome-coolify-mcp",
    "version": "1.1.4",
    "title": "Awesome Coolify",
    "description": "MCP server for Coolify 4.1.x — deploy, diagnose, and CRUD for keys, servers, projects, and environments via action-based tools",
    "websiteUrl": "https://github.com/clezcoding/awesome-coolify",
    "icons": [
      {
        "src": "data:image/png;base64,{…}",
        "mimeType": "image/png",
        "sizes": ["192x192"]
      },
      {
        "src": "https://cdn.jsdelivr.net/gh/clezcoding/awesome-coolify@main/docs/assets/favicon-32.png",
        "mimeType": "image/png",
        "sizes": ["32x32"]
      },
      {
        "src": "https://cdn.jsdelivr.net/gh/clezcoding/awesome-coolify@main/docs/assets/mcp-icon-192.png",
        "mimeType": "image/png",
        "sizes": ["192x192"]
      }
    ]
  }
}

icons[] length: 3 (data URI first + 2 CDN entries). Version: 1.1.4.

Path B: npm npx

.cursor/mcp.json config:

Plain npx from the awesome-coolify repo root collides with the local package name — use sh -c with cwd outside the repo:

{
  "mcpServers": {
    "awesome-coolify-mcp": {
      "command": "sh",
      "args": ["-c", "cd /tmp && exec npx -y awesome-coolify-mcp@1.1.4"]
    }
  }
}

UI observation (Path B)

  • Server name: awesome-coolify-mcp (connected — green after sh -c workaround)
  • Tools listed: visible
  • Icon: generic letter "A" only — same client limitation as Path A

Initialize result (Path B)

The published probe returned the same serverInfo shape shown for Path A: version 1.1.4, three icon entries, embedded PNG first, then both jsDelivr URLs.

Server emits icons correctly

The single Path A excerpt above is the canonical initialize sample. icons[] length is three: one embedded data URI plus two jsDelivr PNG entries. Never paste the Base64 payload inline; use {…} and verify through the stdio probe.

Stdio initialize dump procedure

Path A (local dist):

npm run build
node -e "
const { spawn } = require('node:child_process');
const cp = spawn('node', ['dist/index.js'], { stdio: ['pipe','pipe','inherit'] });
let buf = '';
cp.stdout.on('data', d => {
  buf += d;
  if (buf.includes('serverInfo')) { console.log(buf); cp.kill(); }
});
cp.stdin.write(JSON.stringify({
  jsonrpc: '2.0', id: 1, method: 'initialize',
  params: {
    protocolVersion: '2024-11-05',
    capabilities: {},
    clientInfo: { name: 'verify', version: '1.0.0' }
  }
}) + '\n');
"

Path B (npm npx): same probe with spawn('npx', ['-y', 'awesome-coolify-mcp@1.1.4'], { cwd: '/tmp', … }) — run from outside the awesome-coolify repo to avoid package-name collision.

CDN asset reachable

curl -I https://cdn.jsdelivr.net/gh/clezcoding/awesome-coolify@main/docs/assets/favicon-32.png
# HTTP/2 200 — content-type: image/png

curl -I https://cdn.jsdelivr.net/gh/clezcoding/awesome-coolify@main/docs/assets/mcp-icon-192.png
# HTTP/2 200 — content-type: image/png

Both jsDelivr URLs return HTTP/2 200 image/png (verified 2026-07-29; re-checked 2026-07-31).

Spec / SDK alignment

@modelcontextprotocol/typescript-sdk documents icons on McpServer constructor Implementation (src, optional mimeType, sizes, theme). Icon.src accepts HTTPS URLs or data: Base64 PNG. Our V1 wiring matches SDK multi-entry pattern (Context7 /modelcontextprotocol/typescript-sdk).

Cursor client evidence

Cursor forum report Can't get mcp icons to work in cursor ide (Mar 2026): staff confirmed icons can be accepted from the server while Cursor UI still may not render custom MCP server icons. MCP Inspector can show icons when Cursor does not.

Earlier related bug: icons.sizes array vs string validation (forum #145029) — connection works here (tools load), so this is display-path limitation, not handshake rejection.

Phase 16 D-09 documented the same client limitation for CDN-only icons; Phase 27 refreshes evidence for data URI + multi-size CDN workarounds. Re-verified at package 1.1.4 (v3.3 milestone) — same client limitation.

Conclusion

CheckPath A (dist/)Path B (npx)
serverInfo.icons includes data URI
serverInfo.icons includes CDN PNG(s)
serverInfo.version === 1.1.4
jsDelivr PNG 200
title / tools visible in Cursor
Custom icon in Cursor MCP list✗ (client limitation)✗ (client limitation)

Pass criteria (D-05): Documented client limitation with initialize dump for both paths — server correct, Cursor UI omits custom icon. V1 baseline sufficient; V2–V4 not attempted.