Skip to main content
Glama

download_model

Destructive

Download any model file into the connected ComfyUI's models directory from a URL (HuggingFace, HTTP, S3, Azure) and track status or cancel transfers; search for missing models to install candidates.

Instructions

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/').

  • 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. WHAT COMES AFTER THAT CANCEL DEPENDS ON THE ROUTE, and the note says which — for a local stream re-issuing resumes the .partial or restarts cleanly, but for a ComfyUI-Manager dispatch there is no local .partial and the host may still be fetching, so re-issuing is a duplicate dispatch that CORRUPTS the file. An older record that predates the route being stored says the route is UNKNOWN and tells you to verify the file before re-issuing, rather than guessing either way. 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 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 '. 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: } 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 /models// 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) — or pass a per-request auth, which overrides the configured token for that download; 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.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idNoThe 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).
urlNoREQUIRED 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.
authNoaction:"download" / action:"download_civitai" — optional per-request authentication for private/gated model URLs. When provided it overrides built-in HuggingFace/CivitAI token handling.
nsfwNoaction:"search_civitai" — include NSFW results (default false).
sortNoaction:"search_civitai" — ranking (default 'Highest Rated').
boardNoaction:"search_creators" — leaderboard to rank by when no query is given (default 'overall'). Ignored with a query.
limitNoMax 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.
queryNoREQUIRED 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.
typesNoaction:"search_civitai" — only these model types (e.g. ['LORA']).
actionYesWhich 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`.
filterNoaction:"search" — optional HuggingFace pipeline/library tag to narrow results, e.g. 'diffusers' or 'text-to-image'.
creatorNoaction:"search_civitai" — only models by this CivitAI creator (EXACT username — find it with action:"search_creators"). At least one of query/creator is required.
tray_idNoaction:"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 <tray_id>)` — pass that here, together with `id`, to report on (or stop) exactly one of them.
filenameNoaction:"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).
model_idNoaction:"download_civitai" — CivitAI model id. The latest version is used unless model_version_id is also provided.
workflowNoREQUIRED for action:"resolve_missing" — the ComfyUI workflow in API format (JSON string or object).
base_modelsNoaction:"search_civitai" — only these base-model families, CivitAI labels: 'Flux.1 D', 'SDXL 1.0', 'SD 1.5', 'Pony', 'Illustrious', 'Wan Video', …
model_version_idNoaction:"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.
target_subfolderNoREQUIRED 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.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv0.52.6
    • changedInput schema / properties / auth / description
      Previous value: -"action:\"download\" — optional per-request authentication for private/gated model URLs. When provided it overrides built-in HuggingFace/CivitAI token handling."New value: +"action:\"download\" / action:\"download_civitai\" — optional per-request authentication for private/gated model URLs. When provided it overrides built-in HuggingFace/CivitAI token handling."
  2. Addedv0.50.93
  3. Removedv0.49.0
  4. Addedv0.48.1
  5. Removedv0.45.0
  6. Changed3 schema fields changedv0.19.1
    • changedInput schema / properties / target_subfolder / description
      Previous value: -"Target subfolder under ComfyUI models/ (e.g. 'checkpoints', 'loras', 'vae')"New value: +"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."
    • removedInput schema / properties / target_subfolder / enum
      Removed value: -[
      -  "checkpoints",
      -  "loras",
      -  "vae",
      -  "upscale_models",
      -  "controlnet",
      -  "embeddings",
      -  "clip",
      -  "diffusers",
      -  "diffusion_models",
      -  "gligen",
      -  "hypernetworks",
      -  "photomaker",
      -  "style_models",
      -  "text_encoders",
      -  "unet"
      -]
    • addedInput schema / properties / target_subfolder / minLength
      Added value: +1
  7. Changed3 schema fields changedv0.13.0
    • removedInput schema / additionalProperties
      Removed value: -false
    • removedInput schema / properties / auth / anyOf
      Removed value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "token": {
      -        "description": "Bearer token value",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "bearer",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "token"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "password": {
      -        "description": "Basic auth password",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "basic",
      -        "type": "string"
      -      },
      -      "username": {
      -        "description": "Basic auth username",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "username",
      -      "password"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "header_name": {
      -        "description": "HTTP header name",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "header_value": {
      -        "description": "HTTP header value",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "header",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "header_name",
      -      "header_value"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "query_param": {
      -        "description": "Query parameter name",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "query_value": {
      -        "description": "Query parameter value",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "query",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "query_param",
      -      "query_value"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "access_key_id": {
      -        "description": "AWS/S3-compatible access key id",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "endpoint": {
      -        "description": "Optional S3-compatible endpoint for R2-style storage",
      -        "format": "uri",
      -        "type": "string"
      -      },
      -      "region": {
      -        "description": "Optional AWS region override",
      -        "type": "string"
      -      },
      -      "secret_access_key": {
      -        "description": "AWS/S3-compatible secret access key",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "session_token": {
      -        "description": "Optional temporary session token",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "s3",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "access_key_id",
      -      "secret_access_key"
      -    ],
      -    "type": "object"
      -  }
      -]
    • addedInput schema / properties / auth / oneOf
      Added value: +[
      +  {
      +    "properties": {
      +      "token": {
      +        "description": "Bearer token value",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "bearer",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "token"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "properties": {
      +      "password": {
      +        "description": "Basic auth password",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "basic",
      +        "type": "string"
      +      },
      +      "username": {
      +        "description": "Basic auth username",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "username",
      +      "password"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "properties": {
      +      "header_name": {
      +        "description": "HTTP header name",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "header_value": {
      +        "description": "HTTP header value",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "header",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "header_name",
      +      "header_value"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "properties": {
      +      "query_param": {
      +        "description": "Query parameter name",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "query_value": {
      +        "description": "Query parameter value",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "query",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "query_param",
      +      "query_value"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "properties": {
      +      "access_key_id": {
      +        "description": "AWS/S3-compatible access key id",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "endpoint": {
      +        "description": "Optional S3-compatible endpoint for R2-style storage",
      +        "format": "uri",
      +        "type": "string"
      +      },
      +      "region": {
      +        "description": "Optional AWS region override",
      +        "type": "string"
      +      },
      +      "secret_access_key": {
      +        "description": "AWS/S3-compatible secret access key",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "session_token": {
      +        "description": "Optional temporary session token",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "s3",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "access_key_id",
      +      "secret_access_key"
      +    ],
      +    "type": "object"
      +  }
      +]
  8. Changed1 schema field changedv0.7.1
    • changedInput schema / properties / auth / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "token": {
      -        "description": "Bearer token value",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "bearer",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "token"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "password": {
      -        "description": "Basic auth password",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "basic",
      -        "type": "string"
      -      },
      -      "username": {
      -        "description": "Basic auth username",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "username",
      -      "password"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "header_name": {
      -        "description": "HTTP header name",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "header_value": {
      -        "description": "HTTP header value",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "header",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "header_name",
      -      "header_value"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "query_param": {
      -        "description": "Query parameter name",
      -        "minLength": 1,
      -        "type": "string"
      -      },
      -      "query_value": {
      -        "description": "Query parameter value",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "query",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "query_param",
      -      "query_value"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "token": {
      +        "description": "Bearer token value",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "bearer",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "token"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "password": {
      +        "description": "Basic auth password",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "basic",
      +        "type": "string"
      +      },
      +      "username": {
      +        "description": "Basic auth username",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "username",
      +      "password"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "header_name": {
      +        "description": "HTTP header name",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "header_value": {
      +        "description": "HTTP header value",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "header",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "header_name",
      +      "header_value"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "query_param": {
      +        "description": "Query parameter name",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "query_value": {
      +        "description": "Query parameter value",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "query",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "query_param",
      +      "query_value"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "access_key_id": {
      +        "description": "AWS/S3-compatible access key id",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "endpoint": {
      +        "description": "Optional S3-compatible endpoint for R2-style storage",
      +        "format": "uri",
      +        "type": "string"
      +      },
      +      "region": {
      +        "description": "Optional AWS region override",
      +        "type": "string"
      +      },
      +      "secret_access_key": {
      +        "description": "AWS/S3-compatible secret access key",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "session_token": {
      +        "description": "Optional temporary session token",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "s3",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "access_key_id",
      +      "secret_access_key"
      +    ],
      +    "type": "object"
      +  }
      +]
  9. Changed1 schema field changedv0.7.0
    • addedInput schema / properties / auth
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "token": {
      +          "description": "Bearer token value",
      +          "minLength": 1,
      +          "type": "string"
      +        },
      +        "type": {
      +          "const": "bearer",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "type",
      +        "token"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "password": {
      +          "description": "Basic auth password",
      +          "type": "string"
      +        },
      +        "type": {
      +          "const": "basic",
      +          "type": "string"
      +        },
      +        "username": {
      +          "description": "Basic auth username",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "type",
      +        "username",
      +        "password"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "header_name": {
      +          "description": "HTTP header name",
      +          "minLength": 1,
      +          "type": "string"
      +        },
      +        "header_value": {
      +          "description": "HTTP header value",
      +          "type": "string"
      +        },
      +        "type": {
      +          "const": "header",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "type",
      +        "header_name",
      +        "header_value"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "query_param": {
      +          "description": "Query parameter name",
      +          "minLength": 1,
      +          "type": "string"
      +        },
      +        "query_value": {
      +          "description": "Query parameter value",
      +          "type": "string"
      +        },
      +        "type": {
      +          "const": "query",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "type",
      +        "query_param",
      +        "query_value"
      +      ],
      +      "type": "object"
      +    }
      +  ],
      +  "description": "Optional per-request authentication for private/gated model URLs. When provided it overrides built-in HuggingFace/CivitAI token handling."
      +}
  10. First observedv0.1.0

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations (openWorldHint, destructiveHint, idempotentHint false) are enriched substantially: the description marks actions 'Read-only', explains the destructive cancel semantics, leftover .partial resumable bytes, remote-vs-local dispatch caveats, stale-heartbeat handling, and the 'silently rejects the download... does not guarantee the file landed' failure modes. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well organized by action with a clear required/optional breakdown, but notably verbose with substantial repetition — the remote ComfyUI caveat (network_mode=personal_cloud, 'does not guarantee the file landed') and the stale-heartbeat/duplicate-dispatch warning are restated nearly verbatim across multiple actions. Comprehensive, yet could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given there is no output schema, the description thoroughly explains return values and side effects: status reports download state, destination path, byte progress; search returns ranked lists with modelId, author, downloads, likes; resolve_missing reports size, source, precision and VRAM fit. Error/edge cases (id matching nothing, unknown route, duplicate ids) are all covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Though schema coverage is 100%, the description adds significant meaning beyond the schema: it explains how params flow between actions (e.g., 'Each hit's username feeds action:"search_civitai" {creator:...}'), clarifies when tray_id is needed, interprets limit per action, and gives usage context for base_models, creator (EXACT username), and workflow (API format).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a very specific verb+resource (download models into ComfyUI) and enumerates 8 distinct actions with clear responsibilities. It also distinguishes itself from siblings, e.g. 'For packs of custom nodes (not models) use search_custom_nodes instead'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage guidance is explicit and exhaustive: it specifies when to use each action, which params are required per action, and explicitly points to alternatives ('For CIVITAI searches... use action:"search_civitai" instead'; 'For HuggingFace search use action:"search"'). Flow sequences are spelled out (search_civitai → download_civitai).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.