save_workflow_template
Save a ComfyUI workflow JSON to the server's template registry under a named slot. Use to store and retrieve workflow configurations. Overwrite disabled by default to prevent accidental replacement.
Instructions
Save a ComfyUI workflow JSON to the server's template registry under a named slot. Overwrites are disabled by default.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Template name. Letters, digits, '-', '_'; max 64 chars. Must start alphanumeric. | |
| workflow | Yes | Complete ComfyUI workflow JSON (from ComfyUI's 'Save (API Format)'). | |
| description | No | ||
| overwrite | No | Allow overwriting an existing template with the same name. |
Implementation Reference
- src/tools/templates.ts:75-125 (handler)The handler for the save_workflow_template tool. Validates the name, checks if template already exists, optionally overwrites, reads prior createdAt, and writes StoredTemplate JSON to disk.
server.tool( "save_workflow_template", "Save a ComfyUI workflow JSON to the server's template registry under a named slot. Overwrites are disabled by default.", saveSchema, async (args) => { validateName(args.name); const file = templatePath(store.dir, args.name); let existed = false; try { await fs.access(file); existed = true; } catch { existed = false; } if (existed && !args.overwrite) { throw new Error( `Template "${args.name}" already exists. Pass overwrite=true to replace it.`, ); } const now = new Date().toISOString(); let createdAt = now; if (existed) { try { const prior = JSON.parse( await fs.readFile(file, "utf-8"), ) as StoredTemplate; createdAt = prior.createdAt ?? now; } catch { // ignore parse failure, treat as fresh create } } const record: StoredTemplate = { name: args.name, description: args.description, createdAt, updatedAt: now, workflow: args.workflow as Workflow, }; await fs.writeFile(file, JSON.stringify(record, null, 2)); return { content: [ { type: "text" as const, text: existed ? `Updated template "${args.name}" at ${file}` : `Saved template "${args.name}" at ${file}`, }, ], }; }, ); - src/tools/templates.ts:38-54 (schema)Input schema (saveSchema) for save_workflow_template: name (string), workflow (record), description (optional string), overwrite (boolean, default false).
const saveSchema = { name: z .string() .describe( "Template name. Letters, digits, '-', '_'; max 64 chars. Must start alphanumeric.", ), workflow: z .record(z.string(), z.any()) .describe( "Complete ComfyUI workflow JSON (from ComfyUI's 'Save (API Format)').", ), description: z.string().optional(), overwrite: z .boolean() .default(false) .describe("Allow overwriting an existing template with the same name."), }; - src/server.ts:48-49 (registration)Registration call: registerTemplateTools(s, client, templateStore) wires up the tool on the MCP server.
registerTemplateTools(s, client, templateStore); return s; - src/tools/templates.ts:70-74 (registration)The registerTemplateTools export that calls server.tool(...) to register save_workflow_template and other template tools.
export function registerTemplateTools( server: McpServer, client: ComfyUIClient, store: TemplateStore, ): void { - src/tools/templates.ts:8-28 (helper)Helper utilities: TEMPLATE_NAME_PATTERN regex, validateName(), templatePath(), ensureTemplatesDir(), TemplateStore interface, StoredTemplate interface, defaultTemplatesDir().
const TEMPLATE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/; export interface TemplateStore { dir: string; } export async function ensureTemplatesDir(dir: string): Promise<void> { await fs.mkdir(dir, { recursive: true }); } function templatePath(dir: string, name: string): string { return path.join(dir, `${name}.json`); } function validateName(name: string): void { if (!TEMPLATE_NAME_PATTERN.test(name)) { throw new Error( `Invalid template name "${name}". Must start with alphanumeric; only letters, digits, '-', '_' allowed; max 64 chars.`, ); } }