summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/config.md290
-rw-r--r--doc/mcp.md302
2 files changed, 592 insertions, 0 deletions
diff --git a/doc/config.md b/doc/config.md
new file mode 100644
index 0000000..f200cdc
--- /dev/null
+++ b/doc/config.md
@@ -0,0 +1,290 @@
+# 設定ファイル仕様
+
+## 1. 概要
+
+`mcp-sd15`のモデル構成と生成設定はTOMLファイルで管理する。起動時に次のように指定する。
+
+```powershell
+uv run mcp-sd15 --config C:\path\to\config.toml
+```
+
+`--config`を省略した場合は、現在のworking directoryにある`config.toml`を読み込む。
+設定値をCLIやMCPツール入力で上書きすることはできない。
+
+## 2. モデルディレクトリ
+
+`model.root`の下には次のディレクトリ構成が必要である。
+
+```text
+<model.root>/
+├─ checkpoints/
+│ └─ <model.checkpoint>
+├─ vae/
+│ └─ <model.vae>
+├─ lora/
+│ └─ <model.lora.file>
+└─ controlnet/
+ ├─ <controlnet.depth.model>
+ ├─ <controlnet.openpose.model>
+ └─ <controlnet.inpaint.model>
+```
+
+各モデル項目にはパスではなくファイル名だけを記述する。絶対パス、ディレクトリ名を含む
+相対パス、`.`、`..`は拒否される。
+
+## 3. 設定項目一覧
+
+| TOML key | 型 | 必須 | 既定値 |
+|---|---|---:|---|
+| `model.root` | string | Yes | なし |
+| `model.checkpoint` | string | Yes | なし |
+| `model.vae` | string | No | 未使用 |
+| `model.lora[].file` | string | LoRA使用時 | なし |
+| `model.lora[].weight` | number | No | `1.0` |
+| `generation.steps` | integer | No | `25` |
+| `generation.cfg_scale` | number | No | `7.0` |
+| `generation.scheduler` | string enum | No | `dpmpp_2m` |
+| `generation.default_size` | string enum | No | `square_512` |
+| `controlnet.depth.enabled` | boolean | No | `false` |
+| `controlnet.depth.model` | string | 有効時 | なし |
+| `controlnet.depth.preprocessor` | string | No | `midas` |
+| `controlnet.openpose.enabled` | boolean | No | `false` |
+| `controlnet.openpose.model` | string | 有効時 | なし |
+| `controlnet.inpaint.enabled` | boolean | No | `false` |
+| `controlnet.inpaint.model` | string | 有効時 | なし |
+| `output.enabled` | boolean | No | `false` |
+| `output.directory` | string | No | `./outputs` |
+
+## 4. `[model]`
+
+base checkpoint、VAE、LoRAを指定する必須tableである。
+
+```toml
+[model]
+root = "D:/AI/models"
+checkpoint = "model.safetensors"
+vae = "vae.safetensors"
+```
+
+### `root`
+
+- 必須の空でない文字列
+- 絶対パスを推奨
+- 相対パスの場合はconfigファイルが置かれたディレクトリを基準に解決
+- 起動時にディレクトリの存在を確認
+
+### `checkpoint`
+
+- 必須のファイル名
+- `<root>/checkpoints/<checkpoint>`として解決
+- 起動時にファイルの存在を確認
+- サーバ初期化時にSD1.x pipelineとしてロードできなければ起動失敗
+
+### `vae`
+
+- 任意のファイル名
+- 指定した場合は`<root>/vae/<vae>`として解決し、base modelのVAEを置換
+- 指定時は起動時にファイルの存在を確認
+- 省略時はcheckpointに含まれるVAEを使用
+
+## 5. `[[model.lora]]`
+
+LoRAごとにarray of tablesを追加する。0個以上指定でき、記述順にadapter名が割り当てられる。
+
+```toml
+[[model.lora]]
+file = "detail.safetensors"
+weight = 0.8
+
+[[model.lora]]
+file = "style.safetensors"
+weight = 0.5
+```
+
+| Key | 型 | 制約 |
+|---|---|---|
+| `file` | string | 必須のファイル名。`<root>/lora/<file>`に存在すること |
+| `weight` | number | `-4.0`以上`4.0`以下。既定値`1.0` |
+
+同じ`file`を複数回指定することはできない。LoRAを使わない場合は
+`[[model.lora]]`を記述しない。
+
+## 6. `[generation]`
+
+全ツールに共通する推論パラメータを指定する。table自体を省略した場合はすべて既定値となる。
+
+```toml
+[generation]
+steps = 25
+cfg_scale = 7.0
+scheduler = "dpmpp_2m"
+default_size = "square_512"
+```
+
+### `steps`
+
+- integerのみ
+- 範囲は`1`以上`150`以下
+- booleanや小数は不可
+
+### `cfg_scale`
+
+- finiteなintegerまたはfloat
+- 範囲は`0.0`以上`30.0`以下
+- `NaN`や無限大は不可
+
+### `scheduler`
+
+次の値だけを指定できる。
+
+| 値 | Diffusers scheduler |
+|---|---|
+| `dpmpp_2m` | DPM-Solver++、solver order 2 |
+| `ddim` | DDIM |
+| `euler` | Euler Discrete |
+| `euler_a` | Euler Ancestral Discrete |
+
+### `default_size`
+
+MCPツールで`size`を省略した場合に使用するサイズIDである。
+
+| 値 | 解像度 |
+|---|---:|
+| `square_512` | 512 x 512 |
+| `landscape_512` | 512 x 384 |
+| `portrait_512` | 384 x 512 |
+
+## 7. `[controlnet.*]`
+
+ControlNetは用途ごとに個別設定する。各tableを省略するとその機能は無効になる。
+
+### Depth
+
+```toml
+[controlnet.depth]
+enabled = true
+model = "control_v11f1p_sd15_depth.safetensors"
+preprocessor = "midas"
+```
+
+| Key | 仕様 |
+|---|---|
+| `enabled` | boolean。既定値`false` |
+| `model` | 有効時に必須。`<root>/controlnet/<model>`として解決 |
+| `preprocessor` | `midas`のみ指定可能。省略時も`midas` |
+
+### OpenPose
+
+```toml
+[controlnet.openpose]
+enabled = true
+model = "control_v11p_sd15_openpose.safetensors"
+```
+
+この設定はMCPの`openpose`と`openpose_full`の両方で使用する。前者はbody、後者は
+body、hand、faceを抽出する。preprocessorをMCPや設定から切り替えることはできない。
+
+### Inpaint
+
+```toml
+[controlnet.inpaint]
+enabled = true
+model = "control_v11p_sd15_inpaint.safetensors"
+```
+
+元画像とmaskからControlNet Inpaint用conditionを生成する。maskの輝度が50%を超える領域が
+再生成対象になる。
+
+### Annotatorモデル
+
+MiDaSとOpenPoseのannotator重みは`controlnet_aux`のローカルcacheに事前配置する必要がある。
+サーバは推論時に外部ネットワークから自動取得せず、`local_files_only=true`でロードする。
+annotator重みの場所をこのTOMLから指定する項目はない。
+
+## 8. `[output]`
+
+生成したPNGをMCPレスポンスに加えてローカル保存するかを指定する。
+
+```toml
+[output]
+enabled = false
+directory = "./outputs"
+```
+
+| Key | 仕様 |
+|---|---|
+| `enabled` | `true`で保存、`false`でMCP返却のみ。既定値`false` |
+| `directory` | 保存先。既定値`./outputs` |
+
+相対`directory`はconfigファイルのディレクトリを基準に解決する。保存が有効な場合、
+ディレクトリは最初の保存時に作成され、ファイル名はランダムUUIDの`<uuid>.png`となる。
+
+## 9. 最小設定例
+
+Text-to-Imageだけを使用する最小構成は次のとおり。
+
+```toml
+[model]
+root = "D:/AI/models"
+checkpoint = "model.safetensors"
+```
+
+この場合、VAEとLoRAは使用せず、全ControlNetとローカル保存は無効になる。生成設定には
+既定値が使用される。
+
+## 10. 全設定例
+
+```toml
+[model]
+root = "D:/AI/models"
+checkpoint = "model.safetensors"
+vae = "vae.safetensors"
+
+[[model.lora]]
+file = "detail.safetensors"
+weight = 0.8
+
+[[model.lora]]
+file = "style.safetensors"
+weight = 0.5
+
+[generation]
+steps = 25
+cfg_scale = 7.0
+scheduler = "dpmpp_2m"
+default_size = "square_512"
+
+[controlnet.depth]
+enabled = true
+model = "control_v11f1p_sd15_depth.safetensors"
+preprocessor = "midas"
+
+[controlnet.openpose]
+enabled = true
+model = "control_v11p_sd15_openpose.safetensors"
+
+[controlnet.inpaint]
+enabled = true
+model = "control_v11p_sd15_inpaint.safetensors"
+
+[output]
+enabled = false
+directory = "./outputs"
+```
+
+## 11. 起動時validation
+
+次のいずれかに該当するとMCPサーバは起動しない。
+
+- TOML syntaxが不正
+- 必須tableまたは必須値がない
+- 値の型、列挙値、数値範囲が不正
+- モデル項目にファイル名以外のパスが指定されている
+- LoRAファイル名が重複している
+- `model.root`が存在しない
+- checkpoint、指定VAE、LoRA、有効なControlNetのファイルが存在しない
+- CUDAが利用できない
+- base checkpoint、VAE、LoRAがDiffusersでロードできない
+
+未定義のkeyは現在の実装ではエラーにはならないが、処理には使用されない。タイプミスを
+見逃さないため、この文書に記載したkeyだけを使用することを推奨する。
diff --git a/doc/mcp.md b/doc/mcp.md
new file mode 100644
index 0000000..0c50f75
--- /dev/null
+++ b/doc/mcp.md
@@ -0,0 +1,302 @@
+# MCPツール仕様
+
+## 1. 概要
+
+`mcp-sd15` はstdio transportで動作し、Stable Diffusion 1.xによる画像生成を行う
+次の3ツールを公開する。
+
+| ツール | 用途 |
+|---|---|
+| `generate_image` | テキストから画像を生成する |
+| `generate_guided_image` | DepthまたはOpenPoseで誘導して画像を生成する |
+| `inpaint_image` | 元画像のmask指定領域を再生成する |
+
+全ツールの出力は1枚のPNGである。生成パラメータ、モデル、LoRA、ControlNet強度、seedは
+ツール入力には公開しない。これらは設定ファイルまたはサーバ内部で管理する。
+
+## 2. 共通仕様
+
+### 2.1 Prompt
+
+| 項目 | 仕様 |
+|---|---|
+| `positive_prompt` | 必須の文字列。前後の空白を除去した結果が空の場合はエラー |
+| `negative_prompt` | 任意の文字列。省略または`null`の場合は空文字列 |
+| 最大長 | それぞれ10,000文字 |
+
+### 2.2 Image size
+
+`size`には次の列挙値だけを指定できる。省略または`null`の場合は
+`generation.default_size`が使用される。
+
+| 値 | 幅 | 高さ |
+|---|---:|---:|
+| `square_512` | 512 | 512 |
+| `landscape_512` | 512 | 384 |
+| `portrait_512` | 384 | 512 |
+
+任意の`width`や`height`は指定できない。
+
+### 2.3 入力画像
+
+`input_image`と`mask_image`は、次のいずれかの文字列で指定する。
+
+- PNGまたはJPEGバイナリをBase64エンコードした文字列
+- `data:image/png;base64,...`形式のdata URI
+- `data:image/jpeg;base64,...`または`data:image/jpg;base64,...`形式のdata URI
+
+画像入力には次の制限がある。
+
+| 項目 | 制限 |
+|---|---|
+| 画像形式 | PNG、JPEGのみ |
+| Base64文字列長 | 36,000,000文字以下 |
+| pixel数 | 40,000,000 pixel以下 |
+| Base64 | 改行やBase64以外の文字を含まない正規のBase64 |
+
+入力画像は生成サイズにリサイズされる。通常画像にはLanczos、maskにはnearest-neighborが
+使用される。
+
+### 2.4 出力
+
+成功時はMCPの`ImageContent`を1件返す。
+
+```json
+{
+ "type": "image",
+ "data": "iVBORw0KGgoAAA...",
+ "mimeType": "image/png"
+}
+```
+
+`data`はMCP SDKによってBase64エンコードされる。PNGには次のtext metadataが埋め込まれる。
+
+| Key | 内容 |
+|---|---|
+| `seed` | サーバが生成したseed |
+| `size` | 使用したサイズID |
+| `mode` | `text_to_image`、`guided_image`、`inpaint_image`のいずれか |
+| `timestamp` | UTCのISO 8601生成日時 |
+| `elapsed_seconds` | キュー待ちを含む処理時間(秒) |
+
+出力ファイルの保存が有効な場合も、MCPレスポンスには同じPNGが返される。
+
+## 3. `generate_image`
+
+設定済みのbase checkpoint、VAE、LoRAを使ってText-to-Imageを実行する。
+
+### 入力
+
+| 名前 | 型 | 必須 | 既定値 |
+|---|---|---:|---|
+| `positive_prompt` | string | Yes | なし |
+| `negative_prompt` | string \| null | No | `null`(内部では空文字列) |
+| `size` | size enum \| null | No | `generation.default_size` |
+
+### 呼び出し例
+
+```json
+{
+ "positive_prompt": "a small lighthouse on a rocky coast, sunset",
+ "negative_prompt": "low quality, blurry",
+ "size": "landscape_512"
+}
+```
+
+### JSON Schema
+
+```json
+{
+ "type": "object",
+ "title": "generate_imageArguments",
+ "properties": {
+ "positive_prompt": {
+ "type": "string",
+ "title": "Positive Prompt"
+ },
+ "negative_prompt": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "default": null,
+ "title": "Negative Prompt"
+ },
+ "size": {
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": ["square_512", "landscape_512", "portrait_512"]
+ },
+ {"type": "null"}
+ ],
+ "default": null,
+ "title": "Size"
+ }
+ },
+ "required": ["positive_prompt"]
+}
+```
+
+## 4. `generate_guided_image`
+
+入力画像を固定preprocessorに通し、対応するControlNetで画像生成を誘導する。
+
+### 入力
+
+| 名前 | 型 | 必須 | 既定値 |
+|---|---|---:|---|
+| `positive_prompt` | string | Yes | なし |
+| `control_mode` | control mode enum | Yes | なし |
+| `input_image` | string | Yes | なし |
+| `negative_prompt` | string \| null | No | `null`(内部では空文字列) |
+| `size` | size enum \| null | No | `generation.default_size` |
+
+`control_mode`の意味は次のとおり。
+
+| 値 | ControlNet設定 | 前処理 |
+|---|---|---|
+| `depth` | `controlnet.depth` | MiDaS depth |
+| `openpose` | `controlnet.openpose` | body pose |
+| `openpose_full` | `controlnet.openpose` | body、hand、face pose |
+
+要求したControlNetが設定で無効の場合はツールエラーになる。`openpose`と
+`openpose_full`は同じControlNetモデルを共有する。
+
+### 呼び出し例
+
+```json
+{
+ "positive_prompt": "a dancer wearing a red dress, studio lighting",
+ "control_mode": "openpose_full",
+ "input_image": "data:image/png;base64,iVBORw0KGgoAAA...",
+ "negative_prompt": "deformed hands",
+ "size": "portrait_512"
+}
+```
+
+### JSON Schema
+
+```json
+{
+ "type": "object",
+ "title": "generate_guided_imageArguments",
+ "properties": {
+ "positive_prompt": {
+ "type": "string",
+ "title": "Positive Prompt"
+ },
+ "control_mode": {
+ "type": "string",
+ "enum": ["depth", "openpose", "openpose_full"],
+ "title": "Control Mode"
+ },
+ "input_image": {
+ "type": "string",
+ "title": "Input Image"
+ },
+ "negative_prompt": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "default": null,
+ "title": "Negative Prompt"
+ },
+ "size": {
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": ["square_512", "landscape_512", "portrait_512"]
+ },
+ {"type": "null"}
+ ],
+ "default": null,
+ "title": "Size"
+ }
+ },
+ "required": ["positive_prompt", "control_mode", "input_image"]
+}
+```
+
+## 5. `inpaint_image`
+
+元画像とmask画像を使い、白い領域をControlNet Inpaintで再生成する。
+
+### 入力
+
+| 名前 | 型 | 必須 | 既定値 |
+|---|---|---:|---|
+| `positive_prompt` | string | Yes | なし |
+| `input_image` | string | Yes | なし |
+| `mask_image` | string | Yes | なし |
+| `negative_prompt` | string \| null | No | `null`(内部では空文字列) |
+| `size` | size enum \| null | No | `generation.default_size` |
+
+`mask_image`はgrayscaleに変換される。輝度が50%を超えるpixelが再生成対象で、黒い領域は
+保持対象となる。
+
+### 呼び出し例
+
+```json
+{
+ "positive_prompt": "a wooden table with a ceramic vase",
+ "input_image": "data:image/png;base64,iVBORw0KGgoAAA...",
+ "mask_image": "data:image/png;base64,iVBORw0KGgoAAA...",
+ "negative_prompt": "artifacts",
+ "size": "square_512"
+}
+```
+
+### JSON Schema
+
+```json
+{
+ "type": "object",
+ "title": "inpaint_imageArguments",
+ "properties": {
+ "positive_prompt": {
+ "type": "string",
+ "title": "Positive Prompt"
+ },
+ "input_image": {
+ "type": "string",
+ "title": "Input Image"
+ },
+ "mask_image": {
+ "type": "string",
+ "title": "Mask Image"
+ },
+ "negative_prompt": {
+ "anyOf": [{"type": "string"}, {"type": "null"}],
+ "default": null,
+ "title": "Negative Prompt"
+ },
+ "size": {
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": ["square_512", "landscape_512", "portrait_512"]
+ },
+ {"type": "null"}
+ ],
+ "default": null,
+ "title": "Size"
+ }
+ },
+ "required": ["positive_prompt", "input_image", "mask_image"]
+}
+```
+
+## 6. 実行制御とエラー
+
+生成処理はサーバ内の単一lockで直列化される。同時に複数の要求を受信した場合、GPU推論は
+1件ずつ実行される。
+
+主なツールエラーは次のとおり。
+
+| 分類 | 例 |
+|---|---|
+| 入力エラー | 空のprompt、不正なsize、不正なcontrol mode |
+| 画像エラー | Base64不正、未対応形式、画像破損、上限超過 |
+| 設定エラー | 要求したControlNetが無効、モデルをロードできない |
+| 推論エラー | Diffusers処理失敗、出力画像数不正 |
+| CUDA OOM | VRAM不足。CUDA cacheの解放を試みた後にエラーを返す |
+| 保存エラー | output directoryの作成またはPNG書込み失敗 |
+
+エラー時に画像は返されない。設定ファイル自体やbase modelが不正な場合は、MCPツールを
+公開する前のサーバ起動処理が失敗する。