> ## Documentation Index
> Fetch the complete documentation index at: https://comfyui-mcp.artokun.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 应用（微应用）

> 把工作流变成一键应用：一份清单、一张暴露出来的运行表单，以及每次运行都会把值打补丁进去的 API 提示快照。在面板里转换，从面板、手机或智能体运行，并发布到公共注册表。

**应用**是为**不带画布**的一键运行而打包的工作流。它是你机器上的一个目录，里面放四样
东西：

| 文件              | 它是什么                                                                |
| --------------- | ------------------------------------------------------------------- |
| `manifest.json` | 名称、描述、`appMode {inputs, outputs}`、`deps`、`hideWorkflow`、`published` |
| `prompt.json`   | API 格式的提示**快照** —— 每次运行都会把值打补丁进去                                    |
| `workflow.json` | litegraph UI 节点图 —— 设置了 `hideWorkflow` 时**不存在**                     |
| `thumbnail.png` | 可选的卡片图                                                              |

包住在 ComfyUI 用户目录下的
`<user>/comfyui-mcp-panel/apps/<app-id>/` —— 故意**不是**工作流目录，这样隐藏的应用
永远不会出现在工作流浏览器里。

```
workflow ⇄ convert (panel) ⇄ app bundle on disk ⇄ run form ⇄ patch snapshot ⇄ ComfyUI queue
                                    ⇅
                        publish / install ⇄ public registry
```

应用自成一层的原因：画布是*运行*你已经信任的工作流的错误界面。带五个带标签字段的表单
才是对的，也是手机或智能体根本能驱动的唯一界面。

<Note>
  存储和运行实现只有**一份** —— 面板包的 HTTP 路由
  （`/comfyui_mcp_panel/apps/*`）。桌面面板、移动端 Apps 标签页，以及 `apps_*` MCP
  工具都是它的客户端，所以无论从哪启动，应用行为都一样。
</Note>

## 要求

应用由**面板包**（`comfyui-mcp-panel`）提供，不是单靠 MCP 服务器。如果你 ComfyUI 上的
包早于这项功能，`apps` 配合 `action:"list"` 会以明确的 *「此 ComfyUI 上的面板包早于
Apps 功能」* 消息失败 —— 更新包并重启 ComfyUI。

## 把工作流转换成应用

在面板里，**Apps** 工具栏按钮（Civitai 旁边）打开应用网格。转换当前打开的工作流会做
三件事：

1. 如果工作流已经带着一份，就**导入 ComfyUI APP 模式配置**，否则用**启发式**挑选输入
   和输出（提示控件、种子、采样器设置；`SaveImage` 类节点当输出）。导入的 APP 模式
   输入在**任何**节点类型上都会被尊重，所以自定义节点端点能熬过转换。
2. **扫描依赖** —— 节点图需要的模型和自定义节点包 —— 写进 `manifest.deps`。
3. 以 API 格式**快照提示**。转换时的控件值变成每个输入的表单 `default`。

`appMode.inputs` 里的每个输入带着 `nodeId`、`widget`、`label`，以及 `text`、`number`、
`combo`、`toggle`、`image` 或 `model` 的 `kind`；combo 还带着 `choices`。运行表单就是
从这些渲染出来的 —— 桌面和移动端都是。

### 隐藏工作流

`hideWorkflow` 会把 `workflow.json` 从包里完全拿掉，于是节点图不会交给运行或安装这个
应用的人。

<Warning>
  **`hideWorkflow` 是混淆，从来不是安全。** 通过 ComfyUI 自己的 `/history` 运行应用的
  人仍然能看到 API 提示，应用安装的模型和自定义节点也会暴露节点图的依赖。把它当成
  「别弄乱我的工作流浏览器」，而不是保护一份你泄漏不起的节点图。
</Warning>

## 运行应用

一次运行会把你的表单值打补丁进已存快照，再把结果入队。补丁键是 `"<nodeId>.<widget>"`
—— 例如 `{"6.text": "a cat", "3.seed": 42}`。键只在**第一个**点上切开，所以自己就
带点的控件名（LoRA 堆、`lora_1.model`）会保持完整。

打补丁是**严格的**：指向快照里不存在的节点或输入的键是硬错误，不是安静跳过。对不上
意味着清单已经和快照脱节，大声失败比带着过期值跑下去更好。你省略的输入保留转换时的
默认值。

运行返回一个 `prompt_id`；轮询它拿状态（`pending` → `running` → `done`，如果 ComfyUI
从没听说过它则是 `unknown`），以及按每个输出节点分组的输出。

### 在 RunPod 实例上运行

面板的 **Run on RunPod** 路径以**干跑**模式复用同一套补丁引擎：面板要打好补丁的提示
*但不*在本地入队，把钉死的依赖推到实例上，再把提示入队到那边。

<Warning>
  带**图像输入**的应用拒绝在实例上跑。上传落在**本地** ComfyUI 上，实例够不到 ——
  所以面板会诚实拒绝，而不是入队一次会因缺文件失败的运行。
</Warning>

## 发布与 Explore

面板的 **Explore** 标签页是一个公共注册表（Cloudflare Worker，后面是 D1 + R2），带
热门 / 最新 / 最多星列表和搜索。热门是 7 天 `stars * 3 + runs`。发布会上传整个包
—— 清单、提示、未隐藏时的工作流、缩略图 —— 挂在以 sha256 为键的创作者身份下。

从 Explore 安装时会先弹出**依赖同意对话框**：应用的 `deps` 是*报告*的，从不静默安装。
你点一张卡片，不会因此在你机器上装模型或自定义节点包。

<Note>
  `pricing_json` 和 `hosted_only` 存在于清单 schema 里，并原样透传，但没有东西读它们。
  它们给一份仅设计阶段的变现预留空间 —— 今天没有付费应用行为。
</Note>

## `apps` MCP 工具

一个工具，五个动作，全是面板 Apps API 上的薄代理。它是**无画布**的那一面：移动端 App
和直接驱动的智能体用的就是它。它在编排器的 `call_tool` 白名单上 —— `list`/`get`/
`run_status` 是只读的，`run` 带着和 `enqueue_workflow` 一样的风险姿态（它入队的是用户
显式点过的任务）。

| 动作                    | 效果                                                                                            |
| --------------------- | --------------------------------------------------------------------------------------------- |
| `action:"list"`       | 列出这台 ComfyUI 上登记的每个应用 —— 每条是完整清单加上 `has_workflow` / `has_prompt` / `has_thumbnail`。没有其他参数。只读。 |
| `action:"get"`        | 按 id 取一个应用的清单 + 包事实。`appMode.inputs` 就是运行表单。只读。                                               |
| `action:"run"`        | 把 `values` 打补丁进快照并入队。返回 `prompt_id`。                                                          |
| `action:"run_status"` | 按 `prompt_id` 轮询一次运行：`status` 加上这次运行的输出（每个输出节点的图像 / 视频文件引用、文本输出）。只读。                          |
| `action:"import"`     | 从公共注册表把一个应用安装到这台 ComfyUI。                                                                     |

### 参数

`action` 是 schema 里唯一必填的参数 —— 每个动作需要不同的子集，所以其余在 schema 里
都是可选的，是否存在由处理器强制，并点名它缺的字段。

| 动作           | 参数             | 类型                | 说明                                |
| ------------ | -------------- | ----------------- | --------------------------------- |
| `get`        | `app_id`       | `string`（uuid），必填 | 来自 `action:"list"`                |
| `run`        | `app_id`       | `string`（uuid），必填 |                                   |
|              | `values`       | `object`，可选       | 键为 `"<nodeId>.<widget>"`；未知键会大声失败 |
| `run_status` | `app_id`       | `string`（uuid），必填 |                                   |
|              | `prompt_id`    | `string`，必填       | 必须匹配 `^[0-9a-zA-Z-]{1,64}$`       |
| `import`     | `registry_url` | `string`（URL），必填  | 必须是默认注册表或已加入允许列表的源                |
|              | `app_id`       | `string`（uuid），必填 | **注册表**应用的 uuid                   |
|              | `slug`         | `string`，可选       | 记入本地元数据                           |
|              | `version`      | `integer`，可选      | 记入本地元数据                           |

`prompt_id` 的形状约束会强制**两次** —— 在 schema 边界，以及在处理器内部再一次 ——
因为这个 id 会插进 URL 路径。即使调用方绕过 schema，形状像路径穿越的「prompt id」也
绝不能到达 URL 构建器。

按工具生成的 schema 参考见 [应用工具](/docs/docs/tools/apps)。

### 从注册表导入

`action:"import"` 在服务端拉取注册表包，并把它创建成本地应用。**注册表 id 变成本地
id**，所以再导入一个你已经有的应用会报告 id 冲突，而不是复制一份。缩略图住在单独的
注册表端点，会分开拉取并转发，于是装好的应用还留着卡片图。

依赖**不会**被安装。工具返回清单里的 `deps`，好让调用方报告它们，并让用户故意去装。

<Warning>
  `registry_url` 是允许列表，不是随便一个 URL。拉取发生在**服务器上**，所以任意 URL
  会是 SSRF 原语 —— 回环或局域网地址，或重定向进其中一个的公网 URL。除非操作员通过
  `COMFYUI_MCP_REGISTRY_URLS`（逗号分隔，给开发 / 预发用）把额外源加入允许列表，否则
  只接受默认公共注册表。重定向会被直接拒绝，而不是跟随。
</Warning>

## 限制与校验

你实际会撞上的东西：

| 限制              | 值          | 在哪                                 |
| --------------- | ---------- | ---------------------------------- |
| 包 / 提示 JSON     | 16 MB      | 比普通节点图更宽，因为提示可能带着 base64 图像        |
| 缩略图             | 5 MB       | 在写任何东西**之前**解码并校验，这样坏缩略图不能留下半成品包   |
| 应用名             | 120 字符     | 截断                                 |
| 描述              | 4000 字符    | 截断                                 |
| Combo `choices` | 200 条      | 截断                                 |
| 注册表拉取           | 16 MB，30 秒 | 同时检查声明的 `content-length` **和**实际字节 |

你会注意到的校验：

* **应用 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"` 拉取包。

这是手机能做、聊天做不到的最清楚的一件事 —— 跑一条真实工作流，带真实输入，视野里
完全没有画布。

## 参见

* [应用工具](/docs/docs/tools/apps) —— 按工具生成的 schema 参考
* [侧边栏面板](/docs/docs/zh/panel) —— 应用在那里转换、发布和浏览
* [移动端 App](/docs/docs/zh/mobile) —— 上下文里的 Apps 标签页
* [RunPod 实例](/docs/docs/tools/runpod) —— 「Run on RunPod」路径瞄准的实例
* [路线图](/docs/docs/zh/roadmap)
