包住在 ComfyUI 用户目录下的
<user>/comfyui-mcp-panel/apps/<app-id>/ —— 故意不是工作流目录,这样隐藏的应用
永远不会出现在工作流浏览器里。
存储和运行实现只有一份 —— 面板包的 HTTP 路由
(
/comfyui_mcp_panel/apps/*)。桌面面板、移动端 Apps 标签页,以及 apps_* MCP
工具都是它的客户端,所以无论从哪启动,应用行为都一样。要求
应用由面板包(comfyui-mcp-panel)提供,不是单靠 MCP 服务器。如果你 ComfyUI 上的
包早于这项功能,apps 配合 action:"list" 会以明确的 「此 ComfyUI 上的面板包早于
Apps 功能」 消息失败 —— 更新包并重启 ComfyUI。
把工作流转换成应用
在面板里,Apps 工具栏按钮(Civitai 旁边)打开应用网格。转换当前打开的工作流会做 三件事:- 如果工作流已经带着一份,就导入 ComfyUI APP 模式配置,否则用启发式挑选输入
和输出(提示控件、种子、采样器设置;
SaveImage类节点当输出)。导入的 APP 模式 输入在任何节点类型上都会被尊重,所以自定义节点端点能熬过转换。 - 扫描依赖 —— 节点图需要的模型和自定义节点包 —— 写进
manifest.deps。 - 以 API 格式快照提示。转换时的控件值变成每个输入的表单
default。
appMode.inputs 里的每个输入带着 nodeId、widget、label,以及 text、number、
combo、toggle、image 或 model 的 kind;combo 还带着 choices。运行表单就是
从这些渲染出来的 —— 桌面和移动端都是。
隐藏工作流
hideWorkflow 会把 workflow.json 从包里完全拿掉,于是节点图不会交给运行或安装这个
应用的人。
运行应用
一次运行会把你的表单值打补丁进已存快照,再把结果入队。补丁键是"<nodeId>.<widget>"
—— 例如 {"6.text": "a cat", "3.seed": 42}。键只在第一个点上切开,所以自己就
带点的控件名(LoRA 堆、lora_1.model)会保持完整。
打补丁是严格的:指向快照里不存在的节点或输入的键是硬错误,不是安静跳过。对不上
意味着清单已经和快照脱节,大声失败比带着过期值跑下去更好。你省略的输入保留转换时的
默认值。
运行返回一个 prompt_id;轮询它拿状态(pending → running → done,如果 ComfyUI
从没听说过它则是 unknown),以及按每个输出节点分组的输出。
在 RunPod 实例上运行
面板的 Run on RunPod 路径以干跑模式复用同一套补丁引擎:面板要打好补丁的提示 但不在本地入队,把钉死的依赖推到实例上,再把提示入队到那边。发布与 Explore
面板的 Explore 标签页是一个公共注册表(Cloudflare Worker,后面是 D1 + R2),带 热门 / 最新 / 最多星列表和搜索。热门是 7 天stars * 3 + runs。发布会上传整个包
—— 清单、提示、未隐藏时的工作流、缩略图 —— 挂在以 sha256 为键的创作者身份下。
从 Explore 安装时会先弹出依赖同意对话框:应用的 deps 是报告的,从不静默安装。
你点一张卡片,不会因此在你机器上装模型或自定义节点包。
pricing_json 和 hosted_only 存在于清单 schema 里,并原样透传,但没有东西读它们。
它们给一份仅设计阶段的变现预留空间 —— 今天没有付费应用行为。apps MCP 工具
一个工具,五个动作,全是面板 Apps API 上的薄代理。它是无画布的那一面:移动端 App
和直接驱动的智能体用的就是它。它在编排器的 call_tool 白名单上 —— list/get/
run_status 是只读的,run 带着和 enqueue_workflow 一样的风险姿态(它入队的是用户
显式点过的任务)。
参数
action 是 schema 里唯一必填的参数 —— 每个动作需要不同的子集,所以其余在 schema 里
都是可选的,是否存在由处理器强制,并点名它缺的字段。
prompt_id 的形状约束会强制两次 —— 在 schema 边界,以及在处理器内部再一次 ——
因为这个 id 会插进 URL 路径。即使调用方绕过 schema,形状像路径穿越的「prompt id」也
绝不能到达 URL 构建器。
按工具生成的 schema 参考见 应用工具。
从注册表导入
action:"import" 在服务端拉取注册表包,并把它创建成本地应用。注册表 id 变成本地
id,所以再导入一个你已经有的应用会报告 id 冲突,而不是复制一份。缩略图住在单独的
注册表端点,会分开拉取并转发,于是装好的应用还留着卡片图。
依赖不会被安装。工具返回清单里的 deps,好让调用方报告它们,并让用户故意去装。
限制与校验
你实际会撞上的东西:
你会注意到的校验:
- 应用 id 必须是 uuid。 其他任何东西都会在路径建好之前被拒绝,解析后的包路径还会 再检查是否落在应用根目录之内。
- 提示必须是 API 格式 —— 数字节点 id 键,每个节点是
{class_type, inputs}对象。 UI 格式的节点图会被拒绝。 - 除非设置了
hideWorkflow,否则需要 UI 工作流。 - 创建已存在的应用是冲突,不是覆盖。
- 部分清单更新真的是部分的。 发布或隐藏应用只发送它自己的字段,不会抹掉你的名称、
描述或
appMode。 - 未知清单键会被丢掉,除了保留的透传字段,这样更旧的机器会忽略它不认识的字段, 而不是失败。
COMFYUI_MCP_APPS_DIR 覆盖(主要用于测试);默认从 ComfyUI 自己的
用户目录派生,所以便携安装也能熬过去。
在手机上
移动端 App 带了一个真正的 Apps 标签页 —— 不是预览。它有两半:- My Apps —— 装在你机器上的应用,通过桥接用
action:"list"列出。点开一个会打开 生成的运行表单,用action:"run"入队,并每 2 秒轮询action:"run_status"(上限 30 分钟),直到输出渲染出来。 - Explore —— 公共注册表,从手机直接走 HTTPS(没有桥接那一跳,所以配对之前就能
浏览)。安装走另一个方向:机器自己通过
action:"import"拉取包。