From 9a21873e2461ad42844aa7af6c166711d0036ff2 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 26 Oct 2026 10:32:45 +0000 Subject: [PATCH] :sparkles: Add an icon to the MCP browser extension Give the extension the Penpot logo, white on a black rounded square, so it reads on light and dark toolbars. The SVG source sits next to PNGs at 16, 32, 48 and 128 px, which both manifests list as the extension icons and the toolbar button icon. The README explains how to redraw the PNGs from the SVG. --- mcp/packages/browser-extension/README.md | 9 ++++++++ .../public/icons/icon-128.png | Bin 0 -> 4167 bytes .../public/icons/icon-16.png | Bin 0 -> 472 bytes .../public/icons/icon-32.png | Bin 0 -> 1115 bytes .../public/icons/icon-48.png | Bin 0 -> 1713 bytes .../browser-extension/public/icons/icon.svg | 6 +++++ .../browser-extension/scripts/manifest.mjs | 9 ++++++++ .../browser-extension/src/manifest.test.ts | 21 +++++++++++++++++- 8 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 mcp/packages/browser-extension/public/icons/icon-128.png create mode 100644 mcp/packages/browser-extension/public/icons/icon-16.png create mode 100644 mcp/packages/browser-extension/public/icons/icon-32.png create mode 100644 mcp/packages/browser-extension/public/icons/icon-48.png create mode 100644 mcp/packages/browser-extension/public/icons/icon.svg diff --git a/mcp/packages/browser-extension/README.md b/mcp/packages/browser-extension/README.md index c9d4a0943d..06a997fe36 100644 --- a/mcp/packages/browser-extension/README.md +++ b/mcp/packages/browser-extension/README.md @@ -17,6 +17,15 @@ for the plugin to answer again, and then runs the task. The popup turns waking on or off and lists the paired sessions and server connections. +The icon is the Penpot logo; `public/icons/icon.svg` is its source. To redraw the PNGs after +changing it: + +```sh +for size in 16 32 48 128; do + rsvg-convert -w $size -h $size public/icons/icon.svg -o public/icons/icon-$size.png +done +``` + ## How a tab is woken - **Chrome** unfreezes the page in place: the extension attaches the debugger to the tab, diff --git a/mcp/packages/browser-extension/public/icons/icon-128.png b/mcp/packages/browser-extension/public/icons/icon-128.png new file mode 100644 index 0000000000000000000000000000000000000000..a545f42dd5394505fd2364d9cee44e1592b74bf9 GIT binary patch literal 4167 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 Hu0mjf)Os7& literal 0 HcmV?d00001 diff --git a/mcp/packages/browser-extension/public/icons/icon.svg b/mcp/packages/browser-extension/public/icons/icon.svg new file mode 100644 index 0000000000..b12e54c10e --- /dev/null +++ b/mcp/packages/browser-extension/public/icons/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/mcp/packages/browser-extension/scripts/manifest.mjs b/mcp/packages/browser-extension/scripts/manifest.mjs index 6fab3ff8bd..29fb4bdc2c 100644 --- a/mcp/packages/browser-extension/scripts/manifest.mjs +++ b/mcp/packages/browser-extension/scripts/manifest.mjs @@ -1,6 +1,13 @@ /** Browsers the extension is built for, one directory of `dist/` each. */ export const BROWSERS = ["chrome", "firefox"]; +const ICONS = { + 16: "icons/icon-16.png", + 32: "icons/icon-32.png", + 48: "icons/icon-48.png", + 128: "icons/icon-128.png", +}; + const CONTENT_SCRIPTS = [ { matches: ["https://design.penpot.app/*", "https://localhost/*", "http://localhost/*"], @@ -23,9 +30,11 @@ export function createManifest(browser) { name: "Penpot MCP Wake", version: "0.1.0", description: "Wakes a background Penpot tab when an MCP task needs it.", + icons: ICONS, action: { default_title: "Penpot MCP Wake", default_popup: "popup.html", + default_icon: { 16: ICONS[16], 32: ICONS[32] }, }, content_scripts: CONTENT_SCRIPTS, }; diff --git a/mcp/packages/browser-extension/src/manifest.test.ts b/mcp/packages/browser-extension/src/manifest.test.ts index 82f2c04fc3..520abd32c6 100644 --- a/mcp/packages/browser-extension/src/manifest.test.ts +++ b/mcp/packages/browser-extension/src/manifest.test.ts @@ -1,4 +1,5 @@ import assert from "node:assert/strict"; +import { access } from "node:fs/promises"; import test from "node:test"; import { BROWSERS, createManifest } from "../scripts/manifest.mjs"; @@ -56,6 +57,24 @@ test("runs the content script on Penpot and on local development instances", () test("opens the popup from the toolbar button", () => { for (const manifest of [chrome, firefox]) { - assert.deepEqual(manifest.action, { default_title: "Penpot MCP Wake", default_popup: "popup.html" }); + assert.deepEqual(manifest.action, { + default_title: "Penpot MCP Wake", + default_popup: "popup.html", + default_icon: { 16: "icons/icon-16.png", 32: "icons/icon-32.png" }, + }); + } +}); + +test("has icons for the toolbar, the extensions page and the stores, all in public/", async () => { + for (const manifest of [chrome, firefox]) { + assert.deepEqual(manifest.icons, { + 16: "icons/icon-16.png", + 32: "icons/icon-32.png", + 48: "icons/icon-48.png", + 128: "icons/icon-128.png", + }); + for (const path of Object.values(manifest.icons as Record)) { + await access(new URL(`../public/${path}`, import.meta.url)); + } } });