Penpot MCP Container

Penpot MCP Container

A containerized deployment of the Penpot MCP Server that enables LLMs to interact directly with Penpot design projects using the Model Context Protocol (MCP).

:package: Container Image

Container Registry: ghcr.io/astrateam-net/penpot-mcp:0.0.1

docker pull ghcr.io/astrateam-net/penpot-mcp:0.0.1

Source Code: View the build configuration and Dockerfile

:rocket: Why Use This Container?

Solves the HTTP/Private Network Access Problem

The upstream Penpot MCP project has a known limitation with modern Chromium browsers (v142+):

Browser Compatibility Issue: Starting with Chromium version 142, Google has hardened the private network access (PNA) enforcement layer. This means that newer Chromium-based browsers (Chrome, Edge, Vivaldi, Opera, Brave, etc.) will not allow Penpot to connect to a local plugin server by default.

The workaround suggested in the upstream README:

  • Use Firefox, or
  • Use an older version of a Chromium-based browser (up to Chromium version 141)

Our solution: Deploy this container behind a reverse proxy (Traefik, nginx, Caddy, etc.) with HTTPS, and the browser will allow the connection! :tada:

When accessed via HTTPS through a reverse proxy, the browser treats it as a secure connection, bypassing the private network access restrictions entirely.

Additional Benefits

:white_check_mark: No local Node.js installation required - Everything runs in the container
:white_check_mark: Consistent environment - Same setup across all machines
:white_check_mark: Easy deployment - Works with Docker Compose, Kubernetes, or any container orchestrator
:white_check_mark: Production-ready - Multi-platform builds (amd64 + arm64)
:white_check_mark: Automatic updates - Rebuild when upstream updates
:white_check_mark: Isolated - No conflicts with other Node.js projects on your system

:clipboard: Quick Start

Using Docker Compose with Traefik

services:
  penpot-mcp:
    image: ghcr.io/astrateam-net/penpot-mcp:0.0.1
    container_name: penpot-mcp
    labels:
      - "traefik.enable=true"
      
      # Main router for plugin server (port 4400)
      - "traefik.http.routers.penpot-mcp.rule=Host(`penpot-api.yourdomain.com`)"
      - "traefik.http.routers.penpot-mcp.entrypoints=websecure"
      - "traefik.http.routers.penpot-mcp.tls.certresolver=letsencrypt"
      - "traefik.http.services.penpot-mcp-plugin.loadbalancer.server.port=4400"
      - "traefik.http.routers.penpot-mcp.service=penpot-mcp-plugin"
      
      # MCP router for /mcp and /sse (port 4401)
      - "traefik.http.routers.penpot-mcp-mcp.rule=Host(`penpot-api.yourdomain.com`) && (PathPrefix(`/mcp`) || PathPrefix(`/sse`))"
      - "traefik.http.routers.penpot-mcp-mcp.entrypoints=websecure"
      - "traefik.http.routers.penpot-mcp-mcp.tls.certresolver=letsencrypt"
      - "traefik.http.services.penpot-mcp-mcp.loadbalancer.server.port=4401"
      - "traefik.http.routers.penpot-mcp-mcp.service=penpot-mcp-mcp"
      - "traefik.http.routers.penpot-mcp-mcp.priority=10"
    networks:
      - traefik
    environment:
      - MCP_PORT=4401
      - PLUGIN_PORT=4400

Using Docker Run

docker run -d \
  --name penpot-mcp \
  -p 4400:4400 \
  -p 4401:4401 \
  -e MCP_PORT=4401 \
  -e PLUGIN_PORT=4400 \
  ghcr.io/astrateam-net/penpot-mcp:0.0.1

:wrench: Configuration

Environment Variables

  • MCP_PORT - Port for MCP server (default: 4401)
    • Controls the /mcp and /sse endpoints
  • PLUGIN_PORT - Port for plugin server (default: 4400)
    • Controls where the plugin manifest is served

Endpoints

Once deployed behind Traefik with HTTPS:

  • MCP Server (Modern HTTP): https://penpot-api.yourdomain.com/mcp
  • MCP Server (Legacy SSE): https://penpot-api.yourdomain.com/sse
  • Plugin Manifest: https://penpot-api.yourdomain.com/manifest.json

:open_book: Usage

1. Deploy the Container

Deploy the container behind your reverse proxy (Traefik, nginx, etc.) with HTTPS enabled.

2. Load the Plugin in Penpot

  1. Open Penpot in your browser
  2. Navigate to a design file
  3. Open the Plugins menu
  4. Load the plugin using your HTTPS URL: https://penpot-api.yourdomain.com/manifest.json
  5. Open the plugin UI
  6. Click “Connect to MCP server”

The connection will work because it’s over HTTPS! :white_check_mark:

3. Connect an MCP Client

For HTTP-capable clients (Claude Code, etc.):

claude mcp add penpot -t http https://penpot-api.yourdomain.com/mcp

For stdio-only clients (Claude Desktop):

Use mcp-remote with your HTTPS endpoint:

{
    "mcpServers": {
        "penpot": {
            "command": "npx",
            "args": ["-y", "mcp-remote", "https://penpot-api.yourdomain.com/sse"]
        }
    }
}

Note: With HTTPS, you don’t need the --allow-http flag!

:building_construction: Architecture

The container runs two services:

  1. MCP Server (port 4401) - Provides MCP tools to LLMs

    • /mcp - Modern Streamable HTTP endpoint
    • /sse - Legacy SSE endpoint
  2. Plugin Server (port 4400) - Serves the Penpot plugin

    • /manifest.json - Plugin manifest
    • Plugin UI and assets

Both services run in the same container and can be routed via Traefik based on path prefixes.

:counterclockwise_arrows_button: Updating

The container builds from the upstream repository. To update:

  1. Update the GIT_REF in docker-bake.hcl to point to a specific commit or branch
  2. Rebuild the container
  3. Deploy the new version

:bug: Troubleshooting

Connection Issues

  • Ensure HTTPS is enabled - The browser restriction only applies to HTTP
  • Check Traefik routing - Verify both ports (4400, 4401) are properly routed
  • Check container logs - docker logs penpot-mcp to see both services

Plugin Not Loading

  • Verify the plugin server is accessible: curl https://penpot-api.yourdomain.com/manifest.json
  • Check browser console for CORS or network errors
  • Ensure the plugin URL uses HTTPS, not HTTP

:memo: Comparison: Container vs Local Installation

Feature Container Local npm install
Browser Compatibility :white_check_mark: Works with all browsers via HTTPS :cross_mark: Requires Firefox or old Chromium
Setup Complexity :white_check_mark: One command :cross_mark: Requires Node.js, npm, build steps
Isolation :white_check_mark: Isolated environment :cross_mark: Can conflict with other projects
Portability :white_check_mark: Same everywhere :cross_mark: Different per machine
Production Ready :white_check_mark: Yes :warning: Requires process management
Updates :white_check_mark: Rebuild container :cross_mark: Manual npm update + rebuild

:link: Links

:handshake: Contributing

This container is built from the upstream penpot/penpot-mcp repository.

To contribute to the Penpot MCP project itself, please see the upstream repository.

To contribute to this container build, see the source repository.

:page_facing_up: License

This container follows the same license as the upstream project (MPL-2.0).

:folded_hands: Credits


Enjoy seamless Penpot MCP integration with any browser! :artist_palette::sparkles:

4 Likes

Thanks for this contribution!

Note, however, that while it initially appeared that private network access was being restricted more heavily, it turned out that browsers are now implementing a popup-based access control mechanism, such that there actually isn’t a connectivity problem with (most) Chromium-based browsers. We have updated the Penpot MCP README accordingly.

2 Likes