comfyui-mcp
README.md
# comfyui-mcp
MCP server exposing a local (or LAN) ComfyUI instance's HTTP API as tools, so an
LLM client (Claude Desktop, Claude Code, etc.) can queue generations, inspect the
queue/history, upload reference images, browse installed models/nodes, and pull
back generated images -- without hand-rolling `curl` calls every time.
Built with Python + FastMCP, stdio transport (local subprocess, talks to ComfyUI
over HTTP on `127.0.0.1:8188` by default).
## Requirements
- Python 3.10+
- A running ComfyUI instance reachable over HTTP (default assumes the same
machine, default port)
## Install
```bash
cd comfyui-mcp # this directory
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # macOS/Linux
pip install -r requirements.txt
```
## Configure
Environment variables (optional -- sane defaults for a local install):
| Variable | Default | Purpose |
|---|---|---|
| `COMFYUI_BASE_URL` | `http://127.0.0.1:8188` | Where ComfyUI's API is reachable |
| `COMFYUI_HTTP_TIMEOUT` | `30` | Per-request HTTP timeout in seconds (not the job-wait timeout, which is a per-tool-call parameter) |
| `COMFYUI_MOUNT_DIR` | `E:\Claude\Projects\Krea2\comfy_out` | Where `comfyui_save_output` writes renders — a folder the client/sandbox can see |
| `COMFYUI_LORA_DIR` | *(unset)* | LoRA `.safetensors` directory, for `comfyui_get_lora_metadata` (ComfyUI's API exposes LoRA names but not their path) |
| `COMFYUI_MODELS_DIR` | *(unset)* | Parent `models/` dir; `COMFYUI_LORA_DIR` falls back to `<this>/loras` |
The last three power the filesystem-backed tools. They assume the MCP server
process runs on the same (Windows) host as ComfyUI, which is the intended setup.
Copy `.env.example` to `.env` and edit if your ComfyUI runs on a different
host/port, or just set the variables in your MCP client config (see below).
## Register with an MCP client
**Claude Code:**
```bash
claude mcp add comfyui -- python /absolute/path/to/comfyui-mcp/comfyui_mcp/server.py
```
**Claude Desktop** (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"comfyui": {
"command": "python",
"args": ["/absolute/path/to/comfyui-mcp/comfyui_mcp/server.py"],
"env": {
"COMFYUI_BASE_URL": "http://127.0.0.1:8188"
}
}
}
}
```
Use the venv's Python interpreter path (`.venv/Scripts/python.exe` on Windows,
`.venv/bin/python` on macOS/Linux) if you don't want to rely on a global install.
## Tools
| Tool | Purpose |
|---|---|
| `comfyui_generate_image` | High-level text-to-image: builds a standard txt2img graph and submits it (checkpoint, prompts, size, sampler, steps, cfg, seed, etc.) |
| `comfyui_queue_prompt` | Submit any raw API-format node graph (img2img, ControlNet, LoRA, custom nodes -- anything exported from ComfyUI's "Save (API Format)") |
| `comfyui_get_queue` | List running/pending jobs |
| `comfyui_manage_queue` | Clear pending queue, or remove specific pending jobs |
| `comfyui_get_history` | Get a finished job's result, or list recent history |
| `comfyui_manage_history` | Clear history, or remove specific entries |
| `comfyui_interrupt` | Stop the currently running job |
| `comfyui_free_memory` | Unload models / free VRAM |
| `comfyui_upload_image` | Upload a reference image (for img2img, ControlNet, etc.) |
| `comfyui_upload_mask` | Upload an inpainting mask tied to a reference image |
| `comfyui_view_image` | Fetch actual image bytes for a filename (the only tool that returns image content); optional `max_dim` returns a downscaled thumbnail |
| `comfyui_save_output` | Copy a finished render out of ComfyUI into `COMFYUI_MOUNT_DIR` so the client/sandbox can reach, present, or edit it |
| `comfyui_get_lora_metadata` | Read a LoRA's trigger words / base model / training resolution from its safetensors header (no model load) |
| `comfyui_list_templates` | List server-side workflow templates and the slots each accepts |
| `comfyui_run_template` | Run a named template, filling in only its slots (no hand-retyped graphs) |
| `comfyui_get_progress` | Live progress/ETA (node, step, percent) for a running job, via ComfyUI's websocket |
| `comfyui_get_node_info` | Browse/inspect node types and their input/output schemas |
| `comfyui_list_models` | List model folder types, or filenames within one (checkpoints, loras, vae, ...) |
| `comfyui_list_embeddings` | List installed textual-inversion embeddings |
| `comfyui_get_system_stats` | Python/ComfyUI version + per-device VRAM/RAM |
## Design notes
- **Endpoint shapes were verified against ComfyUI's actual `server.py`**
(fetched from `comfyanonymous/ComfyUI` master), not assumed, since the API
has no formal versioned spec.
- **Images are references, not inline bytes, by default.** `comfyui_generate_image`
and `comfyui_get_history` return `{filename, subfolder, type}` for each output
image; call `comfyui_view_image` to actually fetch and view one. This keeps
responses small when a batch produces several images, most of which the agent
won't need to inspect.
- **Large ComfyUI payloads are summarized by default.** `/object_info` (all node
schemas) and `/queue`/`/history` (which embed full node graphs) can be tens to
hundreds of KB. `comfyui_get_queue`, `comfyui_get_history`, and
`comfyui_get_node_info` default to condensed output with a `summary=false` /
explicit `node_class` escape hatch for full detail.
- **`wait` + polling for completion; websocket for progress.** Job *completion*
is detected by polling `/history/{prompt_id}` (it only populates once a job
finishes) up to a per-call `timeout` — this maps cleanly onto a synchronous
tool call, and `wait=false` returns immediately with a `prompt_id` to check
later via `comfyui_get_history`. Live *progress* (node/step/percent) can't be
polled from `/history`, so a single background subscription to ComfyUI's `/ws`
websocket caches the latest progress per `prompt_id`, surfaced by
`comfyui_get_progress`. The websocket is best-effort: if it can't connect (or
`websockets` isn't installed), progress reports `"unknown"` and nothing else
breaks.
- **The filesystem bridge (`comfyui_save_output`, `comfyui_get_lora_metadata`).**
These are the only tools that touch the host filesystem. ComfyUI's output/ dir
isn't visible to the client's sandbox, and its API exposes LoRA names but not
their on-disk paths — so both tools read/write local paths directly. Every
access is confined to a configured root (`COMFYUI_MOUNT_DIR` / `COMFYUI_LORA_DIR`)
and validated against directory traversal. `comfyui_save_output` fetches bytes
through the existing `/view` endpoint rather than reading ComfyUI's output dir
directly, so it works without knowing where ComfyUI stores files.
- **Server-side workflow templates.** `comfyui_run_template` renders a stored
API graph (`comfyui_mcp/templates/*.json`) by substituting typed *slots* —
`"{{seed}}"` as a whole value keeps its int/bool/null type; `"{{x}}"` inside a
longer string is spliced as text. A graph that references an undeclared slot is
rejected before submission, rather than shipping a literal `{{typo}}`. Add your
own canonical graphs (Krea2 base, film-grain tail, caption stack) as new files
in that directory.
- **No response_format (json/markdown) toggle.** Every tool returns plain JSON.
For a single-user local tool this is simpler and more predictable than
maintaining two output shapes per tool; revisit if this ever needs to serve a
chat-facing UI that benefits from markdown.
- **Newer `/api/jobs` endpoint intentionally not used.** ComfyUI's current
master branch has a richer job-status API (`/api/jobs/{id}` with explicit
pending/in_progress/completed/failed status), but it's very recent and may
not exist on older ComfyUI installs. `/history` + `/queue` are long-standing
and work everywhere, so they're used for polling instead. Worth revisiting if
you're always running latest ComfyUI.
## Testing
Run the unit tests:
```bash
.venv\Scripts\python.exe -m pytest tests/ -q
```
They cover the pure logic in the newer tools without needing a live ComfyUI:
the safetensors metadata reader, template loading + slot substitution (including
type preservation and undeclared-slot rejection), path-traversal safety, the
`http`→`ws` URL derivation, the progress tracker's websocket-message handling,
the `prompt`/`slots` JSON-string coercion, and image downscaling. All 20 tools
also register cleanly with FastMCP.
**Exercise the filesystem/networked tools against a real ComfyUI instance**
before relying on them — checkpoint/sampler/scheduler names are install-specific
(use `comfyui_list_models` and `comfyui_get_node_info(node_class="KSampler")`),
and `comfyui_save_output` / `comfyui_get_lora_metadata` depend on the
`COMFYUI_MOUNT_DIR` / `COMFYUI_LORA_DIR` paths being correct for your machine.
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues