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),
53 lines • 3.89 kB
JavaScript
import { z } from "zod";
import { stopComfyUI, startComfyUI, restartComfyUI, } from "../services/process-control.js";
import { errorToToolResult } from "../utils/errors.js";
/**
* The three ComfyUI process-lifecycle tools collapsed into one
* action-parameterized `restart_comfyui` tool (0.50.0 surface consolidation,
* slice 7).
*
* SHAPE: a FLAT object with an `action` enum — deliberately NOT a
* z.discriminatedUnion, which the MCP SDK renders as a schema with ZERO visible
* parameters, hiding every input from the model.
*
* REQUIREDNESS: all three retired tools took NO parameters at all, so `action`
* is not merely the only schema-required field, it is the only field. There is
* consequently no per-action presence guard to write here — the handler's only
* job is to dispatch. Each branch calls the same service function the old tool
* called, with the same (empty) arguments, and returns the identical content
* block: the service result as pretty-printed JSON.
*/
export function registerProcessControlTools(server) {
server.tool("restart_comfyui", "Control the lifecycle of the ComfyUI server process. Driven by the `action` parameter:\n" +
'- action:"restart" — Restart ComfyUI: stops the running process (capturing its config), waits for the port to free, relaunches with the same arguments, and polls the API for bounded readiness. Also works against a REMOTE/tunnelled ComfyUI (via --comfyui-url) by rebooting through ComfyUI-Manager over HTTP and polling for it to come back (requires ComfyUI-Manager present and its security level permitting the reboot). When COMFYUI_RESTART_COMMAND is set, a LOCAL restart runs that command instead of kill+relaunch — the recovery path for an externally managed install (a container, a systemd unit, a launcher) whose launch path cannot be proven from here. This is the normal way to reload newly installed custom nodes, and the escalation when queue (action:"cancel") reports a job WEDGED.\n' +
'- action:"start" — Start ComfyUI using process info saved from a previous action:"stop" call. Supports both Desktop app and manual Python installs. Polls the API for bounded readiness before reporting ready. Local installs only.\n' +
'- action:"stop" — Stop the running ComfyUI process. Captures process info so it can be restarted with action:"start". Kills the process tree and resets the WebSocket client. Local installs only. Anything queued or rendering is lost.', {
action: z
.enum(["restart", "start", "stop"])
.describe('Which process operation to perform. None of them takes any other parameter. "restart" stops and relaunches in one call (and is the only action that also works against a remote/tunnelled ComfyUI); "start" relaunches from the info a previous "stop" saved; "stop" kills the running process tree.'),
}, async (args) => {
try {
const json = (value) => ({
content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
});
switch (args.action) {
case "restart":
return json(await restartComfyUI());
case "start":
return json(await startComfyUI());
case "stop":
return json(await stopComfyUI());
default: {
// Unreachable given the zod enum, but a clear runtime guard beats a
// silent undefined if the schema and switch ever drift apart.
const exhaustive = args.action;
throw new Error(`Unknown restart_comfyui action "${String(exhaustive)}". Expected one of: restart, start, stop.`);
}
}
}
catch (err) {
return errorToToolResult(err);
}
});
}
//# sourceMappingURL=process-control.js.map