comfyui-mcp
# ComfyUI OpenAI/FAL-Compatible Images API
A single-container, multi-protocol image-generation backend backed by [ComfyUI](https://github.com/comfyanonymous/ComfyUI). The container starts ComfyUI on the first generation request, keeps it alive while you use it, and cold-stops it after an idle timeout so GPU memory is freed when nothing is generating.
Supported protocols:
- **OpenAI-compatible** — `POST /v1/images/generations`, `GET /v1/models`
- **FAL.ai-compatible** — `POST /fal/run/{model_id}`, `POST /fal/queue/{model_id}`, `GET /fal/queue/{model_id}/requests/{request_id}/status`
- **Wrapper native** — `POST /generate`, `GET /health`, `GET /status`, `POST /stop`
Generated images are persisted under `ComfyUI/output` and served at `/outputs/{filename}`, so `response_format: url` and FAL-style responses return real URLs.
## Endpoints
### OpenAI-compatible
`POST /v1/images/generations` accepts the standard OpenAI request shape:
```json
{
"prompt": "a photo of an astronaut riding a horse on the moon",
"n": 1,
"size": "512x512",
"response_format": "b64_json"
}
```
Supported parameters:
- `prompt` (required)
- `n` (1–4, default 1)
- `size` — `"WIDTHxHEIGHT"`, e.g. `"512x512"` (default), `"1024x1024"`
- `response_format` — `"b64_json"` (default) or `"url"`
- `model` — accepted but currently informational
- `quality`, `style`, `user` — accepted but ignored
- ComfyUI overrides: `negative_prompt`, `width`, `height`, `steps`, `cfg`, `seed`
### FAL.ai-compatible
`POST /fal/run/{model_id}` accepts a FAL-style payload:
```json
{
"prompt": "a serene mountain landscape with cherry blossoms",
"image_size": "landscape_16_9",
"num_images": 1,
"seed": 42
}
```
Supported fields:
- `prompt` (required)
- `negative_prompt`
- `image_size` — e.g. `square_hd`, `landscape_16_9`, `portrait_16_9`
- `aspect_ratio` — e.g. `1:1`, `16:9`, `9:16`
- `width` / `height` (override size/aspect)
- `num_inference_steps` → mapped to ComfyUI steps
- `guidance_scale` → mapped to ComfyUI cfg
- `seed`
- `num_images` (1–4)
- `image_url` / `reference_image_urls` — rejected with a clear error (editing is not supported)
Response shape mirrors FAL:
```json
{
"images": [
{
"url": "http://192.168.2.51:8002/outputs/abc123.png",
"width": 1536,
"height": 1024,
"content_type": "image/png"
}
],
"prompt": "a serene mountain landscape with cherry blossoms",
"seed": 42,
"has_nsfw_concepts": [false]
}
```
## Running the container
```bash
cd wrapper
# place v1-5-pruned-emaonly.safetensors in this directory first
docker compose up -d --build
```
The API is exposed on port `8002` (ComfyUI direct is on `8190`).
## Environment variables
| Variable | Default | Description |
|---|---|---|
| `IDLE_TIMEOUT` | `300` | Seconds of inactivity before ComfyUI is stopped |
| `COMFYUI_PORT` | `8188` | Internal ComfyUI port |
| `API_PORT` | `8000` | Internal API port |
| `PUBLIC_URL` | *(request base URL)* | Base URL used for generated image links, e.g. `http://192.168.2.51:8002` |
| `OPENAI_API_KEY` | *(none)* | Optional Bearer token required on OpenAI endpoints |
| `MODEL_ID` | `comfyui-sd1-5` | Model id advertised by `/v1/models` |
## Using with Hermes
Hermes supports FAL.ai as a backend. Point Hermes at this container by making `fal.run` / `queue.fal.run` resolve to `http://192.168.2.51:8002`. The easiest way is to add a local DNS or proxy rule, or set the FAL client base URL if Hermes/FAL's SDK exposes one.
Set `FAL_KEY` to any non-empty dummy value in Hermes config, pick any FAL model id (e.g. `fal-ai/flux-2/klein/9b`), and generation requests will be handled by your local ComfyUI backend.
## Example requests
OpenAI:
```bash
curl -X POST http://127.0.0.1:8002/v1/images/generations \
-H "Content-Type: application/json" \
-d '{
"prompt": "a photo of an astronaut riding a horse on the moon",
"size": "512x512",
"response_format": "b64_json"
}'
```
FAL:
```bash
curl -X POST http://127.0.0.1:8002/fal/run/fal-ai/flux-2/klein/9b \
-H "Content-Type: application/json" \
-d '{
"prompt": "a serene mountain landscape with cherry blossoms",
"image_size": "landscape_16_9"
}'
```
## Cold-start behavior
The first request after the wrapper has been idle will trigger a ComfyUI startup. The API server waits for ComfyUI to start and generate the image, so the client may observe a longer response time on the first call. Subsequent calls are fast until the idle timeout elapses and ComfyUI is stopped again.
TDQS
Scored across 41 tools
Several tools have overlapping boundaries: comfy_cli duplicates queue, get_history, upload_image, and download_model via its actions; generate_image overlaps with create_workflow + enqueue_workflow; install_comfyui and install_custom_node both manage custom nodes. Despite the descriptions, an agent faces ambiguous choices for common tasks like listing jobs or running a workflow, which will lead to misselection.
Most tools follow a predictable pattern: action-oriented tools use verb_noun (get_workflow, create_workflow, download_model) while domain-oriented tools use noun names (queue, apps, batch, kitchen). The split is deliberate and readable, with only minor deviations like 'bisect' and 'calculate' that are single verbs rather than verb_noun.
41 tools is excessive even for a broad ComfyUI automation domain (workflow authoring, execution, models, training, cloud pods, etc.). Although some consolidation already exists via action-driven mega-tools, the surface remains heavy and could be reduced by merging related single tools.
The surface covers nearly all headless ComfyUI workflows: generation, workflow CRUD, queue management, history, models, custom node management, training, cloud pods, and batch runs. The main gap is the absence of live-canvas panel tools (panel_*), which are repeatedly referenced but not included, preventing direct canvas inspection or manipulation from this server alone.