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),
79 lines • 2.85 kB
JavaScript
import { logger } from "../utils/logger.js";
/**
* Captures server.tool(...) registrations into a plain map instead of a live
* MCP server. This powers the compact tool mode (COMFYUI_MCP_TOOL_MODE=compact)
* for small/local LLMs: the full ~200-schema surface overwhelms their context,
* so the real server registers only meta-tools (list_tools / describe_tool /
* call_tool) that consult this catalog and dispatch to the original handlers.
* Every file in src/tools registers via the 4-arg
* server.tool(name, description, zodRawShape, handler) overload; capture()
* parses defensively so other SDK overloads degrade to warn-and-skip rather
* than breaking startup.
*/
export class ToolCatalog {
tools = new Map();
category = "general";
/** Category applied to subsequent captures (set per register-group). */
setCategory(category) {
this.category = category;
}
get(name) {
return this.tools.get(name);
}
/** Categories in first-seen order, each with its tools in registration order. */
byCategory() {
const grouped = new Map();
for (const tool of this.tools.values()) {
const list = grouped.get(tool.category);
if (list)
list.push(tool);
else
grouped.set(tool.category, [tool]);
}
return grouped;
}
/**
* Duck-typed stand-in accepted by the registerXxxTools(server) functions.
* Only .tool() is implemented — a grep of src/tools confirms no register
* function touches any other McpServer member.
*/
asRegistrar() {
const registrar = {
tool: (...args) => {
this.capture(args);
return {};
},
};
return registrar;
}
capture(args) {
const name = args[0];
const handler = args[args.length - 1];
if (typeof name !== "string" || typeof handler !== "function" || args.length < 2) {
logger.warn("ToolCatalog: skipped a server.tool() call with an unrecognized shape", {
argTypes: args.map((a) => typeof a),
});
return;
}
let description = "";
let schema;
for (const arg of args.slice(1, -1)) {
if (typeof arg === "string")
description = arg;
else if (arg && typeof arg === "object" && schema === undefined)
schema = arg;
}
if (this.tools.has(name)) {
logger.warn(`ToolCatalog: duplicate tool '${name}' — keeping the first registration`);
return;
}
this.tools.set(name, {
name,
description,
category: this.category,
schema,
handler: handler,
});
}
}
//# sourceMappingURL=catalog.js.map