psforge 0.2.0__tar.gz
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.
- psforge-0.2.0/LICENSE +21 -0
- psforge-0.2.0/PKG-INFO +594 -0
- psforge-0.2.0/README.md +563 -0
- psforge-0.2.0/psforge/__init__.py +5 -0
- psforge-0.2.0/psforge/app.py +5 -0
- psforge-0.2.0/psforge/decorators.py +91 -0
- psforge-0.2.0/psforge/ps_adapter/__init__.py +12 -0
- psforge-0.2.0/psforge/ps_adapter/action_manager.py +5 -0
- psforge-0.2.0/psforge/ps_adapter/application.py +149 -0
- psforge-0.2.0/psforge/ps_adapter/context.py +219 -0
- psforge-0.2.0/psforge/ps_adapter/process_guard.py +109 -0
- psforge-0.2.0/psforge/ps_adapter/utils.py +80 -0
- psforge-0.2.0/psforge/registry.py +121 -0
- psforge-0.2.0/psforge/resources/__init__.py +3 -0
- psforge-0.2.0/psforge/resources/registry.py +3 -0
- psforge-0.2.0/psforge/server.py +79 -0
- psforge-0.2.0/psforge/tools/__init__.py +3 -0
- psforge-0.2.0/psforge/tools/action_tools.py +149 -0
- psforge-0.2.0/psforge/tools/adjustment_tools.py +316 -0
- psforge-0.2.0/psforge/tools/batch_tools.py +124 -0
- psforge-0.2.0/psforge/tools/document_tools.py +341 -0
- psforge-0.2.0/psforge/tools/filter_tools.py +252 -0
- psforge-0.2.0/psforge/tools/history_tools.py +241 -0
- psforge-0.2.0/psforge/tools/image_tools.py +201 -0
- psforge-0.2.0/psforge/tools/layer_ordering_tools.py +306 -0
- psforge-0.2.0/psforge/tools/layer_properties_tools.py +364 -0
- psforge-0.2.0/psforge/tools/layer_tools.py +316 -0
- psforge-0.2.0/psforge/tools/layer_transform_tools.py +331 -0
- psforge-0.2.0/psforge/tools/mask_tools.py +286 -0
- psforge-0.2.0/psforge/tools/registry.py +6 -0
- psforge-0.2.0/psforge/tools/selection_tools.py +248 -0
- psforge-0.2.0/psforge/tools/session_tools.py +244 -0
- psforge-0.2.0/psforge/tools/text_tools.py +390 -0
- psforge-0.2.0/pyproject.toml +51 -0
psforge-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 PSForge Contributors
|
|
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.
|
psforge-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: psforge
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: AI-Powered Photoshop Automation via Model Context Protocol (MCP)
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: photoshop,mcp,automation,ai,adobe,com
|
|
8
|
+
Author: deermiya
|
|
9
|
+
Requires-Python: >=3.10,<3.15
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Dist: loguru (>=0.7.3,<0.8.0)
|
|
23
|
+
Requires-Dist: mcp (>=1.6.0,<2.0.0)
|
|
24
|
+
Requires-Dist: photoshop-python-api (>=0.24.0,<0.25.0)
|
|
25
|
+
Requires-Dist: psutil (>=7.0.0,<8.0.0)
|
|
26
|
+
Requires-Dist: tenacity (>=9.0.0,<10.0.0)
|
|
27
|
+
Project-URL: Homepage, https://github.com/deermiya/PSForge
|
|
28
|
+
Project-URL: Repository, https://github.com/deermiya/PSForge
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# PSForge
|
|
32
|
+
|
|
33
|
+
[](https://www.python.org/downloads/)
|
|
34
|
+
[](https://modelcontextprotocol.io/)
|
|
35
|
+
[](LICENSE)
|
|
36
|
+
[](https://www.microsoft.com/windows)
|
|
37
|
+
|
|
38
|
+
**🎨 AI-Powered Photoshop Automation via Model Context Protocol**
|
|
39
|
+
|
|
40
|
+
[English](README.md) | [中文](README_ZH.md)
|
|
41
|
+
|
|
42
|
+
PSForge is a comprehensive MCP (Model Context Protocol) server that bridges AI assistants like Claude with Adobe Photoshop. It provides **61 powerful tools** for complete Photoshop automation through a clean, well-architected Python interface.
|
|
43
|
+
|
|
44
|
+
> **⚡ Quick Start:** See [QUICKSTART.md](QUICKSTART.md) for setup and testing guide
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## ✨ Key Features
|
|
49
|
+
|
|
50
|
+
- 🛠️ **61 Photoshop Tools** - Complete automation from documents to filters
|
|
51
|
+
- 🧠 **Context On-Demand** - Query PS state when needed, zero overhead on normal operations
|
|
52
|
+
- ⚡ **Batch Execution** - Run multiple operations in a single COM round trip
|
|
53
|
+
- 🔄 **Robust & Reliable** - Auto-retry with exponential backoff, process monitoring
|
|
54
|
+
- 🏗️ **Clean Architecture** - Four-layer design with auto-discovery
|
|
55
|
+
- 🎯 **Type-Safe** - Full type annotations and parameter validation
|
|
56
|
+
- 📝 **Comprehensive Logging** - Debug logs for troubleshooting
|
|
57
|
+
- 🚀 **Easy to Extend** - Drop a new tool file, it auto-registers
|
|
58
|
+
|
|
59
|
+
## 📋 Requirements
|
|
60
|
+
|
|
61
|
+
| Component | Version | Notes |
|
|
62
|
+
|-----------|---------|-------|
|
|
63
|
+
| **Python** | 3.10 - 3.14 | Required |
|
|
64
|
+
| **OS** | Windows | Uses COM interface |
|
|
65
|
+
| **Photoshop** | CC 2019+ | Must be running |
|
|
66
|
+
| **MCP Client** | Any | Claude Desktop, Cursor, etc. |
|
|
67
|
+
|
|
68
|
+
## 🚀 Quick Installation
|
|
69
|
+
|
|
70
|
+
### Using Poetry (Recommended)
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Clone or download the project
|
|
74
|
+
cd psforge
|
|
75
|
+
|
|
76
|
+
# Install dependencies
|
|
77
|
+
poetry install
|
|
78
|
+
|
|
79
|
+
# Verify installation
|
|
80
|
+
poetry run python check_tools.py
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Using pip
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
cd psforge
|
|
87
|
+
pip install -e .
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## ⚙️ Configuration
|
|
91
|
+
|
|
92
|
+
### For Claude Desktop
|
|
93
|
+
|
|
94
|
+
**Step 1:** Edit `%APPDATA%\Claude\claude_desktop_config.json`
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"mcpServers": {
|
|
99
|
+
"psforge": {
|
|
100
|
+
"command": "D:\\your-path\\PSForge\\start_psforge.bat"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
⚠️ **Important:** Replace the path with your actual project path!
|
|
107
|
+
|
|
108
|
+
**Step 2:** Restart Claude Desktop
|
|
109
|
+
|
|
110
|
+
**Step 3:** Test in Claude:
|
|
111
|
+
```
|
|
112
|
+
Get Photoshop session info using PSForge
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### For Cursor / Other MCP Clients
|
|
116
|
+
|
|
117
|
+
Configure according to your client's documentation:
|
|
118
|
+
- **Command:** `poetry run psforge` (or just `psforge` if installed globally)
|
|
119
|
+
- **Protocol:** stdio
|
|
120
|
+
- **Working Directory:** Your psforge installation path
|
|
121
|
+
|
|
122
|
+
See [claude_desktop_config.example.json](claude_desktop_config.example.json) for reference.
|
|
123
|
+
|
|
124
|
+
## 🏗️ Architecture
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
┌─────────────────────────────────────────┐
|
|
128
|
+
│ AI Client (Claude / Cursor) │
|
|
129
|
+
│ Natural Language Commands │
|
|
130
|
+
└──────────────┬──────────────────────────┘
|
|
131
|
+
│ MCP Protocol (stdio)
|
|
132
|
+
┌──────────────▼──────────────────────────┐
|
|
133
|
+
│ Layer 1: MCP Server (FastMCP) │
|
|
134
|
+
│ • Auto-discovery & Registration │
|
|
135
|
+
│ • server.py + registry.py │
|
|
136
|
+
└──────────────┬──────────────────────────┘
|
|
137
|
+
│ Tool Calls
|
|
138
|
+
┌──────────────▼──────────────────────────┐
|
|
139
|
+
│ Layer 2: Tools (61 tools) │
|
|
140
|
+
│ • 15 modules by functionality │
|
|
141
|
+
│ • Full parameter validation │
|
|
142
|
+
└──────────────┬──────────────────────────┘
|
|
143
|
+
│ PS Operations
|
|
144
|
+
┌──────────────▼──────────────────────────┐
|
|
145
|
+
│ Layer 3: PS Adapter │
|
|
146
|
+
│ • Connection Management │
|
|
147
|
+
│ • Context Tracking │
|
|
148
|
+
│ • Process Guard & Retry │
|
|
149
|
+
└──────────────┬──────────────────────────┘
|
|
150
|
+
│ Windows COM / ExtendScript
|
|
151
|
+
┌──────────────▼──────────────────────────┐
|
|
152
|
+
│ Layer 4: Adobe Photoshop │
|
|
153
|
+
│ • Direct API Calls │
|
|
154
|
+
│ • JavaScript Execution │
|
|
155
|
+
└─────────────────────────────────────────┘
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## 🛠️ Tool Categories (61 Total)
|
|
159
|
+
|
|
160
|
+
<details>
|
|
161
|
+
<summary><b>📄 Document Tools (5)</b></summary>
|
|
162
|
+
|
|
163
|
+
- `create_document` - Create new document with full control (size, resolution, color mode)
|
|
164
|
+
- `open_image` - Open image file as document
|
|
165
|
+
- `save_document` - Save as PSD/JPG/PNG with quality settings
|
|
166
|
+
- `close_document` - Close with or without saving
|
|
167
|
+
- `crop_document` - Crop to specified bounds
|
|
168
|
+
|
|
169
|
+
</details>
|
|
170
|
+
|
|
171
|
+
<details>
|
|
172
|
+
<summary><b>📑 Layer Tools (6)</b></summary>
|
|
173
|
+
|
|
174
|
+
- `create_layer` - Create new empty layer
|
|
175
|
+
- `delete_layer` - Delete active layer (with safety checks)
|
|
176
|
+
- `duplicate_layer` - Duplicate layer with optional rename
|
|
177
|
+
- `merge_visible_layers` - Merge all visible layers
|
|
178
|
+
- `flatten_image` - Flatten to single background layer
|
|
179
|
+
- `rasterize_layer` - Convert text/shape/smart object to pixels
|
|
180
|
+
|
|
181
|
+
</details>
|
|
182
|
+
|
|
183
|
+
<details>
|
|
184
|
+
<summary><b>🎨 Layer Properties (6)</b></summary>
|
|
185
|
+
|
|
186
|
+
- `set_layer_opacity` - Opacity 0-100%
|
|
187
|
+
- `set_layer_blend_mode` - 27 blend modes (Normal, Multiply, Screen, Overlay, etc.)
|
|
188
|
+
- `set_layer_visibility` - Show/hide layer
|
|
189
|
+
- `set_layer_locked` - Lock/unlock layer
|
|
190
|
+
- `rename_layer` - Rename active layer
|
|
191
|
+
- `fill_layer` - Fill with solid RGB color
|
|
192
|
+
|
|
193
|
+
</details>
|
|
194
|
+
|
|
195
|
+
<details>
|
|
196
|
+
<summary><b>🔄 Layer Transform (5)</b></summary>
|
|
197
|
+
|
|
198
|
+
- `move_layer` - Translate by X/Y pixels
|
|
199
|
+
- `scale_layer` - Scale by percentage (proportional or independent W/H)
|
|
200
|
+
- `rotate_layer` - Rotate by degrees
|
|
201
|
+
- `fit_layer_to_document` - Fit or fill canvas
|
|
202
|
+
- `resize_image` - Resize entire document (5 resample methods)
|
|
203
|
+
|
|
204
|
+
</details>
|
|
205
|
+
|
|
206
|
+
<details>
|
|
207
|
+
<summary><b>📚 Layer Ordering (5)</b></summary>
|
|
208
|
+
|
|
209
|
+
- `move_layer_up` / `move_layer_down` - Move one position
|
|
210
|
+
- `move_layer_to_top` / `move_layer_to_bottom` - Move to extremes
|
|
211
|
+
- `move_layer_to_position` - Position relative to named layer (above/below)
|
|
212
|
+
|
|
213
|
+
</details>
|
|
214
|
+
|
|
215
|
+
<details>
|
|
216
|
+
<summary><b>✍️ Text Tools (5)</b></summary>
|
|
217
|
+
|
|
218
|
+
- `create_text_layer` - Create with content, position, font, size, color
|
|
219
|
+
- `update_text_content` - Change text content
|
|
220
|
+
- `set_text_font` - Set font family and/or size
|
|
221
|
+
- `set_text_color` - Set RGB color
|
|
222
|
+
- `set_text_alignment` - Left/Center/Right alignment
|
|
223
|
+
|
|
224
|
+
</details>
|
|
225
|
+
|
|
226
|
+
<details>
|
|
227
|
+
<summary><b>🎭 Filter Tools (4)</b></summary>
|
|
228
|
+
|
|
229
|
+
- `apply_gaussian_blur` - Gaussian blur (radius 0.1-250)
|
|
230
|
+
- `apply_motion_blur` - Motion blur (angle + distance)
|
|
231
|
+
- `apply_sharpen` - Unsharp Mask (amount/radius/threshold)
|
|
232
|
+
- `apply_noise` - Add noise (Uniform/Gaussian, monochromatic option)
|
|
233
|
+
|
|
234
|
+
</details>
|
|
235
|
+
|
|
236
|
+
<details>
|
|
237
|
+
<summary><b>🌈 Adjustment Tools (6)</b></summary>
|
|
238
|
+
|
|
239
|
+
- `adjust_brightness_contrast` - Brightness (-150 to 150) / Contrast (-50 to 100)
|
|
240
|
+
- `adjust_hue_saturation` - Hue/Saturation/Lightness adjustments
|
|
241
|
+
- `auto_levels` - Automatic levels correction
|
|
242
|
+
- `auto_contrast` - Automatic contrast correction
|
|
243
|
+
- `desaturate` - Convert to grayscale
|
|
244
|
+
- `invert` - Invert colors
|
|
245
|
+
|
|
246
|
+
</details>
|
|
247
|
+
|
|
248
|
+
<details>
|
|
249
|
+
<summary><b>⬜ Selection Tools (4)</b></summary>
|
|
250
|
+
|
|
251
|
+
- `select_all` - Select entire document
|
|
252
|
+
- `select_rectangle` - Create rectangular selection
|
|
253
|
+
- `deselect` - Remove selection
|
|
254
|
+
- `invert_selection` - Invert current selection
|
|
255
|
+
|
|
256
|
+
</details>
|
|
257
|
+
|
|
258
|
+
<details>
|
|
259
|
+
<summary><b>🖼️ Image Tools (2)</b></summary>
|
|
260
|
+
|
|
261
|
+
- `place_image` - Place external image as new layer
|
|
262
|
+
- `get_layers` - Get comprehensive info on all layers
|
|
263
|
+
|
|
264
|
+
</details>
|
|
265
|
+
|
|
266
|
+
<details>
|
|
267
|
+
<summary><b>🎭 Mask Tools (3)</b></summary>
|
|
268
|
+
|
|
269
|
+
- `create_layer_mask` - Reveal-all or hide-all mask
|
|
270
|
+
- `apply_layer_mask` - Apply and remove mask
|
|
271
|
+
- `delete_layer_mask` - Delete mask without applying
|
|
272
|
+
|
|
273
|
+
</details>
|
|
274
|
+
|
|
275
|
+
<details>
|
|
276
|
+
<summary><b>⏮️ History Tools (3)</b></summary>
|
|
277
|
+
|
|
278
|
+
- `undo` - Undo multiple steps (1-50)
|
|
279
|
+
- `redo` - Redo multiple steps (1-50)
|
|
280
|
+
- `get_history` - Get list of all history states
|
|
281
|
+
|
|
282
|
+
</details>
|
|
283
|
+
|
|
284
|
+
<details>
|
|
285
|
+
<summary><b>⚡ Action & Script Tools (2)</b></summary>
|
|
286
|
+
|
|
287
|
+
- `play_action` - Execute Photoshop action from action set
|
|
288
|
+
- `execute_script` - Run arbitrary ExtendScript/JavaScript
|
|
289
|
+
|
|
290
|
+
</details>
|
|
291
|
+
|
|
292
|
+
<details>
|
|
293
|
+
<summary><b>ℹ️ Session Tools (3)</b></summary>
|
|
294
|
+
|
|
295
|
+
- `get_session_info` - PS version, running status, document count
|
|
296
|
+
- `get_active_document_info` - Detailed document information
|
|
297
|
+
- `get_selection_info` - Current selection bounds and dimensions
|
|
298
|
+
|
|
299
|
+
</details>
|
|
300
|
+
|
|
301
|
+
<details>
|
|
302
|
+
<summary><b>🚀 Batch Tools (2)</b></summary>
|
|
303
|
+
|
|
304
|
+
- `execute_batch` - Run multiple ExtendScript snippets in a single COM round trip
|
|
305
|
+
- `select_layer_by_name` - Activate a layer by name (recursive search including layer groups)
|
|
306
|
+
|
|
307
|
+
</details>
|
|
308
|
+
|
|
309
|
+
## 💡 Usage Examples
|
|
310
|
+
|
|
311
|
+
### Example 1: Create a Social Media Banner
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
You: Create a 1200x628 Instagram post with a blue background and centered white text saying "Hello PSForge"
|
|
315
|
+
|
|
316
|
+
Claude will:
|
|
317
|
+
1. create_document(width=1200, height=628, name="Instagram Post")
|
|
318
|
+
2. create_layer(name="Background")
|
|
319
|
+
3. fill_layer(red=52, green=152, blue=219) # Nice blue
|
|
320
|
+
4. create_text_layer(text="Hello PSForge", x=600, y=314, font_size=72, color_r=255, color_g=255, color_b=255)
|
|
321
|
+
5. set_text_alignment(alignment="CENTER")
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Example 2: Batch Apply Effects
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
You: Apply a 5px Gaussian blur and increase brightness by 20 on the current layer
|
|
328
|
+
|
|
329
|
+
Claude will:
|
|
330
|
+
1. apply_gaussian_blur(radius=5)
|
|
331
|
+
2. adjust_brightness_contrast(brightness=20, contrast=0)
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Example 3: Complex Layer Manipulation
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
You: Duplicate the current layer, move it down, reduce opacity to 50%, and apply motion blur
|
|
338
|
+
|
|
339
|
+
Claude will:
|
|
340
|
+
1. duplicate_layer()
|
|
341
|
+
2. move_layer_down()
|
|
342
|
+
3. set_layer_opacity(opacity=50)
|
|
343
|
+
4. apply_motion_blur(angle=0, radius=20)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## 🧪 Testing
|
|
347
|
+
|
|
348
|
+
### Quick Connection Test
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
# Requires Photoshop to be running
|
|
352
|
+
poetry run python test_connection.py
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Expected output:**
|
|
356
|
+
```
|
|
357
|
+
✅ All tests passed! PSForge is working correctly
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Verify All Tools
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
poetry run python check_tools.py
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Expected output:**
|
|
367
|
+
```
|
|
368
|
+
✅ Success! All 61 tools registered
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Run Unit Tests
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
poetry run pytest tests/unit/
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Run Integration Tests
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
# ⚠️ Warning: These tests will create/modify documents in Photoshop
|
|
381
|
+
poetry run pytest tests/integration/
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## 🔧 Development
|
|
385
|
+
|
|
386
|
+
### Project Structure
|
|
387
|
+
|
|
388
|
+
```
|
|
389
|
+
psforge/
|
|
390
|
+
├── psforge/
|
|
391
|
+
│ ├── server.py # MCP server entry point
|
|
392
|
+
│ ├── registry.py # Auto-discovery system
|
|
393
|
+
│ ├── decorators.py # Error handling & logging
|
|
394
|
+
│ ├── app.py # Version and metadata
|
|
395
|
+
│ ├── ps_adapter/ # Photoshop interface layer
|
|
396
|
+
│ │ ├── application.py # Connection singleton + retry
|
|
397
|
+
│ │ ├── context.py # On-demand state querying
|
|
398
|
+
│ │ ├── process_guard.py # Health check & auto-restart
|
|
399
|
+
│ │ └── utils.py # Helpers & validation
|
|
400
|
+
│ ├── tools/ # 15 tool modules (61 tools)
|
|
401
|
+
│ │ ├── session_tools.py
|
|
402
|
+
│ │ ├── document_tools.py
|
|
403
|
+
│ │ ├── layer_tools.py
|
|
404
|
+
│ │ ├── batch_tools.py
|
|
405
|
+
│ │ └── ... (11 more)
|
|
406
|
+
│ └── resources/
|
|
407
|
+
│ └── (resource providers)
|
|
408
|
+
├── tests/
|
|
409
|
+
│ ├── unit/ # Unit tests
|
|
410
|
+
│ └── integration/ # Integration tests
|
|
411
|
+
├── test_connection.py # Quick connection test
|
|
412
|
+
├── check_tools.py # Tool registration checker
|
|
413
|
+
├── pyproject.toml # Dependencies & config
|
|
414
|
+
├── README.md # This file
|
|
415
|
+
├── README_ZH.md # 中文文档
|
|
416
|
+
├── QUICKSTART.md # Quick start guide
|
|
417
|
+
├── CHANGELOG.md # Version history
|
|
418
|
+
└── .gitignore # Git ignore rules
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Adding Custom Tools
|
|
422
|
+
|
|
423
|
+
PSForge uses an auto-discovery system. Just drop a new Python file into `tools/`:
|
|
424
|
+
|
|
425
|
+
**Example:** `psforge/tools/my_custom_tools.py`
|
|
426
|
+
|
|
427
|
+
```python
|
|
428
|
+
from psforge.decorators import debug_tool, log_tool_call
|
|
429
|
+
from psforge.ps_adapter import PhotoshopApp
|
|
430
|
+
from psforge.registry import register_tool
|
|
431
|
+
|
|
432
|
+
def register(mcp):
|
|
433
|
+
"""This function is called automatically by the registry."""
|
|
434
|
+
registered_tools = []
|
|
435
|
+
|
|
436
|
+
@debug_tool
|
|
437
|
+
@log_tool_call
|
|
438
|
+
def my_awesome_tool(param: str) -> dict:
|
|
439
|
+
"""Do something awesome in Photoshop.
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
param: Parameter description.
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
dict: Operation result.
|
|
446
|
+
"""
|
|
447
|
+
ps_app = PhotoshopApp()
|
|
448
|
+
doc = ps_app.get_active_document()
|
|
449
|
+
|
|
450
|
+
if not doc:
|
|
451
|
+
return {
|
|
452
|
+
"success": False,
|
|
453
|
+
"error": "No active document",
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
try:
|
|
457
|
+
# Your implementation here
|
|
458
|
+
result = ps_app.execute_javascript(f'alert("{param}");')
|
|
459
|
+
|
|
460
|
+
return {
|
|
461
|
+
"success": True,
|
|
462
|
+
"message": f"Executed with param: {param}",
|
|
463
|
+
}
|
|
464
|
+
except Exception as e:
|
|
465
|
+
return {
|
|
466
|
+
"success": False,
|
|
467
|
+
"error": str(e),
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
registered_tools.append(register_tool(mcp, my_awesome_tool, "my_awesome_tool"))
|
|
471
|
+
return registered_tools
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
**That's it!** The tool will be automatically discovered and registered on next server start.
|
|
475
|
+
|
|
476
|
+
### Code Quality
|
|
477
|
+
|
|
478
|
+
```bash
|
|
479
|
+
# Format code (line-length 120)
|
|
480
|
+
poetry run ruff format .
|
|
481
|
+
|
|
482
|
+
# Lint code
|
|
483
|
+
poetry run ruff check .
|
|
484
|
+
|
|
485
|
+
# Fix auto-fixable issues
|
|
486
|
+
poetry run ruff check --fix .
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## 🐛 Troubleshooting
|
|
490
|
+
|
|
491
|
+
### Problem: "Could not connect to Photoshop"
|
|
492
|
+
|
|
493
|
+
**Solutions:**
|
|
494
|
+
1. Ensure Photoshop is running
|
|
495
|
+
2. Check if scripting is enabled: Preferences → General → Enable Remote Connections
|
|
496
|
+
3. Restart Photoshop
|
|
497
|
+
4. Check `psforge_debug.log` for detailed errors
|
|
498
|
+
|
|
499
|
+
### Problem: "Operation timed out"
|
|
500
|
+
|
|
501
|
+
**Solutions:**
|
|
502
|
+
- Default timeout is 30 seconds
|
|
503
|
+
- PSForge will auto-kill and restart PS on timeout
|
|
504
|
+
- Check if Photoshop has dialog boxes open (should be auto-disabled)
|
|
505
|
+
- Verify PS isn't frozen or unresponsive
|
|
506
|
+
|
|
507
|
+
### Problem: Tools not showing in Claude
|
|
508
|
+
|
|
509
|
+
**Solutions:**
|
|
510
|
+
1. Verify `claude_desktop_config.json` path is correct
|
|
511
|
+
2. Use absolute path for `start_psforge.bat` (no `~` or relative paths)
|
|
512
|
+
3. Restart Claude Desktop completely
|
|
513
|
+
4. Check Claude Desktop logs: `%APPDATA%\Claude\logs\`
|
|
514
|
+
|
|
515
|
+
### Problem: Import errors
|
|
516
|
+
|
|
517
|
+
**Solutions:**
|
|
518
|
+
```bash
|
|
519
|
+
# Reinstall dependencies
|
|
520
|
+
poetry install
|
|
521
|
+
|
|
522
|
+
# Or with pip
|
|
523
|
+
pip install -e .
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## 📝 Debug Logging
|
|
527
|
+
|
|
528
|
+
PSForge automatically logs to `psforge_debug.log` in the working directory.
|
|
529
|
+
|
|
530
|
+
**View logs:**
|
|
531
|
+
```bash
|
|
532
|
+
# Windows
|
|
533
|
+
type psforge_debug.log
|
|
534
|
+
|
|
535
|
+
# Or open in editor
|
|
536
|
+
notepad psforge_debug.log
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
**Log levels:**
|
|
540
|
+
- `INFO` - General operation flow
|
|
541
|
+
- `DEBUG` - Detailed execution steps
|
|
542
|
+
- `WARNING` - Non-critical issues
|
|
543
|
+
- `ERROR` - Failures and exceptions
|
|
544
|
+
|
|
545
|
+
## 📄 License
|
|
546
|
+
|
|
547
|
+
MIT License - See [LICENSE](LICENSE) file for details
|
|
548
|
+
|
|
549
|
+
## 🤝 Contributing
|
|
550
|
+
|
|
551
|
+
Contributions are welcome! Please ensure:
|
|
552
|
+
|
|
553
|
+
- ✅ All functions have complete docstrings (Google style)
|
|
554
|
+
- ✅ Full type annotations on all parameters and returns
|
|
555
|
+
- ✅ Tests pass: `poetry run pytest`
|
|
556
|
+
- ✅ Code formatted: `poetry run ruff format .`
|
|
557
|
+
- ✅ Linting passes: `poetry run ruff check .`
|
|
558
|
+
- ✅ Tools return `{"success": bool, ...}` format (no `get_context_info()` in tool returns)
|
|
559
|
+
|
|
560
|
+
**Built with:**
|
|
561
|
+
- [photoshop-python-api](https://github.com/loonghao/photoshop-python-api) - Photoshop Python API
|
|
562
|
+
- [Model Context Protocol](https://modelcontextprotocol.io/) - MCP specification
|
|
563
|
+
- [mcp](https://pypi.org/project/mcp/) - MCP Python SDK
|
|
564
|
+
|
|
565
|
+
## 📚 Documentation
|
|
566
|
+
|
|
567
|
+
- [Quick Start Guide](QUICKSTART.md) - Get up and running in 5 minutes
|
|
568
|
+
- [Changelog](CHANGELOG.md) - Version history and changes
|
|
569
|
+
- [中文文档](README_ZH.md) - Chinese documentation
|
|
570
|
+
|
|
571
|
+
## 📦 Version History
|
|
572
|
+
|
|
573
|
+
### v0.2.0 (2026-06-01)
|
|
574
|
+
|
|
575
|
+
**Performance:** Removed automatic `get_context_info()` from all tool returns — each tool call now saves one COM round trip. Fixed 3×3 double retry nesting down to single-layer retry.
|
|
576
|
+
|
|
577
|
+
**New tools:** `execute_batch` (batch JS execution in one COM call), `select_layer_by_name` (recursive layer lookup). Total: **61 tools / 15 modules**.
|
|
578
|
+
|
|
579
|
+
**Cleanup:** Removed dead code — `ActionManager` placeholder, unused `execute_with_timeout`, `OperationCounter`, and redundant schema building in `register_tool`.
|
|
580
|
+
|
|
581
|
+
See [CHANGELOG.md](CHANGELOG.md) for full details.
|
|
582
|
+
|
|
583
|
+
### v0.1.0 (2024-05-26)
|
|
584
|
+
|
|
585
|
+
Initial release. 59 tools, 4-layer architecture, auto-discovery registration, context-aware returns.
|
|
586
|
+
|
|
587
|
+
## ⭐ Star History
|
|
588
|
+
|
|
589
|
+
If you find PSForge useful, please consider giving it a star! ⭐
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
**Made with ❤️ for the Photoshop automation community**
|
|
594
|
+
|