> ## 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.

# Models

> Search (HuggingFace + CivitAI), download, list, and remove models; resolve a workflow's missing models with VRAM-aware candidates; manage embeddings and VRAM.

<Info>4 tools. Generated from the live MCP tool schemas — do not edit by hand; run `npm run docs:gen`.</Info>

<Tip>**You don't type these calls.** Ask your agent for what you want in ordinary English — it chooses the tool and fills in the arguments. The JSON on this page is what it sends. New here? Start with [Using the tools](/docs/using-tools).</Tip>

## download\_model

Find model weights and get them onto the connected ComfyUI, and track the transfers. Driven by the `action` parameter:

* action:"download" — Download a model file to the connected ComfyUI's models directory from a URL (HuggingFace, direct HTTP(S), s3://, or Azure Blob). Requires `url` + `target_subfolder`. PREFER this over a raw shell download (curl/wget) for model weights: it lands the file in the right models/ subfolder. LOCAL ComfyUI: streams to disk and surfaces live progress in the panel download tray. REMOTE ComfyUI: dispatches the fetch to the ComfyUI host via the ComfyUI-Manager install-model HTTP API (downloaded server-side; a per-request `auth` header can't be forwarded). This requires the host's Manager to run with network\_mode=personal\_cloud (or loopback) and a permissive security level — a stricter gate silently rejects the download, and Manager reports the queue task 'done' even on failure, so a remote dispatch does not guarantee the file landed. target\_subfolder accepts any relative subfolder (incl. nested, e.g. 'loras/\<subdir>').
* action:"status" — Check on downloads started by action:"download" / action:"download\_civitai". Reports each download's state (downloading / done / error / cancelled), its destination path once it lands, and byte progress when the panel progress channel is enabled. Use this after a download reports it is still running — that means the transfer is in flight, NOT that it failed. Across an AGENT/sidebar session reconnect a download this MCP streams locally keeps running and is normally resolvable by `id` or by `url`. An ORCHESTRATOR RESTART is different: a record carried across one reports only that this MCP STOPPED WATCHING — not that the bytes stopped, which it does not check. READ THE NOTE ON THAT RECORD before acting: it distinguishes a local stream (nothing is writing it; re-issue) from a ComfyUI-Manager dispatch (the fetch runs on the ComfyUI host, which a restart here does not touch, so re-issuing writes a second copy to the same destination and CORRUPTS the model). And NOT FOUND NEVER MEANS STOPPED: both the cross-session record and the carry-over are written best-effort, so their absence is evidence of nothing. Omit `id` and `url` to list every tracked download. A previous session's download whose heartbeat has gone stale is reported with a stale-heartbeat NOTE: action:"cancel" can close it once the writer is proven gone, and re-issuing action:"download" then resumes or restarts it. Read-only.
* action:"cancel" — Cancel ONE in-flight download by its `id` (from action:"status" or from the download that started it) — REQUIRED, and it must be the id of the download you mean, since a wrong id stops someone else's transfer. Aborts only that download's transfer; other downloads keep running. An id that names no tracked download is reported as such, not silently treated as success. The partially-downloaded bytes are left on disk as a resumable .partial and are NEVER reported as a completed file, so nothing corrupt lands in your models directory; re-issuing the same download later resumes where it left off. Idempotent: cancelling an already-finished, failed, or already-cancelled download just reports its current state. A download whose AbortController lives in ANOTHER live session cannot be aborted from here (stop it from the panel download tray) — but a download left 'downloading' by a session that is PROVEN gone (heartbeat stale AND its process no longer exists) CAN be cancelled from here: the stale record is closed as cancelled, after which re-issuing action:"download" resumes the leftover .partial or restarts cleanly. While the writer cannot be proven gone, the cancel refuses rather than risk two writers on one file. NOTE: for a download dispatched to a REMOTE ComfyUI via ComfyUI-Manager (server-side fetch), the local job is marked cancelled but the host may keep fetching — there is no Manager API to stop it.
* action:"search" — Search HuggingFace Hub for models usable in ComfyUI (checkpoints, LoRAs, VAEs, ControlNets, etc.); `query` is required. Read-only and network-only: queries HuggingFace over HTTP, does NOT require a running ComfyUI or COMFYUI\_PATH and does not download anything. Returns a ranked list with modelId, author, downloads, likes, and tags. Pick a result's download URL and pass it to action:"download". For CIVITAI searches ('find a Flux LoRA on Civitai') use action:"search\_civitai" instead — it filters by type + base model and returns ids for action:"download\_civitai". For packs of custom nodes (not models) use search\_custom\_nodes.
* action:"search\_civitai" — Search CivitAI by keyword for checkpoints, LoRAs, embeddings, VAEs, and ControlNets — THE action for 'find me a \<base model> LoRA on Civitai'. Read-only and network-only (public CivitAI REST API; no token or running ComfyUI required; CIVITAI\_API\_TOKEN unlocks gated results). Filter by `types` (LORA, Checkpoint, TextualInversion, VAE, Controlnet, …) and `base_models` (CivitAI labels: 'Flux.1 D', 'SDXL 1.0', 'SD 1.5', 'Pony', 'Illustrious', 'Wan Video') — ALWAYS pass base\_models when the user's checkpoint family is known, so results actually fit their setup. Each hit returns the model\_id and version\_id that action:"download\_civitai" takes directly, plus trigger words to use in the prompt after installing. Flow: action:"search\_civitai" → pick a hit → action:"download\_civitai" \{model\_version\_id, target\_subfolder} → wire/prompt with the trained words. Pass `creator` (exact username, e.g. from action:"search\_creators") to list ONE creator's models — with or without a `query`; at least one of the two is required. SFW-only by default. For HuggingFace search use action:"search".
* action:"search\_creators" — Find CivitAI CREATORS — THE action for 'who are the top creators on Civitai' and 'find creator \<name>'. Read-only and network-only (no token or running ComfyUI required). Two modes: with NO `query` it returns the site's creator LEADERBOARD (civitai.com/leaderboard — rank, score, downloads, likes; pick a `board`: 'overall' \[default], 'overall\_90' \[last 90 days], 'overall\_nsfw' \[mature], 'new\_creators' \[first model \<30 days ago]); with a `query` it searches usernames (public /api/v1/creators; partial match, returns model counts, NOT ranked). Each hit's username feeds action:"search\_civitai" \{creator: \<username>} directly. SCOPE CAVEAT: the /api/v1/creators index only lists creators who have published MODELS. A creator who posts only images/videos (no models) legitimately returns 0 hits here — that is a gap in this endpoint, NOT proof the creator doesn't exist. For a media-only creator, browse their images via the panel CivitAI browser (panel\_open\_civitai \{creator}) or the logged-in browser session instead.
* action:"download\_civitai" — Download a model from CivitAI into the connected ComfyUI's models/ directory. Requires `target_subfolder` plus at least one of `model_id` / `model_version_id`. Resolves a CivitAI model id (latest version) or a model-version id to a download URL via the CivitAI REST API. LOCAL ComfyUI (COMFYUI\_PATH set): streams the file to disk under \<COMFYUI\_PATH>/models/\<target\_subfolder>/ and returns the saved absolute path. REMOTE ComfyUI: dispatches the download to the ComfyUI host via the ComfyUI-Manager install-model HTTP API (fetched server-side). Gated/early-access models require CIVITAI\_API\_TOKEN locally (sent as a bearer header, never in the URL); remote Manager-side fetches rely on tokens configured on the ComfyUI host. NOTE (remote): the server-side install requires the host's ComfyUI-Manager to run with network\_mode=personal\_cloud (or loopback) and a permissive security level; a stricter gate silently rejects the download, and Manager reports the queue task 'done' even on failure — so a remote dispatch does not guarantee the file landed.
* action:"resolve\_missing" — Find the model files a `workflow` needs but this ComfyUI does NOT have, and search CivitAI + HuggingFace for installable candidates. THE action for 'this Template says a model is missing — go get it'. Detects by comparing each model widget against the option list the server actually publishes, so it covers checkpoints, LoRAs, VAEs, ControlNets, UNets, CLIP and custom-pack model types without any per-node mapping. Each candidate reports size, source, precision/quantisation (fp16 / fp8 / GGUF Q4\_K\_M …) and whether it FITS this GPU's VRAM — so when the exact file is too big you can see the quantised variant that isn't. Read-only: it downloads nothing. Pass a chosen candidate to action:"download" (url) or action:"download\_civitai" (id), using the reported directory as target\_subfolder. For missing custom NODE PACKS (not models) use list\_packs (action:"install\_deps") instead.

<Tip>**In plain terms:** Everything to do with GETTING a model: searching HuggingFace or CivitAI, fetching the file, and watching or stopping the transfer. The `action:"resolve_missing"` one is the answer to "this workflow says a model is missing" — it works out what is actually absent and finds downloadable candidates, including smaller quantised versions when the full file will not fit your GPU.</Tip>

### Parameters

<ParamField path="action" type="enum" required>
  Which model operation to perform. "download" requires `url` + `target_subfolder`; "status" takes an optional `id`/`tray_id`/`url` (omit all three to list everything); "cancel" requires `id` (optional `tray_id`); "search" requires `query`; "search\_civitai" requires `query` and/or `creator`; "search\_creators" takes an optional `query` (omit for the leaderboard `board`); "download\_civitai" requires `target_subfolder` plus `model_id` and/or `model_version_id`; "resolve\_missing" requires `workflow`.
  Options: `action:"download"`, `action:"status"`, `action:"cancel"`, `action:"search"`, `action:"search_civitai"`, `action:"search_creators"`, `action:"download_civitai"`, `action:"resolve_missing"`.
</ParamField>

<ParamField path="url" type="string">
  REQUIRED for action:"download" — the direct download URL for the model file. OPTIONAL for action:"status" — adopt an in-flight download by its source URL when you don't have the id (e.g. after a reconnect); reports the matching job without starting a duplicate.
</ParamField>

<ParamField path="target_subfolder" type="string">
  REQUIRED for action:"download" and action:"download\_civitai". Target subfolder under ComfyUI models/. Standard names: checkpoints, loras, vae, upscale\_models, controlnet, embeddings, clip, diffusers, diffusion\_models, gligen, hypernetworks, photomaker, style\_models, text\_encoders, unet. Any other relative subfolder (incl. nested like 'loras/\<subdir>') is allowed; absolute paths and '..' escapes are rejected.
</ParamField>

<ParamField path="filename" type="string">
  action:"download" — override filename (auto-detected from the URL if omitted). action:"download\_civitai" — override the saved filename (defaults to the CivitAI file name, or the URL basename).
</ParamField>

<ParamField path="auth" type="object">
  action:"download" — optional per-request authentication for private/gated model URLs. When provided it overrides built-in HuggingFace/CivitAI token handling.
</ParamField>

<ParamField path="id" type="string">
  The download id. REQUIRED for action:"cancel" — this is the handle that says WHICH transfer to stop, so take it from action:"status" (or from the reply that started the download) rather than guessing; an id that matches nothing is reported as not found. OPTIONAL for action:"status" — omit to list every tracked download (incl. in-flight ones from before a reconnect).
</ParamField>

<ParamField path="tray_id" type="string">
  action:"status" / action:"cancel" — use this when two rows come back with the SAME `id`, so the id alone cannot say which one you mean. That happens when two different source URLs are downloading to the same destination file. Every row prints its own tray id as `(tray &lt;tray_id&gt;)` — pass that here, together with `id`, to report on (or stop) exactly one of them.
</ParamField>

<ParamField path="query" type="string">
  REQUIRED for action:"search" — the HuggingFace search query (e.g. 'SDXL', 'flux', 'controlnet'). action:"search\_civitai" — keyword search (e.g. 'detail enhancer', a character name); optional when `creator` is given (then it narrows that creator's models). action:"search\_creators" — username search (partial match, e.g. 'alcait'); omit to get the top-creators leaderboard instead.
</ParamField>

<ParamField path="filter" type="string">
  action:"search" — optional HuggingFace pipeline/library tag to narrow results, e.g. 'diffusers' or 'text-to-image'.
</ParamField>

<ParamField path="limit" type="integer">
  Max results (default 10, or 8 candidates per missing model for action:"resolve\_missing"). Per-action ceilings, unchanged from the tools this folds in: "search" 50, "search\_civitai" 25, "search\_creators" 50, "resolve\_missing" 20.
</ParamField>

<ParamField path="creator" type="string">
  action:"search\_civitai" — only models by this CivitAI creator (EXACT username — find it with action:"search\_creators"). At least one of query/creator is required.
</ParamField>

<ParamField path="types" type="enum[]">
  action:"search\_civitai" — only these model types (e.g. \['LORA']).
</ParamField>

<ParamField path="base_models" type="string[]">
  action:"search\_civitai" — only these base-model families, CivitAI labels: 'Flux.1 D', 'SDXL 1.0', 'SD 1.5', 'Pony', 'Illustrious', 'Wan Video', …
</ParamField>

<ParamField path="sort" type="enum">
  action:"search\_civitai" — ranking (default 'Highest Rated').
  Options: `Highest Rated`, `Most Downloaded`, `Newest`.
</ParamField>

<ParamField path="nsfw" type="boolean">
  action:"search\_civitai" — include NSFW results (default false).
</ParamField>

<ParamField path="board" type="enum">
  action:"search\_creators" — leaderboard to rank by when no query is given (default 'overall'). Ignored with a query.
  Options: `overall`, `overall_90`, `overall_nsfw`, `new_creators`.
</ParamField>

<ParamField path="model_version_id" type="integer">
  action:"download\_civitai" — CivitAI model-version id (from the URL ?modelVersionId=...). If both model\_id and model\_version\_id are given, this selects the specific version of that model.
</ParamField>

<ParamField path="model_id" type="integer">
  action:"download\_civitai" — CivitAI model id. The latest version is used unless model\_version\_id is also provided.
</ParamField>

<ParamField path="workflow" type="string | object">
  REQUIRED for action:"resolve\_missing" — the ComfyUI workflow in API format (JSON string or object).
</ParamField>

### Examples

**You say:** Find me a Flux model I can actually run.

```json theme={null}
{
  "tool": "download_model",
  "arguments": {
    "action": "search",
    "query": "flux schnell",
    "limit": 5
  }
}
```

**You get back:** Matching models with their download URLs and file sizes. Nothing is downloaded — this is a search.

**You say:** Get that one.

```json theme={null}
{
  "tool": "download_model",
  "arguments": {
    "action": "download",
    "url": "https://huggingface.co/black-forest-labs/FLUX.1-schnell/resolve/main/flux1-schnell.safetensors",
    "target_subfolder": "checkpoints"
  }
}
```

**You get back:** Live progress in the panel's download tray, and the path the file landed at. `target_subfolder` decides which ComfyUI dropdown it shows up in — checkpoints, loras, vae and so on.

<Warning>Model files are large — many are 5-25 GB. Check you have the disk space before agreeing to a few of these.</Warning>

**You say:** Is that download still going?

```json theme={null}
{
  "tool": "download_model",
  "arguments": {
    "action": "status"
  }
}
```

**You get back:** Every tracked download with its state and byte progress. Pass an `id` to ask about just one.

**You say:** This workflow won't run, it says something's missing. Find it for me.

```json theme={null}
{
  "tool": "download_model",
  "arguments": {
    "action": "resolve_missing",
    "workflow": {
      "4": {
        "class_type": "CheckpointLoaderSimple",
        "inputs": {
          "ckpt_name": "sd_xl_base_1.0.safetensors"
        }
      },
      "9": {
        "class_type": "SaveImage",
        "inputs": {
          "filename_prefix": "portrait",
          "images": [
            "8",
            0
          ]
        }
      }
    }
  }
}
```

<Note>Shortened for readability — two nodes of a real API-format graph are shown. In practice the agent passes the whole thing: the graph it just loaded with get\_workflow, or the one it built for you.</Note>

**You get back:** Each missing file with candidate downloads, their sizes and precision, and whether each one fits your VRAM. It downloads nothing — you pick, then it fetches.

***

## list\_local\_models

Inspect what models this ComfyUI has installed, and where it looks for them. Driven by the `action` parameter:

* action:"list" — List model files available to the connected ComfyUI, grouped by type. Read-only. Queries ComfyUI's /models REST endpoint first (works with remote ComfyUI and respects extra\_model\_paths.yaml — symlinked / mounted dirs the install-path filesystem scan would miss), then falls back to a filesystem scan of COMFYUI\_PATH/models/ when the REST endpoint is unavailable. Size and modified time are only available on the filesystem fallback path. Use to see which models are already available before generating or downloading; use download\_model action:"search" to discover new models on HuggingFace, then action:"download" to fetch them. For models fetched via download\_model action:"download\_civitai", any CivitAI trigger/activation words and base model are shown inline (read from the `&lt;file&gt;.civitai.json` sidecar) — apply those trigger words in your prompt when generating with that model. A `civitai:` line under an entry is that model's CivitAI page URL (modelId + INSTALLED modelVersionId, from the same sidecar) — use it to reference the source or check for newer versions.
* action:"remove" — DELETES a model FILE from the local ComfyUI models directories. `path` is REQUIRED and is a file path relative to models/. THIS IS DESTRUCTIVE AND HAS NO UNDO: the file is unlinked, not moved to a recycle bin, and a large checkpoint can take hours to re-download — confirm the exact path with the user (action:"list" shows it) before calling. Resolves the path across ALL configured roots — the primary \<COMFYUI\_PATH>/models AND every directory in extra\_model\_paths.yaml / extra\_models\_config.yaml (e.g. models stored on another drive like E:) — the same roots ComfyUI loads from. The path must stay within a known root (path traversal and absolute escapes are rejected), and a directory is refused. LOCAL-ONLY: deletes from the local filesystem, so it is not supported against a remote ComfyUI (remove the file on the host). Do NOT confuse this with action:"remove\_path", which edits a config file and deletes nothing.
* action:"embeddings" — List textual-inversion embeddings installed on the connected ComfyUI server (read from its /api/embeddings endpoint, i.e. the models/embeddings folder). Requires a running, reachable ComfyUI (local or remote); takes no other parameters. Returns the embedding names; reference them in positive or negative prompts as embedding:name (e.g. embedding:easynegative). Read-only.
* action:"list\_paths" — View ComfyUI extra search-path config for standalone/manual installs and ComfyUI Desktop. Read-only. Resolves LIVE-FIRST: the file the running ComfyUI actually reads (its --extra-model-paths-config, else the extra\_model\_paths.yaml beside its main.py), falling back to the local heuristic only when no server is reachable — \<ComfyUI root>/extra\_model\_paths.yaml (COMFYUI\_PATH, else the saved default workspace from workspace action:"set\_default") or the Desktop app-data extra\_models\_config.yaml. Reports generic categories, so model categories and custom\_nodes entries are both visible when present. Because it is read-only it never refuses a reachable LOCAL server just because its argv does not prove which file it reads: it shows the server-named config when that file exists here, else the local auto-selected one, always labelled as unconfirmed rather than presented as the live server's. action:"add\_path"/action:"remove\_path" still refuse in that state — a write to an unproven file would be a silent no-op.
* action:"add\_path" — Add a directory to a ComfyUI extra search-path YAML config; `category` + `path` are REQUIRED. Use this for model categories such as checkpoints/loras/vae and, on ComfyUI builds that support it, custom\_nodes. Writes the config file and returns the updated view; restart ComfyUI to apply.
* action:"remove\_path" — Remove a directory from a ComfyUI extra search-path YAML config; `category` + `path` are REQUIRED. Matches the stored path exactly. This edits the YAML only — it deletes NO model files and frees no disk space (that is action:"remove"). Restart ComfyUI after removing an active path.

<Tip>**In plain terms:** Everything to do with what you ALREADY have: the installed model files, the embeddings, and the extra folders ComfyUI searches. It also has the one delete: `action:"remove"` unlinks a model file.</Tip>

### Parameters

<ParamField path="action" type="enum" required>
  Which inventory operation to perform. "list" (optional `model_type`), "embeddings" and "list\_paths" are READ-ONLY. "remove" DELETES the model file named by `path` — required, and destructive. "add\_path"/"remove\_path" edit the extra-search-path YAML and require `category` + `path`; they never touch model files.
  Options: `action:"list"`, `action:"remove"`, `action:"embeddings"`, `action:"list_paths"`, `action:"add_path"`, `action:"remove_path"`.
</ParamField>

<ParamField path="model_type" type="enum">
  action:"list" — filter by model type (e.g. 'checkpoints', 'loras'). Lists all types if omitted.
  Options: `checkpoints`, `loras`, `vae`, `upscale_models`, `controlnet`, `embeddings`, `clip`, `diffusers`, `diffusion_models`, `gligen`, `hypernetworks`, `photomaker`, `style_models`, `text_encoders`, `unet`.
</ParamField>

<ParamField path="path" type="string">
  REQUIRED by three actions, and it means two DIFFERENT things — read this before calling. action:"remove": the MODEL FILE to DELETE, relative to the ComfyUI models/ directory (e.g. 'checkpoints/sd\_xl\_base\_1.0.safetensors'); the leading segment is the category used to locate the file in extra roots too. action:"add\_path" / action:"remove\_path": a DIRECTORY to add to / remove from the extra-search-path YAML for `category` (absolute paths are safest; relative paths are resolved by ComfyUI) — no file is deleted.
</ParamField>

<ParamField path="target" type="enum">
  action:"list\_paths" / "add\_path" / "remove\_path" — config target. auto (default) is LIVE-FIRST: the running ComfyUI's own --extra-model-paths-config, else the extra\_model\_paths.yaml next to its main.py. When no server is reachable, auto shows the Desktop config if one exists, otherwise standalone. When a reachable LOCAL server does not expose main.py, listing degrades to the server-named config (if it exists here) or the local auto-selected one, explicitly marked as an unconfirmed display fallback; mutations refuse instead. standalone forces \<ComfyUI root>/extra\_model\_paths.yaml, where the root is COMFYUI\_PATH (or an auto-detected install) and falls back to the saved default workspace; desktop forces the OS app-data extra\_models\_config.yaml. Use standalone/desktop (or config\_path) to deliberately target a file the running server does not read.
  Options: `auto`, `standalone`, `desktop`.
</ParamField>

<ParamField path="config_path" type="string">
  action:"list\_paths" / "add\_path" / "remove\_path" — explicit YAML config path override, mainly for advanced/manual installs.
</ParamField>

<ParamField path="group" type="string">
  action:"add\_path" / "remove\_path" — top-level YAML group to edit. Defaults to comfyui\_mcp.
</ParamField>

<ParamField path="category" type="string">
  REQUIRED for action:"add\_path" / action:"remove\_path" — the ComfyUI search-path category, e.g. checkpoints, loras, vae, diffusion\_models, unet\_gguf, or custom\_nodes.
</ParamField>

<ParamField path="is_default" type="boolean">
  action:"add\_path" — set is\_default on a newly-created group. Existing groups are not overwritten.
</ParamField>

### Examples

**You say:** Which checkpoints do I already have?

```json theme={null}
{
  "tool": "list_local_models",
  "arguments": {
    "action": "list",
    "model_type": "checkpoints"
  }
}
```

**You get back:** The model filenames in that folder — the exact strings a workflow needs. Omit `model_type` to see every folder at once.

**You say:** Delete that old LoRA, I'm out of disk space.

```json theme={null}
{
  "tool": "list_local_models",
  "arguments": {
    "action": "remove",
    "path": "loras/old-character-v1.safetensors"
  }
}
```

**You get back:** Confirmation, and how much space came back.

<Warning>This deletes the file. There is no undo and no recycle bin — you would have to download it again. Check the path is the one you mean. Note that `action:"remove_path"` is a different thing entirely: it edits the search-path config and deletes nothing.</Warning>

**You say:** Also look for models on my E: drive.

```json theme={null}
{
  "tool": "list_local_models",
  "arguments": {
    "action": "add_path",
    "category": "checkpoints",
    "path": "E:/Models/checkpoints"
  }
}
```

**You get back:** The updated extra-search-path config. ComfyUI needs a restart before it picks the folder up.

***

## clear\_vram

Free GPU VRAM by unloading cached models from ComfyUI. Use this between generation runs with different model families (e.g. switching from SDXL to Flux) or when running low on VRAM. Optionally unload only models or only memory.

### Parameters

<ParamField path="unload_models" type="boolean" default="true">
  Unload all cached models (default: true)
</ParamField>

<ParamField path="free_memory" type="boolean" default="true">
  Free cached memory/intermediates (default: true)
</ParamField>

### Example

<Note>No worked example yet — the call below is a skeleton generated from the required parameters. Real examples live in `scripts/tool-doc-examples.ts`; contributions welcome.</Note>

```json theme={null}
{
  "tool": "clear_vram",
  "arguments": {}
}
```

***

## model\_metadata

Curate a model file's embedded .safetensors metadata (Model Explorer). Driven by the `action` parameter:

* action:"read" — Read a model file's CURRENT embedded metadata + evidence, for curating it. Returns classify (asset\_type/base/precision/rank), the current model\_card and prompt\_director namespaces, read-only modelspec, top training tags (ss\_tag\_frequency), the Civitai description, and example prompts. Call this FIRST when the user wants to improve/curate a model's embedded .safetensors metadata, so you propose from real data. NOTE: this is the embedded-in-the-tensor metadata (model\_card/prompt\_director/modelspec/ss\_\*) — NOT the separate lora\_catalog. `category` = ComfyUI model folder ('loras','checkpoints','vae',…); `name` = filename incl. .safetensors — BOTH required for read/propose, e.g. \{action:"read", category:"loras", name:"my\_model.safetensors"}. DEPENDENCY: the curated read proxies the OPTIONAL 'comfyui-model-explorer' custom node. When that node is absent but the model file is reachable on the LOCAL filesystem, the tool does NOT hard-fail — it degrades to a structured 'model\_explorer: unavailable' result with local evidence (file stat, the download\_model action:"download\_civitai" sidecar, and the raw embedded safetensors metadata). Without local filesystem access, it still returns the same structured unavailable result, but without file evidence.
* action:"propose" — PROPOSE cleaned embedded metadata into the user's diff-review window. This does NOT write the file — the user sees your proposed fields vs current, edits/discusses, and their Confirm does the write. Call whenever you have a proposal OR the user asks you to revise one; each call REPLACES the live proposal, so send the FULL field set you're proposing. Include only fields you're confident about. Keys: display\_name, description\_clean, semantic\_intent, prompt\_guidance, preservation\_guidance, trigger\_tokens\[] (EXACT tokens — never invent), activation\_phrases\[], negative\_tokens\[], tags\[], compatible\_families\[], default\_strength\_model, default\_strength\_clip, strength\_min, strength\_max. NEVER write metadata directly.
* action:"fetch\_civitai" — READ-ONLY: pull this model's data from Civitai (civitai.com) — the rich description, trainedWords, example prompts (with the prompt text used in the sample images), tags, nsfw flag, and source\_url — WITHOUT writing anything. Call this when the embedded metadata is thin (empty model\_card/prompt\_director, no ss\_tag\_frequency) or to flesh out details before proposing. Treat the result as RAW input: distill the (often marketing-heavy) description, and MINE THE EXAMPLE PROMPTS for the real trigger — the trigger is frequently ONLY in the sample prompts even when trainedWords is EMPTY (e.g. every prompt starting with 'photo in the style of X' means X is the trigger). Adult models (civitai.red) resolve through this same API. Then clean it up and call action:"propose". DEPENDENCY: automatic by-hash lookup uses the OPTIONAL 'comfyui-model-explorer' custom node. If that node isn't installed, pass 'version\_id' (the CivitAI modelVersionId) and this action degrades to CivitAI's public REST API directly — no node, no auth. Without both the node AND a version\_id it returns a clear 'optional feature unavailable' message rather than enriching.

### Parameters

<ParamField path="action" type="enum" required>
  Which metadata operation to perform. All three actions require `category` + `name`; "propose" also requires `fields` (optional `note`); "fetch\_civitai" takes an optional `version_id`.
  Options: `action:"read"`, `action:"propose"`, `action:"fetch_civitai"`.
</ParamField>

<ParamField path="category" type="string">
  ComfyUI model folder, e.g. 'loras'. REQUIRED for all three actions.
</ParamField>

<ParamField path="name" type="string">
  model filename incl. .safetensors. REQUIRED for all three actions.
</ParamField>

<ParamField path="fields" type="object">
  action:"propose" — REQUIRED proposed field map (see description).
</ParamField>

<ParamField path="note" type="string">
  action:"propose" — optional one-line note about this revision.
</ParamField>

<ParamField path="version_id" type="integer">
  action:"fetch\_civitai" — force a specific Civitai modelVersionId if hash lookup misses.
</ParamField>

### Example

<Note>No worked example yet — the call below is a skeleton generated from the required parameters. Real examples live in `scripts/tool-doc-examples.ts`; contributions welcome.</Note>

```json theme={null}
{
  "tool": "model_metadata",
  "arguments": {
    "action": "read",
    "category": "loras",
    "name": "my_model.safetensors"
  }
}
```

***
