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).
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
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! ![]()
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
No local Node.js installation required - Everything runs in the container
Consistent environment - Same setup across all machines
Easy deployment - Works with Docker Compose, Kubernetes, or any container orchestrator
Production-ready - Multi-platform builds (amd64 + arm64)
Automatic updates - Rebuild when upstream updates
Isolated - No conflicts with other Node.js projects on your system
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
Configuration
Environment Variables
MCP_PORT- Port for MCP server (default:4401)- Controls the
/mcpand/sseendpoints
- Controls the
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
Usage
1. Deploy the Container
Deploy the container behind your reverse proxy (Traefik, nginx, etc.) with HTTPS enabled.
2. Load the Plugin in Penpot
- Open Penpot in your browser
- Navigate to a design file
- Open the Plugins menu
- Load the plugin using your HTTPS URL:
https://penpot-api.yourdomain.com/manifest.json - Open the plugin UI
- Click “Connect to MCP server”
The connection will work because it’s over HTTPS! ![]()
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!
Architecture
The container runs two services:
-
MCP Server (port 4401) - Provides MCP tools to LLMs
/mcp- Modern Streamable HTTP endpoint/sse- Legacy SSE endpoint
-
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.
Updating
The container builds from the upstream repository. To update:
- Update the
GIT_REFindocker-bake.hclto point to a specific commit or branch - Rebuild the container
- Deploy the new version
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-mcpto 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
Comparison: Container vs Local Installation
| Feature | Container | Local npm install |
|---|---|---|
| Browser Compatibility | ||
| Setup Complexity | ||
| Isolation | ||
| Portability | ||
| Production Ready | ||
| Updates |
Links
- Container Image:
ghcr.io/astrateam-net/penpot-mcp:0.0.1 - Source Code: GitHub Repository
- Upstream Project: penpot/penpot-mcp
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.
License
This container follows the same license as the upstream project (MPL-2.0).
Credits
- Penpot MCP - The upstream project
- Penpot - The design tool
Enjoy seamless Penpot MCP integration with any browser! ![]()
![]()