photopea-mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +273 -0
- package/dist/bridge/script-builder.d.ts +40 -0
- package/dist/bridge/script-builder.js +698 -0
- package/dist/bridge/script-builder.js.map +1 -0
- package/dist/bridge/types.d.ts +237 -0
- package/dist/bridge/types.js +3 -0
- package/dist/bridge/types.js.map +1 -0
- package/dist/bridge/websocket-server.d.ts +29 -0
- package/dist/bridge/websocket-server.js +335 -0
- package/dist/bridge/websocket-server.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +17 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/document.d.ts +3 -0
- package/dist/tools/document.js +115 -0
- package/dist/tools/document.js.map +1 -0
- package/dist/tools/export.d.ts +3 -0
- package/dist/tools/export.js +123 -0
- package/dist/tools/export.js.map +1 -0
- package/dist/tools/image.d.ts +3 -0
- package/dist/tools/image.js +232 -0
- package/dist/tools/image.js.map +1 -0
- package/dist/tools/layer.d.ts +3 -0
- package/dist/tools/layer.js +203 -0
- package/dist/tools/layer.js.map +1 -0
- package/dist/tools/text.d.ts +3 -0
- package/dist/tools/text.js +91 -0
- package/dist/tools/text.js.map +1 -0
- package/dist/tools/workflows.d.ts +3 -0
- package/dist/tools/workflows.js +99 -0
- package/dist/tools/workflows.js.map +1 -0
- package/dist/utils/file-io.d.ts +4 -0
- package/dist/utils/file-io.js +28 -0
- package/dist/utils/file-io.js.map +1 -0
- package/dist/utils/platform.d.ts +2 -0
- package/dist/utils/platform.js +23 -0
- package/dist/utils/platform.js.map +1 -0
- package/package.json +59 -0
- package/src/frontend/index.html +639 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 attalla1
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/photopea-icon.svg" alt="Photopea" width="120" height="120">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Photopea MCP Server</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
AI-powered image editing through <a href="https://www.photopea.com">Photopea</a>, controlled by your agent via the <a href="https://modelcontextprotocol.io">Model Context Protocol</a>.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/photopea-mcp-server"><img src="https://img.shields.io/npm/v/photopea-mcp-server.svg" alt="npm version"></a>
|
|
13
|
+
<a href="https://github.com/attalla1/photopea-mcp-server/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/photopea-mcp-server.svg" alt="license"></a>
|
|
14
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/node/v/photopea-mcp-server.svg" alt="node"></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
## Demo
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img src="assets/demo.gif" alt="Demo" width="1000">
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<em>Prompt used in this demo: <a href="examples/album-cover-demo.md">examples/album-cover-demo.md</a></em>
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
## How It Works
|
|
28
|
+
|
|
29
|
+
```mermaid
|
|
30
|
+
graph LR
|
|
31
|
+
A[Agent] <-->|stdio| B[MCP Server]
|
|
32
|
+
B <-->|WebSocket| C[Browser]
|
|
33
|
+
C <-->|postMessage| D[Photopea]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Your agent sends editing commands through the MCP protocol. The server translates these into Photopea JavaScript API calls and executes them via a WebSocket bridge to the browser.
|
|
37
|
+
|
|
38
|
+
**Note:** A browser window will open automatically on the first tool call. This is expected -- Photopea runs entirely in the browser and the server needs it to perform image editing operations.
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
claude mcp add -s user photopea -- npx -y photopea-mcp-server
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Then start a new Claude Code session and ask it to edit images. The Photopea editor will open in your browser automatically on the first tool call.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
### Claude Code
|
|
51
|
+
|
|
52
|
+
**npx (recommended):**
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
claude mcp add -s user photopea -- npx -y photopea-mcp-server
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Global install:**
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install -g photopea-mcp-server
|
|
62
|
+
claude mcp add -s user photopea -- photopea-mcp-server
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Claude Desktop
|
|
66
|
+
|
|
67
|
+
Add to your Claude Desktop config file (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"mcpServers": {
|
|
72
|
+
"photopea": {
|
|
73
|
+
"command": "npx",
|
|
74
|
+
"args": ["-y", "photopea-mcp-server"]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Cursor
|
|
81
|
+
|
|
82
|
+
Add to Cursor MCP settings (`.cursor/mcp.json` in your project or `~/.cursor/mcp.json` globally):
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"mcpServers": {
|
|
87
|
+
"photopea": {
|
|
88
|
+
"command": "npx",
|
|
89
|
+
"args": ["-y", "photopea-mcp-server"]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### VS Code (Copilot)
|
|
96
|
+
|
|
97
|
+
Add to `.vscode/mcp.json` in your project:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"servers": {
|
|
102
|
+
"photopea": {
|
|
103
|
+
"command": "npx",
|
|
104
|
+
"args": ["-y", "photopea-mcp-server"]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Windsurf
|
|
111
|
+
|
|
112
|
+
Add to Windsurf MCP settings (`~/.windsurf/mcp.json`):
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"mcpServers": {
|
|
117
|
+
"photopea": {
|
|
118
|
+
"command": "npx",
|
|
119
|
+
"args": ["-y", "photopea-mcp-server"]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Available Tools
|
|
126
|
+
|
|
127
|
+
### Document (5 tools)
|
|
128
|
+
|
|
129
|
+
| Tool | Description |
|
|
130
|
+
|------|-------------|
|
|
131
|
+
| `photopea_create_document` | Create a new document with specified dimensions and settings |
|
|
132
|
+
| `photopea_open_file` | Open an image from a URL or local file path |
|
|
133
|
+
| `photopea_get_document_info` | Get active document info (name, dimensions, resolution, color mode) |
|
|
134
|
+
| `photopea_resize_document` | Resize the active document (resamples content to fit) |
|
|
135
|
+
| `photopea_close_document` | Close the active document |
|
|
136
|
+
|
|
137
|
+
### Layer (11 tools)
|
|
138
|
+
|
|
139
|
+
| Tool | Description |
|
|
140
|
+
|------|-------------|
|
|
141
|
+
| `photopea_add_layer` | Add a new empty art layer |
|
|
142
|
+
| `photopea_add_fill_layer` | Add a solid color fill layer |
|
|
143
|
+
| `photopea_delete_layer` | Delete a layer by name or index |
|
|
144
|
+
| `photopea_select_layer` | Make a layer active by name or index |
|
|
145
|
+
| `photopea_set_layer_properties` | Set opacity, blend mode, visibility, name, or lock state |
|
|
146
|
+
| `photopea_move_layer` | Translate a layer by x/y offset |
|
|
147
|
+
| `photopea_duplicate_layer` | Duplicate a layer with optional new name |
|
|
148
|
+
| `photopea_reorder_layer` | Move a layer in the stack (above, below, top, bottom) |
|
|
149
|
+
| `photopea_group_layers` | Group named layers into a layer group |
|
|
150
|
+
| `photopea_ungroup_layers` | Ungroup a layer group |
|
|
151
|
+
| `photopea_get_layers` | Get the full layer tree as JSON |
|
|
152
|
+
|
|
153
|
+
### Text & Shape (3 tools)
|
|
154
|
+
|
|
155
|
+
| Tool | Description |
|
|
156
|
+
|------|-------------|
|
|
157
|
+
| `photopea_add_text` | Add a text layer at specified coordinates |
|
|
158
|
+
| `photopea_edit_text` | Edit content or style of an existing text layer |
|
|
159
|
+
| `photopea_add_shape` | Add a shape (rectangle or ellipse) |
|
|
160
|
+
|
|
161
|
+
### Image & Effects (9 tools)
|
|
162
|
+
|
|
163
|
+
| Tool | Description |
|
|
164
|
+
|------|-------------|
|
|
165
|
+
| `photopea_place_image` | Place an image from URL or local path |
|
|
166
|
+
| `photopea_apply_adjustment` | Apply brightness/contrast, hue/saturation, levels, or curves |
|
|
167
|
+
| `photopea_apply_filter` | Apply gaussian blur, sharpen, unsharp mask, noise, or motion blur |
|
|
168
|
+
| `photopea_transform_layer` | Scale, rotate, or flip a layer |
|
|
169
|
+
| `photopea_add_gradient` | Apply a linear gradient fill |
|
|
170
|
+
| `photopea_make_selection` | Create a rectangular, elliptical, or full selection |
|
|
171
|
+
| `photopea_modify_selection` | Expand, contract, feather, or invert a selection |
|
|
172
|
+
| `photopea_fill_selection` | Fill the current selection with a color |
|
|
173
|
+
| `photopea_clear_selection` | Deselect the current selection |
|
|
174
|
+
|
|
175
|
+
### Export & Utility (6 tools)
|
|
176
|
+
|
|
177
|
+
| Tool | Description |
|
|
178
|
+
|------|-------------|
|
|
179
|
+
| `photopea_export_image` | Export to PNG, JPG, WebP, PSD, or SVG |
|
|
180
|
+
| `photopea_load_font` | Load a custom font from a URL (TTF, OTF, WOFF2) |
|
|
181
|
+
| `photopea_list_fonts` | List available fonts, with optional search filter |
|
|
182
|
+
| `photopea_run_script` | Execute arbitrary Photopea JavaScript |
|
|
183
|
+
| `photopea_undo` | Undo one or more actions |
|
|
184
|
+
| `photopea_redo` | Redo one or more actions |
|
|
185
|
+
|
|
186
|
+
## Usage Examples
|
|
187
|
+
|
|
188
|
+
Once installed, ask your agent to perform image editing tasks:
|
|
189
|
+
|
|
190
|
+
**Create a poster:**
|
|
191
|
+
> "Create a 1920x1080 document with a dark blue background, add the title 'Hello World' in white 72px Arial, and export it as a PNG to ~/Desktop/poster.png"
|
|
192
|
+
|
|
193
|
+
**Edit a photo:**
|
|
194
|
+
> "Open ~/photos/portrait.jpg, increase the brightness by 30, apply a slight gaussian blur of 2px, and export as JPG to ~/Desktop/edited.jpg"
|
|
195
|
+
|
|
196
|
+
**Composite images:**
|
|
197
|
+
> "Create a 1200x630 document, place ~/assets/background.png as the base layer, then place ~/assets/logo.png and move it to the top-right corner"
|
|
198
|
+
|
|
199
|
+
**Batch adjustments:**
|
|
200
|
+
> "Open ~/photos/sunset.jpg, apply hue/saturation with +20 saturation, apply an unsharp mask with amount 50 and radius 2, then export as PNG"
|
|
201
|
+
|
|
202
|
+
## Development
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
git clone https://github.com/attalla1/photopea-mcp-server.git
|
|
206
|
+
cd photopea-mcp-server
|
|
207
|
+
npm install
|
|
208
|
+
npm run build
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Commands
|
|
212
|
+
|
|
213
|
+
| Command | Description |
|
|
214
|
+
|---------|-------------|
|
|
215
|
+
| `npm run build` | Compile TypeScript to `dist/` |
|
|
216
|
+
| `npm run dev` | Watch mode with auto-reload |
|
|
217
|
+
| `npm test` | Run unit and integration tests |
|
|
218
|
+
| `npm start` | Start the server |
|
|
219
|
+
|
|
220
|
+
### Architecture
|
|
221
|
+
|
|
222
|
+
The server has four main components:
|
|
223
|
+
|
|
224
|
+
**MCP Server** (`src/server.ts`) -- Registers all 34 tools with the MCP SDK and connects via stdio transport.
|
|
225
|
+
|
|
226
|
+
**WebSocket Bridge** (`src/bridge/websocket-server.ts`) -- Manages the connection between the MCP server and the browser. Queues script execution requests and handles responses with timeouts.
|
|
227
|
+
|
|
228
|
+
**Script Builder** (`src/bridge/script-builder.ts`) -- Pure functions that translate tool parameters into Photopea JavaScript API calls. Each builder function generates a script string that Photopea can execute.
|
|
229
|
+
|
|
230
|
+
**Browser Frontend** (`src/frontend/index.html`) -- A single-page app that loads Photopea in an iframe, connects to the WebSocket bridge, and relays scripts to Photopea via `postMessage`. Returns results back through the WebSocket.
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
src/
|
|
234
|
+
index.ts # Entry point: HTTP server, browser launch, MCP startup
|
|
235
|
+
server.ts # MCP server initialization and tool registration
|
|
236
|
+
bridge/
|
|
237
|
+
websocket-server.ts # WebSocket bridge with request queue
|
|
238
|
+
script-builder.ts # Photopea JS code generators
|
|
239
|
+
types.ts # Protocol message types
|
|
240
|
+
tools/
|
|
241
|
+
document.ts # Document operations (5 tools)
|
|
242
|
+
layer.ts # Layer operations (11 tools)
|
|
243
|
+
text.ts # Text and shape operations (3 tools)
|
|
244
|
+
image.ts # Image, adjustment, filter operations (9 tools)
|
|
245
|
+
export.ts # Export and utility operations (6 tools)
|
|
246
|
+
utils/
|
|
247
|
+
file-io.ts # Local file read/write, URL fetching
|
|
248
|
+
platform.ts # Port discovery, browser launch
|
|
249
|
+
frontend/
|
|
250
|
+
index.html # Browser UI with Photopea iframe
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Security
|
|
254
|
+
|
|
255
|
+
- The MCP server binds to `127.0.0.1` (localhost only) and is not accessible from the network.
|
|
256
|
+
- The `photopea_run_script` tool executes arbitrary JavaScript inside Photopea's sandboxed iframe. It is marked as destructive and requires user approval in MCP clients that support tool annotations.
|
|
257
|
+
- File operations (`open_file`, `export_image`, `place_image`) read and write files with the same permissions as the user running the server.
|
|
258
|
+
|
|
259
|
+
## Known Limitations
|
|
260
|
+
|
|
261
|
+
- Heavy scripts (e.g., gradients with many color steps) may cause the Photopea browser UI to become unresponsive. The operations still complete successfully in the background and exports will work as expected.
|
|
262
|
+
- Refreshing the browser page will discard all unsaved work. Export your documents before refreshing.
|
|
263
|
+
- Only one browser tab should be open at a time. Multiple tabs will conflict over the WebSocket connection.
|
|
264
|
+
- The `reorder_layer` tool may cause the Photopea UI to become unresponsive. To avoid this, create layers in the desired order rather than reordering after creation.
|
|
265
|
+
|
|
266
|
+
## Requirements
|
|
267
|
+
|
|
268
|
+
- Node.js >= 18
|
|
269
|
+
- A modern web browser (Chrome, Firefox, Edge, Safari)
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
MIT
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { CreateDocumentParams, ResizeDocumentParams, AddLayerParams, AddFillLayerParams, SetLayerPropertiesParams, MoveLayerParams, DuplicateLayerParams, ReorderLayerParams, GroupLayersParams, LayerTarget, AddTextParams, EditTextParams, AddShapeParams, ApplyAdjustmentParams, ApplyFilterParams, TransformLayerParams, AddGradientParams, MakeSelectionParams, ModifySelectionParams, FillSelectionParams, ExportImageParams } from "./types.js";
|
|
2
|
+
/** Convert a CSS hex color string to {r, g, b} components (0-255). */
|
|
3
|
+
export declare function hexToRgb(hex: string): {
|
|
4
|
+
r: number;
|
|
5
|
+
g: number;
|
|
6
|
+
b: number;
|
|
7
|
+
};
|
|
8
|
+
/** Escape a string for safe embedding inside single-quoted JS literals. */
|
|
9
|
+
export declare function escapeString(str: string): string;
|
|
10
|
+
export declare function buildCreateDocument(params: CreateDocumentParams): string;
|
|
11
|
+
export declare function buildGetDocumentInfo(): string;
|
|
12
|
+
export declare function buildResizeDocument(params: ResizeDocumentParams): string;
|
|
13
|
+
export declare function buildCloseDocument(params: {
|
|
14
|
+
save: boolean;
|
|
15
|
+
}): string;
|
|
16
|
+
export declare function buildAddLayer(params: AddLayerParams): string;
|
|
17
|
+
export declare function buildAddFillLayer(params: AddFillLayerParams): string;
|
|
18
|
+
export declare function buildDeleteLayer(params: LayerTarget): string;
|
|
19
|
+
export declare function buildSelectLayer(params: LayerTarget): string;
|
|
20
|
+
export declare function buildSetLayerProperties(params: SetLayerPropertiesParams): string;
|
|
21
|
+
export declare function buildMoveLayer(params: MoveLayerParams): string;
|
|
22
|
+
export declare function buildDuplicateLayer(params: DuplicateLayerParams): string;
|
|
23
|
+
export declare function buildReorderLayer(params: ReorderLayerParams): string;
|
|
24
|
+
export declare function buildGroupLayers(params: GroupLayersParams): string;
|
|
25
|
+
export declare function buildGetLayers(): string;
|
|
26
|
+
export declare function buildAddText(params: AddTextParams): string;
|
|
27
|
+
export declare function buildEditText(params: EditTextParams): string;
|
|
28
|
+
export declare function buildAddShape(params: AddShapeParams): string;
|
|
29
|
+
export declare function buildApplyAdjustment(params: ApplyAdjustmentParams): string;
|
|
30
|
+
export declare function buildApplyFilter(params: ApplyFilterParams): string;
|
|
31
|
+
export declare function buildTransformLayer(params: TransformLayerParams): string;
|
|
32
|
+
export declare function buildAddGradient(params: AddGradientParams): string;
|
|
33
|
+
export declare function buildMakeSelection(params: MakeSelectionParams): string;
|
|
34
|
+
export declare function buildModifySelection(params: ModifySelectionParams): string;
|
|
35
|
+
export declare function buildFillSelection(params: FillSelectionParams): string;
|
|
36
|
+
export declare function buildClearSelection(): string;
|
|
37
|
+
export declare function buildExportImage(params: ExportImageParams): string;
|
|
38
|
+
export declare function buildRunScript(script: string): string;
|
|
39
|
+
export declare function buildUndo(steps?: number): string;
|
|
40
|
+
export declare function buildRedo(steps: number): string;
|