A Model Context Protocol (MCP) server that provides full manipulation capabilities for Penpot - the open-source design tool. This server enables AI assistants to create, modify, and manage Penpot designs programmatically, similar to Figma plugin capabilities.
๐ณ Multi-architecture Docker images available: linux/amd64, linux/arm64
Example chat interface created entirely through natural conversation with an AI assistant using this MCP server. See Example 7: Chat Interface for the complete conversation that generated this design.
The screenshot above demonstrates how you can describe a design in natural language, and the AI assistant will create it in Penpot using the MCP server's capabilities - handling layout, styling, components, and interactions automatically.
- Create & Manage Files: Create new design files, list projects, and manage file metadata
- Shape Operations: Create rectangles, circles, frames, paths, text, and SVG shapes
- Modify Designs: Update shape properties, move objects, resize, rotate, and style
- Page Management: Add, remove, and organize pages within files
- Component System: Create and manage reusable components
- Direct API integration with Penpot
- Session-based updates with revision tracking
- Support for batch operations
list_teams- List all accessible teamslist_projects- List all accessible projectslist_files- List files in a projectget_file- Get file data and structurecreate_file- Create a new design filerename_file- Rename an existing filedelete_file- Delete a file permanently
list_pages- List all pages in a fileadd_page- Add a new page to a fileget_page_shapes- Get all shapes on a specific page (basic info)query_shapes- Query and filter shapes with criteria (like grep). Filter by type, area, color, font, text content. Select fields to return. Useful for bulk operationsget_shape_properties- Get detailed properties of a specific shape (colors, text, fonts, effects, etc.)rename_page- Rename a pagedelete_page- Delete a page from a filemove_shapes- Move shapes to different parent/frame or reorder
create_rectangle- Create rectangle shapescreate_circle- Create circle/ellipse shapescreate_frame- Create frame containerscreate_text- Create text elements with alignment (left, center, right, justify), fonts, and stylingcreate_svg- Create SVG elementscreate_path- Create custom paths (planned)
update_shape- Modify shape properties (position, size, style, etc.)delete_shape- Remove shapes from the designduplicate_shapes- Duplicate shapes (planned)group_shapes- Group multiple shapes (planned)
align_shapes- Align multiple shapes (left, center, right, top, middle, bottom)distribute_shapes- Distribute shapes evenly with equal spacing (horizontal, vertical)
create_component- Create reusable component from shapeupdate_component- Update component name/pathdelete_component- Delete component from librarylist_components- List all components in fileinstantiate_component- Create component instance (planned)
create_team- Create a new teamupdate_team- Update team settingsdelete_team- Delete a teamlist_team_members- List all members of a teaminvite_team_member- Invite user to join teamremove_team_member- Remove member from teamupdate_team_member_role- Update member permissionscreate_project- Create new project in teamupdate_project- Update project settingsdelete_project- Delete a project
create_share_link- Create shareable link for filelist_share_links- List all share links for filedelete_share_link- Delete a share link
list_comment_threads- List comment threads in fileget_comments- Get all comments in threadcreate_comment_thread- Create new comment threadadd_comment- Add comment to existing threadupdate_comment- Update existing commentdelete_comment- Delete a commentdelete_comment_thread- Delete entire threadupdate_comment_thread_status- Mark thread as resolved/unresolved
export_shape- Export shape/frame as image (PNG, JPG, SVG, PDF)list_file_media- List all media used in fileupload_file_media- Upload image file (PNG, JPG, SVG, GIF, WEBP)upload_file_media_from_url- Upload image from URLdelete_file_media- Delete media objectclone_media- Clone media from another file
upload_font- Upload custom font (TTF, OTF, WOFF, WOFF2)list_team_fonts- List all fonts in teamget_font_variants- Get all variants of font familyupdate_font_variant- Update font metadatadelete_font_variant- Delete font variant
create_webhook- Create webhook for event notificationslist_webhooks- List all webhooks for teamupdate_webhook- Update webhook settingsdelete_webhook- Delete a webhookget_webhook_events- Get info about webhook event types
search_files- Search files by namesearch_projects- Search projects by namesearch_shapes- Search shapes within filesearch_components- Search components by nameadvanced_search- Search across multiple resource types
get_profile- Get current user profileupdate_profile- Update user profile settingslist_recent_files- List recently accessed filesget_file_permissions- Get file permissionsget_team_stats- Get team statistics
Install globally from npm:
# Install globally
npm install -g @zcubekr/penpot-mcp-server
# Run the server
penpot-mcp-server
# Or run in HTTP mode
TRANSPORT=http penpot-mcp-serverOr install as a project dependency:
# Install as dependency
npm install @zcubekr/penpot-mcp-server
# Run via npx
npx penpot-mcp-serverPull the pre-built multi-architecture image from GitHub Container Registry:
# Pull latest version
docker pull ghcr.io/zcube/penpot-mcp-server:latest
# Or pull specific version
docker pull ghcr.io/zcube/penpot-mcp-server:v1.0.0
# Or pull development version
docker pull ghcr.io/zcube/penpot-mcp-server:main-devSupported Architectures:
linux/amd64(x86_64)linux/arm64(ARM64/Apple Silicon)
git clone https://github.com/zcube/penpot-mcp-server.git
cd penpot-mcp-server
npm install
npm run buildSet up your Penpot credentials as environment variables:
export PENPOT_API_URL="https://design.penpot.app"
export PENPOT_ACCESS_TOKEN="your-access-token-here"Or create a .env file (not recommended for production):
PENPOT_API_URL=https://design.penpot.app
PENPOT_ACCESS_TOKEN=your-access-token-here
- Log in to your Penpot account
- Go to Settings โ Access Tokens
- Create a new access token
- Copy and save it securely
If you're running a self-hosted Penpot instance, you need to enable access token support:
Important: Due to Cloudflare security restrictions on the public Penpot instance, you may need to use a self-hosted server for API access.
Add enable-access-tokens to your Penpot server configuration:
# docker-compose.yml or penpot-config.env
environment:
- PENPOT_FLAGS=...enable-access-tokensIf you have other flags, append enable-access-tokens to the list:
# Example with multiple flags
environment:
- PENPOT_FLAGS=enable-registration enable-login enable-access-tokensAfter enabling this flag, restart your Penpot server and you'll be able to generate access tokens from Settings โ Access Tokens.
This server supports two transport modes:
- stdio mode (default) - For local MCP clients like Claude Desktop
- HTTP/SSE mode - For external access via HTTP with Server-Sent Events
Add to your Claude Desktop configuration (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"penpot": {
"command": "node",
"args": ["/path/to/penpot-mcp-server/dist/index.js"],
"env": {
"PENPOT_API_URL": "https://design.penpot.app",
"PENPOT_ACCESS_TOKEN": "your-access-token"
}
}
}
}node dist/index.jsFor external access, you can run the server in HTTP mode with Server-Sent Events:
# Run with Docker
docker run -d \
--name penpot-mcp-server \
-p 3000:3000 \
-e TRANSPORT=http \
-e PENPOT_API_URL=https://design.penpot.app \
-e PENPOT_ACCESS_TOKEN=your-access-token \
ghcr.io/zcube/penpot-mcp-server:latest
# With custom port and self-hosted Penpot
docker run -d \
--name penpot-mcp-server \
-p 8080:8080 \
-e TRANSPORT=http \
-e HTTP_PORT=8080 \
-e PENPOT_API_URL=https://penpot.mycompany.com \
-e PENPOT_ACCESS_TOKEN=your-access-token \
ghcr.io/zcube/penpot-mcp-server:latest
# View logs
docker logs -f penpot-mcp-server
# Stop server
docker stop penpot-mcp-server
docker rm penpot-mcp-server# Using npm script
npm run dev:http
# Or with environment variable
TRANSPORT=http node dist/index.js
# With custom port
TRANSPORT=http HTTP_PORT=8080 node dist/index.js# Required
export PENPOT_ACCESS_TOKEN="your-access-token"
# Optional
export PENPOT_API_URL="https://design.penpot.app" # Default
export HTTP_PORT="3000" # Default
export HTTP_HOST="0.0.0.0" # Default
# Security options
export ALLOWED_ORIGINS="https://example.com,https://app.example.com"
export ALLOWED_HOSTS="localhost,example.com"
export ENABLE_DNS_REBINDING_PROTECTION="true"Once running, the server exposes:
-
MCP Endpoint:
http://localhost:3000/mcp- GET: Establish SSE stream for receiving messages
- POST: Send JSON-RPC messages to the server
- DELETE: Close session and cleanup
-
Health Check:
http://localhost:3000/health- Returns server status and active session count
// Initialize connection (GET request)
const eventSource = new EventSource('http://localhost:3000/mcp');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Received:', data);
};
// Send message (POST request)
fetch('http://localhost:3000/mcp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'mcp-session-id': sessionId, // From SSE endpoint response
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'tools/list',
}),
});# Using docker-compose
docker compose up -d
# Or with docker run
docker run -d \
-e TRANSPORT=http \
-e HTTP_PORT=3000 \
-e PENPOT_ACCESS_TOKEN=your-token \
-p 3000:3000 \
penpot-mcp-server:latestWhen running in HTTP mode:
- Use HTTPS in production - Run behind a reverse proxy (nginx, Caddy, etc.)
- Enable CORS restrictions - Use
ALLOWED_ORIGINSto restrict access - Enable DNS rebinding protection - Set
ENABLE_DNS_REBINDING_PROTECTION=true - Firewall rules - Restrict access to trusted networks
- Token security - Keep access tokens secure, rotate regularly
Once connected, you can ask your AI assistant to:
- "Create a new design file for a mobile app landing page"
- "Add a rectangle with red fill at position 100,100"
- "Create a frame called 'Hero Section' and add some text inside"
- "List all shapes on the current page"
- "Move the rectangle to position 200,200 and make it 300x200"
- "Create a circle with blue stroke and no fill"
This server uses Penpot's RPC API with the following structure:
- Endpoint:
https://design.penpot.app/api/rpc/command/<method-name> - Authentication: Bearer token via
Authorization: Token <token> - Content-Type:
application/jsonorapplication/transit+json
All tests run automatically on every push and pull request!
The GitHub Actions workflow:
- ๐งช Runs comprehensive test suite (45 tests covering 76+ tools)
- โ Tests against external Penpot instance using penpot-test environment
- ๐ณ Builds and validates Docker images (multi-arch)
- ๐ Uploads test results as artifacts
Workflow: .github/workflows/docker.yml โ integration-test job
You can also test against a real Penpot instance:
- Create a Penpot account at https://design.penpot.app
- Generate an access token in Settings โ Access Tokens
- Set environment variables:
export PENPOT_API_URL="https://design.penpot.app"
export PENPOT_ACCESS_TOKEN="your-token-here"- Run tests:
# Run full test suite
npm test
# Or run with npx
npx tsx test-tools.tsThe test suite will:
- โ Test all 70+ MCP tools
- โ Create a test file with shapes
- โ Test components, comments, sharing
- โ Search functionality
- โ Verify all operations
See TESTING.md for detailed testing guide.
# Create .env file
echo "PENPOT_API_URL=https://design.penpot.app" > .env
echo "PENPOT_ACCESS_TOKEN=your-token" >> .env
# Run with Docker Compose
docker compose up -d
# View logs
docker compose logs -f
# Run tests
docker compose --profile test up penpot-mcp-test# Production image
docker build -t penpot-mcp-server:latest .
# Test image
docker build -f Dockerfile.test -t penpot-mcp-test:latest .See DOCKER.md for comprehensive Docker guide.
# Watch mode for development
npm run watch
# Run in development
npm run dev
# Run tests during development
npm testWe welcome contributions! Before submitting changes:
-
Test GitHub Actions locally with nektos/act
# Install act brew install act # macOS # or curl -s https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash # Test workflows before pushing act -j build-and-test # Test with larger runner image act -P ubuntu-latest=catthehacker/ubuntu:act-latest
-
Test Docker builds locally
docker build -t penpot-mcp-server:test . -
Run tests with local Penpot container
docker compose -f docker-compose.penpot.yml up -d docker compose -f docker-compose.penpot.yml --profile test up penpot-mcp-test
See CONTRIBUTING.md for complete development guide including:
- Setting up development environment
- Testing workflows with act
- Docker build testing
- Code style guidelines
- Pull request process
This server implements tools based on Penpot's 25 RPC command modules:
| Module | Coverage | Tools |
|---|---|---|
| โ files.clj | Full | create_file, get_file, list_files, rename_file, delete_file |
| โ files_create.clj | Full | create_file |
| โ files_update.clj | Full | All shape/page manipulation via update-file RPC |
| โ projects.clj | Full | list_projects, create_project, update_project, delete_project |
| โ teams.clj | Full | list_teams, create_team, update_team, delete_team |
| โ teams_invitations.clj | Partial | invite_team_member |
| โ files_share.clj | Full | create_share_link, list_share_links, delete_share_link |
| โ comments.clj | Full | All comment and thread operations |
| โ media.clj | Full | upload_file_media, list_file_media, delete, clone |
| โ fonts.clj | Full | Upload fonts, list, update, delete font variants |
| โ webhooks.clj | Full | Create, list, update, delete webhooks |
| โ search.clj | Full | Search files, projects, shapes, components |
| โ profile.clj | Partial | get_profile, update_profile, recent files, permissions |
| โ auth.clj | N/A | Authentication handled via access token |
| โ profile.clj | N/A | User profile management |
| โ audit.clj | N/A | Admin-only audit logs |
| โ viewer.clj | N/A | View-only operations |
Legend: โ
Implemented |
Version 1.0.0 brings full implementation of all previously partial features:
- File Upload: Upload images from local file system
- URL Import: Import images directly from URLs
- Format Support: PNG, JPG, SVG, GIF, WEBP
- Management: Delete and clone media objects
- Real multipart/form-data upload support
- Upload Fonts: TTF, OTF, WOFF, WOFF2 formats
- Font Families: Manage multiple font families per team
- Font Variants: Multiple weights and styles
- Team Fonts: Shared font libraries across team
- Event Notifications: file:created, file:updated, comment:created, etc.
- HTTPS Endpoints: Secure webhook delivery
- Management: Create, update, delete, list webhooks
- Status Control: Enable/disable webhooks
- File Search: Search across all projects
- Project Search: Find projects by name
- Shape Search: Find shapes within files by name/type
- Component Search: Locate components in libraries
- Advanced Search: Multi-resource type searches
- Thread Management: Create, delete, resolve threads
- Comment Operations: Add, update, delete comments
- Position Tracking: Comments tied to specific locations
- Resolution Status: Mark threads as resolved/unresolved
- User Profile: Get and update user settings
- Recent Files: Access history tracking
- Permissions: Check file access levels
- Team Stats: Project, file, and member counts
- 19/25 RPC modules implemented (76% coverage)
- 70+ MCP tools (up from 50+)
- 25+ new tools added in v1.0.0
- All major Penpot features now accessible via AI
MIT
This project uses the Penpot OpenAPI specification from https://design.penpot.app/api/openapi.json.
The openapi.json file in this repository is maintained for version control purposes to track changes in the Penpot API over time. The copyright for the OpenAPI specification remains with the Penpot project and its contributors.
The src/generated/ directory contains TypeScript client code automatically generated from the Penpot OpenAPI specification using @hey-api/openapi-ts (MIT License).
The type definitions in src/types.ts are based on Penpot's RPC API structure and were created by analyzing the Penpot API responses and behavior.
Contributions are welcome! Please feel free to submit a Pull Request.
