diff --git a/mcp/README.md b/mcp/README.md index 199281cd07..9e2ac3707b 100644 --- a/mcp/README.md +++ b/mcp/README.md @@ -2,9 +2,14 @@ # Penpot's Official MCP Server -Penpot integrates a LLM layer built on the Model Context Protocol (MCP) via Penpot's Plugin API to interact with a Penpot design file. Penpot's MCP server enables LLMs to perfom data queries, transformation and creation operations. +Penpot integrates a LLM layer built on the Model Context Protocol +(MCP) via Penpot's Plugin API to interact with a Penpot design +file. Penpot's MCP server enables LLMs to perfom data queries, +transformation and creation operations. -Penpot's MCP Server is unlike any other you've seen. You get design-to- design, code-to-design and design-code supercharged workflows. +Penpot's MCP Server is unlike any other you've seen. You get +design-to- design, code-to-design and design-code supercharged +workflows. [![Penpot MCP video playlist](https://github.com/user-attachments/assets/204f1d99-ce51-41dd-a5dd-1ef739f8f089)](https://www.youtube.com/playlist?list=PLgcCPfOv5v57SKMuw1NmS0-lkAXevpn10) @@ -12,9 +17,10 @@ Penpot's MCP Server is unlike any other you've seen. You get design-to- design, ## Architecture -The **Penpot MCP Server** exposes tools to AI clients (LLMs), which support the retrieval -of design data as well as the modification and creation of design elements. -The MCP server communicates with Penpot via the dedicated **Penpot MCP Plugin**, +The **Penpot MCP Server** exposes tools to AI clients (LLMs), which +support the retrieval of design data as well as the modification and +creation of design elements. The MCP server communicates with Penpot +via the dedicated **Penpot MCP Plugin**, which connects to the MCP server via WebSocket. This enables the LLM to carry out tasks in the context of a design file by executing code that leverages the Penpot Plugin API. @@ -44,23 +50,36 @@ Follow the steps below to enable the integration. ### Prerequisites -The project requires [Node.js](https://nodejs.org/) (tested with v22). -Following the installation of Node.js, the tools `npm` and `npx` should be -available in your terminal. +The project requires [Node.js](https://nodejs.org/) (tested with v22.x +with corepack). -You should probably be using penpot devenv, where all this dependencies are -already present and correctly setup. +Following the installation of Node.js, the tools `pnpm` and `npx` +should be available in your terminal. For ensure corepack installed +and enabled correctly, just execute the `./scripts/setup`. + +It is also required to have `caddy` executeable in the path, it is +used for start a local server for generate types documentation from +the current branch. If you want to run it outside devenv where all +dependencies are already provided, please download caddy from +[here](https://caddyserver.com/download). + +You should probably be using penpot devenv, where all this +dependencies are already present and correctly setup. But nothing +prevents you execute this outside of devenv if you satisfy the +specified dependencies. ### 1. Build & Launch the MCP Server and the Plugin Server If it's your first execution, install the required dependencies: + ```shell cd mcp/ ./scripts/setup ``` Then build all components and start the two servers: + ```shell pnpm run bootstrap ``` @@ -69,8 +88,34 @@ This bootstrap command will: * install dependencies for all components (`pnpm -r run install`) * build all components (`pnpm -r run build`) + * build plugins types (`pnpm run build-types`) * start all components (`pnpm -r --parallel run start`) +If you want to have types scrapped from a remote repository, the best +apprach is executing the following: + +```shell +PENPOT_PLUGINS_API_DOC_URL=https://doc.plugins.penpot.app pnpm run build:types +pnpm run bootstrap +``` + +Or this, if you want skip build step bacause you have already have all +build artifacts ready (per example from previous `bootstrap` command): + +``` +PENPOT_PLUGINS_API_DOC_URL=https://doc.plugins.penpot.app pnpm run build:types +pnpm run start +``` + +If you want just to update the types definitions with the plugins api doc from the +current branch: + +```shell +pnpm run build:types +``` + +(That command will build plugins doc locally and will generate the types yaml from +the locally build documentation) ### 2. Load the Plugin in Penpot and Establish the Connection @@ -80,14 +125,14 @@ This bootstrap command will: > Starting with Chromium version 142, the private network access (PNA) restrictions have been hardened, > and when connecting to `localhost` from a web application served from a different origin > (such as https://design.penpot.app), the connection must explicitly be allowed. -> +> > Most Chromium-based browsers (e.g. Chrome, Vivaldi) will display a popup requesting permission > to access the local network. Be sure to approve the request to allow the connection. -> +> > Some browsers take additional security measures, and you may need to disable them. > For example, in Brave, disable the "Shield" for the Penpot website to allow local network access. -> -> If your browser refuses to connect to the locally served plugin, check its configuration or +> +> If your browser refuses to connect to the locally served plugin, check its configuration or > try a different browser (e.g. Firefox) that does not enforce these restrictions. 1. Open Penpot in your browser diff --git a/mcp/package.json b/mcp/package.json index ff96a6be16..0cab1824a8 100644 --- a/mcp/package.json +++ b/mcp/package.json @@ -5,10 +5,11 @@ "scripts": { "build": "pnpm -r run build", "build:multi-user": "pnpm -r run build:multi-user", + "build:types": "./scripts/build-types", "start": "pnpm -r --parallel run start", "start:multi-user": "pnpm -r --parallel --filter \"./packages/*\" run start:multi-user", "bootstrap": "pnpm -r install && pnpm run build && pnpm run start", - "bootstrap:multi-user": "npm run install && npm run build:multi-user && pnpm run start:multi-user", + "bootstrap:multi-user": "pnpm -r install && pnpm run build:multi-user && pnpm run start:multi-user", "fmt": "prettier --write packages/", "fmt:check": "prettier --check packages/" }, diff --git a/mcp/packages/server/data/api_types.yml b/mcp/packages/server/data/api_types.yml index d7094c06b0..585947e276 100644 --- a/mcp/packages/server/data/api_types.yml +++ b/mcp/packages/server/data/api_types.yml @@ -30,6 +30,7 @@ Penpot: currentFile: null | File; currentPage: null | Page; viewport: Viewport; + flags: Flags; history: HistoryContext; library: LibraryContext; fonts: FontsContext; @@ -268,6 +269,12 @@ Penpot: ``` const viewportSettings = context.viewport;console.log(viewportSettings); ``` + flags: |- + ``` + readonly flags: Flags + ``` + + Provides flags to customize the API behavior. history: |- ``` readonly history: HistoryContext @@ -4477,6 +4484,7 @@ Context: currentFile: null | File; currentPage: null | Page; viewport: Viewport; + flags: Flags; history: HistoryContext; library: LibraryContext; fonts: FontsContext; @@ -4572,6 +4580,12 @@ Context: ``` const viewportSettings = context.viewport;console.log(viewportSettings); ``` + flags: |- + ``` + readonly flags: Flags + ``` + + Provides flags to customize the API behavior. history: |- ``` readonly history: HistoryContext @@ -6763,6 +6777,31 @@ Fill: ``` The optional image fill defined by an ImageData object. +Flags: + overview: |- + Interface Flags + =============== + + This subcontext allows the API o change certain defaults + + ``` + interface Flags { + naturalChildOrdering: boolean; + } + ``` + + Referenced by: Context, Penpot + members: + Properties: + naturalChildOrdering: |- + ``` + naturalChildOrdering: boolean + ``` + + If `true` the .children property will be always sorted in the z-index ordering. + Also, appendChild method will be append the children in the top-most position. + The insertchild method is changed acordingly to respect this ordering. + Defaults to false FlexLayout: overview: |- Interface FlexLayout diff --git a/mcp/scripts/build b/mcp/scripts/build index 2a69fe9260..41af7a4684 100755 --- a/mcp/scripts/build +++ b/mcp/scripts/build @@ -2,6 +2,11 @@ # NOTE: this script should be called from the parent directory to # properly work +SCRIPT_DIR=$(dirname $0); +URL=${1:-http://localhost:9090} + +echo "Preparing bundle for types from $URL" + set -ex corepack enable; @@ -13,24 +18,12 @@ rm -rf node_modules; rm -rf packages/server/dist; rm -rf packages/server/node_modules; -pushd ../plugins -pnpm install -pnpm run build:doc +pushd $SCRIPT_DIR; +set +e +./build-types $URL; +set -e popd -rsync -avr ../plugins/dist/doc/ ./types-generator/doc/ - -pushd types-generator -set +e; -pixi install; -pnpx concurrently --kill-others-on-fail -k \ - "caddy file-server --root doc --listen :9090" \ - "pixi run python prepare_api_docs.py http://localhost:9090"; -rm -rf doc; -popd - -set -e; - pnpm -r --filter "!mcp-plugin" install; pnpm -r --filter "mcp-server" run build:multi-user; @@ -39,6 +32,8 @@ rsync -avr packages/server/dist/ ./dist/; cp packages/server/package.json ./dist/; cp packages/server/pnpm-lock.yaml ./dist/; +touch ./dist/pnpm-workspace.yaml; + cat < -This will generate `../mcp-server/data/api_types.yml`. +This will generate `../packages/server/data/api_types.yml`. diff --git a/mcp/types-generator/build b/mcp/types-generator/build new file mode 100755 index 0000000000..9f05568c88 --- /dev/null +++ b/mcp/types-generator/build @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +export URL=${1:-http://localhost:9090} + +SCRIPT_DIR=$(dirname $0); +pushd $SCRIPT_DIR; +echo "Scrapping $URL..." + +set -e +pixi install; +pixi run python prepare_api_docs.py $URL;