Skip to main content
Glama

Penpot MCP Server

AI-powered design tool access for self-hosted Penpot via Model Context Protocol.

License: Apache 2.0 Python 3.13+ MCP Protocol Tools: 66


What is this?

An MCP server that gives AI agents (like Claude Code, Cursor, or any MCP-compatible client) full programmatic access to your self-hosted Penpot instance. AI can read, create, modify, and export design elements — from rectangles and text to full UI components — all through natural language.

Think of it as the bridge between your AI assistant and your design tool.

Problems it solves

Problem

Solution

Manual design work

AI creates UI components, layouts, and prototypes directly in Penpot

No programmatic API for Penpot

66 tools covering projects, shapes, text, exports, comments, and more

Design-to-code gap

Generate CSS from any shape, export to SVG/PNG, extract design tokens

Repetitive tasks

Batch operations — rename shapes, update colors, create variants

Design system maintenance

Read/write components, colors, typographies programmatically


Architecture

graph TB AI["AI Agent<br/>(Claude Code, Cursor, etc.)"] MCP["penpot-mcp<br/>Python + FastMCP<br/>:8787"] PG["PostgreSQL<br/>penpot-postgres<br/>:5432"] BE["Penpot Backend<br/>penpot-backend<br/>:6060"] FE["Penpot Frontend<br/>penpot-frontend<br/>:8080"] EX["Penpot Exporter<br/>penpot-exporter<br/>:6061"] AI -->|"Streamable HTTP"| MCP MCP -->|"Direct SQL reads<br/>(asyncpg)"| PG MCP -->|"RPC API writes<br/>(httpx)"| BE MCP -->|"Export requests"| BE BE -->|"Render"| EX FE -->|"Proxy"| BE style AI fill:#7c3aed,color:#fff style MCP fill:#2563eb,color:#fff style PG fill:#16a34a,color:#fff style BE fill:#ea580c,color:#fff style FE fill:#ea580c,color:#fff style EX fill:#ea580c,color:#fff

Dual-access strategy:

  • Reads go directly to PostgreSQL via asyncpg — fast and reliable

  • Writes go through Penpot's RPC API via httpx — ensures proper change tracking and undo history

  • Exports use Penpot's built-in exporter (headless Chromium) for pixel-perfect SVG/PNG output


Tech Stack

Component

Technology

Purpose

Language

Python 3.13

Runtime

MCP SDK

FastMCP

Protocol handling, tool registration

Database

asyncpg

Direct PostgreSQL access

HTTP Client

httpx

Penpot RPC API calls

Validation

Pydantic v2

Automatic parameter validation

Package Manager

uv

Fast Python dependency management

Container

Docker

Deployment alongside Penpot


Quick Start

Prerequisites

  1. Self-hosted Penpot running via Docker Compose (official guide)

  2. Docker and Docker Compose v2 installed

  3. Access tokens enabled in your Penpot instance (see Enable Access Tokens)

Option A: Automated Setup

git clone https://github.com/ancrz/penpot-mcp-server.git cd penpot-mcp-server chmod +x setup.sh ./setup.sh

The script will guide you through configuration, build the Docker image, and start the server.

Option B: Manual Setup

1. Clone the repository

git clone https://github.com/ancrz/penpot-mcp-server.git cd penpot-mcp-server

2. Create your configuration

cp .env.example .env

Edit .env with your Penpot details:

# Your Penpot access token (see "Enable Access Tokens" below) PENPOT_ACCESS_TOKEN=your-token-here # Your Penpot database password (from your Penpot docker-compose.yml) PENPOT_DB_PASS=your-db-password # Public URL where you access Penpot in the browser PENPOT_PUBLIC_URL=http://localhost:9001

3. Add the MCP service to your Penpot Docker stack

Add the penpot-mcp service definition to your existing Penpot docker-compose.yml. See docker-compose.penpot.yml for the complete service definition to copy.

4. Build and start

docker compose up -d --build penpot-mcp

5. Verify it's running

curl -s http://localhost:8787/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'

You should see a JSON response with the server capabilities.


Connect to Claude Code

Add this to your project's .mcp.json file (or ~/.claude.json for global access):

{ "mcpServers": { "penpot": { "type": "streamable-http", "url": "http://localhost:8787/mcp" } } }

Restart Claude Code. You should see 66 tools from the penpot server listed when you run /mcp.

Example prompts

Once connected, you can ask Claude things like:

  • "List my Penpot projects"

  • "Create a login form with email/password fields and a submit button"

  • "Export the Login Card frame as SVG"

  • "What colors are defined in the design system?"

  • "Add a comment at position (100, 200) saying 'Review this layout'"


Tools Overview

The server provides 66 tools across 11 categories. See TOOLS.md for the complete reference with all parameters.

Category

Count

Examples

Projects & Teams

4

list_projects, list_teams, list_files, search_files

File Operations

9

create_file, get_file_pages, rename_file, duplicate_file

Shape Reading

6

get_shape_tree, get_shape_details, get_shape_css, search_shapes

Components & Tokens

4

get_design_tokens, get_colors_library, get_typography_library

Comments

6

create_comment, reply_to_comment, resolve_comment

Media & Fonts

3

upload_media, list_media_assets, list_fonts

Database & Advanced

3

query_database, get_webhooks, get_profile

Snapshots

2

create_snapshot, get_snapshots

Export

2

export_frame_png, export_frame_svg

Shape Creation

8

create_rectangle, create_frame, create_text, create_path

Shape Modification

12

set_fill, set_stroke, set_layout, move_shape, resize_shape

Text Operations

5

set_text_content, set_font, set_font_size, set_text_align

Advanced Analysis

2

get_file_raw_data, compare_revisions


Configuration Reference

All settings are via environment variables. See .env.example for a template.

Variable

Default

Description

PENPOT_BASE_URL

http://penpot-frontend:8080

Internal Penpot URL (Docker network)

PENPOT_PUBLIC_URL

http://localhost:9001

Public URL where you access Penpot in browser

PENPOT_ACCESS_TOKEN

API access token (preferred auth method)

PENPOT_EMAIL

Penpot login email (fallback auth)

PENPOT_PASSWORD

Penpot login password (fallback auth)

PENPOT_DB_HOST

penpot-postgres

PostgreSQL host

PENPOT_DB_PORT

5432

PostgreSQL port

PENPOT_DB_NAME

penpot

Database name

PENPOT_DB_USER

penpot

Database user

PENPOT_DB_PASS

Database password

MCP_HOST

0.0.0.0

MCP server bind address

MCP_PORT

8787

MCP server port

MCP_LOG_LEVEL

info

Log level (debug/info/warning/error)


Enable Access Tokens

Penpot requires a feature flag to enable API access tokens.

1. Update your Penpot .env file

Add enable-access-tokens to your PENPOT_FLAGS:

PENPOT_FLAGS=enable-login-with-password enable-registration enable-access-tokens

2. Restart Penpot

docker compose restart penpot-backend penpot-frontend

3. Create a token

  1. Open Penpot in your browser

  2. Click your avatar (bottom-left) → Access Tokens

  3. Click "Generate new token"

  4. Give it a name (e.g., "MCP Server")

  5. Copy the token and paste it into your .env as PENPOT_ACCESS_TOKEN


Penpot Docker Integration

The MCP server runs as a Docker container alongside your existing Penpot stack. You need to add it to your Penpot docker-compose.yml.

See docker-compose.penpot.yml for the exact service definition to add. The key points:

  • It connects to the penpot Docker network (same as other Penpot services)

  • It depends on penpot-postgres (with health check) and penpot-backend

  • It exposes port 8787 on localhost only (127.0.0.1:8787:8787)

  • Environment variables reference Docker internal hostnames


Development

Running locally (outside Docker)

# Install uv if needed curl -LsSf https://astral.sh/uv/install.sh | sh # Install dependencies uv sync # Run the server (needs .env configured for local access) uv run penpot-mcp

For local development, point PENPOT_DB_HOST and PENPOT_DB_PORT to your host-mapped PostgreSQL port, and PENPOT_BASE_URL to http://localhost:9001.

Running tests

uv sync --group dev uv run pytest tests/ -v

Project structure

penpot-mcp-server/ ├── src/penpot_mcp/ │ ├── server.py # FastMCP entry point, 66 tool registrations │ ├── config.py # Pydantic Settings configuration │ ├── services/ │ │ ├── db.py # asyncpg connection pool │ │ ├── api.py # httpx RPC API client │ │ ├── changes.py # Penpot change operations builder │ │ └── transit.py # Transit+JSON decoder │ ├── tools/ │ │ ├── projects.py # Team & project queries │ │ ├── files.py # File CRUD operations │ │ ├── shapes.py # Shape reading & search │ │ ├── create.py # Shape creation │ │ ├── modify.py # Shape modification │ │ ├── text.py # Text operations │ │ ├── export.py # PNG/SVG export │ │ ├── components.py # Components & design tokens │ │ ├── comments.py # Comments & collaboration │ │ ├── media.py # Media assets & fonts │ │ ├── database.py # Raw SQL queries │ │ └── advanced.py # File raw data & revision comparison │ └── transformers/ │ ├── css.py # Shape → CSS conversion │ ├── svg.py # Shape → SVG conversion │ └── layout.py # Layout → CSS flexbox/grid ├── tests/ │ ├── conftest.py │ ├── test_projects.py │ ├── test_files.py │ ├── test_shapes.py │ └── test_e2e_login_form.py ├── pyproject.toml ├── Dockerfile ├── .env.example ├── setup.sh ├── docker-compose.penpot.yml ├── TOOLS.md └── LICENSE

License

This project is licensed under the Apache License 2.0.


Acknowledgments

-
security - not tested
A
license - permissive license
-
quality - not tested

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ancrz/penpot-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server