> ## 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_*` MCP 도구는 모두 그 클라이언트이므로, 어디서 실행하든 앱은
  똑같이 동작합니다.
</Note>

## 요구 사항

앱은 MCP 서버만이 아니라 **패널 팩** (`comfyui-mcp-panel`)이
제공합니다. ComfyUI의 팩이 이 기능보다 오래되면, `apps`의
`action:"list"`가 \*"the panel pack on this ComfyUI predates the Apps
feature"\*라는 명시적 메시지로 실패합니다 — 팩을 업데이트하고 ComfyUI를 재시작하세요.

## 워크플로우를 앱으로 변환하기

패널에서 **앱** 툴바 버튼(Civitai 옆)이 앱 그리드를 엽니다.
열린 워크플로우를 변환하면 세 가지를 합니다:

1. 워크플로우가 이미 가지고 있으면 **ComfyUI APP-모드 설정을 가져오고**,
   없으면 입력과 출력을 **휴리스틱으로** 고릅니다 (프롬프트 위젯, 시드,
   샘플러 설정. 출력은 `SaveImage` 계열 노드). 가져온 APP-모드
   입력은 **어떤** 노드 타입이든 존중되므로, 커스텀 노드 엔드포인트가
   변환을 견딥니다.
2. **의존성을 스캔**합니다 — 그래프가 필요로 하는 모델과 커스텀 노드 팩을
   `manifest.deps`로.
3. API 형식으로 **프롬프트를 스냅샷**합니다. 변환 시점의 위젯 값이
   각 입력의 폼 `default`가 됩니다.

`appMode.inputs`의 각 입력은 `nodeId`, `widget`, `label`, 그리고
`text`, `number`, `combo`, `toggle`, `image`, 또는 `model`의 `kind`를
가집니다. 콤보는 `choices`도 가집니다. 실행 폼이 데스크톱과 모바일에서
렌더링하는 것이 그것입니다.

### 워크플로우 숨기기

`hideWorkflow`는 번들에서 `workflow.json`을 완전히 빼므로, 그래프가
앱을 실행하거나 설치하는 사람에게 건네지지 않습니다.

<Warning>
  **`hideWorkflow`는 난독일 뿐, 보안이 아닙니다.** API 프롬프트는 여전히
  ComfyUI 자체의 `/history`를 통해 앱을 실행하는 누구에게나 보이며, 앱이
  설치하는 모델과 커스텀 노드가 그래프의 의존성을 드러냅니다.
  "워크플로우 브라우저를 어지럽히지 마"로 다루세요. 새어 나가면 안 되는
  그래프의 보호가 아닙니다.
</Warning>

## 앱 실행하기

실행은 폼 값을 저장된 스냅샷에 패치하고 결과를 대기열에 넣습니다.
패치 키는 `"<nodeId>.<widget>"`입니다 — 예를 들어 `{"6.text": "a cat",
"3.seed": 42}`. 키는 **첫** 점만으로 갈라지므로, 점 자체를 담은
위젯 이름(LoRA 스택, `lora_1.model`)은 그대로 남습니다.

패치는 **엄격**합니다: 스냅샷에 없는 노드나 입력을 가리키는 키는
조용한 건너뛰기가 아니라 무조건 오류입니다. 빗나감은 매니페스트가
스냅샷에서 어긋났다는 뜻이고, 오래된 값으로 실행하는 것보다 크게
실패하는 편이 낫습니다. 생략한 입력은 변환 시점 기본값을 유지합니다.

실행은 `prompt_id`를 반환합니다. 상태를 폴링하세요 (`pending` → `running` →
`done`, ComfyUI가 들어 본 적 없으면 `unknown`) 그리고 각 출력 노드 아래
묶인 출력을.

### RunPod 파드에서 실행하기

패널의 **RunPod에서 실행** 경로는 같은 패치 엔진을 **dry** 모드로 재사용합니다:
패널이 로컬에서 대기열에 넣지 *않고* 패치된 프롬프트를 요청하고, 고정된
의존성을 파드에 밀어 넣은 뒤, 그 대신 거기서 프롬프트를 대기열에 넣습니다.

<Warning>
  **이미지 입력**이 있는 앱은 파드에서 실행을 거부합니다. 업로드는
  **로컬** ComfyUI에 착지하고, 파드는 거기에 닿을 수 없습니다 — 그래서 패널은
  없는 파일로 실패할 실행을 대기열에 넣는 대신 정직하게 거절합니다.
</Warning>

## 게시와 Explore

패널의 **Explore** 탭은 공개 레지스트리입니다 (D1 + R2를 뒷배로 하는
Cloudflare Worker). 트렌딩 / 새로움 / 별이 많은 목록과 검색이 있습니다. 트렌딩은
7일 `stars * 3 + runs`입니다. 게시는 번들 — 매니페스트, 프롬프트,
숨기지 않았다면 워크플로우, 썸네일 — 을 sha256 키 크리에이터 신원 아래
업로드합니다.

Explore에서 설치하면 먼저 **의존성 동의 대화상자**가 보입니다: 앱의
`deps`는 *보고될* 뿐, 조용히 설치되지 않습니다. 카드를 탭했다고 해서
장비에 모델이나 커스텀 노드 팩이 설치되지 않습니다.

<Note>
  `pricing_json`과 `hosted_only`는 매니페스트 스키마에 있고 그대로
  통과하지만, 아무것도 읽지 않습니다. 설계 전용 수익화 단계를 위한
  자리를 예약합니다 — 오늘 유료 앱 동작은 없습니다.
</Note>

## `apps` MCP 도구

액션 다섯 개의 도구 하나, 모두 패널의 Apps API 위 얇은 프록시입니다.
**캔버스 없는** 표면입니다: 모바일 앱과 직접 구동되는 에이전트가 쓰는 것.
오케스트레이터의 `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`만 스키마 필수 매개변수입니다 — 각 액션이 다른
부분집합을 필요로 하므로, 나머지는 스키마에서 선택 사항이고 존재는
핸들러가 강제하며, 빠진 필드 이름을 말합니다.

| 액션           | 매개변수           | 타입                  | 메모                                       |
| ------------ | -------------- | ------------------- | ---------------------------------------- |
| `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` 형태 제약은 **두 번** 강제됩니다 — 스키마 경계에서,
그리고 다시 핸들러 안에서 — id가 URL 경로에 보간되기 때문입니다.
순회 형태의 "프롬프트 id"가 스키마를 우회한 호출자라도 URL
빌더에 닿아서는 안 됩니다.

생성된 도구별 스키마 레퍼런스는
[앱 도구](/docs/docs/tools/apps)를 참고하세요.

### 레지스트리에서 가져오기

`action:"import"`는 서버 측에서 레지스트리 번들을 가져와 로컬
앱으로 만듭니다. **레지스트리 id가 로컬 id가 되므로**, 이미 가진
앱을 다시 가져오면 복제하는 대신 id 충돌을 보고합니다. 썸네일은
별도 레지스트리 엔드포인트에 있으며 따로 가져와 전달되므로,
설치된 앱이 카드 아트를 유지합니다.

의존성은 설치되지 **않습니다**. 도구가 매니페스트의 `deps`를 반환하므로
호출자가 보고하고 사용자가 의도적으로 설치하게 합니다.

<Warning>
  `registry_url`은 자유 URL이 아니라 허용 목록입니다. 가져오기는 **서버에서**
  일어나므로, 임의 URL은 SSRF 원시가 됩니다 — 루프백이나 LAN
  주소, 또는 그곳으로 리다이렉트하는 공개 URL. 운영자가
  `COMFYUI_MCP_REGISTRY_URLS`(쉼표 구분, 개발/스테이징용)로 추가 오리진을
  허용 목록하지 않는 한 기본 공개 레지스트리만 받아들여집니다.
  리다이렉트는 따라가지 않고 아예 거부됩니다.
</Warning>

## 제한과 유효성 검사

실제로 부딪힐 수 있는 것:

| 제한             | 값          | 어디                                                    |
| -------------- | ---------- | ----------------------------------------------------- |
| 번들 / 프롬프트 JSON | 16 MB      | 프롬프트가 base64 이미지를 실을 수 있어 평범한 그래프보다 넓음                |
| 썸네일            | 5 MB       | 무엇이든 쓰기 **전에** 디코드하고 검증하므로, 나쁜 썸네일이 반만 만든 번들을 남길 수 없음 |
| 앱 이름           | 120자       | 잘림                                                    |
| 설명             | 4000자      | 잘림                                                    |
| 콤보 `choices`   | 200개       | 잘림                                                    |
| 레지스트리 가져오기     | 16 MB, 30초 | 선언된 `content-length` **그리고** 실제 바이트에서 검사              |

눈에 띄는 유효성 검사:

* **앱 id는 uuid여야 합니다.** 그 외는 경로가 만들어지기 전에 거부되며,
  해석된 번들 경로는 앱 루트 아래 포함인지 다시 검사됩니다.
* **프롬프트는 API 형식이어야 합니다** — 숫자 노드 id 키, 각 노드는
  `{class_type, inputs}` 객체. UI 형식 그래프는 거부됩니다.
* **`hideWorkflow`가 설정되지 않는 한 UI 워크플로우가 필요합니다**.
* **이미 있는 앱을 만드는 것**은 덮어쓰기가 아니라 충돌입니다.
* **부분 매니페스트 업데이트는 정말로 부분입니다.** 앱을 게시하거나 숨기면
  자기 필드만 보내고 이름, 설명, 또는
  `appMode`를 지우지 않습니다.
* **알 수 없는 매니페스트 키는 버려집니다.** 예약된 통과
  필드는 제외. 그래서 오래된 장비는 이해하지 못하는 필드에서
  실패하는 대신 무시합니다.

앱 루트는 `COMFYUI_MCP_APPS_DIR`로 재정의할 수 있습니다 (주로 테스트용).
기본값은 ComfyUI 자체 사용자 디렉터리에서 파생되므로, 포터블
설치에서도 살아남습니다.

## 휴대폰에서

모바일 앱은 실제 **앱** 탭을 제공합니다 — 미리보기가 아닙니다. 두 절반이
있습니다:

* **내 앱** — 장비에 설치된 앱, 브리지를 통해
  `action:"list"`로 나열. 하나를 탭하면 생성된 실행 폼이 열리고,
  `action:"run"`으로 대기열에 넣고, 출력이 렌더될 때까지 2초마다
  `action:"run_status"`를 폴링합니다 (30분으로 묶임).
* **Explore** — 공개 레지스트리, 휴대폰에서 **직접 HTTPS**로 칩니다
  (브리지 홉 없음, 그래서 페어링 전에도 둘러보기가 동작). 설치는
  반대 방향입니다: 장비가 `action:"import"`로 번들을 스스로 가져옵니다.

이것이 채팅이 할 수 없는, 휴대폰이 가장 분명히 하는 일입니다 — 실제
워크플로우를, 실제 입력으로, 어디에도 캔버스 없이 실행하기.

## 참고

* [앱 도구](/docs/docs/tools/apps) — 생성된 도구별 스키마 레퍼런스
* [사이드바 패널](/docs/docs/ko/panel) — 앱을 변환, 게시, 탐색하는 곳
* [모바일 앱](/docs/docs/ko/mobile) — 맥락 속의 앱 탭
* [RunPod 파드](/docs/docs/tools/runpod) — "RunPod에서 실행" 경로가 겨냥하는 파드
* [로드맵](/docs/docs/ko/roadmap)
