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 0000000000..a545f42dd5
Binary files /dev/null and b/mcp/packages/browser-extension/public/icons/icon-128.png differ
diff --git a/mcp/packages/browser-extension/public/icons/icon-16.png b/mcp/packages/browser-extension/public/icons/icon-16.png
new file mode 100644
index 0000000000..3e6eb3e20e
Binary files /dev/null and b/mcp/packages/browser-extension/public/icons/icon-16.png differ
diff --git a/mcp/packages/browser-extension/public/icons/icon-32.png b/mcp/packages/browser-extension/public/icons/icon-32.png
new file mode 100644
index 0000000000..31f2fe30e5
Binary files /dev/null and b/mcp/packages/browser-extension/public/icons/icon-32.png differ
diff --git a/mcp/packages/browser-extension/public/icons/icon-48.png b/mcp/packages/browser-extension/public/icons/icon-48.png
new file mode 100644
index 0000000000..f92dd70100
Binary files /dev/null and b/mcp/packages/browser-extension/public/icons/icon-48.png differ
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));
+ }
}
});