# Design.md ## 1. 設計方針 | 方針 | 内容 | |---|---| | MCP公開面を小さくする | LLMには生成意図に必要な入力だけを公開する | | 実行設定はTOMLへ集約 | モデル・VAE・LoRA・ControlNet・生成パラメータを一元管理 | | SD1.x互換に限定 | SDXL / FLUX等は対象外 | | 依存分離 | MCP層とDiffusion層を直接密結合させない | | 単一GPU前提 | 生成処理は1本のキューで直列化 | | ControlNetは固定3種 | Depth / Openpose / Inpaintのみ | | 過剰な汎用化を避ける | 未使用ControlNetや動的Tool設定は持たない | --- ## 2. 全体アーキテクチャ ```text MCP Client / LLM │ ▼ ┌──────────────────────┐ │ MCP Server │ │ - tool schema │ │ - request validation │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ ImageGenerationService│ │ - request routing │ │ - queue control │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ ModelManager │ │ - checkpoint │ │ - VAE │ │ - LoRA │ │ - ControlNet │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ Diffusers / PyTorch │ │ CUDA │ └──────────────────────┘ ``` --- ## 3. モジュール構成 ```text generate-image-sd15-mcp/ ├─ pyproject.toml ├─ uv.lock ├─ .python-version ├─ config.example.toml ├─ src/ │ └─ mcp_sd15/ │ ├─ __init__.py │ ├─ cli.py │ ├─ server.py │ ├─ config.py │ ├─ schema.py │ ├─ service.py │ ├─ model_manager.py │ ├─ pipeline_factory.py │ ├─ preprocessors/ │ │ ├─ depth.py │ │ └─ openpose.py │ └─ tools/ │ ├─ generate_image.py │ ├─ generate_guided_image.py │ └─ inpaint_image.py └─ tests/ ├─ test_config.py ├─ test_schema.py ├─ test_model_paths.py └─ test_tools.py ``` --- ## 4. 各モジュールの責務 | モジュール | 責務 | |---|---| | `cli.py` | `--config`, `--version`の処理、transport起動分岐 | | `server.py` | MCP server起動、Tool登録 | | `config.py` | TOML読込、型変換、validation | | `schema.py` | MCP入力値・内部request型 | | `service.py` | Tool要求を生成処理へ振り分け | | `model_manager.py` | checkpoint / VAE / LoRA / ControlNetの管理 | | `pipeline_factory.py` | Diffusers pipeline構築 | | `preprocessors/depth.py` | Midas前処理 | | `preprocessors/openpose.py` | Openpose / Openpose Full前処理 | | `tools/*` | MCP Toolからserviceへの薄いadapter | --- ## 5. 起動フロー | Step | 処理 | |---|---| | 1 | CLI引数を解析 | | 2 | TOMLを読込 | | 3 | 設定値をvalidation | | 4 | モデルパスを解決 | | 5 | checkpoint存在確認 | | 6 | VAE / LoRA / ControlNet存在確認 | | 7 | Base SD1.x pipelineを構築 | | 8 | checkpoint内蔵VAEを確認し、外部VAE指定時は差し替え | | 9 | LoRAを順次ロード | | 10 | GPUへ配置 | | 11 | MCP Toolを公開 | | 12 | `[server].transport`に従いstdioまたはstreamable-httpでリクエスト待受開始 | モデル構成の初期化に失敗した場合はToolを公開せず、プロセスを異常終了する。 --- ## 6. 設定オブジェクト 推奨内部型: ```python @dataclass(frozen=True) class LoRAConfig: file: str weight: float = 1.0 @dataclass(frozen=True) class ModelConfig: root: Path checkpoint: str vae: str | None loras: tuple[LoRAConfig, ...] @dataclass(frozen=True) class GenerationConfig: steps: int cfg_scale: float scheduler: str default_size: str clip_skip: int = 0 pad_last_block: bool = False @dataclass(frozen=True) class PromptConfig: positive: str = "" negative: str = "" ``` Pydanticは必須とせず、`tomllib + dataclass + 明示的validation`を基本とする。 --- ## 7. モデルパス解決 | 種類 | 解決先 | |---|---| | checkpoint | `/checkpoints/` | | VAE | `/vae/` | | LoRA | `/lora/` | | ControlNet | `/controlnet/` | | prompt | `/prompts/` | 設計上、MCP入力から任意モデルパスを指定することは禁止する。 --- ## 8. Diffusers構成 | 機能 | 実装方針 | |---|---| | Base model | SD1.x互換checkpointをロード | | VAE | pipeline componentとして必須。設定された外部VAEがある場合のみ置換 | | LoRA | 複数adapterをロード | | LoRA weight | `set_adapters`相当で適用 | | LoRA fuse | 将来オプション。初期実装では必須としない | | dtype | FP16 | | device | CUDA | | scheduler | TOMLで指定 | | batch | 1 | | images per prompt | 1 | | CPU offload | 初期値OFF | Schedulerの文字列変換は`PipelineFactory`へ集約し、Tool層とService層には分岐を置かない。 | 設定値 | Diffusers実装 | 追加設定 | |---|---|---| | `dpmpp_2m_karras` | `DPMSolverMultistepScheduler` | `algorithm_type="dpmsolver++"`, `solver_order=2`, `use_karras_sigmas=True` | | `dpmpp_2m_sde_karras` | `DPMSolverMultistepScheduler` | `algorithm_type="sde-dpmsolver++"`, `solver_order=2`, `use_karras_sigmas=True` | | `euler_a` | `EulerAncestralDiscreteScheduler` | pipeline scheduler configを継承 | | `ddim` | `DDIMScheduler` | pipeline scheduler configを継承 | | `lcm` | `LCMScheduler` | pipeline scheduler configを継承 | LCM-LoRAも通常のLoRAと同じ`[[model.lora]]`でロードする。`lcm`選択時にstepsやCFGを 自動調整せず、TOMLの`generation.steps`と`generation.cfg_scale`をそのままpipelineへ渡す。 --- ## 9. ControlNet設計 ### 9.1 モード | MCP mode | ControlNet | Preprocessor | |---|---|---| | `depth` | Depth 1.1 | Midas | | `openpose` | Openpose 1.1 | body | | `openpose_full` | Openpose 1.1 | body + hand + face | | `inpaint` | Inpaint 1.1 | mask生成規約に従う | ### 9.2 パイプライン ```text Depth/Openpose: input image │ ▼ preprocessor │ ▼ control image │ ▼ StableDiffusionControlNetPipeline │ ▼ PNG ``` ```text Inpaint: input image + mask │ ▼ ControlNet Inpaint input │ ▼ Inpaint-compatible pipeline │ ▼ PNG ``` ### 9.3 ロード方針 8GB級GPUを主対象とするため、ControlNetは必要時ロードを基本候補とする。 | 状態 | 動作 | |---|---| | 未ロード | 必要なControlNetをロード | | 同一ControlNet | 再利用 | | 別ControlNet要求 | 既存ControlNetを解放後ロード | | generation中 | 切替禁止 | --- ## 10. MCP Tool設計 ### `generate_image` ```text Input: - positive_prompt - negative_prompt? - size? Output: - image/png - generation metadata ``` ### `generate_guided_image` ```text Input: - positive_prompt - negative_prompt? - control_mode: depth | openpose | openpose_full - input_image - size? Output: - image/png - generation metadata ``` ### `inpaint_image` ```text Input: - positive_prompt - negative_prompt? - input_image - mask_image - size? Output: - image/png - generation metadata ``` Tool層はDiffusers APIを直接呼ばず、必ずService層を経由する。 --- ## 11. 生成キュー ```text MCP Request │ ▼ asyncio.Semaphore(1) │ ▼ GenerationService │ ▼ GPU ``` | 項目 | 方針 | |---|---| | 同時GPU処理 | 1 | | キュー | FIFO相当 | | OOM防止 | 並列生成禁止 | | cancellation | MCP SDKで扱える範囲で対応 | | timeout | 設定値として追加可能 | --- ## 12. 出力 | 項目 | 仕様 | |---|---| | Format | PNG | | MCP返却 | ImageContent相当 | | ローカル保存 | 設定により有効化可能 | | ファイル名 | UUIDまたはgeneration ID | | metadata | seed, size, mode, timestamp等 | | prompt保存 | ログ方針により設定 | --- ## 13. エラー設計 | エラー分類 | 例 | 処理 | |---|---|---| | CONFIG_ERROR | TOML不正 | 起動失敗 | | MODEL_NOT_FOUND | モデル未配置 | 起動失敗 | | MODEL_INCOMPATIBLE | SD1.x非互換 | 起動失敗 | | INVALID_REQUEST | 不正size / mode | Tool error | | INVALID_IMAGE | 画像形式不正 | Tool error | | CUDA_OOM | VRAM不足 | Tool error + GPU状態回復 | | GENERATION_FAILED | 推論例外 | Tool error | | INTERNAL_ERROR | 想定外例外 | ログ出力 + Tool error | --- ## 14. pyproject / uv方針 ### Runtime依存 | Package | 用途 | |---|---| | `mcp` | MCP server | | `torch` | CUDA 13.2 / Tensor | | `torchvision` | PyTorch画像model依存 | | `diffusers` | SD / ControlNet | | `transformers` | CLIP | | `peft` | LoRA | | `safetensors` | モデル形式 | | `pillow` | 画像I/O | | `numpy` | 数値処理 | | `opencv-python` | 画像前処理 | ### Development依存 | Package | 用途 | |---|---| | `pytest` | テスト | | `ruff` | lint / format | | `pyright` | 型チェック | ### 例 ```toml [project] name = "generate-image-sd15-mcp" version = "0.1.0" requires-python = ">=3.11,<3.12" [project.scripts] generate-image-sd15-mcp = "mcp_sd15.cli:main" ``` 運用は`pyproject.toml + uv.lock`を基準とする。 --- ## 15. テスト設計 | テスト種別 | GPU | 内容 | |---|---:|---| | Config parsing | 不要 | TOML読込・型検証・scheduler enum検証 | | Path resolution | 不要 | モデルパス解決 | | MCP schema | 不要 | Tool schema検証 | | Request validation | 不要 | mode / size / image必須条件 | | Service routing | 不要 | 適切なbackend呼出 | | Model load smoke | 必要 | checkpoint / VAE / LoRA | | Txt2Img smoke | 必要 | 512x512生成 | | Depth smoke | 必要 | ControlNet Depth | | Openpose smoke | 必要 | Openpose / Full | | Inpaint smoke | 必要 | mask付き生成 | --- ## 16. 将来拡張 初期設計では以下を実装対象外とする。 | 項目 | 方針 | |---|---| | SDXL / FLUX | 対象外 | | Multi-ControlNet | 対象外 | | MCPからのモデル切替 | 対象外 | | 任意width / height | 対象外 | | batch > 1 | 対象外 | | LoRA動的追加 | 対象外 | | Web UI | 対象外 | | 学習機能 | 対象外 | | 複数GPU | 対象外 | 必要になった場合のみ、既存のService / ModelManager境界を維持したまま拡張する。