> ## Documentation Index
> Fetch the complete documentation index at: https://comfyui-mcp.artokun.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> Environment variables, transports, and connection targeting.

All configuration is via environment variables (set in the server's `env` block in
`~/.claude/settings.json`) or CLI flags. Precedence for the ComfyUI target:
`--comfyui-url` / `COMFYUI_URL` → `COMFYUI_HOST`/`COMFYUI_PORT` → auto-detection.

## Deployment modes

`comfyui-mcp` operates in one of three modes, auto-selected from the environment:

| Mode       | Trigger                                                       | Local FS? | Process control? | WebSocket?        |
| ---------- | ------------------------------------------------------------- | --------- | ---------------- | ----------------- |
| **Local**  | default                                                       | yes       | yes              | yes               |
| **Remote** | `--comfyui-url` / `COMFYUI_URL` points at a non-loopback host | no        | no               | yes               |
| **Cloud**  | `COMFYUI_API_KEY` is set (targets Comfy Cloud)                | no        | no               | no (HTTP polling) |

Tools that require a local install (`restart_comfyui` with `action: "start"` / `apply_manifest` / `list_local_models` (`action:"remove"`) / `get_image (action:"list_outputs")` / etc.)
return a clear error when running in remote or cloud mode. In remote and cloud modes the server skips
local `COMFYUI_PATH` auto-detection so a stale local install can't silently absorb uploads or model
downloads the agent intends for the actual target — set `COMFYUI_PATH` explicitly if you want to
mix-and-match.

## Connection

<ParamField path="COMFYUI_URL" type="string">
  Full URL of the ComfyUI instance, e.g. `https://my-comfy.example.com`. Equivalent to the
  `--comfyui-url` CLI flag. Takes precedence over host/port and skips port auto-detection.
  A **path prefix is preserved** (e.g. `https://host/comfyapi`) so reverse-proxied instances
  route correctly. When the host is non-loopback (anything other than `127.0.0.1` / `localhost` /
  `::1` / `0.0.0.0`), the server enters **remote mode** and skips `COMFYUI_PATH` auto-detection.
</ParamField>

<ParamField path="COMFYUI_HOST" type="string" default="127.0.0.1">
  Host of the ComfyUI server.
</ParamField>

<ParamField path="COMFYUI_PORT" type="number">
  Port of the ComfyUI server. Auto-detected (8188, then 8000) when unset.
</ParamField>

<ParamField path="COMFYUI_SSL" type="boolean" default="false">
  Use `https`/`wss` instead of `http`/`ws`.
</ParamField>

<ParamField path="COMFYUI_PATH" type="string">
  Absolute path to the local ComfyUI install. Auto-detected from common locations when unset
  (suppressed in remote/cloud modes). Required by local-only tools (install/manage nodes, remove
  models, read logs, list output files).
</ParamField>

## Remote behind a reverse proxy / API gateway

For a self-hosted ComfyUI exposed under a path prefix and/or its own auth layer (an nginx
route, an API gateway, an SSO edge) — this is **not** Comfy Cloud:

* `COMFYUI_URL` **preserves a path prefix** (e.g. `https://host/comfyapi`), so requests route
  under it instead of hitting `/prompt`, `/system_stats`, … at the root.
* The `COMFYUI_AUTH_*` variables attach a generic auth header to **every** ComfyUI request
  (the direct HTTP calls and the underlying client/WebSocket library). This is independent of
  cloud mode, so a gateway-auth'd instance is never misread as Comfy Cloud.

<ParamField path="COMFYUI_AUTH_TOKEN" type="string">
  Auth token for a self-hosted ComfyUI behind a gateway. When set, sent on every ComfyUI
  request. Never logged.
</ParamField>

<ParamField path="COMFYUI_AUTH_HEADER" type="string" default="Authorization">
  Header name that carries the token, e.g. `X-API-Key`.
</ParamField>

<ParamField path="COMFYUI_AUTH_SCHEME" type="string" default="Bearer for Authorization, else none">
  Scheme prefix on the token value, e.g. `Bearer`, `Token`.
</ParamField>

<ParamField path="CF_ACCESS_CLIENT_ID" type="string">
  Cloudflare Access **service token** Client ID. Set together with
  `CF_ACCESS_CLIENT_SECRET` to reach a ComfyUI fronted by Cloudflare Access — both
  are sent (as `CF-Access-Client-Id` / `CF-Access-Client-Secret`) on **every**
  ComfyUI request (HTTP and the queue-watcher WebSocket), so the connector passes
  the Access gate instead of getting the interactive sign-in page. Additive to
  `COMFYUI_AUTH_TOKEN`; both take effect if both are set. Never logged.
</ParamField>

<ParamField path="CF_ACCESS_CLIENT_SECRET" type="string">
  Cloudflare Access service token Client Secret (the pair to `CF_ACCESS_CLIENT_ID`).
  Only sent when **both** are set — a half-configured token is ignored. Never logged.
</ParamField>

```bash theme={null}
# Authorization: Bearer <token>, requests under /comfyapi
COMFYUI_URL=https://gateway.example.com/comfyapi COMFYUI_AUTH_TOKEN=<token> npx -y comfyui-mcp@latest
# custom header: X-API-Key: <token>
COMFYUI_URL=https://gateway.example.com/comfyapi COMFYUI_AUTH_HEADER=X-API-Key COMFYUI_AUTH_TOKEN=<token> npx -y comfyui-mcp@latest
# ComfyUI behind Cloudflare Access — pass a service token (keeps the human sign-in page up)
COMFYUI_URL=https://comfy.example.com CF_ACCESS_CLIENT_ID=<id>.access CF_ACCESS_CLIENT_SECRET=<secret> npx -y comfyui-mcp@latest
```

## Comfy Cloud

Setting `COMFYUI_API_KEY` switches the server into **cloud mode**: all HTTP-backed primitives
(enqueue, history, system stats, queue, view, upload) route to `cloud.comfy.org` over HTTPS with
`X-API-Key` authentication; WebSocket and local-FS/process tools throw a clear `CLOUD_UNSUPPORTED`
error. Architecture and `cloud-client` dispatcher originally contributed by
[@picoSols](https://github.com/picoSols).

<Note>
  **Comfy-Org ships [official agent tooling](https://docs.comfy.org/agent-tools)** — Comfy Cloud MCP (public beta) and the Comfy In-App Agent (private alpha), both maintained by the Comfy team and both running on Comfy Cloud. If you only target Comfy Cloud, that's likely the right choice; see [Local vs. Comfy Cloud](./local-vs-comfy-cloud). `comfyui-mcp`'s cloud-mode below is best when you want a single MCP across local / remote / cloud, or you need it today (it's MIT and shipping now).
</Note>

<ParamField path="COMFYUI_API_KEY" type="string">
  Comfy Cloud API key. When set, the server enters cloud mode and talks to the configured cloud
  URL instead of a local ComfyUI. Never logged.
</ParamField>

<ParamField path="COMFYUI_CLOUD_URL" type="string" default="https://cloud.comfy.org">
  Override the Comfy Cloud endpoint (mainly for testing / staging).
</ParamField>

## Tokens

<ParamField path="CIVITAI_API_TOKEN" type="string">
  CivitAI API token. Used for gated/early-access downloads. Sent as a bearer header (never in URLs).
</ParamField>

<ParamField path="HUGGINGFACE_TOKEN" type="string">
  HuggingFace token for higher search/download rate limits.
</ParamField>

<ParamField path="HF_ENDPOINT" type="string">
  HuggingFace mirror endpoint for network-restricted regions (e.g.
  `https://hf-mirror.com`). All `huggingface.co` API and download URLs are
  rewritten to this host; your `HUGGINGFACE_TOKEN` still rides along for gated
  repos. The de-facto standard var — the same one `huggingface_hub` honors.
</ParamField>

<ParamField path="CIVITAI_ENABLED" type="string">
  Set to `0` to disable Civitai access entirely (regions where civitai.com is
  unreachable). User-initiated Civitai tools fail fast with a clear "disabled
  by config" message instead of hanging; background provenance lookups
  quietly no-op.
</ParamField>

<ParamField path="GITHUB_TOKEN" type="string">
  GitHub token used by skill generation and node-metadata fetches to avoid rate limits.
</ParamField>

<ParamField path="COMFY_API_KEY" type="string">
  comfy.org API key forwarded to hosted API nodes via the `/prompt` `extra_data` payload.
  If the env var is unset, the key is read from `~/.comfy-api-key` (trimmed file
  contents; `chmod 600` recommended) — handy for headless setups that keep secrets
  out of environment/process listings.
</ParamField>

<ParamField path="REGISTRY_ACCESS_TOKEN" type="string">
  Comfy Registry API key used by `node_pack` (`action: "publish"`) to publish a node pack. Passed to comfy-cli via env, never placed in args or logs.
</ParamField>

## Behavior

<ParamField path="COMFYUI_WORKFLOWS_DIR" type="string" default="~/.comfyui-mcp/workflows">
  Directory scanned for `*.json` workflows. Each becomes an auto-loaded run tool.
</ParamField>

<ParamField path="LOG_LEVEL" type="string" default="info">
  Logging verbosity: `debug`, `info`, `warn`, `error`.
</ParamField>

## Model downloads

<ParamField path="COMFYUI_DOWNLOAD_CACHE_DIR" type="string" default="~/.comfyui-mcp/cache">
  Content-addressed cache for model downloads. Repeat or concurrent downloads of the same URL reuse the cached file; the target model path is materialized via hardlink (falling back to copy).
</ParamField>

<ParamField path="COMFYUI_LRU_CACHE_SIZE_GB" type="number" default="0">
  Max size of the download cache in GB. `0` disables eviction; above the limit, least-recently-used cached files are deleted after a download completes.
</ParamField>

## Process supervision (local installs)

Applies to `restart_comfyui` (actions `start` and `restart`) when comfyui-mcp manages a local ComfyUI process.

<ParamField path="COMFYUI_STARTUP_CHECK_INTERVAL_S" type="number" default="1">
  Seconds between readiness probes after launching ComfyUI.
</ParamField>

<ParamField path="COMFYUI_STARTUP_CHECK_MAX_TRIES" type="number" default="60">
  Maximum readiness probes before reporting that startup is not confirmed. With the
  default 1s interval this is a \~60s budget. It was raised from 20 because ComfyUI
  with a normal set of custom nodes routinely takes longer than 20s to answer
  `/system_stats` on a cold start, and the shorter budget reported a startup as
  unconfirmed moments before a healthy instance became ready.

  Exhausting the budget means startup is **not confirmed yet** — not that it failed.
</ParamField>

<ParamField path="COMFYUI_ALWAYS_RESTART" type="boolean" default="false">
  When enabled, a ComfyUI process that exits unexpectedly is automatically restarted. A deliberate `restart_comfyui` with `action: "stop"` is never restarted.
</ParamField>

<ParamField path="COMFYUI_RESTART_MAX_ATTEMPTS" type="number" default="3">
  Maximum auto-restarts allowed within the restart window before giving up.
</ParamField>

<ParamField path="COMFYUI_RESTART_WINDOW_S" type="number" default="60">
  Sliding window (seconds) over which auto-restart attempts are counted.
</ParamField>

## Panel orchestrator & the bridge

The [comfyui-mcp-panel](https://github.com/artokun/comfyui-mcp-panel) sidebar is
driven by the **panel orchestrator** — a background process that owns a loopback
WebSocket bridge and runs an autonomous Claude Agent SDK session per panel tab on
your **Claude subscription** (no API keys). The panel pack auto-starts it on
ComfyUI load, so you normally don't run anything by hand — see
[Sidebar Panel](./panel). To run it yourself:

```bash theme={null}
npx -y comfyui-mcp@latest connect
```

<ParamField path="COMFYUI_MCP_PANEL_ORCHESTRATOR" type="boolean" default="false">
  Run the panel orchestrator instead of an MCP server (same as `--panel-orchestrator`).
</ParamField>

<ParamField path="COMFYUI_MCP_PANEL_MODEL" type="string" default="claude-opus-5">
  Model for the background panel agents.
</ParamField>

<ParamField path="COMFYUI_MCP_BRIDGE_PORT" type="number" default="9180">
  Loopback port for the panel WebSocket bridge that the **panel orchestrator**
  owns (default **9180**).
</ParamField>

<ParamField path="COMFYUI_MCP_STALL_S" type="number" default="180">
  Render-stall threshold (seconds) for the orchestrator's queue/render watchdog: a
  running job whose node/progress hasn't advanced for this long is flagged as stalled,
  and a one-line STALL/BACKLOG note is prepended to the agent's next turn. Video steps
  are legitimately slow, so the default is high. Clamped to **15–3600s**. The panel's
  **Render stall warning (seconds)** setting (Settings → Comfy MCP Agent → General)
  overrides this **live** via a `set_config` bridge frame — no reconnect needed —
  taking precedence over this env value.
</ParamField>

### Secure bridge (driving a remote/cloud pod)

When `connect <url>` targets a **remote https** ComfyUI (e.g. a RunPod pod), the
pod's HTTPS panel page can't open a plain `ws://127.0.0.1` socket to the bridge on
your machine — browsers block it (mixed content / Private Network Access). The
orchestrator automatically upgrades to a secure `wss://` tunnel so it works with
no prompt, in any browser. See [Cloud deployment](./cloud-deployment) for the full
walkthrough and [Self-hosted relay](./self-hosted-relay) for running your own
tunnel infrastructure instead of the default cloudflared quick tunnel.

<ParamField path="COMFYUI_MCP_INSECURE_BRIDGE" type="boolean" default="false">
  Force the plain loopback `ws://` bridge even when driving a remote https
  target, instead of auto-upgrading to a secure tunnel. Use this if you reach
  the pod through your own SSH port-forward (so its page is already a loopback
  origin) and don't want a Cloudflare dependency. Same as `--insecure-bridge`.
</ParamField>

<ParamField path="COMFYUI_MCP_TUNNEL_BACKEND" type="string" default="cloudflared">
  Which secure-bridge backend to use for a remote target: `cloudflared` (default
  — an ephemeral quick tunnel, zero setup) or `relay` (dial a
  [self-hosted relay](./self-hosted-relay) you operate, for a stable domain and no
  third-party quick-tunnel dependency). Only takes effect when secure mode is
  active (remote https target, not `COMFYUI_MCP_INSECURE_BRIDGE`).
</ParamField>

<ParamField path="COMFYUI_MCP_RELAY_URL" type="string">
  Your relay's `wss://` URL. Required when `COMFYUI_MCP_TUNNEL_BACKEND=relay`.
</ParamField>

<ParamField path="COMFYUI_MCP_RELAY_KEY" type="string">
  Optional shared secret gating who can open a session on your relay at all
  (`?key=`), independent of the per-session bridge token. Only relevant in relay
  mode, and only if your relay deployment sets `RELAY_ACCESS_KEY`.
</ParamField>

## Job watching

Completion notifications for enqueued jobs are tracked by a watcher (WebSocket where
available, HTTP polling otherwise).

<ParamField path="COMFYUI_JOB_TIMEOUT_S" type="number" default="1800">
  Maximum seconds the watcher waits for a job to complete before giving up. Raise this
  for very long video renders or heavy multi-stage workflows. (The job itself keeps
  running in ComfyUI — only the completion notification is abandoned.)
</ParamField>

<ParamField path="COMFYUI_JOB_POLL_INTERVAL_S" type="number" default="2">
  Seconds between HTTP history polls while a job is being watched.
</ParamField>

<ParamField path="COMFYUI_MCP_INTERRUPT_S" type="number" default="30">
  Cancel honor window (seconds) for `queue` (action:"cancel"): how long to wait for an
  interrupt to
  actually stop the running job before escalating (to `/free`, then reporting the render
  WEDGED). ComfyUI only checks the interrupt flag between nodes/steps, so a multi-minute
  single step won't honor it immediately — this wait is what detects a true wedge.
</ParamField>

## Restricting the tool surface

For a **hosted** deployment — a shared Open WebUI, a team frontend — the operator is not
the person prompting. These variables withhold tools from the model entirely: a withheld
tool is never registered, so it is absent from `tools/list`, absent from `call_tool`, and
the model never learns it exists.

<ParamField path="COMFYUI_MCP_TOOL_PRESET" type="string">
  `safe` — everything except tools that change the machine or the model library.
  Installing, deleting and restarting are withheld. **Rendering still works, and so do
  the things that come with it**: queueing generations, `list_api_nodes` (hosted partner
  nodes that spend PAID credits), and `report_issue` (files a public GitHub issue). Use
  `readonly` if a shared frontend's users must not be able to spend or publish.
  `readonly` — inspection only: no renders queued, nothing written, nothing spent.
  Both also withhold the whole `panel_*` surface, which drives a live shared canvas.
</ParamField>

<ParamField path="COMFYUI_MCP_TOOL_DENY" type="string">
  Comma-separated tool names to withhold, e.g. `restart_comfyui,download_model`. A
  trailing `*` matches a family: `train_*`. Applied on top of any preset **and** on top
  of an allow list.
</ParamField>

<ParamField path="COMFYUI_MCP_TOOL_ALLOW" type="string">
  Comma-separated allow list. When set, the surface is **exactly** these tools — anything
  not named is withheld even if no deny rule mentions it. Use it to opt individual tools
  back in past a preset: `COMFYUI_MCP_TOOL_PRESET=safe` plus
  `COMFYUI_MCP_TOOL_ALLOW=panel_graph_outline,panel_query_graph`.

  Only an **exact name** opts a tool back in past a preset. A glob (`list_*`) narrows the
  surface like any other entry but cannot re-open what a preset closed — otherwise
  `ALLOW=list_*` would re-admit `list_packs`, whose `install_deps` action installs and
  runs third-party code, and `ALLOW=*` would make every preset inert.
</ParamField>

```bash A hosted deployment that cannot install or restart anything theme={null}
COMFYUI_MCP_TOOL_PRESET=safe npx comfyui-mcp@latest --http --host 0.0.0.0 --port 9100
```

<Warning>
  This is a boundary against the **model** and the people prompting it — not against
  whoever sets the environment, who can simply unset it, and not a substitute for keeping
  an untrusted party off the ComfyUI host.

  A misconfiguration **refuses to start** rather than starting unrestricted: an unknown
  preset name, or a variable that is set but empty (an unexpanded `${VAR}` in a compose
  file), aborts with the reason. Coming up with a full tool surface while you believe it
  is restricted is worse than having no filter at all.
</Warning>

## Transport

The server speaks **stdio** by default (what Claude Code expects). It can also serve the
**streamable-HTTP** transport for remote/multi-client setups.

<ParamField path="MCP_TRANSPORT" type="string" default="stdio">
  `stdio` or `http`. Equivalent flags: `--stdio`, `--http`.
</ParamField>

<ParamField path="MCP_HOST" type="string" default="127.0.0.1">
  HTTP bind host (with `--http`). Flag: `--host`.
</ParamField>

<ParamField path="MCP_PORT" type="number" default="9100">
  HTTP bind port (with `--http`). Flag: `--port`.
</ParamField>

```bash Run the HTTP transport theme={null}
npx comfyui-mcp@latest --http --host 0.0.0.0 --port 9100 --comfyui-url https://my-comfy.example.com
```
