penpot-api-mcp
MCP server wrapping the Penpot REST API for headless design automation. Provides read, search, and export access to Penpot projects, files, and design objects — without requiring a browser session.
Part of the Bodai Ecosystem alongside Mahavishnu, Akosha, Dhara, Session-Buddy, and Crackerjack.
Why this exists
The official @penpot/mcp (TypeScript) requires a live browser plugin to operate — it is the right tool for interactive canvas manipulation. This server targets the complementary use case: background automation, asset export pipelines, and AI-driven design queries that run without a browser.
Tools
| Tool | Description |
|---|---|
list_projects |
List all projects for the authenticated user |
get_project_files |
List design files in a project |
get_file |
Fetch the full content of a design file |
get_object_tree |
Return the design object hierarchy for a file |
search_objects |
Search objects by name or type |
export_object |
Export a design object as PNG/SVG (base64-encoded) |
Setup
uv sync
touch .env # then fill in credentials (see Configuration below)
Configuration
Environment variables (prefix PENPOT_):
| Variable | Description | Default |
|---|---|---|
PENPOT_ACCESS_TOKEN |
API access token (preferred) | — |
PENPOT_EMAIL |
Email for password auth (fallback) | — |
PENPOT_PASSWORD |
Password for password auth (fallback) | — |
PENPOT_BASE_URL |
API base URL for self-hosted instances | https://design.penpot.app/api |
Either PENPOT_ACCESS_TOKEN or PENPOT_EMAIL + PENPOT_PASSWORD must be set.
Transport settings (prefix PENPOT_MCP_)
The CLI transport layer uses a separate env prefix from the Penpot API client. Override defaults via:
| Variable | Description | Default |
|---|---|---|
PENPOT_MCP_HTTP_HOST |
Bind host for the MCP HTTP server | 127.0.0.1 |
PENPOT_MCP_HTTP_PORT |
Bind port for the MCP HTTP server | 3051 |
PENPOT_MCP_ENABLE_HTTP_TRANSPORT |
Toggle HTTP transport on/off | true |
Note: PENPOT_HTTP_PORT (without the MCP_ segment) is not honored by the CLI; the active prefix is PENPOT_MCP_.
Running
# HTTP mode (default — Claude Code compatible)
uv run python -m penpot_api_mcp start --force
Server listens on http://localhost:3051/mcp. The server is HTTP-only; bare uv run python -m penpot_api_mcp without a subcommand falls through to Typer help and does not start a JSON-RPC loop. To bridge to stdio, run the HTTP server behind an external stdio-to-HTTP shim.
MCP configuration
{
"mcpServers": {
"penpot-api": {
"type": "http",
"url": "http://localhost:3051/mcp"
}
}
}
Installation via Bodai Marketplace
This repo ships a Bodai Claude Code plugin manifest (.claude-plugin/plugin.json) plus a colocated .mcp.json and three slash commands in commands/. To install via the Bodai marketplace, first register the marketplace with Claude Code, then install the plugin by name. Once installed, the slash commands /penpot-list, /penpot-search, and /penpot-export become available alongside the mcp__penpot-api__* tools, and the MCP client talks to the server over http://localhost:3051/mcp as configured in .mcp.json. Penpot credentials still need to be present in the environment (PENPOT_ACCESS_TOKEN or PENPOT_EMAIL + PENPOT_PASSWORD); the plugin manifest only wires the transport, it does not provision Penpot auth.
Development
uv run pytest # Run tests
uv run crackerjack # Full quality suite (ruff + mypy + pytest + bandit)
uv run ruff check --fix # Lint
uv run mypy . # Type check
Architecture
penpot_api_mcp/
├── utils/transit.py # Transit+JSON encode/decode (Penpot's wire format)
├── config/settings.py # Pydantic settings (PENPOT_* env vars)
├── clients/ # httpx async client with dual auth
├── models/ # Pydantic models: Project, File, Object, ObjectTree
├── tools/ # FastMCP tool registrations
├── server.py # FastMCP app + health endpoints
└── __main__.py # MCPServerCLIFactory entrypoint (Oneiric)
Transit+JSON
Penpot's RPC layer uses Transit+JSON — a Clojure serialization format where map keys are ~:keyword and UUIDs are ~uUUID. The utils/transit.py module handles encode/decode at the API boundary, keeping all Python models clean.
Authentication
Two modes are supported:
- API token (
PENPOT_ACCESS_TOKEN): sent asAuthorization: Token <token>header - Email + password: authenticates via
/rpc/command/login-with-password, then relies on the httpx cookie jar (auth-tokencookie) for all subsequent requests
License
BSD 3-Clause. See LICENSE.
Metadata
Release files for penpot-api-mcp 0.4.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| penpot_api_mcp-0.4.2.tar.gz | 48.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| penpot_api_mcp-0.4.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 72.6 kB
Release files / penpot_api_mcp-0.4.2.tar.gz
| Download URL | penpot_api_mcp-0.4.2.tar.gz |
|---|---|
| Size | 48.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d15b93922850021141f4d5e0906ac8aa3c1259263ca1c0c46754834e2e1514d2
|
|
BLAKE2b-256 checksum How to use checksums |
8826303ac24a78fd5f8f38715b60f04b486430bbbc7cae45038783221aa83056
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / penpot_api_mcp-0.4.2-py3-none-any.whl
| Download URL | penpot_api_mcp-0.4.2-py3-none-any.whl |
|---|---|
| Size | 24.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
db1a1f960149551e6476af80410a6ab5451d3431838e389da4179e75c6f5d20a
|
|
BLAKE2b-256 checksum How to use checksums |
44511a79997253093c9c3a4d828d7e425ad7bdedaafe378f7f91d0297c38df68
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|