comfyui-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.mcp.json +11 -0
  2. package/dist/comfyui/client.d.ts +16 -0
  3. package/dist/comfyui/client.d.ts.map +1 -0
  4. package/dist/comfyui/client.js +75 -0
  5. package/dist/comfyui/client.js.map +1 -0
  6. package/dist/comfyui/events.d.ts +9 -0
  7. package/dist/comfyui/events.d.ts.map +1 -0
  8. package/dist/comfyui/events.js +40 -0
  9. package/dist/comfyui/events.js.map +1 -0
  10. package/dist/comfyui/types.d.ts +66 -0
  11. package/dist/comfyui/types.d.ts.map +1 -0
  12. package/dist/comfyui/types.js +3 -0
  13. package/dist/comfyui/types.js.map +1 -0
  14. package/dist/config.d.ts +28 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +93 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +22 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/services/mermaid-converter.d.ts +8 -0
  23. package/dist/services/mermaid-converter.d.ts.map +1 -0
  24. package/dist/services/mermaid-converter.js +235 -0
  25. package/dist/services/mermaid-converter.js.map +1 -0
  26. package/dist/services/mermaid-parser.d.ts +31 -0
  27. package/dist/services/mermaid-parser.d.ts.map +1 -0
  28. package/dist/services/mermaid-parser.js +464 -0
  29. package/dist/services/mermaid-parser.js.map +1 -0
  30. package/dist/services/model-resolver.d.ts +25 -0
  31. package/dist/services/model-resolver.d.ts.map +1 -0
  32. package/dist/services/model-resolver.js +123 -0
  33. package/dist/services/model-resolver.js.map +1 -0
  34. package/dist/services/registry-client.d.ts +28 -0
  35. package/dist/services/registry-client.d.ts.map +1 -0
  36. package/dist/services/registry-client.js +32 -0
  37. package/dist/services/registry-client.js.map +1 -0
  38. package/dist/services/skill-generator.d.ts +33 -0
  39. package/dist/services/skill-generator.d.ts.map +1 -0
  40. package/dist/services/skill-generator.js +438 -0
  41. package/dist/services/skill-generator.js.map +1 -0
  42. package/dist/services/workflow-composer.d.ts +43 -0
  43. package/dist/services/workflow-composer.d.ts.map +1 -0
  44. package/dist/services/workflow-composer.js +333 -0
  45. package/dist/services/workflow-composer.js.map +1 -0
  46. package/dist/services/workflow-executor.d.ts +15 -0
  47. package/dist/services/workflow-executor.d.ts.map +1 -0
  48. package/dist/services/workflow-executor.js +63 -0
  49. package/dist/services/workflow-executor.js.map +1 -0
  50. package/dist/tools/index.d.ts +3 -0
  51. package/dist/tools/index.d.ts.map +1 -0
  52. package/dist/tools/index.js +15 -0
  53. package/dist/tools/index.js.map +1 -0
  54. package/dist/tools/model-management.d.ts +3 -0
  55. package/dist/tools/model-management.d.ts.map +1 -0
  56. package/dist/tools/model-management.js +97 -0
  57. package/dist/tools/model-management.js.map +1 -0
  58. package/dist/tools/registry-search.d.ts +3 -0
  59. package/dist/tools/registry-search.d.ts.map +1 -0
  60. package/dist/tools/registry-search.js +70 -0
  61. package/dist/tools/registry-search.js.map +1 -0
  62. package/dist/tools/skill-generator.d.ts +3 -0
  63. package/dist/tools/skill-generator.d.ts.map +1 -0
  64. package/dist/tools/skill-generator.js +42 -0
  65. package/dist/tools/skill-generator.js.map +1 -0
  66. package/dist/tools/workflow-compose.d.ts +3 -0
  67. package/dist/tools/workflow-compose.d.ts.map +1 -0
  68. package/dist/tools/workflow-compose.js +180 -0
  69. package/dist/tools/workflow-compose.js.map +1 -0
  70. package/dist/tools/workflow-execute.d.ts +3 -0
  71. package/dist/tools/workflow-execute.d.ts.map +1 -0
  72. package/dist/tools/workflow-execute.js +115 -0
  73. package/dist/tools/workflow-execute.js.map +1 -0
  74. package/dist/tools/workflow-visualize.d.ts +3 -0
  75. package/dist/tools/workflow-visualize.d.ts.map +1 -0
  76. package/dist/tools/workflow-visualize.js +111 -0
  77. package/dist/tools/workflow-visualize.js.map +1 -0
  78. package/dist/utils/errors.d.ts +24 -0
  79. package/dist/utils/errors.d.ts.map +1 -0
  80. package/dist/utils/errors.js +65 -0
  81. package/dist/utils/errors.js.map +1 -0
  82. package/dist/utils/image.d.ts +4 -0
  83. package/dist/utils/image.d.ts.map +1 -0
  84. package/dist/utils/image.js +10 -0
  85. package/dist/utils/image.js.map +1 -0
  86. package/dist/utils/logger.d.ts +7 -0
  87. package/dist/utils/logger.d.ts.map +1 -0
  88. package/dist/utils/logger.js +22 -0
  89. package/dist/utils/logger.js.map +1 -0
  90. package/package.json +34 -0
@@ -0,0 +1,70 @@
1
+ import { z } from "zod";
2
+ import { searchNodes, getNodePackDetails } from "../services/registry-client.js";
3
+ import { errorToToolResult } from "../utils/errors.js";
4
+ export function registerRegistrySearchTools(server) {
5
+ server.tool("search_custom_nodes", "Search the ComfyUI Registry for custom node packs by keyword", {
6
+ query: z.string().describe("Search query for custom node packs"),
7
+ limit: z
8
+ .number()
9
+ .int()
10
+ .min(1)
11
+ .max(50)
12
+ .optional()
13
+ .describe("Max results to return (default 10)"),
14
+ page: z
15
+ .number()
16
+ .int()
17
+ .min(1)
18
+ .optional()
19
+ .describe("Page number for pagination (default 1)"),
20
+ }, async (args) => {
21
+ try {
22
+ const results = await searchNodes(args.query, {
23
+ limit: args.limit,
24
+ page: args.page,
25
+ });
26
+ const text = results.length === 0
27
+ ? `No custom nodes found for "${args.query}".`
28
+ : results
29
+ .map((r, i) => `${i + 1}. **${r.name}** (${r.id})\n` +
30
+ ` ${r.description ?? "No description"}\n` +
31
+ ` Author: ${r.author} | Installs: ${r.total_install ?? "N/A"} | Version: ${r.latest_version ?? "N/A"}`)
32
+ .join("\n\n");
33
+ return { content: [{ type: "text", text }] };
34
+ }
35
+ catch (err) {
36
+ return errorToToolResult(err);
37
+ }
38
+ });
39
+ server.tool("get_node_pack_details", "Get detailed information about a specific ComfyUI custom node pack from the Registry", {
40
+ id: z.string().describe("Node pack ID (e.g. 'comfyui-impact-pack')"),
41
+ }, async (args) => {
42
+ try {
43
+ const details = await getNodePackDetails(args.id);
44
+ const lines = [
45
+ `# ${details.name}`,
46
+ "",
47
+ details.description ?? "",
48
+ "",
49
+ `- **Author**: ${details.author}`,
50
+ `- **License**: ${details.license ?? "N/A"}`,
51
+ `- **Repository**: ${details.repository ?? "N/A"}`,
52
+ `- **Total Installs**: ${details.total_install ?? "N/A"}`,
53
+ `- **Latest Version**: ${details.latest_version ?? "N/A"}`,
54
+ `- **Created**: ${details.created_at ?? "N/A"}`,
55
+ `- **Updated**: ${details.updated_at ?? "N/A"}`,
56
+ ];
57
+ if (details.nodes?.length) {
58
+ lines.push("", "## Nodes Provided", ...details.nodes.map((n) => `- ${n}`));
59
+ }
60
+ if (details.versions?.length) {
61
+ lines.push("", "## Recent Versions", ...details.versions.slice(0, 5).map((v) => `- **${v.version}**${v.changelog ? `: ${v.changelog}` : ""}`));
62
+ }
63
+ return { content: [{ type: "text", text: lines.join("\n") }] };
64
+ }
65
+ catch (err) {
66
+ return errorToToolResult(err);
67
+ }
68
+ });
69
+ }
70
+ //# sourceMappingURL=registry-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-search.js","sourceRoot":"","sources":["../../src/tools/registry-search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSkillGeneratorTools(server: McpServer): void;
3
+ //# sourceMappingURL=skill-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-generator.d.ts","sourceRoot":"","sources":["../../src/tools/skill-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6CnE"}
@@ -0,0 +1,42 @@
1
+ import { z } from "zod";
2
+ import { generateSkill } from "../services/skill-generator.js";
3
+ import { errorToToolResult } from "../utils/errors.js";
4
+ import { writeFile, mkdir } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ export function registerSkillGeneratorTools(server) {
7
+ server.tool("generate_node_skill", "Analyze a ComfyUI custom node pack and generate a Claude skill (.md) file describing all its nodes, inputs/outputs, and usage examples. Accepts a ComfyUI Registry ID or a GitHub repository URL as the source.", {
8
+ source: z
9
+ .string()
10
+ .describe("ComfyUI Registry node ID (e.g. 'comfyui-impact-pack') or GitHub repository URL"),
11
+ install_in: z
12
+ .string()
13
+ .optional()
14
+ .describe("Optional directory path to save the generated SKILL.md file"),
15
+ }, async (args) => {
16
+ try {
17
+ const markdown = await generateSkill(args.source);
18
+ // Optionally write to disk
19
+ if (args.install_in) {
20
+ const dir = args.install_in;
21
+ await mkdir(dir, { recursive: true });
22
+ const filePath = join(dir, "SKILL.md");
23
+ await writeFile(filePath, markdown, "utf-8");
24
+ return {
25
+ content: [
26
+ {
27
+ type: "text",
28
+ text: `Skill file written to ${filePath}\n\n${markdown}`,
29
+ },
30
+ ],
31
+ };
32
+ }
33
+ return {
34
+ content: [{ type: "text", text: markdown }],
35
+ };
36
+ }
37
+ catch (err) {
38
+ return errorToToolResult(err);
39
+ }
40
+ });
41
+ }
42
+ //# sourceMappingURL=skill-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-generator.js","sourceRoot":"","sources":["../../src/tools/skill-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAW,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,UAAU,2BAA2B,CAAC,MAAiB;IAC3D,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,iNAAiN,EACjN;QACE,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,CACP,gFAAgF,CACjF;QACH,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,6DAA6D,CAC9D;KACJ,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAElD,2BAA2B;YAC3B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC;gBAC5B,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;gBACvC,MAAM,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAC7C,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,yBAAyB,QAAQ,OAAO,QAAQ,EAAE;yBACzD;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;aACrD,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerWorkflowComposeTools(server: McpServer): void;
3
+ //# sourceMappingURL=workflow-compose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-compose.d.ts","sourceRoot":"","sources":["../../src/tools/workflow-compose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAkEpE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyJpE"}
@@ -0,0 +1,180 @@
1
+ import { z } from "zod";
2
+ import { createWorkflow, modifyWorkflow, TEMPLATE_NAMES, } from "../services/workflow-composer.js";
3
+ import { getObjectInfo } from "../comfyui/client.js";
4
+ import { errorToToolResult, ValidationError } from "../utils/errors.js";
5
+ import { logger } from "../utils/logger.js";
6
+ function parseWorkflow(input) {
7
+ if (typeof input === "string") {
8
+ try {
9
+ const parsed = JSON.parse(input);
10
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
11
+ throw new ValidationError("Workflow JSON must be an object with node IDs as keys");
12
+ }
13
+ return parsed;
14
+ }
15
+ catch (err) {
16
+ if (err instanceof ValidationError)
17
+ throw err;
18
+ throw new ValidationError(`Invalid JSON string: ${err.message}`);
19
+ }
20
+ }
21
+ if (typeof input === "object" && input !== null && !Array.isArray(input)) {
22
+ return input;
23
+ }
24
+ throw new ValidationError("Workflow must be a JSON string or object");
25
+ }
26
+ const operationSchema = z.discriminatedUnion("op", [
27
+ z.object({
28
+ op: z.literal("set_input"),
29
+ node_id: z.string(),
30
+ input_name: z.string(),
31
+ value: z.any(),
32
+ }),
33
+ z.object({
34
+ op: z.literal("add_node"),
35
+ class_type: z.string(),
36
+ inputs: z.record(z.any()).optional(),
37
+ id: z.string().optional(),
38
+ }),
39
+ z.object({
40
+ op: z.literal("remove_node"),
41
+ node_id: z.string(),
42
+ }),
43
+ z.object({
44
+ op: z.literal("connect"),
45
+ source_id: z.string(),
46
+ output_index: z.number(),
47
+ target_id: z.string(),
48
+ input_name: z.string(),
49
+ }),
50
+ z.object({
51
+ op: z.literal("insert_between"),
52
+ source_id: z.string(),
53
+ output_index: z.number(),
54
+ target_id: z.string(),
55
+ input_name: z.string(),
56
+ new_class_type: z.string(),
57
+ new_inputs: z.record(z.any()).optional(),
58
+ }),
59
+ ]);
60
+ export function registerWorkflowComposeTools(server) {
61
+ // 1. create_workflow
62
+ server.tool("create_workflow", `Create a ComfyUI workflow from a named template. Available templates: ${TEMPLATE_NAMES.join(", ")}. Returns the complete workflow JSON ready for execution or further modification.`, {
63
+ template: z
64
+ .enum(TEMPLATE_NAMES)
65
+ .describe("Template name: txt2img, img2img, upscale, or inpaint"),
66
+ params: z
67
+ .record(z.any())
68
+ .optional()
69
+ .default({})
70
+ .describe("Template parameters (e.g. checkpoint, positive_prompt, negative_prompt, width, height, steps, cfg, seed, sampler_name, scheduler, denoise, image_path, mask_path, upscale_model)"),
71
+ }, async ({ template, params }) => {
72
+ try {
73
+ logger.info("Creating workflow", { template, params });
74
+ const workflow = createWorkflow(template, params);
75
+ return {
76
+ content: [
77
+ {
78
+ type: "text",
79
+ text: JSON.stringify(workflow, null, 2),
80
+ },
81
+ ],
82
+ };
83
+ }
84
+ catch (err) {
85
+ return errorToToolResult(err);
86
+ }
87
+ });
88
+ // 2. modify_workflow
89
+ server.tool("modify_workflow", "Apply modification operations to an existing ComfyUI workflow. Supports: set_input, add_node, remove_node, connect, insert_between. Returns the modified workflow JSON and IDs of any newly added nodes.", {
90
+ workflow: z
91
+ .union([z.string(), z.record(z.any())])
92
+ .describe("ComfyUI workflow JSON (as a JSON string or object)"),
93
+ operations: z
94
+ .array(operationSchema)
95
+ .describe("Array of operations to apply in order. Each has an 'op' field: set_input, add_node, remove_node, connect, or insert_between"),
96
+ }, async ({ workflow, operations }) => {
97
+ try {
98
+ logger.info("Modifying workflow", { opCount: operations.length });
99
+ const parsed = parseWorkflow(workflow);
100
+ const result = modifyWorkflow(parsed, operations);
101
+ return {
102
+ content: [
103
+ {
104
+ type: "text",
105
+ text: JSON.stringify({
106
+ workflow: result.workflow,
107
+ added_node_ids: result.added_ids,
108
+ }, null, 2),
109
+ },
110
+ ],
111
+ };
112
+ }
113
+ catch (err) {
114
+ return errorToToolResult(err);
115
+ }
116
+ });
117
+ // 3. get_node_info
118
+ server.tool("get_node_info", "Query ComfyUI's /object_info endpoint to get available node type definitions. Optionally filter by node type name (substring match). Returns node inputs, outputs, and descriptions.", {
119
+ node_type: z
120
+ .string()
121
+ .optional()
122
+ .describe("Filter by node class_type name (case-insensitive substring match). Omit to list all available nodes."),
123
+ }, async ({ node_type }) => {
124
+ try {
125
+ logger.info("Getting node info", { filter: node_type });
126
+ const info = await getObjectInfo();
127
+ let entries = Object.entries(info);
128
+ if (node_type) {
129
+ const lower = node_type.toLowerCase();
130
+ entries = entries.filter(([name]) => name.toLowerCase().includes(lower));
131
+ }
132
+ if (entries.length === 0) {
133
+ return {
134
+ content: [
135
+ {
136
+ type: "text",
137
+ text: node_type
138
+ ? `No nodes found matching "${node_type}"`
139
+ : "No node definitions returned from ComfyUI",
140
+ },
141
+ ],
142
+ };
143
+ }
144
+ // For large result sets, return just names + descriptions
145
+ if (entries.length > 20) {
146
+ const summary = entries.map(([name, def]) => ({
147
+ name,
148
+ display_name: def.display_name,
149
+ category: def.category,
150
+ description: def.description || "",
151
+ }));
152
+ return {
153
+ content: [
154
+ {
155
+ type: "text",
156
+ text: JSON.stringify({
157
+ count: summary.length,
158
+ nodes: summary,
159
+ hint: "Use a more specific node_type filter to see full definitions with inputs/outputs",
160
+ }, null, 2),
161
+ },
162
+ ],
163
+ };
164
+ }
165
+ const result = Object.fromEntries(entries);
166
+ return {
167
+ content: [
168
+ {
169
+ type: "text",
170
+ text: JSON.stringify(result, null, 2),
171
+ },
172
+ ],
173
+ };
174
+ }
175
+ catch (err) {
176
+ return errorToToolResult(err);
177
+ }
178
+ });
179
+ }
180
+ //# sourceMappingURL=workflow-compose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-compose.js","sourceRoot":"","sources":["../../src/tools/workflow-compose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerWorkflowExecuteTools(server: McpServer): void;
3
+ //# sourceMappingURL=workflow-execute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-execute.d.ts","sourceRoot":"","sources":["../../src/tools/workflow-execute.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAUzE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgJpE"}
@@ -0,0 +1,115 @@
1
+ import { z } from "zod";
2
+ import { executeWorkflow, getJobStatus, getQueueStatus, cancelCurrentJob, getSystemInfo, } from "../services/workflow-executor.js";
3
+ import { errorToToolResult } from "../utils/errors.js";
4
+ export function registerWorkflowExecuteTools(server) {
5
+ server.tool("run_workflow", "Execute a ComfyUI workflow (API format JSON). Returns generated images as base64. The workflow must be in ComfyUI's API/prompt format — a mapping of node IDs to {class_type, inputs}.", {
6
+ workflow: z
7
+ .record(z.string(), z.any())
8
+ .describe("ComfyUI workflow in API format (node ID -> {class_type, inputs})"),
9
+ timeout_ms: z
10
+ .number()
11
+ .int()
12
+ .positive()
13
+ .optional()
14
+ .describe("Execution timeout in milliseconds (default: 10 minutes)"),
15
+ disable_random_seed: z
16
+ .boolean()
17
+ .optional()
18
+ .describe("If true, do not randomize seed values"),
19
+ }, async (args) => {
20
+ try {
21
+ const result = await executeWorkflow(args.workflow, {
22
+ timeout_ms: args.timeout_ms,
23
+ disable_random_seed: args.disable_random_seed,
24
+ });
25
+ const content = [];
26
+ content.push({
27
+ type: "text",
28
+ text: `Workflow executed successfully. prompt_id: ${result.prompt_id}, images: ${result.images.length}`,
29
+ });
30
+ for (const img of result.images) {
31
+ content.push({
32
+ type: "image",
33
+ data: img.data,
34
+ mimeType: img.mime,
35
+ });
36
+ }
37
+ return { content };
38
+ }
39
+ catch (err) {
40
+ return errorToToolResult(err);
41
+ }
42
+ });
43
+ server.tool("get_job_status", "Check the execution status of a ComfyUI prompt/job by its ID.", {
44
+ prompt_id: z.string().describe("The prompt ID returned by run_workflow"),
45
+ }, async (args) => {
46
+ try {
47
+ const status = await getJobStatus(args.prompt_id);
48
+ return {
49
+ content: [
50
+ {
51
+ type: "text",
52
+ text: JSON.stringify(status, null, 2),
53
+ },
54
+ ],
55
+ };
56
+ }
57
+ catch (err) {
58
+ return errorToToolResult(err);
59
+ }
60
+ });
61
+ server.tool("get_queue", "Get the current ComfyUI execution queue showing running and pending jobs.", {}, async () => {
62
+ try {
63
+ const queue = await getQueueStatus();
64
+ return {
65
+ content: [
66
+ {
67
+ type: "text",
68
+ text: JSON.stringify({
69
+ running: queue.queue_running.length,
70
+ pending: queue.queue_pending.length,
71
+ queue_running: queue.queue_running,
72
+ queue_pending: queue.queue_pending,
73
+ }, null, 2),
74
+ },
75
+ ],
76
+ };
77
+ }
78
+ catch (err) {
79
+ return errorToToolResult(err);
80
+ }
81
+ });
82
+ server.tool("cancel_job", "Interrupt/cancel the currently running ComfyUI job.", {}, async () => {
83
+ try {
84
+ await cancelCurrentJob();
85
+ return {
86
+ content: [
87
+ {
88
+ type: "text",
89
+ text: "Current job cancelled successfully.",
90
+ },
91
+ ],
92
+ };
93
+ }
94
+ catch (err) {
95
+ return errorToToolResult(err);
96
+ }
97
+ });
98
+ server.tool("get_system_stats", "Get ComfyUI system information including GPU, VRAM, Python version, and OS details.", {}, async () => {
99
+ try {
100
+ const stats = await getSystemInfo();
101
+ return {
102
+ content: [
103
+ {
104
+ type: "text",
105
+ text: JSON.stringify(stats, null, 2),
106
+ },
107
+ ],
108
+ };
109
+ }
110
+ catch (err) {
111
+ return errorToToolResult(err);
112
+ }
113
+ });
114
+ }
115
+ //# sourceMappingURL=workflow-execute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-execute.js","sourceRoot":"","sources":["../../src/tools/workflow-execute.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerWorkflowVisualizeTools(server: McpServer): void;
3
+ //# sourceMappingURL=workflow-visualize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-visualize.d.ts","sourceRoot":"","sources":["../../src/tools/workflow-visualize.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2BpE,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkHtE"}
@@ -0,0 +1,111 @@
1
+ import { z } from "zod";
2
+ import { convertToMermaid } from "../services/mermaid-converter.js";
3
+ import { parseMermaid, resolveWorkflow } from "../services/mermaid-parser.js";
4
+ import { getObjectInfo } from "../comfyui/client.js";
5
+ import { errorToToolResult, ValidationError } from "../utils/errors.js";
6
+ import { logger } from "../utils/logger.js";
7
+ function parseWorkflow(input) {
8
+ if (typeof input === "string") {
9
+ try {
10
+ const parsed = JSON.parse(input);
11
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
12
+ throw new ValidationError("Workflow JSON must be an object with node IDs as keys");
13
+ }
14
+ return parsed;
15
+ }
16
+ catch (err) {
17
+ if (err instanceof ValidationError)
18
+ throw err;
19
+ throw new ValidationError(`Invalid JSON string: ${err.message}`);
20
+ }
21
+ }
22
+ if (typeof input === "object" && input !== null && !Array.isArray(input)) {
23
+ return input;
24
+ }
25
+ throw new ValidationError("Workflow must be a JSON string or object");
26
+ }
27
+ export function registerWorkflowVisualizeTools(server) {
28
+ server.tool("visualize_workflow", "Convert a ComfyUI workflow JSON into a Mermaid flowchart diagram. Returns mermaid syntax showing nodes grouped by category (loading, conditioning, sampling, image, output) with connections labeled by data type.", {
29
+ workflow: z
30
+ .union([z.string(), z.record(z.any())])
31
+ .describe("ComfyUI workflow JSON (as a JSON string or object)"),
32
+ show_values: z
33
+ .boolean()
34
+ .optional()
35
+ .default(true)
36
+ .describe("Include widget values (seed, steps, cfg, etc.) in node labels"),
37
+ direction: z
38
+ .enum(["LR", "TB"])
39
+ .optional()
40
+ .default("LR")
41
+ .describe("Flowchart direction: LR (left-to-right) or TB (top-to-bottom)"),
42
+ }, async ({ workflow, show_values, direction }) => {
43
+ try {
44
+ logger.info("Visualizing workflow");
45
+ const parsed = parseWorkflow(workflow);
46
+ const nodeCount = Object.keys(parsed).length;
47
+ if (nodeCount === 0) {
48
+ throw new ValidationError("Workflow contains no nodes");
49
+ }
50
+ const mermaid = convertToMermaid(parsed, {
51
+ showValues: show_values,
52
+ direction,
53
+ });
54
+ return {
55
+ content: [
56
+ {
57
+ type: "text",
58
+ text: `\`\`\`mermaid\n${mermaid}\n\`\`\``,
59
+ },
60
+ ],
61
+ };
62
+ }
63
+ catch (err) {
64
+ return errorToToolResult(err);
65
+ }
66
+ });
67
+ server.tool("mermaid_to_workflow", "Convert a Mermaid flowchart diagram back into a ComfyUI workflow JSON. " +
68
+ "Parses node definitions, connections (with data type labels), and widget values from the mermaid syntax. " +
69
+ "Resolves node types and wires connections using ComfyUI's /object_info schemas. " +
70
+ "Fills missing inputs with defaults. Returns a valid, executable ComfyUI API workflow.", {
71
+ mermaid: z
72
+ .string()
73
+ .describe("Mermaid flowchart text (with or without ```mermaid code fence). " +
74
+ "Nodes should use ComfyUI class_type names as labels. " +
75
+ "Connections should be labeled with data types (e.g., -->|MODEL|)."),
76
+ }, async ({ mermaid }) => {
77
+ try {
78
+ logger.info("Converting mermaid to workflow");
79
+ // Parse the mermaid text into nodes and edges
80
+ const parsed = parseMermaid(mermaid);
81
+ logger.info(`Parsed ${parsed.nodes.size} nodes and ${parsed.edges.length} edges`);
82
+ // Fetch node definitions from ComfyUI for schema resolution
83
+ const objectInfo = await getObjectInfo();
84
+ // Resolve into a valid workflow
85
+ const { workflow, warnings } = resolveWorkflow(parsed, objectInfo);
86
+ const nodeCount = Object.keys(workflow).length;
87
+ const connectionCount = Object.values(workflow).reduce((count, node) => count +
88
+ Object.values(node.inputs).filter((v) => Array.isArray(v) &&
89
+ v.length === 2 &&
90
+ typeof v[0] === "string" &&
91
+ typeof v[1] === "number").length, 0);
92
+ const content = [];
93
+ // Summary
94
+ let summary = `Converted mermaid to workflow: ${nodeCount} nodes, ${connectionCount} connections.`;
95
+ if (warnings.length > 0) {
96
+ summary += `\n\n**Warnings (${warnings.length}):**\n${warnings.map((w) => `- ${w}`).join("\n")}`;
97
+ }
98
+ content.push({ type: "text", text: summary });
99
+ // The workflow JSON
100
+ content.push({
101
+ type: "text",
102
+ text: JSON.stringify(workflow, null, 2),
103
+ });
104
+ return { content };
105
+ }
106
+ catch (err) {
107
+ return errorToToolResult(err);
108
+ }
109
+ });
110
+ }
111
+ //# sourceMappingURL=workflow-visualize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-visualize.js","sourceRoot":"","sources":["../../src/tools/workflow-visualize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3E,MAAM,IAAI,eAAe,CAAC,uDAAuD,CAAC,CAAC;YACrF,CAAC;YACD,OAAO,MAAsB,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,eAAe;gBAAE,MAAM,GAAG,CAAC;YAC9C,MAAM,IAAI,eAAe,CAAC,wBAAyB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzE,OAAO,KAAqB,CAAC;IAC/B,CAAC;IACD,MAAM,IAAI,eAAe,CAAC,0CAA0C,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,MAAiB;IAC9D,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,oNAAoN,EACpN;QACE,QAAQ,EAAE,CAAC;aACR,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;aACtC,QAAQ,CAAC,oDAAoD,CAAC;QACjE,WAAW,EAAE,CAAC;aACX,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,OAAO,CAAC,IAAI,CAAC;aACb,QAAQ,CAAC,+DAA+D,CAAC;QAC5E,SAAS,EAAE,CAAC;aACT,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;aAClB,QAAQ,EAAE;aACV,OAAO,CAAC,IAAI,CAAC;aACb,QAAQ,CAAC,+DAA+D,CAAC;KAC7E,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,EAAE;QAC7C,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACpC,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;YAEvC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;YAC7C,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;gBACpB,MAAM,IAAI,eAAe,CAAC,4BAA4B,CAAC,CAAC;YAC1D,CAAC;YAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,EAAE;gBACvC,UAAU,EAAE,WAAW;gBACvB,SAAS;aACV,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,kBAAkB,OAAO,UAAU;qBAC1C;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,yEAAyE;QACvE,2GAA2G;QAC3G,kFAAkF;QAClF,uFAAuF,EACzF;QACE,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,QAAQ,CACP,kEAAkE;YAChE,uDAAuD;YACvD,mEAAmE,CACtE;KACJ,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACpB,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;YAE9C,8CAA8C;YAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YACrC,MAAM,CAAC,IAAI,CACT,UAAU,MAAM,CAAC,KAAK,CAAC,IAAI,cAAc,MAAM,CAAC,KAAK,CAAC,MAAM,QAAQ,CACrE,CAAC;YAEF,4DAA4D;YAC5D,MAAM,UAAU,GAAG,MAAM,aAAa,EAAE,CAAC;YAEzC,gCAAgC;YAChC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAEnE,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;YAC/C,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CACpD,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CACd,KAAK;gBACL,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAC/B,CAAC,CAAC,EAAE,EAAE,CACJ,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;oBAChB,CAAC,CAAC,MAAM,KAAK,CAAC;oBACd,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ;oBACxB,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ,CAC3B,CAAC,MAAM,EACV,CAAC,CACF,CAAC;YAEF,MAAM,OAAO,GAA0C,EAAE,CAAC;YAE1D,UAAU;YACV,IAAI,OAAO,GAAG,kCAAkC,SAAS,WAAW,eAAe,eAAe,CAAC;YACnG,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,OAAO,IAAI,mBAAmB,QAAQ,CAAC,MAAM,SAAS,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnG,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YAE9C,oBAAoB;YACpB,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;aACxC,CAAC,CAAC;YAEH,OAAO,EAAE,OAAO,EAAE,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ export declare class ComfyUIError extends Error {
3
+ readonly code: string;
4
+ readonly details?: unknown | undefined;
5
+ constructor(message: string, code: string, details?: unknown | undefined);
6
+ toToolResult(): CallToolResult;
7
+ }
8
+ export declare class ConnectionError extends ComfyUIError {
9
+ constructor(message: string);
10
+ }
11
+ export declare class WorkflowExecutionError extends ComfyUIError {
12
+ constructor(message: string, details?: unknown);
13
+ }
14
+ export declare class ValidationError extends ComfyUIError {
15
+ constructor(message: string);
16
+ }
17
+ export declare class RegistryError extends ComfyUIError {
18
+ constructor(message: string, details?: unknown);
19
+ }
20
+ export declare class ModelError extends ComfyUIError {
21
+ constructor(message: string, details?: unknown);
22
+ }
23
+ export declare function errorToToolResult(err: unknown): CallToolResult;
24
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,qBAAa,YAAa,SAAQ,KAAK;aAGnB,IAAI,EAAE,MAAM;aACZ,OAAO,CAAC,EAAE,OAAO;gBAFjC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,YAAA;IAMnC,YAAY,IAAI,cAAc;CAe/B;AAED,qBAAa,eAAgB,SAAQ,YAAY;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,sBAAuB,SAAQ,YAAY;gBAC1C,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAI/C;AAED,qBAAa,eAAgB,SAAQ,YAAY;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,aAAc,SAAQ,YAAY;gBACjC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAI/C;AAED,qBAAa,UAAW,SAAQ,YAAY;gBAC9B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAI/C;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAO9D"}