Complete technical reference for ComfyUI MCP Server tools, parameters, and behavior.
- Generation Tools
- Viewing Tools
- Job Management Tools
- Asset Management Tools
- Configuration Tools
- Workflow Tools
- Publish Tools
- Parameters
- Return Values
- Error Handling
- Limits and Constraints
Generate images using Stable Diffusion workflows.
Signature:
generate_image(
prompt: str,
seed: int | None = None,
width: int | None = None,
height: int | None = None,
model: str | None = None,
steps: int | None = None,
cfg: float | None = None,
sampler_name: str | None = None,
scheduler: str | None = None,
denoise: float | None = None,
negative_prompt: str | None = None,
return_inline_preview: bool = False
) -> dictRequired Parameters:
prompt(str): Text description of the image to generate
Optional Parameters:
seed(int): Random seed. Auto-generated if not provided.width(int): Image width in pixels. Default: 512height(int): Image height in pixels. Default: 512model(str): Checkpoint model name. Default: "v1-5-pruned-emaonly.ckpt"steps(int): Number of sampling steps. Default: 20cfg(float): Classifier-free guidance scale. Default: 8.0sampler_name(str): Sampling method. Default: "euler"scheduler(str): Scheduler type. Default: "normal"denoise(float): Denoising strength (0.0-1.0). Default: 1.0negative_prompt(str): Negative prompt. Default: "text, watermark"return_inline_preview(bool): Include thumbnail in response. Default: False
Returns:
{
"asset_id": "uuid-string",
"asset_url": "http://localhost:8188/view?filename=...",
"image_url": "http://localhost:8188/view?filename=...",
"filename": "ComfyUI_00265_.png",
"subfolder": "",
"folder_type": "output",
"workflow_id": "generate_image",
"prompt_id": "uuid-string",
"tool": "generate_image",
"mime_type": "image/png",
"width": 512,
"height": 512,
"bytes_size": 497648,
"inline_preview_base64": "data:image/webp;base64,..." // if return_inline_preview=true
}Examples:
User: "Generate an image of a cat"
Agent: Calls generate_image(prompt="a cat") → returns asset_id
User: "Create a cyberpunk cityscape, 1024x768, high quality, 30 steps, using the SD XL model"
Agent: Calls generate_image(prompt="cyberpunk cityscape", width=1024, height=768, model="sd_xl_base_1.0.safetensors", steps=30, cfg=7.5, sampler_name="dpmpp_2m", negative_prompt="blurry, low quality") → returns asset_id
Generate audio using AceStep workflows.
Signature:
generate_song(
tags: str,
lyrics: str,
seed: int | None = None,
steps: int | None = None,
cfg: float | None = None,
seconds: int | None = None,
lyrics_strength: float | None = None
) -> dictRequired Parameters:
tags(str): Comma-separated descriptive tags (e.g., "electronic, ambient")lyrics(str): Full lyric text
Optional Parameters:
seed(int): Random seed. Auto-generated if not provided.steps(int): Number of sampling steps. Default: 50cfg(float): Classifier-free guidance scale. Default: 5.0seconds(int): Audio duration in seconds. Default: 60lyrics_strength(float): Lyrics influence (0.0-1.0). Default: 0.99
Returns:
{
"asset_id": "uuid-string",
"asset_url": "http://localhost:8188/view?filename=...",
"filename": "ComfyUI_00001_.mp3",
"subfolder": "",
"folder_type": "output",
"workflow_id": "generate_song",
"prompt_id": "uuid-string",
"tool": "generate_song",
"mime_type": "audio/mpeg",
"bytes_size": 1234567
}View generated images inline in chat (thumbnail preview only).
Signature:
view_image(
asset_id: str,
mode: str = "thumb",
max_dim: int | None = None,
max_b64_chars: int | None = None
) -> dict | FastMCPImageParameters:
asset_id(str): Asset ID returned from generation toolsmode(str): Display mode -"thumb"(default) or"metadata"max_dim(int): Maximum dimension in pixels. Default: 512max_b64_chars(int): Maximum base64 character count. Default: 100000
Returns:
Mode: "thumb" (default):
- Returns
FastMCPImageobject for inline display - WebP format, automatically downscaled and optimized
- Size constrained to fit within
max_b64_charslimit
Mode: "metadata":
{
"asset_id": "uuid-string",
"asset_url": "http://localhost:8188/view?filename=...",
"mime_type": "image/png",
"width": 512,
"height": 512,
"bytes_size": 497648,
"workflow_id": "generate_image",
"created_at": "2024-01-01T12:00:00",
"expires_at": "2024-01-02T12:00:00"
}Supported Types:
- Images only: PNG, JPEG, WebP, GIF
- Audio/video assets return error: use
asset_urldirectly
Error Responses:
{
"error": "Asset not found or expired"
}{
"error": "Asset type 'audio/mpeg' not supported for inline viewing. Supported types: image/png, image/jpeg, image/webp, image/gif"
}Examples:
User: "Generate an image of a cat and show it to me"
Agent:
- Calls
generate_image(prompt="a cat")→ gets asset_id - Calls
view_image(asset_id="...")→ displays thumbnail inline
User: "What are the dimensions of that last image I generated?"
Agent: Calls view_image(asset_id="...", mode="metadata") → returns width, height, size, etc.
Check the current state of the ComfyUI job queue.
Signature:
get_queue_status() -> dictReturns:
{
"running_count": 1,
"pending_count": 2,
"running": [
{
"prompt_id": "uuid-string",
"status": "running"
}
],
"pending": [
{
"prompt_id": "uuid-string",
"status": "pending"
}
]
}Use Cases:
- Check if ComfyUI is busy before submitting new jobs
- Monitor queue depth for async awareness
- Determine if a job is still queued vs running
Examples:
User: "Is ComfyUI busy right now? How many jobs are queued?"
Agent: Calls get_queue_status() → reports queue depth and running jobs
User: "Check if there are any jobs waiting before I submit a new one"
Agent: Calls get_queue_status() → checks pending_count, informs user if queue is backed up
Poll the completion status of a specific job by prompt ID.
Signature:
get_job(prompt_id: str) -> dictParameters:
prompt_id(str): Prompt ID returned from generation tools
Returns:
{
"status": "completed",
"prompt_id": "uuid-string"
}Status Values:
"pending": Job is queued but not yet running"running": Job is currently executing"completed": Job finished successfully"error": Job failed (check ComfyUI logs)
Examples:
User: "Generate a complex scene with 50 steps, and let me know when it's done"
Agent:
- Calls
generate_image(prompt="complex scene", steps=50)→ gets prompt_id - Periodically calls
get_job(prompt_id="...")to check status - When status is "completed", informs user and optionally calls
view_image()
User: "Is that image generation I started earlier finished yet?"
Agent: Calls get_job(prompt_id="...") → reports current status (pending/running/completed/error)
Cancel a queued or running job.
Signature:
cancel_job(prompt_id: str) -> dictParameters:
prompt_id(str): Prompt ID of the job to cancel
Returns:
{
"success": true,
"message": "Job cancelled"
}Error Response:
{
"error": "Job not found or already completed"
}Examples:
User: "I started a long image generation task earlier, but I want to cancel it now"
Agent:
- Calls
get_queue_status()to find running jobs - Calls
cancel_job(prompt_id="...")to cancel the job - Confirms cancellation to user
Browse recently generated assets with optional filtering.
Signature:
list_assets(
limit: int | None = None,
workflow_id: str | None = None,
session_id: str | None = None
) -> dictParameters:
limit(int, optional): Maximum number of assets to return. Default: 10workflow_id(str, optional): Filter by workflow ID (e.g.,"generate_image")session_id(str, optional): Filter by session ID for conversation isolation
Returns:
{
"assets": [
{
"asset_id": "uuid-string",
"asset_url": "http://localhost:8188/view?filename=...",
"filename": "ComfyUI_00265_.png",
"workflow_id": "generate_image",
"created_at": "2024-01-01T12:00:00",
"mime_type": "image/png",
"width": 512,
"height": 512
}
],
"count": 1,
"limit": 10
}Use Cases:
- Browse recent generations for AI agent memory
- Filter by workflow to see only images or only audio
- Filter by session for conversation-scoped asset isolation
Examples:
User: "Show me the last 5 images I generated"
Agent: Calls list_assets(workflow_id="generate_image", limit=5) → displays list of recent images
User: "What assets have we created in this conversation?"
Agent: Calls list_assets(session_id="current-session-id") → lists assets from current session
Get complete provenance and parameters for a specific asset.
Signature:
get_asset_metadata(asset_id: str) -> dictParameters:
asset_id(str): Asset ID returned from generation tools
Returns:
{
"asset_id": "uuid-string",
"asset_url": "http://localhost:8188/view?filename=...",
"filename": "ComfyUI_00265_.png",
"subfolder": "",
"folder_type": "output",
"workflow_id": "generate_image",
"mime_type": "image/png",
"width": 512,
"height": 512,
"bytes_size": 497648,
"created_at": "2024-01-01T12:00:00",
"expires_at": "2024-01-02T12:00:00",
"submitted_workflow": {
"3": {
"inputs": {
"text": "a beautiful sunset",
"width": 512,
"height": 512
}
}
},
"comfy_history": [
{
"prompt": [...],
"outputs": {...}
}
]
}Key Fields:
submitted_workflow: Exact workflow JSON that was submitted (enablesregenerate)comfy_history: Complete ComfyUI execution historycreated_at/expires_at: Asset lifecycle timestamps
Use Cases:
- Inspect exact parameters used for an asset
- Retrieve workflow data for regeneration
- Debug generation issues with full provenance
Examples:
User: "What parameters were used to generate that last image?"
Agent: Calls get_asset_metadata(asset_id="...") → retrieves and reports workflow parameters, dimensions, etc.
User: "I want to regenerate that image but with different settings - what were the original settings?"
Agent: Calls get_asset_metadata(asset_id="...") → shows submitted_workflow data for regeneration
Regenerate an existing asset with optional parameter overrides.
Signature:
regenerate(
asset_id: str,
param_overrides: dict | None = None,
seed: int | None = None
) -> dictParameters:
asset_id(str): Asset ID to regenerateparam_overrides(dict, optional): Parameter overrides (e.g.,{"steps": 30, "cfg": 10.0})seed(int, optional): New random seed (use-1for auto-generated)
Returns:
Same schema as generation tools (new asset with new asset_id)
Behavior:
- Uses stored
submitted_workflowfrom original asset - Applies
param_overridesto modify specific parameters - All other parameters remain unchanged from original generation
- Returns a new asset (original is not modified)
Error Response:
{
"error": "No workflow data stored for this asset. Cannot regenerate."
}Examples:
User: "Generate a sunset image with 20 steps"
Agent: Calls generate_image(prompt="a sunset", steps=20) → gets asset_id
User: "Now regenerate that same image but with higher quality - 30 steps and cfg 10"
Agent: Calls regenerate(asset_id="...", param_overrides={"steps": 30, "cfg": 10.0}) → creates new version
User: "Regenerate that image but change the prompt to 'a beautiful sunset, oil painting style'"
Agent: Calls regenerate(asset_id="...", param_overrides={"prompt": "a beautiful sunset, oil painting style"}) → creates variation
User: "Generate a new variation of that image with a different random seed"
Agent: Calls regenerate(asset_id="...", seed=-1) → creates new variation with different seed
List all available checkpoint models in ComfyUI.
Signature:
list_models() -> dictReturns:
{
"models": [
"v1-5-pruned-emaonly.ckpt",
"sd_xl_base_1.0.safetensors",
...
],
"count": 7,
"default": "v1-5-pruned-emaonly.ckpt"
}Examples:
User: "What models are available in ComfyUI?"
Agent: Calls list_models() → reports available checkpoint models
User: "I want to use a different model - show me what's available"
Agent: Calls list_models() → lists models, user selects one, agent uses it in generation
Get current effective defaults for image, audio, and video generation.
Signature:
get_defaults() -> dictReturns:
{
"image": {
"width": 512,
"height": 512,
"model": "v1-5-pruned-emaonly.ckpt",
"steps": 20,
"cfg": 8.0,
"sampler_name": "euler",
"scheduler": "normal",
"denoise": 1.0,
"negative_prompt": "text, watermark"
},
"audio": {
"steps": 50,
"cfg": 5.0,
"model": "ace_step_v1_3.5b.safetensors",
"seconds": 60,
"lyrics_strength": 0.99
},
"video": {
"width": 1280,
"height": 720,
"steps": 20,
"cfg": 8.0,
"duration": 5,
"fps": 16
}
}Examples:
User: "What are the current default settings for image generation?"
Agent: Calls get_defaults() → reports current defaults (width, height, model, steps, etc.)
User: "Show me all the default settings"
Agent: Calls get_defaults() → shows defaults for image, audio, and video generation
Set runtime defaults for image, audio, and/or video generation.
Signature:
set_defaults(
image: dict | None = None,
audio: dict | None = None,
video: dict | None = None,
persist: bool = False
) -> dictParameters:
image(dict): Default values for image generationaudio(dict): Default values for audio generationvideo(dict): Default values for video generationpersist(bool): If True, write to config file. Default: False
Returns:
{
"success": true,
"updated": {
"image": {"success": true, "updated": {...}},
"audio": {"success": true, "updated": {...}}
}
}Error Response:
{
"success": false,
"errors": [
"Model 'invalid_model.ckpt' not found. Available models: ..."
]
}Examples:
User: "Set the default image size to 1024x1024 for this session"
Agent: Calls set_defaults(image={"width": 1024, "height": 1024}) → sets ephemeral defaults
User: "Save the SD XL model as the default image model permanently"
Agent: Calls set_defaults(image={"model": "sd_xl_base_1.0.safetensors"}, persist=True) → saves to config file
The server automatically validates that default models exist in ComfyUI's checkpoints directory. This prevents errors at generation time and provides clear feedback about misconfiguration.
Startup Validation:
- On server startup, all default models (from hardcoded, config file, and environment variables) are validated
- Missing models are logged as warnings (non-fatal) - the server still starts successfully
- Warnings include the model name, source (hardcoded/config/env), and namespace (image/audio/video)
Generation-Time Validation:
- Before rendering a workflow, the resolved model (after applying precedence rules) is checked
- If the model is invalid, generation fails immediately with a clear error message
- Error messages include:
- The model name that was requested
- Where it came from (runtime/config/env/hardcoded)
- A sample of available models (first 5)
- Instructions to use
list_modelsorset_defaults
Refresh-on-Failure:
- If ComfyUI returns an error suggesting a missing model, the server automatically:
- Refreshes the cached model list from ComfyUI
- Re-validates the model
- If still invalid, returns a clear error message
- This handles cases where models are added/removed after server startup
Example Error Messages:
{
"error": "Default model 'v1-5-pruned-emaonly.ckpt' (from hardcoded defaults) not found in ComfyUI checkpoints. Set a valid model via `set_defaults`, config file, or env var. Try `list_models` to see available checkpoints. Available models: ['sd_xl_base_1.0.safetensors', 'cyberrealisticPony_v8.safetensors', ...]"
}Best Practices:
- Use
list_modelsto see available checkpoints before setting defaults - Set defaults via
set_defaultswithpersist=Trueto save valid models - Check server startup logs for validation warnings
- The validation system uses a cached model set for fast checks (no per-call overhead)
List all available workflows in the workflow directory.
Signature:
list_workflows() -> dictReturns:
{
"workflows": [
{
"id": "generate_image",
"name": "Generate Image",
"description": "Execute the 'generate_image' workflow.",
"available_inputs": {
"prompt": {"type": "str", "required": true, "description": "..."},
"width": {"type": "int", "required": false, "description": "..."}
},
"defaults": {},
"updated_at": null,
"hash": null
}
],
"count": 2,
"workflow_dir": "/path/to/workflows"
}Examples:
User: "What workflows are available?"
Agent: Calls list_workflows() → lists all available workflows with descriptions and parameters
User: "Show me what custom workflows I can run"
Agent: Calls list_workflows() → displays workflow catalog with available inputs
Run any saved ComfyUI workflow with constrained parameter overrides.
Signature:
run_workflow(
workflow_id: str,
overrides: dict | None = None,
options: dict | None = None,
return_inline_preview: bool = False
) -> dictParameters:
workflow_id(str): Workflow ID (filename stem, e.g., "generate_image")overrides(dict): Parameter overridesoptions(dict): Reserved for future usereturn_inline_preview(bool): Include thumbnail. Default: False
Returns:
{
"asset_id": "uuid-string",
"asset_url": "http://localhost:8188/view?filename=...",
"workflow_id": "generate_image",
"prompt_id": "..."
}Error Response:
{
"error": "Workflow 'invalid_workflow' not found"
}Examples:
User: "Run the generate_image workflow with a custom prompt and 30 steps"
Agent: Calls run_workflow(workflow_id="generate_image", overrides={"prompt": "...", "steps": 30}) → executes workflow
User: "Use the generate_image workflow to create a 1024x1024 image of a cat with the SD XL model"
Agent: Calls run_workflow(workflow_id="generate_image", overrides={"prompt": "a cat", "width": 1024, "height": 1024, "model": "sd_xl_base_1.0.safetensors"}) → executes workflow
For advanced control over workflow behavior, create a .meta.json file alongside your workflow JSON file.
File Structure:
workflows/
├── my_workflow.json
└── my_workflow.meta.json
Metadata Schema:
{
"name": "My Custom Workflow",
"description": "Does something cool",
"defaults": {
"steps": 30,
"cfg": 7.5
},
"constraints": {
"width": {"min": 64, "max": 2048, "step": 64},
"height": {"min": 64, "max": 2048, "step": 64},
"steps": {"min": 1, "max": 100}
}
}Fields:
name(str, optional): Human-readable workflow namedescription(str, optional): Workflow description shown in tool listingsdefaults(dict, optional): Default parameter values for this workflowconstraints(dict, optional): Parameter validation constraintsmin(number): Minimum allowed valuemax(number): Maximum allowed valuestep(number): Step size for numeric parameters
Behavior:
- Metadata defaults override global defaults for this workflow only
- Constraints validate parameter values when
run_workflowis called - If metadata file is missing, workflow still works with global defaults
Tools for safely publishing ComfyUI-generated assets to web project directories with automatic compression and manifest management.
Key Concepts:
- Session-scoped assets:
asset_ids are valid only for the current server session; restart invalidates them - Zero-config in common cases: Publish directory auto-detected (
public/gen,static/gen, orassets/gen) - Two modes: Demo mode (explicit filename) and Library mode (auto-generated filename with manifest)
- Deterministic compression: Images compressed using a fixed quality/downscale ladder to meet size limits
Get publish configuration and status information. Use this to debug configuration issues and verify setup before publishing.
Signature:
get_publish_info() -> dictReturns:
{
"project_root": {
"path": "E:\\dev\\comfyui-mcp-server",
"detection_method": "cwd"
},
"publish_root": {
"path": "E:\\dev\\comfyui-mcp-server\\public\\gen",
"exists": true,
"writable": true
},
"comfyui_output_root": {
"path": "E:\\comfyui-desktop\\output",
"exists": true,
"detection_method": "auto-detected",
"configured": false
},
"comfyui_tried_paths": [
{
"path": "E:\\dev\\comfyui-mcp-server\\comfyui-desktop\\output",
"exists": false,
"is_valid": false,
"source": "auto_detection"
},
{
"path": "E:\\comfyui-desktop\\output",
"exists": true,
"is_valid": true,
"source": "auto_detection"
}
],
"config_file": "C:\\Users\\user\\AppData\\Roaming\\comfyui-mcp-server\\publish_config.json",
"status": "ready",
"message": "Ready to publish",
"warnings": []
}Field Descriptions:
project_root: Detected project root directory and detection method ("cwd"or"auto-detected")publish_root: Publish directory path, existence, and writabilitycomfyui_output_root: ComfyUI output root path, existence, detection method, and whether it's configuredcomfyui_tried_paths: List of paths checked during auto-detection with validation resultsconfig_file: Path to persistent configuration filestatus:"ready"|"needs_comfyui_root"|"error"message: Human-readable status messagewarnings: List of warnings (e.g., fallback detection used)
Examples:
User: "Check if the publish system is ready to use"
Agent: Calls get_publish_info() → reports status, project root, publish directory, ComfyUI output root
User: "I'm getting an error about ComfyUI output root not being found"
Agent:
- Calls
get_publish_info()→ sees status "needs_comfyui_root" - Suggests using
set_comfyui_output_root()with the path - User provides path: "E:/comfyui-desktop/output"
- Agent calls
set_comfyui_output_root("E:/comfyui-desktop/output")→ configures and persists
Set ComfyUI output root directory in persistent configuration. Recommended for Comfy Desktop and nonstandard installs.
Signature:
set_comfyui_output_root(path: str) -> dictRequired Parameters:
path(str): Absolute or relative path to ComfyUI output directory (e.g.,"E:/comfyui-desktop/output"or"/opt/ComfyUI/output")
Returns (Success):
{
"success": true,
"path": "E:\\comfyui-desktop\\output",
"config_file": "C:\\Users\\user\\AppData\\Roaming\\comfyui-mcp-server\\publish_config.json",
"message": "ComfyUI output root configured: E:\\comfyui-desktop\\output"
}Returns (Error):
{
"error": "COMFYUI_OUTPUT_ROOT_PATH_NOT_FOUND",
"message": "Path does not exist: E:/nonexistent/output",
"path": "E:/nonexistent/output"
}Error Codes:
COMFYUI_OUTPUT_ROOT_PATH_NOT_FOUND: Path does not existCOMFYUI_OUTPUT_ROOT_NOT_DIRECTORY: Path is not a directoryCOMFYUI_OUTPUT_ROOT_INVALID: Path doesn't appear to be a ComfyUI output directoryCONFIG_SAVE_FAILED: Failed to save configuration fileINVALID_PATH: Invalid path format
Configuration Storage:
- Windows:
%APPDATA%/comfyui-mcp-server/publish_config.json - Mac:
~/Library/Application Support/comfyui-mcp-server/publish_config.json - Linux:
~/.config/comfyui-mcp-server/publish_config.json
Examples:
User: "Set the ComfyUI output directory to E:/comfyui-desktop/output"
Agent: Calls set_comfyui_output_root("E:/comfyui-desktop/output") → validates path, saves to config, confirms success
User: "Configure the output directory" (if path is invalid)
Agent:
- Calls
set_comfyui_output_root("...")→ receives error - Reports error to user: "Path does not exist" or "Path doesn't appear to be a ComfyUI output directory"
- Suggests checking the path or using
get_publish_info()to see tried paths
Publish a ComfyUI-generated asset to the project's web directory with optional WebP compression.
Signature:
publish_asset(
asset_id: str,
target_filename: str | None = None,
manifest_key: str | None = None,
web_optimize: bool = False,
max_bytes: int = 600_000,
overwrite: bool = True
) -> dictRequired Parameters:
asset_id(str): Asset ID from generation tools (session-scoped, dies on server restart)
Optional Parameters:
target_filename(str, optional): Target filename (e.g.,"hero.png"). If omitted, auto-generated (library mode). Must match regex:^[a-z0-9][a-z0-9._-]{0,63}\.(webp|png|jpg|jpeg)$manifest_key(str, optional): Manifest key (required iftarget_filenameomitted). Must match regex:^[a-z0-9][a-z0-9._-]{0,63}$web_optimize(bool): IfTrue, convert to WebP and apply compression (default:False). WhenFalse, assets are copied as-is preserving original format.max_bytes(int): Maximum file size in bytes (default:600000). Only used whenweb_optimize=True.overwrite(bool): Whether to overwrite existing file (default:True)
Default Behavior (web_optimize=False):
- Assets are copied as-is, preserving original format (typically PNG from ComfyUI)
- No compression or format conversion
- Original quality preserved
Web Optimization (web_optimize=True):
- Images are converted to WebP format
- Compression ladder applied to meet size limits
- Useful for web deployment where smaller file sizes are important
Two Modes:
Demo Mode (explicit filename):
- User provides
target_filename(e.g.,"hero.png") - Agent calls:
publish_asset(asset_id="...", target_filename="hero.png")(no compression) ORpublish_asset(asset_id="...", target_filename="hero.webp", web_optimize=True)(with compression) - Manifest not updated unless
manifest_keyalso provided
Library Mode (auto-generated with manifest):
- User provides
manifest_key, omitstarget_filename - Agent calls:
publish_asset(asset_id="...", manifest_key="hero-image")(no compression, preserves source format) ORpublish_asset(asset_id="...", manifest_key="hero-image", web_optimize=True)(WebP compression) - Filename auto-generated based on
web_optimize:- If
web_optimize=False:asset_<shortid>.png(matches source format) - If
web_optimize=True:asset_<shortid>.webp
- If
- Manifest automatically updated:
{"hero-image": "asset_0b3eacbc.png"}or{"hero-image": "asset_0b3eacbc.webp"}
Returns (Success):
{
"dest_url": "/gen/hero.webp",
"dest_path": "E:\\dev\\project\\public\\gen\\hero.webp",
"bytes_size": 37478,
"mime_type": "image/webp",
"width": 512,
"height": 512,
"compression_info": {
"compressed": true,
"original_size": 457374,
"original_dimensions": [512, 512],
"quality": 85,
"final_dimensions": [512, 512],
"downscaled": false,
"final_size": 37478
}
}Returns (Error):
{
"error": "Asset 0b3eacbc-25b0-497c-9d63-6d66d9e67387 not found or expired. Assets are session-scoped and die on server restart. Generate a new asset in the current session.",
"error_code": "ASSET_NOT_FOUND_OR_EXPIRED"
}Error Codes:
ASSET_NOT_FOUND_OR_EXPIRED: Asset not in current session (session-scoped)INVALID_TARGET_FILENAME: Filename doesn't match regex patternINVALID_MANIFEST_KEY: Manifest key doesn't match regex patternMANIFEST_KEY_REQUIRED:manifest_keyrequired whentarget_filenameomitted (library mode)SOURCE_PATH_OUTSIDE_ROOT: Source file outside ComfyUI output rootPATH_TRAVERSAL_DETECTED: Path traversal attempt detectedCOMFYUI_OUTPUT_ROOT_NOT_FOUND: ComfyUI output root not configuredPUBLISH_ROOT_NOT_WRITABLE: Publish directory not writablePUBLISH_FAILED: Copy/compression operation failedVALIDATION_ERROR: General validation error
Compression Details (when web_optimize=True):
Images are compressed using a deterministic compression ladder:
- Quality progression: [85, 75, 65, 55, 45, 35]
- Downscale factors: [1.0, 0.9, 0.75, 0.6, 0.5] (if needed)
- Format conversion: PNG/JPEG → WebP
- Size limit: Enforced via
max_bytes(default: 600KB)
The compression ladder tries quality levels first, then downscaling if needed, until the size limit is met. If compression cannot meet the limit, an error is returned.
Note: Compression only occurs when web_optimize=True. By default (web_optimize=False), assets are copied as-is with no compression or format conversion.
Manifest Updates:
The manifest (<publish_root>/manifest.json) is updated only when manifest_key is provided:
{
"hero-image": "asset_0b3eacbc.webp",
"logo": "logo.png"
}Manifest uses simple key → filename mapping (no arrays in v1). Updates are atomic (process-level locking).
Examples:
Demo Mode:
User: "Generate a sunset image and publish it as hero.png"
Agent:
- Calls
generate_image(prompt="a sunset")→ gets asset_id - Calls
publish_asset(asset_id="...", target_filename="hero.png")→ copies as-is, no compression - Reports: "Published to /gen/hero.png (original size)"
User: "Generate a sunset image and publish it as hero.webp, optimize it for web and keep it under 500KB"
Agent:
- Calls
generate_image(prompt="a sunset")→ gets asset_id - Calls
publish_asset(asset_id="...", target_filename="hero.webp", web_optimize=True, max_bytes=500_000)→ converts to WebP and compresses - Reports: "Published to /gen/hero.webp (37478 bytes)"
Library Mode:
User: "Generate a sunset image and add it to the manifest as 'hero-image'"
Agent:
- Calls
generate_image(prompt="a sunset")→ gets asset_id - Calls
publish_asset(asset_id="...", manifest_key="hero-image")→ auto-generates filename with source format, updates manifest - Reports: "Published to /gen/asset_0b3eacbc.png, added to manifest as 'hero-image'
User: "Generate a sunset image, optimize it for web, and add it to the manifest as 'hero-image'"
Agent:
- Calls
generate_image(prompt="a sunset")→ gets asset_id - Calls
publish_asset(asset_id="...", manifest_key="hero-image", web_optimize=True)→ auto-generates WebP filename, compresses, updates manifest - Reports: "Published to /gen/asset_0b3eacbc.webp, added to manifest as 'hero-image'
Typical Workflow:
User: "I want to publish an image to my website"
Agent:
- Calls
get_publish_info()to check configuration - If status is not "ready", suggests using
set_comfyui_output_root()if ComfyUI output root is missing - User provides path or agent proceeds if ready
- Calls
generate_image()or other generation tool - Calls
publish_asset()with user's requested filename or manifest key - Confirms publication and provides URL
Safety Guarantees:
- Only assets from current session can be published (asset_id must exist in registry)
- Source path must be within ComfyUI output root (validated with real path resolution)
- Target filename validated by strict regex (prevents path traversal)
- All paths are canonicalized to prevent symlink/traversal attacks
- Images automatically compressed to meet size limits
Parameters are typed and automatically coerced:
- String parameters:
str(default if no type specified) - Integer parameters:
PARAM_INT_*→int - Float parameters:
PARAM_FLOAT_*→float - Boolean parameters:
PARAM_BOOL_*→bool
Type Coercion:
- JSON-RPC may pass numbers as strings:
"512"→512(int) - Automatic conversion handles both string and numeric inputs
Required Parameters:
prompt(for image workflows)tagsandlyrics(for audio workflows)
Optional Parameters:
- All others have defaults or are auto-generated (e.g.,
seed)
- Per-call values (highest priority) - Explicitly provided in tool calls
- Runtime defaults (
set_defaultstool) - Ephemeral, lost on restart - Config file (
~/.config/comfy-mcp/config.json) - Persistent across restarts - Environment variables (
COMFY_MCP_DEFAULT_*) - System-level configuration - Hardcoded defaults (lowest priority) - Built-in sensible values
Create ~/.config/comfy-mcp/config.json for persistent defaults:
{
"defaults": {
"image": {
"model": "sd_xl_base_1.0.safetensors",
"width": 1024,
"height": 1024,
"steps": 30,
"cfg": 7.5,
"sampler_name": "dpmpp_2m",
"scheduler": "normal",
"denoise": 1.0,
"negative_prompt": "blurry, low quality"
},
"audio": {
"model": "ace_step_v1_3.5b.safetensors",
"seconds": 30,
"steps": 60,
"cfg": 5.0,
"lyrics_strength": 0.99
},
"video": {
"width": 1280,
"height": 720,
"steps": 20,
"cfg": 8.0,
"duration": 5,
"fps": 16
}
}
}Server Configuration:
COMFYUI_URL: ComfyUI server URL (default:http://localhost:8188)COMFY_MCP_WORKFLOW_DIR: Workflow directory path (default:./workflows)COMFY_MCP_ASSET_TTL_HOURS: Asset expiration time in hours (default: 24)
Default Values:
COMFY_MCP_DEFAULT_IMAGE_MODEL: Default image model nameCOMFY_MCP_DEFAULT_AUDIO_MODEL: Default audio model nameCOMFY_MCP_DEFAULT_VIDEO_MODEL: Default video model nameCOMFY_MCP_DEFAULT_IMAGE_WIDTH: Default image width (integer)COMFY_MCP_DEFAULT_IMAGE_HEIGHT: Default image height (integer)COMFY_MCP_DEFAULT_IMAGE_STEPS: Default image steps (integer)COMFY_MCP_DEFAULT_IMAGE_CFG: Default image CFG scale (float)COMFY_MCP_DEFAULT_AUDIO_SECONDS: Default audio duration (integer)COMFY_MCP_DEFAULT_AUDIO_STEPS: Default audio steps (integer)
Environment variables take precedence over config file but are overridden by runtime defaults and per-call values.
When calling tools via the MCP protocol (JSON-RPC), the response is wrapped in the MCP format:
{
"result": {
"content": [
{
"type": "text",
"text": "{...tool return value as JSON string...}"
}
],
"isError": false
}
}The actual tool return value is serialized as a JSON string in result.content[0].text. You need to parse this JSON string to access the tool's return data.
Note: This documentation shows the unwrapped tool return values (what's inside the JSON string), not the MCP protocol wrapper.
All generation tools (generate_image, generate_song, regenerate, run_workflow) return:
{
"asset_id": "uuid-string",
"asset_url": "http://localhost:8188/view?filename=ComfyUI_00265_.png&subfolder=&type=output",
"image_url": "http://localhost:8188/view?filename=ComfyUI_00265_.png&subfolder=&type=output",
"filename": "ComfyUI_00265_.png",
"subfolder": "",
"folder_type": "output",
"workflow_id": "generate_image",
"prompt_id": "uuid-string",
"tool": "generate_image",
"mime_type": "image/png",
"width": 512,
"height": 512,
"bytes_size": 497648,
"inline_preview_base64": "data:image/webp;base64,..."
}Field Descriptions:
asset_id(str): Unique identifier for the asset, use withview_imageandregenerateasset_url(str): Direct URL to access the asset from ComfyUIimage_url(str): Alias forasset_url(for image assets)filename(str): Stable filename identifier (not URL-dependent)subfolder(str): Asset subfolder path (usually empty)folder_type(str): Asset type, typically"output"workflow_id(str): Workflow that generated this assetprompt_id(str): ComfyUI prompt ID, use withget_job()to poll completiontool(str): Tool name that generated this assetmime_type(str): MIME type of the asset (e.g.,"image/png","audio/mpeg")width(int, optional): Image width in pixels (images only)height(int, optional): Image height in pixels (images only)bytes_size(int): File size in bytesinline_preview_base64(str, optional): Base64-encoded thumbnail (ifreturn_inline_preview=true)
Key Points:
asset_idis the primary identifier for follow-up operationsfilename,subfolder, andfolder_typeform a stable identity that is stable across URL/base changesprompt_idenables job status polling viaget_job()- Asset URLs are computed from stable identity, making the system robust to configuration changes
All tools return errors in consistent format:
{
"error": "Error message describing what went wrong"
}Asset Not Found:
{
"error": "Asset not found or expired"
}Invalid Workflow:
{
"error": "Workflow 'invalid_workflow' not found"
}Invalid Model:
{
"error": "Default model 'invalid.ckpt' (from hardcoded defaults) not found in ComfyUI checkpoints. Set a valid model via `set_defaults`, config file, or env var. Try `list_models` to see available checkpoints. Available models: ['sd_xl_base_1.0.safetensors', 'v1-5-pruned-emaonly.ckpt', ...]"
}Or when using set_defaults:
{
"success": false,
"errors": ["Model 'invalid.ckpt' not found. Available models: ..."]
}Unsupported Asset Type:
{
"error": "Asset type 'audio/mpeg' not supported for inline viewing. Supported types: image/png, image/jpeg, image/webp, image/gif"
}Publish Errors:
All publish errors include both human-readable messages and machine-readable error codes:
{
"error": "Asset 0b3eacbc-25b0-497c-9d63-6d66d9e67387 not found or expired. Assets are session-scoped and die on server restart. Generate a new asset in the current session.",
"error_code": "ASSET_NOT_FOUND_OR_EXPIRED"
}Common Publish Error Codes:
ASSET_NOT_FOUND_OR_EXPIRED: Asset not in current sessionINVALID_TARGET_FILENAME: Filename doesn't match validation regexMANIFEST_KEY_REQUIRED:manifest_keyrequired whentarget_filenameomittedCOMFYUI_OUTPUT_ROOT_NOT_FOUND: ComfyUI output root not configuredPUBLISH_FAILED: Copy/compression operation failed
- Maximum dimension: 512px (default, configurable via
max_dim) - Base64 budget: 100KB (default, configurable via
max_b64_chars) - Supported formats: PNG, JPEG, WebP, GIF only
- Automatic optimization: Images are downscaled and re-encoded as WebP
- Default TTL: 24 hours
- Configurable:
COMFY_MCP_ASSET_TTL_HOURSenvironment variable - Automatic cleanup: Expired assets are removed from registry
- Path traversal protection: Workflow IDs are sanitized
- Directory restriction: Only workflows in
workflows/directory - Parameter validation: Overrides constrained to declared parameters
- Polling interval: 1 second
- Maximum attempts: 30 (configurable)
- Timeout: 30 seconds per request
- Session-scoped assets:
asset_ids are valid only for the current server session; restart invalidates them - Filename validation: Target filenames must match regex
^[a-z0-9][a-z0-9._-]{0,63}\.(webp|png|jpg|jpeg)$ - Manifest key validation: Manifest keys must match regex
^[a-z0-9][a-z0-9._-]{0,63}$ - Compression limits: When
web_optimize=True, images compressed to meetmax_byteslimit (default: 600KB); fails with error if limit cannot be met. By default (web_optimize=False), no compression is applied. - Path safety: All paths canonicalized; source must be within ComfyUI output root; target must be within publish root
- Project root detection: Server should be started from repository root (cwd) for best results