Skip to main content

penpot-api-mcp

Code style: crackerjack [Runtime: oneiric Framework: FastMCP uv Python: 3.14+

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.

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 Claude Code marketplace

This repo ships a Claude Code plugin manifest (.claude-plugin/plugin.json) plus a colocated .mcp.json and three slash commands in commands/. To install, register the www-mcp-servers 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 as Authorization: Token <token> header
  • Email + password: authenticates via /rpc/command/login-with-password, then relies on the httpx cookie jar (auth-token cookie) for all subsequent requests

License

BSD 3-Clause. See LICENSE.

Built on Oneiric for runtime configuration and mcp-common for the FastMCP baseline. Crackerjack gates every commit.

Metadata

Release files for penpot-api-mcp 0.4.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for penpot-api-mcp 0.4.3
File Size Uploaded
penpot_api_mcp-0.4.3.tar.gz 49.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for penpot-api-mcp 0.4.3
File Interpreter ABI Platform
penpot_api_mcp-0.4.3-py3-none-any.whl Python 3 none any Details

Total release size: 74.1 kB

Release files / penpot_api_mcp-0.4.3.tar.gz

Download URL penpot_api_mcp-0.4.3.tar.gz
Size 49.7 kB
Tags Source
SHA-256 checksum
How to use checksums
c5bf2ca30cfc429b5290bff78bb8b0b29fa3985f1a7c1b491f73bb25548f5d30
BLAKE2b-256 checksum
How to use checksums
2186af514c2674de63422b8f503f5a0b05a6dd256e760a3a2ac6aaa50e0e0216
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.3-py3-none-any.whl

Download URL penpot_api_mcp-0.4.3-py3-none-any.whl
Size 24.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4ee76d0304d81afef8ee8f6c74080ed41f0d26dd0e4964fb37048f6a9b3842fe
BLAKE2b-256 checksum
How to use checksums
8147885c562057a0552189be0e6fab20d06060e0093337e278a992c9af069a04
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 history Release notifications | RSS feed

This release

0.4.3 This release

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page