diff --git a/README.md b/README.md index fbcbad1..a701a01 100644 --- a/README.md +++ b/README.md @@ -1,122 +1,111 @@ # The Penpot MCP Server -This system enables LLMs to interact with Penpot design projects through a Model Context Protocol (MCP) server and plugin architecture. - -## Quick Start - -If it's your first execution, install and build all components before starting: -```shell -npm install -npm run install-all-and-start -``` - -Otherwise, just start all components: -```shell -npm run start -``` - -Then proceed with loading the plugin and connecting to the MCP server as described in [steps 3-4](#step-3-load-plugin-in-penpot) - -You can also install and build the components without starting them: -```shell -npm run install-all -npm run build-all -``` +This project enables LLMs to interact directly with Penpot design projects +through a Model Context Protocol (MCP) server and plugin architecture. ## Architecture -The system consists of three main components: +This repository is a monorepo containing four main components: 1. **Common Types** (`common/`): - Shared TypeScript definitions for request/response protocol - Ensures type safety across server and plugin components - - Defines `PluginTaskResult`, request/response interfaces, and task parameters -2. **MCP Server** (`mcp-server/`): +2. **Penpot MCP Server** (`mcp-server/`): - Provides MCP tools to LLMs for Penpot interaction - - Runs WebSocket server accepting connections from Penpot plugins + - Runs a WebSocket server accepting connections from the Penpot MCP plugin - Implements request/response correlation with unique task IDs - Handles task timeouts and proper error reporting -3. **Penpot Plugin** (`penpot-plugin/`): - - Connects to MCP server via WebSocket +3. **Penpot MCP Plugin** (`penpot-plugin/`): + - Connects to the MCP server via WebSocket - Executes tasks in Penpot using the Plugin API - - Sends structured responses back to server with success/failure status + - Sends structured responses back to the server# -## Protocol Flow +4. **Helper Scripts** (`helper/`): + - Python scripts that prepare data for the MCP server (development use) -``` -LLM → MCP Server → WebSocket → Penpot Plugin → Penpot API - ↓ ↓ ↓ - Tool Call Task Request Execute Action - ↑ ↑ ↑ -LLM ← MCP Server ← WebSocket ← Penpot Plugin ← Result +## Usage + +### Build & Launch the MCP Server and the Plugin Server + +If it's your first execution, install the required dependencies: +```shell +npm install ``` -### Request Format -``` -{ - id: string, // Unique UUID for correlation - task: string, // Task type (e.g., "printText") - params: object // Task-specific parameters -} +Then build all components and start them: +```shell +npm run bootstrap ``` -### Response Format -``` -{ - id: string, // Matching request ID - result: { - success: boolean, // Task completion status - error?: string, // Error message if failed - data?: any // Optional result data - } -} -``` +This bootstrap command will: + * install dependencies for all components (`npm run install:all`) + * build all components (`npm run build:all`) + * start all components (`npm run start:all`) -## Testing the Connection -For each component, run `npm install` before running other commands -if you haven't installed the component in the past. - -### Step 0: Build the common components - -```bash -cd common -npm run build -``` - -### Step 1: Start the MCP Server - -```bash -cd mcp-server -npm run build -npm start -``` - -### Step 2: Build and Run the Plugin - -```bash -cd penpot-plugin -npm run build -npm run dev -``` - -### Step 3: Load Plugin in Penpot +### Load the Plugin in Penpot and Establish the Connection 1. Open Penpot in your browser 2. Navigate to a design file -3. Go to Plugins menu -4. Load the plugin using the development URL (typically `http://localhost:4400/manifest.json`) +3. Open the Plugins menu +4. Load the plugin using the development URL (`http://localhost:4400/manifest.json` by default) 5. Open the plugin UI +6. In the plugin UI, click "Connect to MCP server". + The connection status should change from "Not connected" to "Connected to MCP server". + (Check the browser's developer console for WebSocket connection logs. + Check the MCP server terminal for WebSocket connection messages.) -### Step 4: Test the Connection +### Connecting an MCP Client -1. In the plugin UI, click "Connect to MCP server" -2. The connection status should change from "Not connected" to "Connected to MCP server" -3. Check the browser's developer console for WebSocket connection logs -4. Check the MCP server terminal for WebSocket connection messages +By default, the server runs on port 4401 and provides: -### Step 5: Use an MCP Client to Interact with the Penpot Project +- **Modern Streamable HTTP endpoint**: `http://localhost:4401/mcp` +- **Legacy SSE endpoint**: `http://localhost:4401/sse` -See [MCP Server README](mcp-server/README.md) \ No newline at end of file +These endpoints can be used directly by MCP clients that support them. +Simply configure the client to the MCP server by providing the respective URL. + +When using a client that only supports stdio transport, +a proxy like `mcp-remote` is required. + +#### Using a Proxy for stdio Transport + +The `mcp-remote` package can proxy stdio transport to HTTP/SSE, +allowing clients that support only stdio to connect to the MCP server indirectly. + +1. Install `mcp-remote` globally if you haven't already: + + npm install -g mcp-remote + +2. Use `mcp-remote` to provide the launch command for your MCP client: + + npx -y mcp-remote http://localhost:4401/sse --allow-http + +#### Example: Claude Desktop + +For Claude Desktop integration, you will need to use a proxy like `mcp-remote` since it only supports stdio transport. +So install it as described above. + +To add the server to Claude Desktop's configuration, locate the configuration file: + +- **Windows**: `%APPDATA%/Claude/claude_desktop_config.json` +- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` + +```json +{ + "mcpServers": { + "penpot": { + "command": "npx", + "args": ["-y", "mcp-remote", "http://localhost:4401/sse", "--allow-http"] + } + } +} +``` + +After updating the configuration file, restart Claude Desktop completely for the changes to take effect. +Be sure to fully quit the app! On Windows, right-click the tray icon and select "Quit". + +After the restart, you should see the MCP server listed when clicking on the "Search and tools" icon at the bottom +of the prompt input area. diff --git a/common/package-lock.json b/common/package-lock.json index 2c374d0..4c37b78 100644 --- a/common/package-lock.json +++ b/common/package-lock.json @@ -7,10 +7,24 @@ "": { "name": "@penpot-mcp/common", "version": "1.0.0", + "dependencies": { + "penpot-mcp": "file:.." + }, "devDependencies": { "typescript": "^5.0.0" } }, + "..": { + "version": "1.0.0", + "dependencies": { + "concurrently": "^8.2.2", + "kill-port": "^2.0.1" + } + }, + "node_modules/penpot-mcp": { + "resolved": "..", + "link": true + }, "node_modules/typescript": { "version": "5.9.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", diff --git a/common/package.json b/common/package.json index 859f077..4a89228 100644 --- a/common/package.json +++ b/common/package.json @@ -13,5 +13,8 @@ }, "files": [ "dist/**/*" - ] + ], + "dependencies": { + "penpot-mcp": "file:.." + } } diff --git a/mcp-server/README.md b/mcp-server/README.md index 617a787..2780894 100644 --- a/mcp-server/README.md +++ b/mcp-server/README.md @@ -1,17 +1,17 @@ # Penpot MCP Server -A Model Context Protocol (MCP) server that provides Penpot integration capabilities for Claude Desktop and other MCP-compatible clients. +A Model Context Protocol (MCP) server that provides Penpot integration +capabilities for AI clients supporting the model context protocol (MCP). ## Prerequisites -- Node.js (tested with v20+) +- Node.js (tested with v22) - npm (with npx on the PATH) -## Installation & Setup +## Setup 1. Install Dependencies - cd mcp-server npm install 2. Build the Project @@ -20,94 +20,8 @@ A Model Context Protocol (MCP) server that provides Penpot integration capabilit 3. Run the Server - - Development Mode (with TypeScript compilation): + npm start - npm run dev - - - Production Mode (requires build first): - - npm start - - -### Summary of Commands - -| Command | Description | -| ---------------------- | -------------------------------------- | -| `npm install` | Install all dependencies | -| `npm run build` | Compile TypeScript to JavaScript | -| `npm run start` | Start the built server | -| `npm run dev` | Start in development mode with ts-node | -| `npm run format` | Format all files with Prettier | -| `npm run format:check` | Check if files are properly formatted | - - -## Client Integration - -The MCP server supports both Streamable HTTP and legacy SSE transports, providing compatibility with various MCP clients. - -Note that we do not support stdio transport directly, as clients tend to spawn multiple instances of the MCP server, -and since the MCP server is also a WebSocket server, this would lead to port conflicts. -Therefore, we recommend using a proxy like `mcp-remote` for clients that support stdio transport only (e.g., Claude Desktop). - -### Starting the Server - -First, build and start the MCP server: - -```bash -npm run build -npm start -``` - -By default, the server runs on port 4401 and provides: - -- **Modern Streamable HTTP endpoint**: `http://localhost:4401/mcp` -- **Legacy SSE endpoint**: `http://localhost:4401/sse` - -### Using a Proxy for stdio Transport - -The `mcp-remote` package can proxy stdio transport to HTTP/SSE. - -1. Install `mcp-remote` globally if you haven't already: - - npm install -g mcp-remote - -2. Use `mcp-remote` to provide the launch command for your MCP client: - - npx -y mcp-remote http://localhost:4401/sse --allow-http - -### Claude Desktop - -For Claude Desktop integration, you will need to use a proxy like `mcp-remote` since it only supports stdio transport. -So install it as described above. - -To add the server to Claude Desktop's configuration, locate the configuration file: - - - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - - **Windows**: `%APPDATA%/Claude/claude_desktop_config.json` - -```json -{ - "mcpServers": { - "penpot": { - "command": "npx", - "args": ["-y", "mcp-remote", "http://localhost:4401/sse", "--allow-http"] - } - } -} -``` - -After updating the configuration file, restart Claude Desktop completely for the changes to take effect. -Be sure to fully quit the app! On Windows, right-click the tray icon and select "Quit". - -After the restart, you should see the MCP server listed when clicking on the "Search and tools" icon at the bottom -of the prompt input area. - -### Other MCP Clients - -For MCP clients that support HTTP transport directly, use: - -- Streamable HTTP for modern clients: `http://localhost:4401/mcp` -- SSE for legacy clients: `http://localhost:4401/sse` ## Penpot Plugin API REPL diff --git a/mcp-server/package-lock.json b/mcp-server/package-lock.json index 99802e4..880eb88 100644 --- a/mcp-server/package-lock.json +++ b/mcp-server/package-lock.json @@ -15,6 +15,7 @@ "class-validator": "^0.14.0", "express": "^4.18.0", "js-yaml": "^4.1.0", + "penpot-mcp": "file:..", "pino": "^9.10.0", "pino-pretty": "^13.1.1", "reflect-metadata": "^0.1.13", @@ -31,6 +32,13 @@ "typescript": "^5.0.0" } }, + "..": { + "version": "1.0.0", + "dependencies": { + "concurrently": "^8.2.2", + "kill-port": "^2.0.1" + } + }, "../common": { "name": "@penpot-mcp/common", "version": "1.0.0", @@ -1849,6 +1857,10 @@ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, + "node_modules/penpot-mcp": { + "resolved": "..", + "link": true + }, "node_modules/pino": { "version": "9.10.0", "resolved": "https://registry.npmjs.org/pino/-/pino-9.10.0.tgz", diff --git a/mcp-server/package.json b/mcp-server/package.json index 984e0e5..b4e9b1d 100644 --- a/mcp-server/package.json +++ b/mcp-server/package.json @@ -28,6 +28,7 @@ "class-validator": "^0.14.0", "express": "^4.18.0", "js-yaml": "^4.1.0", + "penpot-mcp": "file:..", "pino": "^9.10.0", "pino-pretty": "^13.1.1", "reflect-metadata": "^0.1.13", diff --git a/package.json b/package.json index 4491e21..e771fde 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,10 @@ "version": "1.0.0", "description": "", "scripts": { - "install-all": "concurrently --names \"COMMON,MCP-SERVER,PLUGIN\" --prefix-colors \"green,cyan,magenta\" \"npm --prefix common install\" \"npm --prefix mcp-server install\" \"npm --prefix penpot-plugin install\"", - "build-all": "concurrently --names \"COMMON,MCP-SERVER,PLUGIN\" --prefix-colors \"green,cyan,magenta\" --success first \"npm --prefix common install && npm --prefix common run build\" \"npm --prefix mcp-server run build\" \"npm --prefix penpot-plugin run build\"", - "start": "concurrently --names \"MCP-SERVER,PLUGIN-SERVER\" --prefix-colors \"cyan,magenta\" --kill-others-on-fail \"npm --prefix mcp-server start\" \"npm --prefix penpot-plugin run dev\"", - "install-all-and-start": "npm run install-all && npm run build-all && concurrently --names \"MCP-SERVER,PLUGIN-SERVER\" --prefix-colors \"cyan,magenta\" --kill-others-on-fail \"npm --prefix mcp-server start\" \"npm --prefix penpot-plugin run dev\"" + "install:all": "concurrently --names \"COMMON,MCP-SERVER,PLUGIN\" --prefix-colors \"green,cyan,magenta\" \"npm --prefix common install\" \"npm --prefix mcp-server install\" \"npm --prefix penpot-plugin install\"", + "build:all": "concurrently --names \"COMMON,MCP-SERVER,PLUGIN\" --prefix-colors \"green,cyan,magenta\" --success first \"npm --prefix common install && npm --prefix common run build\" \"npm --prefix mcp-server run build\" \"npm --prefix penpot-plugin run build\"", + "start:all": "concurrently --names \"MCP-SERVER,PLUGIN-SERVER\" --prefix-colors \"cyan,magenta\" --kill-others-on-fail \"npm --prefix mcp-server start\" \"npm --prefix penpot-plugin run dev\"", + "bootstrap": "npm run install:all && npm run build:all && npm run start:all" }, "repository": { "type": "git", diff --git a/penpot-plugin/.prettierignore b/penpot-plugin/.prettierignore new file mode 100644 index 0000000..dd44972 --- /dev/null +++ b/penpot-plugin/.prettierignore @@ -0,0 +1 @@ +*.md diff --git a/penpot-plugin/README.md b/penpot-plugin/README.md new file mode 100644 index 0000000..8605113 --- /dev/null +++ b/penpot-plugin/README.md @@ -0,0 +1,21 @@ +# Penpot MCP Plugin + +This project contains a Penpot plugin that accompanies the Penpot MCP server. +It connects to the MCP server via WebSocket, subsequently allowing the MCP +server to execute tasks in Penpot using the Plugin API. + +## Setup + +1. Install Dependencies + + npm install + +2. Build the Project + + npm run build + +3. Start a Local Development Server + + npm run dev start + + This will start a local development server at `http://localhost:4400`. \ No newline at end of file diff --git a/penpot-plugin/package-lock.json b/penpot-plugin/package-lock.json index f0102e4..44a9443 100644 --- a/penpot-plugin/package-lock.json +++ b/penpot-plugin/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "@penpot-mcp/common": "file:../common", "@penpot/plugin-styles": "1.3.2", - "@penpot/plugin-types": "1.3.2" + "@penpot/plugin-types": "1.3.2", + "penpot-mcp": "file:.." }, "devDependencies": { "prettier": "^3.0.0", @@ -19,6 +20,13 @@ "vite-live-preview": "^0.3.2" } }, + "..": { + "version": "1.0.0", + "dependencies": { + "concurrently": "^8.2.2", + "kill-port": "^2.0.1" + } + }, "../common": { "name": "@penpot-mcp/common", "version": "1.0.0", @@ -937,6 +945,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/penpot-mcp": { + "resolved": "..", + "link": true + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", diff --git a/penpot-plugin/package.json b/penpot-plugin/package.json index ee35f28..3f68b4c 100644 --- a/penpot-plugin/package.json +++ b/penpot-plugin/package.json @@ -10,9 +10,10 @@ "format:check": "prettier --check ." }, "dependencies": { + "@penpot-mcp/common": "file:../common", "@penpot/plugin-styles": "1.3.2", "@penpot/plugin-types": "1.3.2", - "@penpot-mcp/common": "file:../common" + "penpot-mcp": "file:.." }, "devDependencies": { "prettier": "^3.0.0", diff --git a/prepare-api-docs/README.md b/prepare-api-docs/README.md deleted file mode 100644 index 31b14da..0000000 --- a/prepare-api-docs/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Preparation of API Documentation for the MCP Server - -The script `prepare_api_docs.py` read API documentation from the Web -and collects it in a single yaml file, which is then used by an MCP -tool to provide API documentation to an LLM on demand. - -## Prerequisites - -Pixi is used for environment management. - -Install the environment via: - - pixi install - -## Running the Script - -To run the script, use: - - pixi run python prepare_api_docs.py - -This will generate `../mcp-server/data/api_types.yml`. \ No newline at end of file diff --git a/prepare-api-docs/.gitattributes b/python-scripts/.gitattributes similarity index 100% rename from prepare-api-docs/.gitattributes rename to python-scripts/.gitattributes diff --git a/prepare-api-docs/.gitignore b/python-scripts/.gitignore similarity index 100% rename from prepare-api-docs/.gitignore rename to python-scripts/.gitignore diff --git a/python-scripts/README.md b/python-scripts/README.md new file mode 100644 index 0000000..bd92806 --- /dev/null +++ b/python-scripts/README.md @@ -0,0 +1,26 @@ +# Helper Scripts for the Penpot MCP Server + +This subproject contains helper scripts used in the development of the +Penpot MCP server. + +## Setup + +This project uses [pixi](https://pixi.sh) for environment management. + +Install the environment via + + pixi install + +## Scripts + +### Preparation of API Documentation for the MCP Server + +The script `prepare_api_docs.py` reads API documentation from the Web +and collects it in a single yaml file, which is then used by an MCP +tool to provide API documentation to an LLM on demand. + +Running the script: + + pixi run python prepare_api_docs.py + +This will generate `../mcp-server/data/api_types.yml`. diff --git a/prepare-api-docs/pixi.lock b/python-scripts/pixi.lock similarity index 100% rename from prepare-api-docs/pixi.lock rename to python-scripts/pixi.lock diff --git a/prepare-api-docs/pixi.toml b/python-scripts/pixi.toml similarity index 68% rename from prepare-api-docs/pixi.toml rename to python-scripts/pixi.toml index e836b6f..c1fdb45 100644 --- a/prepare-api-docs/pixi.toml +++ b/python-scripts/pixi.toml @@ -1,8 +1,8 @@ [project] -authors = ["Dominik Jain "] +authors = ["Oraios AI "] channels = ["conda-forge"] -description = "Add a short description here" -name = "prepare-api-docs" +description = "Scripts supporting the development of the Penpot MCP server" +name = "penpot-mcp-scripts" platforms = ["win-64"] version = "0.1.0" diff --git a/prepare-api-docs/prepare_api_docs.py b/python-scripts/prepare_api_docs.py similarity index 100% rename from prepare-api-docs/prepare_api_docs.py rename to python-scripts/prepare_api_docs.py