# WindowsCaptureMCP 作業手順書

> 参照: [PLAN.md](./PLAN.md)

---

## フェーズ1: プロジェクト初期化

### T-001: pyproject.toml 作成
- **依存**: なし
- **内容**:
  - プロジェクト名: `windows-capture-mcp`
  - Python要件: `>=3.11`
  - 依存: `mcp`, `pywin32`, `Pillow`
  - 開発依存: `pytest`
  - エントリーポイント: `windows-capture-mcp = "windows_capture_mcp.server:main"`
  - ビルドシステム: hatchling
- **完了条件**: `uv sync` が正常終了する

### T-002: ディレクトリ・ファイル作成
- **依存**: T-001
- **内容**:
  - `src/windows_capture_mcp/__init__.py` 作成
  - `src/windows_capture_mcp/server.py` 作成（空のスケルトン）
  - `src/windows_capture_mcp/capture.py` 作成（空のスケルトン）
  - `src/windows_capture_mcp/window.py` 作成（空のスケルトン）
  - `src/windows_capture_mcp/display.py` 作成（空のスケルトン）
  - `tests/__init__.py` 作成
  - `tests/test_capture.py` 作成（空）
  - `tests/test_window.py` 作成（空）
  - `tests/test_display.py` 作成（空）
- **完了条件**: 全ファイルが存在し、`uv run python -c "import windows_capture_mcp"` が通る

### T-003: uv環境構築・依存インストール
- **依存**: T-001, T-002
- **内容**:
  - `uv sync` で仮想環境を構築
  - 全依存がインストールされることを確認
  - `uv run pytest` が実行可能であることを確認
- **完了条件**: `uv run pytest` がエラーなく終了する（テストなしの0件でOK）

### T-004: 定数モジュール定義
- **依存**: T-002
- **内容**:
  - `src/windows_capture_mcp/__init__.py` にハードコード定数を定義
    ```python
    PREVIEW_QUALITY = 30
    PREVIEW_MAX_LONG_SIDE = 1280
    PREVIEW_FORMAT = "jpeg"
    DEFAULT_FORMAT = "png"
    DEFAULT_QUALITY = 90
    ```
- **完了条件**: `from windows_capture_mcp import PREVIEW_QUALITY` 等が成功する

---

## フェーズ2: ディスプレイモジュール (display.py)

### T-005: ディスプレイ一覧取得関数の実装
- **依存**: T-003
- **内容**:
  - `get_displays() -> list[dict]` を実装
  - Win32 API (`EnumDisplayMonitors`, `GetMonitorInfo`) を使用
  - 返却情報: `display_number`, `name`, `width`, `height`, `x`, `y`, `scale_factor`, `is_primary`
  - ディスプレイ番号は1始まり
- **完了条件**: 関数を呼び出して現在のディスプレイ情報が正しく返る

### T-006: ディスプレイ座標変換ヘルパーの実装
- **依存**: T-005
- **内容**:
  - `get_display_rect(display_number: int) -> tuple[int, int, int, int]` を実装
  - 指定ディスプレイ番号の仮想デスクトップ上の矩形 (x, y, width, height) を返す
  - 存在しないディスプレイ番号の場合はエラーを返す
- **完了条件**: 各ディスプレイの矩形が正しく取得できる

### T-007: display.py のユニットテスト作成
- **依存**: T-005, T-006
- **内容**:
  - `tests/test_display.py` にテストを記述
  - `get_displays()` が空でないリストを返すことを確認
  - 各ディスプレイに必要なキーが含まれることを確認
  - `get_display_rect(1)` がタプルを返すことを確認
  - 存在しないディスプレイ番号でエラーが発生することを確認
- **完了条件**: `uv run pytest tests/test_display.py` が全テストパス

---

## フェーズ3: ウィンドウモジュール (window.py)

### T-008: ウィンドウ一覧取得関数の実装
- **依存**: T-003
- **内容**:
  - `list_windows(filter: str | None = None, include_hidden: bool = False) -> list[dict]` を実装
  - Win32 API (`EnumWindows`, `GetWindowText`, `GetWindowRect`, `IsWindowVisible`) を使用
  - プロセス名取得: `GetWindowThreadProcessId` + `psutil` or `OpenProcess`/`GetModuleFileNameEx`
  - 返却情報: `hwnd`, `title`, `process_name`, `x`, `y`, `width`, `height`
  - フィルタ: 部分一致、大文字小文字無視
  - デフォルト: 可視ウィンドウのみ（タイトルが空のものは除外）
- **完了条件**: 関数を呼び出して現在のウィンドウ一覧が正しく返る

### T-009: focus_window 関数の実装
- **依存**: T-003
- **内容**:
  - `focus_window(hwnd: int) -> dict` を実装
  - Win32 API (`SetForegroundWindow`, `BringWindowToTop`) を使用
  - 無効なhwndの場合はエラーを返す
- **完了条件**: 指定ウィンドウが前面に表示される

### T-010: maximize_window 関数の実装
- **依存**: T-003
- **内容**:
  - `maximize_window(hwnd: int) -> dict` を実装
  - Win32 API (`ShowWindow` with `SW_MAXIMIZE`) を使用
- **完了条件**: 指定ウィンドウが最大化される

### T-011: resize_window 関数の実装
- **依存**: T-003
- **内容**:
  - `resize_window(hwnd: int, width: int, height: int) -> dict` を実装
  - Win32 API (`MoveWindow` or `SetWindowPos`) を使用
  - ウィンドウ位置は維持し、サイズのみ変更
- **完了条件**: 指定ウィンドウのサイズが変更される

### T-012: move_window 関数の実装
- **依存**: T-003
- **内容**:
  - `move_window(hwnd: int, x: int, y: int) -> dict` を実装
  - Win32 API (`MoveWindow` or `SetWindowPos`) を使用
  - ウィンドウサイズは維持し、位置のみ変更
- **完了条件**: 指定ウィンドウが移動される

### T-013: window.py のユニットテスト作成
- **依存**: T-008 〜 T-012
- **内容**:
  - `tests/test_window.py` にテストを記述
  - `list_windows()` が空でないリストを返すことを確認
  - 各ウィンドウに必要なキーが含まれることを確認
  - フィルタ機能のテスト（存在するウィンドウ名で部分一致検索）
  - `include_hidden=True` で結果数が増えることを確認
  - ウィンドウ操作関数が無効なhwndでエラーを返すことを確認
- **完了条件**: `uv run pytest tests/test_window.py` が全テストパス

---

## フェーズ4: キャプチャモジュール (capture.py)

### T-014: GDIキャプチャ基盤関数の実装
- **依存**: T-003
- **内容**:
  - `capture_rect(x: int, y: int, width: int, height: int) -> Image` を実装
  - Win32 GDI API (`CreateDC`, `CreateCompatibleDC`, `CreateCompatibleBitmap`, `BitBlt`) を使用
  - 画面上の指定矩形をPillow Imageとして返す
  - リソースの適切な解放（DC、ビットマップ等）
- **完了条件**: 画面の一部をPillow Imageとして取得できる

### T-015: ウィンドウキャプチャ関数の実装
- **依存**: T-014, T-008
- **内容**:
  - `capture_window_image(hwnd: int) -> Image` を実装
  - `GetWindowRect` でウィンドウ矩形を取得し、`capture_rect` でキャプチャ
  - 無効なhwndの場合はエラーを返す
- **完了条件**: 指定ウィンドウのキャプチャ画像が取得できる

### T-016: フルスクリーンキャプチャ関数の実装
- **依存**: T-014, T-006
- **内容**:
  - `capture_fullscreen_image(display_number: int = 1) -> Image` を実装
  - `get_display_rect` でディスプレイ矩形を取得し、`capture_rect` でキャプチャ
- **完了条件**: 指定ディスプレイのフルスクリーン画像が取得できる

### T-017: 領域キャプチャ関数の実装
- **依存**: T-014, T-006
- **内容**:
  - `capture_region_image(x: int, y: int, width: int, height: int, display_number: int = 1) -> Image` を実装
  - ディスプレイのオフセットを加算した絶対座標で `capture_rect` を呼び出す
- **完了条件**: 指定領域のキャプチャ画像が取得できる

### T-018: 画像エンコード関数の実装（本番用）
- **依存**: T-003
- **内容**:
  - `encode_image(image: Image, format: str = "png", quality: int = 90) -> tuple[str, str]` を実装
  - Pillowで指定フォーマットにエンコードし、base64文字列とMIMEタイプを返す
  - 対応フォーマット: png, jpeg, webp
  - リサイズなし（原寸）
- **完了条件**: 各フォーマットでbase64エンコードされた文字列が返る

### T-019: プレビュー画像エンコード関数の実装
- **依存**: T-018
- **内容**:
  - `encode_preview(image: Image) -> tuple[str, str]` を実装
  - 長辺1280pxにリサイズ（アスペクト比維持）
  - JPEG quality=30 で圧縮
  - 定数 `PREVIEW_QUALITY`, `PREVIEW_MAX_LONG_SIDE`, `PREVIEW_FORMAT` を使用
- **完了条件**: リサイズされた低画質JPEG base64文字列が返る

### T-020: capture.py のユニットテスト作成
- **依存**: T-014 〜 T-019
- **内容**:
  - `tests/test_capture.py` にテストを記述
  - `capture_rect` で画面の一部がキャプチャできることを確認
  - `encode_image` で各フォーマット (png/jpeg/webp) のbase64が生成されることを確認
  - `encode_preview` でリサイズとJPEG圧縮が正しく行われることを確認
  - プレビュー画像の長辺が1280px以下であることを確認
- **完了条件**: `uv run pytest tests/test_capture.py` が全テストパス

---

## フェーズ5: MCPサーバー (server.py)

### T-021: MCPサーバー基盤の実装
- **依存**: T-003
- **内容**:
  - MCP Python SDK (`mcp`) を使用してサーバーインスタンスを作成
  - stdio トランスポートの設定
  - `main()` エントリーポイントの定義
  - サーバーの起動・終了処理
- **完了条件**: `uv run windows-capture-mcp` でサーバーが起動する（ツール未登録でもOK）

### T-022: 情報取得ツールの登録 (list_windows, list_displays)
- **依存**: T-021, T-008, T-005
- **内容**:
  - `list_windows` ツールを登録
    - パラメータ: `filter` (optional), `include_hidden` (optional)
    - `window.list_windows()` を呼び出し、結果をJSON形式で返却
  - `list_displays` ツールを登録
    - パラメータ: なし
    - `display.get_displays()` を呼び出し、結果をJSON形式で返却
- **完了条件**: MCPクライアントからツールが呼び出せ、正しいJSONが返る

### T-023: キャプチャツールの登録 (capture_window, capture_fullscreen, capture_region)
- **依存**: T-021, T-015, T-016, T-017, T-018
- **内容**:
  - `capture_window` ツールを登録
    - パラメータ: `hwnd`, `format`, `quality`
    - キャプチャ → エンコード → MCP image content として返却
  - `capture_fullscreen` ツールを登録
    - パラメータ: `display_number`, `format`, `quality`
  - `capture_region` ツールを登録
    - パラメータ: `x`, `y`, `width`, `height`, `display_number`, `format`, `quality`
  - 全ツールで MCP image content (base64埋め込み) を返す
- **完了条件**: MCPクライアントからツールを呼び出し、base64画像が返る

### T-024: プレビューツールの登録 (preview_window, preview_fullscreen, preview_region)
- **依存**: T-021, T-015, T-016, T-017, T-019
- **内容**:
  - `preview_window` ツールを登録
    - パラメータ: `hwnd`
  - `preview_fullscreen` ツールを登録
    - パラメータ: `display_number`
  - `preview_region` ツールを登録
    - パラメータ: `x`, `y`, `width`, `height`, `display_number`
  - 全ツールでプレビュー用エンコード → MCP image content を返す
- **完了条件**: MCPクライアントから呼び出し、低画質JPEG画像が返る

### T-025: ウィンドウ操作ツールの登録 (focus, maximize, resize, move)
- **依存**: T-021, T-009, T-010, T-011, T-012
- **内容**:
  - `focus_window` ツール: パラメータ `hwnd`
  - `maximize_window` ツール: パラメータ `hwnd`
  - `resize_window` ツール: パラメータ `hwnd`, `width`, `height`
  - `move_window` ツール: パラメータ `hwnd`, `x`, `y`
  - 操作結果をテキストメッセージで返却
- **完了条件**: MCPクライアントから呼び出し、ウィンドウ操作が実行される

### T-026: エラーハンドリングの実装
- **依存**: T-022 〜 T-025
- **内容**:
  - 無効なhwndに対するエラーメッセージ
  - 存在しないディスプレイ番号に対するエラーメッセージ
  - キャプチャ失敗時のエラーメッセージ
  - 不正なパラメータ値（負のサイズ等）に対するバリデーション
  - 全エラーをMCPの標準的なエラーレスポンスとして返す
- **完了条件**: 不正な入力に対して適切なエラーメッセージが返る

---

## フェーズ6: 統合テスト・動作確認

### T-027: 全ユニットテストの通過確認
- **依存**: T-007, T-013, T-020
- **内容**:
  - `uv run pytest` で全テストを実行
  - 全テストがパスすることを確認
- **完了条件**: `uv run pytest` が全テストパス（exitcode 0）

### T-028: MCPサーバーの手動動作確認
- **依存**: T-022 〜 T-026
- **内容**:
  - MCPサーバーを起動し、以下のシナリオを手動確認:
    1. `list_displays` でディスプレイ一覧が返ること
    2. `list_windows` でウィンドウ一覧が返ること
    3. `list_windows` + `filter` で絞り込みができること
    4. `capture_fullscreen` で画面キャプチャが返ること
    5. `preview_fullscreen` でプレビュー画像が返ること
    6. `capture_window` で特定ウィンドウのキャプチャが返ること
    7. `focus_window` でウィンドウが前面に来ること
    8. `maximize_window` でウィンドウが最大化されること
- **完了条件**: 全シナリオが正常動作

### T-029: CLAUDE.md の更新
- **依存**: T-028
- **内容**:
  - ステータスを「初期化直後」から「実装完了」に更新
  - ビルド・実行コマンドを追記
  - テスト実行コマンドを追記
- **完了条件**: CLAUDE.mdが最新の状態を反映している

---

---

## フェーズ7: PyPI 公開

### T-030: LICENSE ファイルを作成する
- **依存**: なし
- **内容**:
  - プロジェクトルートに `LICENSE` ファイルを作成
  - 依存ライブラリとの互換性から MIT License を採用
    - mcp: MIT, pywin32: PSF, Pillow: HPND（いずれも MIT 互換）
  - 年とコピーライトホルダー名を記載
- **完了条件**: `LICENSE` ファイルが存在し、内容が正しい

### T-031: pyproject.toml にメタデータを追加する
- **依存**: T-030
- **内容**:
  - 以下のフィールドを `pyproject.toml` に追加:
    - `description`: 1行の概要（英語）
    - `license`: LICENSE ファイルとの整合性を確保
    - `authors`: 名前・メール（個人情報の露出に注意）
    - `readme`: `README.md` を指定
    - `classifiers`: Python バージョン、OS（Windows）、ライセンス等
    - `urls`: Homepage, Repository 等
    - `keywords`: 検索用キーワード
- **完了条件**: `uv build` 時に警告が出ないこと

### T-032: pywin32 の依存に環境マーカーを追加する
- **依存**: なし
- **内容**:
  - `pyproject.toml` の dependencies を修正:
    ```
    "pywin32; sys_platform == 'win32'"
    ```
  - Linux/macOS で `pip install` した際に pywin32 のインストールをスキップさせる
  - 変更後 `uv sync` で環境が壊れないことを確認
- **完了条件**: `uv sync` が正常終了し、pywin32 が引き続き使えること

### T-033: PyPI 用の README.md を作成する
- **依存**: なし
- **内容**:
  - PyPI パッケージページに表示される `README.md` を作成（英語）
  - 含める内容:
    - プロジェクト概要（Windows スクリーンショット MCP サーバー）
    - Windows 専用である旨の明記
    - インストール方法（`uvx` / `pip`）
    - Claude Code での MCP 登録方法
    - 利用可能なツール一覧と簡単な説明
    - 必要要件（Python >=3.11, Windows）
    - ライセンス
- **完了条件**: README.md が存在し、内容が正確であること

### T-034: .gitignore に配布関連ディレクトリを追加する
- **依存**: なし
- **内容**:
  - 以下のエントリが .gitignore に含まれているか確認し、なければ追加:
    - `dist/`
    - `build/`
    - `*.egg-info/`
  - ビルド成果物がリポジトリに混入するのを防ぐ
- **完了条件**: 上記パターンが .gitignore に含まれていること

### T-035: ソースに秘密情報が含まれていないか確認する
- **依存**: なし
- **内容**:
  - ソースコード全体を確認し、以下が含まれていないことを確認:
    - API キー / トークン
    - 個人情報（ローカルパス、ユーザー名等）
    - `.env` ファイルや認証情報
    - テストコード中のハードコードされた秘密値
  - 問題があれば修正し、`.gitignore` にも反映
- **完了条件**: 秘密情報が一切含まれていないこと

### T-036: ローカルでパッケージビルドを確認する
- **依存**: T-030, T-031, T-032, T-033, T-034, T-035
- **内容**:
  - `uv build` を実行し、sdist と wheel が正常に生成されることを確認
  - 生成された `dist/` 内のファイルを検査:
    - 意図しないファイルが含まれていないか（テストファイル、.env、ログ等）
    - 必要なファイルが含まれているか（LICENSE, README.md, ソースコード）
- **完了条件**: `dist/` に sdist (.tar.gz) と wheel (.whl) が生成され、内容が正しいこと

### T-037: TestPyPI で公開テストを行う
- **依存**: T-036
- **内容**:
  1. TestPyPI アカウント作成・2FA 有効化
  2. API トークン取得（プロジェクトスコープ推奨）
  3. `uv publish --publish-url https://test.pypi.org/legacy/` で公開
  4. `uvx --index-url https://test.pypi.org/simple/ windows-capture-mcp` でインストール・起動確認
  5. パッケージページの表示を確認（README、メタデータ等）
- **完了条件**: TestPyPI からインストールして MCP サーバーが起動すること

### T-038: PyPI 本番に公開する
- **依存**: T-037
- **内容**:
  1. PyPI アカウントの 2FA 有効化を確認
  2. API トークン取得（プロジェクトスコープ）
  3. `uv publish` で公開
  4. `uvx windows-capture-mcp` でインストール・起動確認
  5. 公開後、GitHub リポジトリの情報を更新
- **完了条件**: `uvx windows-capture-mcp` で MCP サーバーが正常起動すること

---

## 依存関係図

```
T-001 ─→ T-002 ─→ T-003 ─→ T-004
                      │
          ┌───────────┼───────────────────────┐
          ▼           ▼                       ▼
        T-005       T-008                   T-014
          │           │                       │
          ▼           ├→ T-009          ┌─────┼─────┐
        T-006         ├→ T-010          ▼     ▼     ▼
          │           ├→ T-011        T-015 T-016 T-017
          │           ├→ T-012          │     │     │
          ▼           ▼                 │     │     │
        T-007       T-013              T-018 ←┘     │
          │           │                 │           │
          │           │                 ▼           │
          │           │               T-019         │
          │           │                 │           │
          │           │                 ▼           │
          │           │               T-020         │
          │           │                 │           │
          ▼           ▼                 ▼           │
        T-021 ←───────────────────────────          │
          │                                         │
    ┌─────┼─────┬───────────┐                       │
    ▼     ▼     ▼           ▼                       │
  T-022 T-023 T-024       T-025                     │
    │     │     │           │                       │
    └─────┴─────┴─────┬─────┘                       │
                      ▼                             │
                    T-026                           │
                      │                             │
          ┌───────────┤                             │
          ▼           ▼                             │
        T-027       T-028                           │
                      │                             │
                      ▼                             │
                    T-029

--- フェーズ7: PyPI 公開 ---

  T-030 (LICENSE)
  T-032 (環境マーカー)     ─┐
  T-033 (README.md)        ├──→ T-036 (ビルド確認) ──→ T-037 (TestPyPI) ──→ T-038 (PyPI公開)
  T-034 (.gitignore)       │
  T-035 (秘密情報確認)     ─┘
       │
       └→ T-031 (tomlメタデータ) ─→ T-036
            ↑
          T-030
```

## タスクサマリー

| ID | タスク | フェーズ | 依存 |
|----|--------|----------|------|
| T-001 | pyproject.toml 作成 | 1 | - |
| T-002 | ディレクトリ・ファイル作成 | 1 | T-001 |
| T-003 | uv環境構築・依存インストール | 1 | T-001, T-002 |
| T-004 | 定数モジュール定義 | 1 | T-002 |
| T-005 | ディスプレイ一覧取得関数 | 2 | T-003 |
| T-006 | ディスプレイ座標変換ヘルパー | 2 | T-005 |
| T-007 | display.py ユニットテスト | 2 | T-005, T-006 |
| T-008 | ウィンドウ一覧取得関数 | 3 | T-003 |
| T-009 | focus_window 関数 | 3 | T-003 |
| T-010 | maximize_window 関数 | 3 | T-003 |
| T-011 | resize_window 関数 | 3 | T-003 |
| T-012 | move_window 関数 | 3 | T-003 |
| T-013 | window.py ユニットテスト | 3 | T-008〜T-012 |
| T-014 | GDIキャプチャ基盤関数 | 4 | T-003 |
| T-015 | ウィンドウキャプチャ関数 | 4 | T-014, T-008 |
| T-016 | フルスクリーンキャプチャ関数 | 4 | T-014, T-006 |
| T-017 | 領域キャプチャ関数 | 4 | T-014, T-006 |
| T-018 | 画像エンコード関数（本番用） | 4 | T-003 |
| T-019 | プレビュー画像エンコード関数 | 4 | T-018 |
| T-020 | capture.py ユニットテスト | 4 | T-014〜T-019 |
| T-021 | MCPサーバー基盤 | 5 | T-003 |
| T-022 | 情報取得ツール登録 | 5 | T-021, T-008, T-005 |
| T-023 | キャプチャツール登録 | 5 | T-021, T-015〜T-018 |
| T-024 | プレビューツール登録 | 5 | T-021, T-015〜T-017, T-019 |
| T-025 | ウィンドウ操作ツール登録 | 5 | T-021, T-009〜T-012 |
| T-026 | エラーハンドリング | 5 | T-022〜T-025 |
| T-027 | 全ユニットテスト通過確認 | 6 | T-007, T-013, T-020 |
| T-028 | 手動動作確認 | 6 | T-022〜T-026 |
| T-029 | CLAUDE.md 更新 | 6 | T-028 |
| T-030 | LICENSE ファイル作成 | 7 | - |
| T-031 | pyproject.toml メタデータ追加 | 7 | T-030 |
| T-032 | pywin32 環境マーカー追加 | 7 | - |
| T-033 | PyPI 用 README.md 作成 | 7 | - |
| T-034 | .gitignore 配布関連追加 | 7 | - |
| T-035 | 秘密情報の確認 | 7 | - |
| T-036 | ローカルビルド確認 | 7 | T-030〜T-035 |
| T-037 | TestPyPI 公開テスト | 7 | T-036 |
| T-038 | PyPI 本番公開 | 7 | T-037 |
