refine_image
Refine an existing image by performing a denoising pass guided by a text prompt. Control the degree of change with the denoise parameter.
Instructions
Refine an existing image using img2img: fetch the source image, upload it to ComfyUI, and run a denoising pass guided by the prompt. Lower denoise preserves more of the original; higher denoise gives more freedom to the prompt.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | Text prompt describing the desired refined image | |
| source_image_url | Yes | URL of the source image to refine. Will be fetched and uploaded to ComfyUI. | |
| denoise | No | How much to change the source image (0 = no change, 1 = fully regenerate). Typical: 0.3-0.7 | |
| negative_prompt | No | ||
| steps | No | ||
| cfg | No | ||
| seed | No | ||
| checkpoint | No |
Implementation Reference
- src/tools/refine.ts:43-65 (handler)Handler function that fetches the source image, builds an img2img workflow with denoising, runs it via ComfyUIClient, and returns generated image URLs.
async (args) => { const upload = await client.fetchAndUploadImage(args.source_image_url); const workflow = img2img({ prompt: args.prompt, negativePrompt: args.negative_prompt ?? "", sourceImage: upload.name, denoise: args.denoise, steps: args.steps, cfg: args.cfg, seed: args.seed ?? Math.floor(Math.random() * 2 ** 32), checkpoint: args.checkpoint ?? DEFAULT_CHECKPOINT, }); const result = await client.runWorkflow(workflow); const lines = [ `Refined image (prompt_id: ${result.promptId}, denoise: ${args.denoise}, source: ${upload.name}):`, ...result.images.map((url, i) => ` ${i + 1}. ${url}`), ]; return { content: [{ type: "text" as const, text: lines.join("\n") }] }; }, ); - src/tools/refine.ts:9-33 (schema)Zod schema defining the refine_image tool's input parameters: prompt, source_image_url, denoise (default 0.5), negative_prompt, steps (default 25), cfg (default 7), seed, and checkpoint.
const refineImageSchema = { prompt: z .string() .min(1) .describe("Text prompt describing the desired refined image"), source_image_url: z .string() .url() .describe( "URL of the source image to refine. Will be fetched and uploaded to ComfyUI.", ), denoise: z .number() .min(0) .max(1) .default(0.5) .describe( "How much to change the source image (0 = no change, 1 = fully regenerate). Typical: 0.3-0.7", ), negative_prompt: z.string().optional(), steps: z.number().int().min(1).max(150).default(25), cfg: z.number().min(1).max(30).default(7), seed: z.number().int().optional(), checkpoint: z.string().optional(), }; - src/tools/refine.ts:35-66 (registration)Registers the 'refine_image' tool on the MCP server with its schema and handler callback.
export function registerRefineTool( server: McpServer, client: ComfyUIClient, ): void { server.tool( "refine_image", "Refine an existing image using img2img: fetch the source image, upload it to ComfyUI, and run a denoising pass guided by the prompt. Lower denoise preserves more of the original; higher denoise gives more freedom to the prompt.", refineImageSchema, async (args) => { const upload = await client.fetchAndUploadImage(args.source_image_url); const workflow = img2img({ prompt: args.prompt, negativePrompt: args.negative_prompt ?? "", sourceImage: upload.name, denoise: args.denoise, steps: args.steps, cfg: args.cfg, seed: args.seed ?? Math.floor(Math.random() * 2 ** 32), checkpoint: args.checkpoint ?? DEFAULT_CHECKPOINT, }); const result = await client.runWorkflow(workflow); const lines = [ `Refined image (prompt_id: ${result.promptId}, denoise: ${args.denoise}, source: ${upload.name}):`, ...result.images.map((url, i) => ` ${i + 1}. ${url}`), ]; return { content: [{ type: "text" as const, text: lines.join("\n") }] }; }, ); } - src/server.ts:43-43 (registration)Call site where registerRefineTool is invoked during server build to wire up the refine_image tool.
registerRefineTool(s, client); - src/comfyui/workflows.ts:74-120 (helper)The img2img workflow builder used by refine_image. Builds a ComfyUI workflow with LoadImage, VAEEncode, CLIPTextEncode (pos/neg), CheckpointLoaderSimple, KSampler (with denoise), VAEDecode, and SaveImage nodes.
export function img2img(params: Img2ImgParams): Workflow { return { "3": { class_type: "KSampler", inputs: { seed: params.seed, steps: params.steps, cfg: params.cfg, sampler_name: "euler", scheduler: "normal", denoise: params.denoise, model: ["4", 0], positive: ["6", 0], negative: ["7", 0], latent_image: ["11", 0], }, }, "4": { class_type: "CheckpointLoaderSimple", inputs: { ckpt_name: params.checkpoint }, }, "6": { class_type: "CLIPTextEncode", inputs: { text: params.prompt, clip: ["4", 1] }, }, "7": { class_type: "CLIPTextEncode", inputs: { text: params.negativePrompt, clip: ["4", 1] }, }, "8": { class_type: "VAEDecode", inputs: { samples: ["3", 0], vae: ["4", 2] }, }, "9": { class_type: "SaveImage", inputs: { filename_prefix: "comfyui-mcp-refine", images: ["8", 0] }, }, "10": { class_type: "LoadImage", inputs: { image: params.sourceImage }, }, "11": { class_type: "VAEEncode", inputs: { pixels: ["10", 0], vae: ["4", 2] }, }, }; }