comfyui-mcp
Version:
Local-first, agent-native control plane for ComfyUI — MCP server + autonomous sidebar agent that drives your live graph in natural language on ANY LLM: Claude/ChatGPT/Gemini on your subscription (no API key), free local models via Ollama (fully offline),
29 lines • 2.5 kB
JavaScript
import { z } from "zod";
import { applyManifest, manifestSchema } from "../services/manifest.js";
import { errorToToolResult } from "../utils/errors.js";
export function registerManifestTools(server) {
server.tool("apply_manifest", "Apply a ComfyUI setup manifest from an inline object or .json/.yaml/.yml file. Composes custom-node installs and model downloads, installs pip packages, and reports apt entries as skipped (system packages need manual/root installation). LOCAL ComfyUI: model downloads use the connected server's live/data model roots; pip uses the serving checkout (live main.py root, then COMFYUI_CODE_PATH, then COMFYUI_PATH); filesystem custom-node fallbacks use the live data/base root (live --base-directory, then COMFYUI_PATH). REMOTE ComfyUI: custom_nodes and models are routed through the ComfyUI-Manager HTTP API (handled on the host), while pip and apt entries are reported as skipped (no remote equivalent). Each item reports applied/skipped/failed/pending independently. success is true only when nothing failed AND nothing is still pending. A PARTIAL INSTALL (custom_nodes left unsubmitted when the time budget elapsed) is named in the partial field — a drained Manager queue / panel_node_queue_status does not include those entries; re-run apply_manifest to submit them. Do not restart ComfyUI until they report applied or skipped.", {
manifest: manifestSchema
.optional()
.describe("Inline manifest object. Provide exactly one of `manifest` or `path`."),
path: z
.string()
.optional()
.describe("Path to a .json, .yaml, or .yml manifest file. Provide exactly one of `manifest`, `path`, or `pack`."),
pack: z
.string()
.optional()
.describe("A bundled installer pack by NAME, as reported by list_packs (action:\"list\"). PREFER THIS over `path` for a bundled pack: the name is resolved against the running build at apply time, while a manifest_path captured earlier points into an npx cache directory that a later respawn no longer has (#1568). Provide exactly one of `manifest`, `path`, or `pack`."),
}, async (args) => {
try {
const result = await applyManifest(args);
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
};
}
catch (err) {
return errorToToolResult(err);
}
});
}
//# sourceMappingURL=manifest.js.map