retiform-comfyui-mcp 2.0.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.
@@ -0,0 +1,77 @@
1
+ # --- Python -------------------------------------------------------------
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+ .eggs/
10
+ .venv/
11
+ venv/
12
+ env/
13
+ .Python
14
+
15
+ # --- Secrets / local env (NEVER commit) ---------------------------------
16
+ .env
17
+ .env.*
18
+ *.env
19
+ .git-credentials
20
+ *.pem
21
+ *.key
22
+
23
+ # --- Model weights: users must source these themselves ------------------
24
+ # The repo ships code, workflows and instructions. It never ships another
25
+ # party's licensed artifacts.
26
+ *.gguf
27
+ *.safetensors
28
+ *.ckpt
29
+ *.pth
30
+ *.onnx
31
+ *.bin
32
+ *.pt
33
+ models/
34
+ loras/
35
+ embeddings/
36
+ checkpoints/
37
+ clip/
38
+ vae/
39
+ controlnet/
40
+ upscale_models/
41
+
42
+ # --- Generated output ---------------------------------------------------
43
+ output/
44
+ outputs/
45
+ comfyui/
46
+ comfyui-temp/
47
+ *.job_params_cache.json
48
+ *.png
49
+ *.jpg
50
+ *.jpeg
51
+ *.webp
52
+ *.gif
53
+ *.pdf
54
+
55
+ # --- Runtime ------------------------------------------------------------
56
+ *.log
57
+ logs/
58
+ *.pid
59
+ *.tmp
60
+ *.bak
61
+ *.old
62
+ *.swp
63
+
64
+ # --- Editors / OS -------------------------------------------------------
65
+ .vscode/
66
+ .idea/
67
+ .DS_Store
68
+ Thumbs.db
69
+ *~
70
+
71
+ # --- Tooling ------------------------------------------------------------
72
+ .serena/
73
+ node_modules/
74
+ package-lock.json
75
+
76
+ # Local deployment audit artifacts (not part of the published package)
77
+ audit/
@@ -0,0 +1,138 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [2.0.0] - 2026-11-10
9
+
10
+ First release under the `retiform-comfyui-mcp` distribution name, rebuilt from an earlier
11
+ internal working repository that remains the historical record. This is a
12
+ **major** bump because the package name, distribution name, module path and
13
+ several tool contracts changed.
14
+
15
+ ### Changed
16
+
17
+ - **`generate_logo` is now `generate_image`.** This is a general-purpose image
18
+ generation server and the public name said otherwise. Consumers calling the
19
+ old tool name must update the call site.
20
+ - **The provenance payload is keyed `GenerationInfo`** rather than
21
+ `LogoGenInfo`. Images rendered before this change are still read under the
22
+ legacy key, so nothing already on disk becomes opaque; only the current key is
23
+ written to new images.
24
+ - **The IP-Adapter loaders are configurable.** `CLIPVisionLoader` and
25
+ `IPAdapterModelLoader` no longer assume one installation's filenames: both are
26
+ arguments on `generate_ipadapter`, and the module defaults are overridable via
27
+ `COMFYUI_CLIP_VISION_MODEL` and `COMFYUI_IPADAPTER_MODEL`. A different CLIP
28
+ vision tower or adapter weight was previously a silent failure.
29
+ - **Package renamed** from the internal working name to the `retiform-comfyui-mcp`
30
+ distribution, with the module at `comfyui_mcp_server` and a `src/` layout. The
31
+ distribution name and the module name intentionally differ: PyPI rejected
32
+ `comfyui-mcp-server` as too similar to two existing projects, and the module
33
+ path and the `comfyui-mcp-server` console script are kept stable so an install
34
+ change does not break a running configuration.
35
+ - **Requires Python 3.11+**, raised from 3.10. This is forced by the Pillow pin
36
+ below rather than chosen: Pillow 13 ships cp311 wheels and no 3.10 build. The
37
+ cost is nil because 3.10 reached end-of-life on 2026-10-01, five weeks before
38
+ this release.
39
+ - **Pillow floor raised to 13.0.0.** `pip-audit` reported 59 advisories against
40
+ Pillow 12.3.0, five of them critical; the package's only Pillow call is
41
+ `Image.open()` on files supplied by a client, which is exactly the decoder
42
+ surface those advisories describe. The audit is now clean.
43
+ - **`_parse_param` de-duplicated.** It was defined twice, byte-identical, at
44
+ roughly 40 lines each. Now a single definition.
45
+ - **`.gitignore` rewritten.** The previous file used an inline comment on a
46
+ pattern (`package-lock.json # ...`), which git reads as a filename containing
47
+ the comment text — the pattern matched nothing and the file was not ignored.
48
+ Every pattern is now verified with `git check-ignore`.
49
+ - **Logging routed through the logger module.** Twenty-two raw
50
+ `print(..., file=sys.stderr)` calls bypassed the existing logger; they now go
51
+ through `log_debug` / `log_error`, so a normal run is quiet and detail is
52
+ opt-in via `set_log_level("debug")`.
53
+ - **Version is declared once.** `pyproject.toml` now uses
54
+ `dynamic = ["version"]` with `[tool.hatch.version]` reading the package's
55
+ `__version__`. Declaring it in both places previously allowed drift between
56
+ the installed metadata and what the code reported.
57
+ - **Provenance strings derived, not literal.** The generator string stamped into
58
+ every image was a hardcoded version; it now comes from the package version.
59
+ - **Every filesystem root is environment-driven** — `COMFYUI_PATH`,
60
+ `COMFYUI_MODELS_PATH`, `COMFYUI_OUTPUT_PATH`. Paths were hardcoded to the
61
+ machine the project was developed on, which broke every install elsewhere.
62
+
63
+ ### Fixed
64
+
65
+ - **The MCP handshake advertised the SDK's version, not ours.** `FastMCP`
66
+ accepts no `version` argument in mcp 1.x and does not forward one to the
67
+ low-level server, so `initialize` reported the SDK's own `1.30.0` while the
68
+ package declared `2.0.0`. The version is now set on the inner server after
69
+ construction, which is the attribute the initialize response reads.
70
+ - **VRAM tools never measured the GPU.** `system_check`, `get_vram_usage` and
71
+ `emergency_cleanup` all read `torch.cuda` inside the MCP server's own process.
72
+ That process never allocates a tensor — ComfyUI is a separate PID — so the
73
+ readings were structurally zero: `vram_used_mb: 0` and `reserved: 0` while
74
+ ComfyUI held the memory, and `emergency_cleanup`'s `freed_mb` was always `0`
75
+ by construction. All three now read the driver via `nvidia-smi`.
76
+ - **`emergency_cleanup` now actually frees memory**, by calling ComfyUI's
77
+ `POST /free {"unload_models": true, "free_memory": true}` and reporting real
78
+ before/after figures. An empty `torch.cuda.empty_cache()` in a process that
79
+ holds nothing could never have reclaimed anything.
80
+ - **VRAM is released when a batch finishes** (new `keep_loaded` flag, default
81
+ `false`). Models are held for the duration of a batch — unloading between
82
+ jobs would make every subsequent job pay a full model-load penalty — and
83
+ released at completion.
84
+ - **Workflow templates resolve relative to the package.** Two call sites
85
+ hardcoded an absolute path into a development directory.
86
+ - **`download_model` had no filename sanitization**, so a `../` path could write
87
+ outside the models tree. Now: bare filename only, extension allowlist per
88
+ model type, `http`/`https` only, and an optional bearer token for gated hosts.
89
+ - **A truncated download could leave a corrupt model file** that looks loadable.
90
+ Writes are now atomic via a `.part` file, with an explicit incomplete-download
91
+ error and a size check against `Content-Length`.
92
+ - **`png_metadata` invented provenance.** A partial params dict wrote
93
+ `steps 20` / `euler_ancestral` / `cfg 7.0` / `seed -1` into the embedded A1111
94
+ block, permanently, inside a binary. Unknown values are now rendered as `?`
95
+ and never defaulted.
96
+ - **A `{"min": .., "max": ..}` dict passed as a parameter spec was sent to the
97
+ workflow as a literal**, so randomised batches could run with nothing
98
+ randomised. This now raises with the correct shape named — ranges are
99
+ two-element lists.
100
+ - **Two bare `except:` clauses narrowed** (they swallowed `KeyboardInterrupt`
101
+ and `SystemExit`).
102
+ - **A failed local import degraded silently.** `log_info = None` let the server
103
+ run with no diagnostics; the import now fails loudly.
104
+
105
+ ### Removed
106
+
107
+ - `torch` is no longer a dependency. It was roughly 2GB of CUDA used only to
108
+ produce a number about the wrong process.
109
+ - Client deliverables, a live client brief, a brand template directory, a
110
+ downloader script carrying an API token, four unused evaluation modules, and
111
+ six generations of superseded batch scripts — none of which belong in a
112
+ published package.
113
+ - No model weights, LoRAs, embeddings, CLIP or VAE files are distributed. Users
114
+ source those themselves.
115
+
116
+ ### Added
117
+
118
+ - `CHANGELOG.md`, `pyproject.toml` with `src/` layout, and an MIT `LICENSE` with
119
+ joint copyright.
120
+ - Test suite: 90 tests, up from 34. The previous suite covered none of the
121
+ thirteen tools and passed vacuously, because it replaced the MCP SDK with a
122
+ `MagicMock` whose `@tool()` decorator returned mocks instead of functions.
123
+ Tests now use a real pass-through double that rejects unknown constructor
124
+ keywords against the real SDK's signature, so an argument the SDK does not
125
+ accept fails under test instead of only at import in a user's environment.
126
+ - Tests that fail the build rather than the user: version single-sourcing,
127
+ filesystem-path absoluteness, parameter-spec rejection, download contract,
128
+ and VRAM release semantics.
129
+ - Tests that run against the **real MCP SDK** rather than the pass-through
130
+ test double: an import in a subprocess, a live stdio handshake, and the tool
131
+ count a client actually receives. This is the instrument that catches a wrong
132
+ assumption about the dependency, which no mock can.
133
+ - `.github/FUNDING.yml` and a Sponsors section in the README, carrying the
134
+ GitHub Sponsors link and the self-custody rails. Both travel inside the
135
+ wheel, since the dist-info metadata embeds the README, so the addresses reach
136
+ anyone reading the package from a registry.
137
+
138
+ [2.0.0]: https://github.com/retiform-labs/comfyui-mcp-server/releases/tag/v2.0.0
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 David Newman <david@retiform.dev>
4
+ Copyright (c) 2026 Guan <guan@retiform.dev>
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,445 @@
1
+ Metadata-Version: 2.5
2
+ Name: retiform-comfyui-mcp
3
+ Version: 2.0.0
4
+ Summary: Agentic ComfyUI image generation over the Model Context Protocol: batch discovery, LoRA shaping, and provenance.
5
+ Project-URL: Homepage, https://retiform.dev
6
+ Project-URL: Repository, https://github.com/retiform-labs/comfyui-mcp-server
7
+ Project-URL: Issues, https://github.com/retiform-labs/comfyui-mcp-server/issues
8
+ Author-email: David Newman <david@retiform.dev>, Guan <guan@retiform.dev>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 David Newman <david@retiform.dev>
12
+ Copyright (c) 2026 Guan <guan@retiform.dev>
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: agent,comfyui,image-generation,lora,mcp,model-context-protocol,stable-diffusion
33
+ Classifier: Development Status :: 4 - Beta
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.11
38
+ Classifier: Programming Language :: Python :: 3.12
39
+ Classifier: Programming Language :: Python :: 3.13
40
+ Classifier: Topic :: Multimedia :: Graphics
41
+ Requires-Python: >=3.11
42
+ Requires-Dist: mcp<2,>=1.27.0
43
+ Requires-Dist: pillow>=13.0.0
44
+ Requires-Dist: psutil>=5.9.0
45
+ Requires-Dist: requests>=2.31.0
46
+ Provides-Extra: dev
47
+ Requires-Dist: mypy>=1.11; extra == 'dev'
48
+ Requires-Dist: pip-audit>=2.7; extra == 'dev'
49
+ Requires-Dist: ruff>=0.6; extra == 'dev'
50
+ Description-Content-Type: text/markdown
51
+
52
+ # comfyui-mcp-server
53
+
54
+ An MCP server that gives an agent direct control of a running
55
+ [ComfyUI](https://github.com/comfyanonymous/ComfyUI) instance: submit workflows,
56
+ run randomised batch discovery, shape LoRA stacks, and read back the provenance
57
+ of every image produced.
58
+
59
+ Built for **iterative aesthetic discovery** -- generate wide, curate narrow, and
60
+ keep a verifiable record of the parameters that produced the survivors.
61
+
62
+ > **Not affiliated with** `joenorton/comfyui-mcp-server` or any other project of
63
+ > a similar name. This is an independent implementation (`@retiform-labs`), and
64
+ > its tool surface is specific to the workflow templates it ships.
65
+
66
+ ## What it does
67
+
68
+ Thirteen tools, split into four groups:
69
+
70
+ **Lifecycle** -- `system_check` · `start_comfyui` · `stop_comfyui` · `get_comfyui_status`
71
+
72
+ **Generation** -- `generate_image` · `generate_ipadapter` · `get_job_status`
73
+
74
+ **Batch** -- `batch_generate` · `batch_generate_ipadapter`
75
+
76
+ **Hardware** -- `list_models` · `download_model` · `get_vram_usage` · `emergency_cleanup`
77
+
78
+ ### Randomised batch discovery
79
+
80
+ The point of the batch tools is *divergence*, not repetition. Pass a `randomize`
81
+ spec and each job in the batch draws its own parameters:
82
+
83
+ ```jsonc
84
+ {
85
+ "randomize": {
86
+ "seed": "random", // fresh seed per job, deduplicated
87
+ "sampler": "random", // from a curated safe pool
88
+ "cfg_scale": [5.0, 9.0], // uniform in range
89
+ "loras": {"mode": "auto", "count": [1, 3], "weight": [0.25, 0.7]}
90
+ }
91
+ }
92
+ ```
93
+
94
+ Ranges are **2-element lists** `[min, max]`. A dict like `{"min": 1, "max": 5}` is
95
+ rejected with an error rather than silently sent to the workflow as a literal --
96
+ that mistake is easy to make and produces a batch where nothing varies.
97
+
98
+ ### LoRA stack shape matters more than the sum
99
+
100
+ Two LoRAs at equal weight average two aesthetics into a muddle. A stack
101
+ generally wants **one dominant adapter and one supporting it**:
102
+
103
+ - dominant: `0.55` -- `0.77`
104
+ - supporting: `0.25` -- `0.40`
105
+ - optional style pin: `~0.45`
106
+
107
+ A total weight around `1.3` is normal and is **not** a ceiling -- well-shaped
108
+ stacks run above it and produce the best results.
109
+
110
+
111
+ ## Tool reference
112
+
113
+ Every tool returns JSON. `generate_*` and `batch_*` are **asynchronous**: they
114
+ queue work and return a job id immediately, because a diffusion run takes far
115
+ longer than any sane request timeout. Poll `get_job_status` for the result.
116
+
117
+ ### Lifecycle
118
+
119
+ #### `system_check()`
120
+
121
+ Reports GPU name, driver version, total and free VRAM, and whether ComfyUI is
122
+ responding. Reads `nvidia-smi`, so it sees the whole GPU -- including memory
123
+ held by ComfyUI, which a torch call inside this process never could.
124
+
125
+ ```jsonc
126
+ // no arguments
127
+ {"gpu": "NVIDIA GeForce RTX 4090", "vram_total_mb": 24564,
128
+ "vram_free_mb": 3703, "comfyui_running": true, "comfyui_version": "0.x"}
129
+ ```
130
+
131
+ #### `start_comfyui(lowvram=True, fp16=True, port=8188)`
132
+
133
+ Launches ComfyUI if it is not already running. `lowvram` is the safe default for
134
+ cards under ~8 GB.
135
+
136
+ ```jsonc
137
+ {"success": true, "pid": 41233, "port": 8188, "already_running": false}
138
+ ```
139
+
140
+ #### `stop_comfyui(force=False)`
141
+
142
+ Stops the ComfyUI process. `force=True` sends SIGKILL when a normal shutdown
143
+ hangs.
144
+
145
+ #### `get_comfyui_status()`
146
+
147
+ Lightweight liveness check -- cheaper than `system_check` because it never shells
148
+ out to the driver.
149
+
150
+ ```jsonc
151
+ {"running": true, "port": 8188, "queue_remaining": 0}
152
+ ```
153
+
154
+ ### Generation
155
+
156
+ #### `generate_image(...)`
157
+
158
+ Text-to-image through the packaged SDXL workflow.
159
+
160
+ | Parameter | Default | Notes |
161
+ |---|---|---|
162
+ | `prompt` | *required* | What to generate |
163
+ | `negative_prompt` | `"text, watermark, blurry, low quality"` | What to avoid |
164
+ | `negative_embedding` | `None` | A textual-inversion embedding name |
165
+ | `width` / `height` | `1024` / `1024` | |
166
+ | `steps` | `20` | |
167
+ | `cfg_scale` | `7.0` | |
168
+ | `sampler` | `"euler_ancestral"` | |
169
+ | `scheduler` | `"normal"` | |
170
+ | `lora` | `None` | One LoRA filename from `models/loras/` |
171
+ | `lora_weight` | `0.8` | |
172
+ | `loras` | `None` | Several at once: `[{"name": ..., "weight": ...}]` |
173
+ | `seed` | `None` | Omit for a random seed |
174
+ | `output_format` | `"png"` | PNG carries provenance metadata |
175
+
176
+ ```jsonc
177
+ {"prompt": "a geometric fox mark, single flat ink colour, high contrast",
178
+ "width": 1024, "height": 1024, "steps": 30, "seed": 1777732588}
179
+ // -> {"job_id": "a3f9...", "status": "queued", "params": {...}}
180
+ ```
181
+
182
+ #### `generate_ipadapter(...)`
183
+
184
+ Reference-guided generation. Feeds 1--4 images into the model to steer style,
185
+ composition or content.
186
+
187
+ | Parameter | Default | Notes |
188
+ |---|---|---|
189
+ | `prompt` | *required* | |
190
+ | `reference_images` | *required* | 1--4 filenames from `comfyui/input/` |
191
+ | `reference_weight` | `0.6` | How hard the references pull |
192
+ | `weight_type` | `"style transfer"` | Also `"linear"`, `"ease in"`, `"strong style transfer"` |
193
+ | `start_at` / `end_at` | `0.0` / `1.0` | Fraction of sampling the adapter applies over |
194
+ | `embeds_scaling` | `"V only"` | |
195
+ | `width` / `height` | `512` / `512` | |
196
+ | `steps` | `10` | |
197
+ | `cfg_scale` | `7.5` | |
198
+ | `sampler` / `scheduler` | `"dpmpp_2m"` / `"karras"` | |
199
+ | `clip_vision_model` | env default | Override the CLIP vision tower |
200
+ | `ipadapter_model` | env default | Override the IP-Adapter weight |
201
+
202
+ ```jsonc
203
+ {"prompt": "the reference mark, redrawn as a woodcut",
204
+ "reference_images": ["ref-a.png", "ref-b.png"],
205
+ "reference_weight": 0.65, "weight_type": "style transfer"}
206
+ ```
207
+
208
+ > **Reference images must already exist in ComfyUI's `input/` directory.** This
209
+ > tool does not upload files; it names them. A missing file is a raised error,
210
+ > not a silent no-op.
211
+
212
+ #### `get_job_status(job_id)`
213
+
214
+ Polls a queued job. Returns `queued`, `running`, `completed` or `failed`, and on
215
+ completion the output image filenames with their provenance payload.
216
+
217
+ ```jsonc
218
+ {"job_id": "a3f9...", "status": "completed",
219
+ "images": [{"filename": "image_output_00042_.png", "subfolder": "", "type": "output"}],
220
+ "params": {"seed": 1777732588, "sampler": "euler_ancestral", "steps": 30, ...}}
221
+ ```
222
+
223
+ ### Batch
224
+
225
+ #### `batch_generate(prompts, shared_params=None, randomize=None, deduplicate_seeds=True, priority="normal", keep_loaded=False)`
226
+
227
+ Queues one job per prompt, optionally randomising parameters across the batch.
228
+
229
+ - `prompts` -- a list of positive prompt strings, one per job.
230
+ - `shared_params` -- static parameters applied to every job (accepts an object
231
+ or a JSON string).
232
+ - `randomize` -- per-job draws; overrides `shared_params` where it names the same key.
233
+ - `deduplicate_seeds` -- guarantees no two jobs share a seed.
234
+ - `keep_loaded` -- leave the model resident after the batch. See *VRAM behaviour*.
235
+
236
+ ```jsonc
237
+ {"prompts": ["a fox mark", "an owl mark", "a wave mark"],
238
+ "shared_params": {"width": 1024, "height": 1024, "steps": 24},
239
+ "randomize": {"seed": "random", "cfg_scale": [5.0, 9.0],
240
+ "loras": {"mode": "auto", "count": [1, 2], "weight": [0.25, 0.7]}}}
241
+ ```
242
+
243
+ Randomisation spec forms:
244
+
245
+ | Form | Meaning |
246
+ |---|---|
247
+ | `"random"` | Draw from a curated safe pool |
248
+ | `"random_unsafe"` | Draw from the full pool, including values that often break |
249
+ | `[min, max]` | Uniform draw in a numeric range |
250
+ | `{"mode": "auto", "count": [1,3], "weight": [0.25,0.7]}` | LoRA stack selection |
251
+ | scalar (e.g. `24`) | Fixed at that value |
252
+
253
+ #### `batch_generate_ipadapter(prompts, reference_images, ...)`
254
+
255
+ The reference-guided equivalent, taking the same batch arguments plus the
256
+ IP-Adapter parameters from `generate_ipadapter`.
257
+
258
+ ### Hardware
259
+
260
+ #### `list_models(model_type="all")`
261
+
262
+ Lists what is actually on disk, with sizes. `model_type` filters to one of
263
+ `unet`, `clip`, `vae`, `loras`, `ipadapter`, `clip_vision`.
264
+
265
+ ```jsonc
266
+ {"model_type": "loras"}
267
+ // -> [{"name": "copperplate_v2.safetensors", "type": "loras",
268
+ // "size_mb": 172.4, "format": "safetensors"}]
269
+ ```
270
+
271
+ #### `download_model(url, model_type, filename=None, expected_sha256=None, token=None)`
272
+
273
+ Downloads from a Civitai-style URL. Writes atomically -- a partial download never
274
+ lands under the final name -- and sanitises `filename` to a single path
275
+ component, so a crafted URL cannot write outside the model directory.
276
+
277
+ ```jsonc
278
+ {"url": "https://civitai.com/api/download/models/12345",
279
+ "model_type": "loras", "filename": "copperplate_v2.safetensors"}
280
+ ```
281
+
282
+ #### `get_vram_usage()`
283
+
284
+ Current GPU memory as the driver reports it. Reads `nvidia-smi` rather than this
285
+ process's CUDA context, which never allocates and would always read zero.
286
+
287
+ ```jsonc
288
+ {"used_mb": 9216, "total_mb": 24564, "free_mb": 15348}
289
+ ```
290
+
291
+ #### `emergency_cleanup(restart_comfyui=False)`
292
+
293
+ Frees GPU memory by asking ComfyUI to unload its models, then re-reads the driver
294
+ to report what was **actually** released. Useful before handing the GPU to a
295
+ non-ComfyUI job.
296
+
297
+ ```jsonc
298
+ {"models_unloaded": ["sdxl-base"], "vram_freed_mb": 9001,
299
+ "vram_before_mb": 9216, "vram_after_mb": 215}
300
+ ```
301
+
302
+ > `restart_comfyui=True` is the heavier option: it stops and restarts the server.
303
+ > Use it when a normal unload does not recover the memory.
304
+
305
+ ## Requirements
306
+
307
+ - **Python 3.11+**
308
+ - **A running ComfyUI instance** with the nodes your workflows use
309
+ (`UnetLoaderGGUF` and the IP-Adapter nodes, for the shipped templates)
310
+ - **`nvidia-smi`** on `PATH` for the VRAM tools (NVIDIA drivers)
311
+ - **Models, LoRAs, embeddings and CLIP/VAE weights are NOT included.** Source
312
+ them yourself and place them where ComfyUI expects them. This repository ships
313
+ code, workflow templates and instructions -- never another party's licensed
314
+ artifacts.
315
+
316
+ The IP-Adapter templates reference these filenames; substitute your own:
317
+
318
+ | Node | Default filename | Override with |
319
+ |---|---|---|
320
+ | `CLIPVisionLoader` | `CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors` | `clip_vision_model=` or `COMFYUI_CLIP_VISION_MODEL` |
321
+ | `IPAdapterModelLoader` | `ip-adapter-plus_sdxl_vit-h.bin` | `ipadapter_model=` or `COMFYUI_IPADAPTER_MODEL` |
322
+
323
+ These are **defaults, not requirements.** If your install uses a different CLIP
324
+ vision tower or IP-Adapter weight, pass the filename to `generate_ipadapter` or
325
+ set the environment variable -- no code change, and no failure to diagnose
326
+ silently.
327
+
328
+ A negative embedding is optional; the templates accept one via the
329
+ `negative_embedding` argument (e.g. `DeepNegative_xl_v1`).
330
+
331
+ ## Install
332
+
333
+ ```bash
334
+ pip install retiform-comfyui-mcp
335
+ ```
336
+
337
+ > The **distribution** is `retiform-comfyui-mcp`; the installed **module** is
338
+ > `comfyui_mcp_server` and the **console script** is `comfyui-mcp-server`. The
339
+ > three names differ deliberately: PyPI rejects the bare `comfyui-mcp-server`
340
+ > as too similar to two existing projects, and keeping the module path and the
341
+ > script name stable means an install never breaks a working MCP client config.
342
+
343
+ Or from source:
344
+
345
+ ```bash
346
+ git clone https://github.com/retiform-labs/comfyui-mcp-server
347
+ cd comfyui-mcp-server
348
+ pip install -e ".[dev]"
349
+ ```
350
+
351
+ > **`mcp` is pinned below 2.0** -- in the MCP SDK 2.x line,
352
+ > `mcp.server.fastmcp` is a compatibility stub that raises on import. Do not
353
+ > widen that pin without migrating the server to `MCPServer`.
354
+
355
+ ## Configure
356
+
357
+ All configuration is environment-driven. Nothing is assumed about where ComfyUI
358
+ lives.
359
+
360
+ | Variable | Default | Meaning |
361
+ |---|---|---|
362
+ | `COMFYUI_HOST` | `127.0.0.1` | ComfyUI host |
363
+ | `COMFYUI_PORT` | `8188` | ComfyUI port |
364
+ | `COMFYUI_PATH` | `~/ComfyUI` | ComfyUI install root (the dir with `main.py`) |
365
+ | `COMFYUI_MODELS_PATH` | `$COMFYUI_PATH/models` | Models root |
366
+ | `COMFYUI_OUTPUT_PATH` | `$COMFYUI_PATH/output` | Where renders land |
367
+ | `COMFYUI_CLIP_VISION_MODEL` | `CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors` | CLIP vision tower for reference-guided generation |
368
+ | `COMFYUI_IPADAPTER_MODEL` | `ip-adapter-plus_sdxl_vit-h.bin` | IP-Adapter weight (plus variant) |
369
+ | `COMFYUI_IPADAPTER_BASIC_MODEL` | `ip-adapter_sdxl_vit-h.bin` | IP-Adapter weight used by the VRAM-saving fallback |
370
+ | `COMFYUI_DOWNLOAD_TOKEN` | *(none)* | Bearer token for gated model hosts, so it need not travel through a tool argument |
371
+
372
+ ### MCP client
373
+
374
+ ```jsonc
375
+ {
376
+ "mcpServers": {
377
+ "comfyui": {
378
+ "command": "comfyui-mcp-server",
379
+ "env": { "COMFYUI_PATH": "/opt/ComfyUI" }
380
+ }
381
+ }
382
+ }
383
+ ```
384
+
385
+ ## VRAM behaviour
386
+
387
+ The MCP server is a **separate process** from ComfyUI. It never allocates CUDA
388
+ tensors, so `torch.cuda.memory_allocated()` inside it is structurally zero no
389
+ matter what ComfyUI is holding. This server therefore reads VRAM from the
390
+ driver (`nvidia-smi`) and releases it by asking ComfyUI to unload --
391
+
392
+ - `get_vram_usage` -- live used/free/total from the driver
393
+ - `emergency_cleanup` -- `POST /free {"unload_models": true, "free_memory": true}`
394
+ on ComfyUI, reporting real before/after MB and `freed_mb`
395
+
396
+ `torch` is deliberately **not** a dependency. It cost ~2GB of CUDA to produce a
397
+ number that measured the wrong process.
398
+
399
+ Unloading after every job is usually the wrong trade: the next job then pays a
400
+ full model-load penalty. If you release between jobs, release at **batch**
401
+ boundaries.
402
+
403
+ ## Provenance
404
+
405
+ Generated PNGs carry an A1111-compatible `parameters` block plus a structured
406
+ `GenerationInfo` record. Values that were not supplied are written as `?` and are
407
+ **never** defaulted -- an invented parameter in an embedded block is a permanent,
408
+ machine-readable lie.
409
+
410
+ Images rendered before the rename carry the same payload under the key
411
+ `LogoGenInfo`. Both keys are read; only the current one is written.
412
+
413
+ ## Development
414
+
415
+ ```bash
416
+ pip install -e ".[dev]"
417
+ python -m unittest discover -s tests -v
418
+ ruff check src tests
419
+ ```
420
+
421
+ Nothing under `src/` may contain an absolute filesystem path; a test enforces
422
+ this, because a package that only works on its author's machine is broken for
423
+ everyone else.
424
+
425
+ ## License
426
+
427
+ MIT -- see [LICENSE](LICENSE).
428
+
429
+ Copyright (c) 2026 David Newman and Guan.
430
+
431
+ ---
432
+
433
+ ## Sponsors
434
+
435
+ If comfyui-mcp-server is useful to you, consider supporting its continued development:
436
+
437
+ - **[GitHub Sponsors](https://github.com/sponsors/guan-tends)**
438
+ - **Bitcoin:** `bc1q0gd3mwjg3zy9sghv22kmpg823vss4c0zzdzg24`
439
+ - **Solana:** `Eu8wQcW68TKMs1a6eqzZu8znzU52QLqQugAMG8uCD6y6`
440
+ - **Ethereum / EVM:** `0x2733ff7c865C56d565a99BE1DC11B81cc76850A5`
441
+ - **XRP Ledger:** `r4X6e7McAQj7e8vBCeued1RYu4mCJrREDG`
442
+
443
+ ---
444
+
445
+ Crafted with ❤️ by [Retiform Labs](https://retiform.dev)