TrelloでAIを強化する | 第3章：タスクデータ分析：AIによるチームインサイト

## はじめに

第2章では、**Trello**にカードを追加・更新するMCPサーバーを構築し、タスク自動化エージェントを実現しました。これにより、AIがタスクを作成したり、リスト間を移動したりできるようになり、プロジェクト管理の効率が向上しました。今回は、この基盤を活用して、Trelloのデータからチームの進捗やパフォーマンスを分析する**タスク分析エージェント**を構築します。

この第3章では、Trelloボードのカードデータを解析し、タスクの完了率、平均完了時間、ボトルネックを特定するMCPサーバーを実装します。たとえば、AIが「In Progressリストのタスクが遅延している」と指摘したり、チームの効率に関するインサイトを提供したりできます。コード例とステップごとのガイドで、タスク分析AIの構築を体験しましょう。さあ、始めましょう！

## タスク分析エージェントとは？

タスク分析エージェントは、Trelloのカードデータを解析し、チームのパフォーマンスやプロジェクトの進捗に関するインサイトを提供するAIです。MCPサーバーを介して、以下のような機能を実現できます：
- **完了率分析**：ボード全体や特定リストのタスク完了率を計算。
- **時間分析**：タスクの平均完了時間や遅延を評価。
- **ボトルネック検出**：遅れているリストやタスクを特定し、改善案を提案。

### ユースケース
- プロジェクト管理：AIが遅延リスクを警告し、優先順位を提案。
- チームパフォーマンス：メンバーのタスク完了率や効率を分析。
- プロセス改善：ボトルネックを特定し、ワークフローを最適化。

## 開発環境の準備

第2章の環境を基に、以下の準備を行います：
- **Python 3.8以降**、**mcpライブラリ**、**requestsライブラリ**、**Claude Desktop**：これまでと同じ。
- **python-dotenv**：環境変数の管理（既にインストール済み）。
- **Trelloボード**：分析用のデータを含むボード。

### Trelloのセットアップ
1. **ボード準備**：
   - 第2章のTrelloボード（例：`MCP-Project`）を使用。
   - リストを確認（例：`To Do`、`In Progress`、`Done`）。
   - カードにデータ追加：
     - 各カードに期限（例：`2025-04-22T10:00:00Z`）を設定。
     - カードをリスト間で移動（例：`To Do`から`Done`）して履歴を生成。
   - リストIDを記録（Trello UIのカードURLやAPIで取得）。
2. **APIキーとトークンの確認**：
   - 第2章のAPIキーとトークンを再利用（`read`、`write`スコープが必要）。
3. **環境変数**：
   第2章の`.env`ファイルに以下を追加：
   ```bash
   TRELLO_TO_DO_LIST_ID=your_to_do_list_id
   TRELLO_IN_PROGRESS_LIST_ID=your_in_progress_list_id
   TRELLO_DONE_LIST_ID=your_done_list_id
   ```

## コード例：タスク分析用MCPサーバー

以下のMCPサーバーは、Trelloのカードデータを取得し、完了率や平均完了時間を分析します。

```python
from mcp import MCPServer
import os
from dotenv import load_dotenv
import requests
from datetime import datetime, timezone
import statistics

class TrelloAnalysisServer(MCPServer):
    def __init__(self, host, port, api_key, token, board_id, to_do_list_id, in_progress_list_id, done_list_id):
        super().__init__(host, port)
        self.api_key = api_key
        self.token = token
        self.board_id = board_id
        self.to_do_list_id = to_do_list_id
        self.in_progress_list_id = in_progress_list_id
        self.done_list_id = done_list_id
        self.base_url = "https://api.trello.com/1"
        self.params = {"key": api_key, "token": token}
        self.register_resource("analyze_tasks", self.analyze_tasks)

    def get_cards(self):
        try:
            url = f"{self.base_url}/boards/{self.board_id}/cards"
            response = requests.get(url, params=self.params)
            response.raise_for_status()
            return response.json()
        except Exception as e:
            return {"status": "error", "message": str(e)}

    def get_card_actions(self, card_id):
        try:
            url = f"{self.base_url}/cards/{card_id}/actions"
            response = requests.get(url, params=self.params)
            response.raise_for_status()
            return response.json()
        except Exception as e:
            return {"status": "error", "message": str(e)}

    def analyze_tasks(self, params):
        try:
            cards = self.get_cards()
            if isinstance(cards, dict) and "status" in cards:
                return cards

            total_cards = len(cards)
            to_do_count = sum(1 for card in cards if card["idList"] == self.to_do_list_id)
            in_progress_count = sum(1 for card in cards if card["idList"] == self.in_progress_list_id)
            done_count = sum(1 for card in cards if card["idList"] == self.done_list_id)

            completion_rate = (done_count / total_cards * 100) if total_cards > 0 else 0

            completion_times = []
            for card in cards:
                if card["idList"] == self.done_list_id and card.get("dateLastActivity"):
                    actions = self.get_card_actions(card["id"])
                    if isinstance(actions, dict) and "status" in actions:
                        continue
                    creation_time = None
                    completion_time = datetime.fromisoformat(card["dateLastActivity"].replace("Z", "+00:00"))
                    for action in actions:
                        if action["type"] == "createCard":
                            creation_time = datetime.fromisoformat(action["date"].replace("Z", "+00:00"))
                            break
                    if creation_time:
                        completion_times.append((completion_time - creation_time).total_seconds() / 3600)

            avg_completion_time = statistics.mean(completion_times) if completion_times else 0

            bottlenecks = []
            now = datetime.now(timezone.utc)
            for card in cards:
                if card["idList"] == self.in_progress_list_id and card.get("due"):
                    due_date = datetime.fromisoformat(card["due"].replace("Z", "+00:00"))
                    if due_date < now:
                        bottlenecks.append({
                            "card_id": card["id"],
                            "name": card["name"],
                            "due": card["due"]
                        })

            return {
                "status": "success",
                "analysis": {
                    "completion_rate": f"{completion_rate:.2f}%",
                    "avg_completion_time_hours": f"{avg_completion_time:.2f}",
                    "to_do_count": to_do_count,
                    "in_progress_count": in_progress_count,
                    "done_count": done_count,
                    "bottlenecks": bottlenecks
                }
            }
        except Exception as e:
            return {"status": "error", "message": str(e)}

if __name__ == "__main__":
    load_dotenv()
    server = TrelloAnalysisServer(
        host="localhost",
        port=8113,
        api_key=os.getenv("TRELLO_API_KEY"),
        token=os.getenv("TRELLO_TOKEN"),
        board_id=os.getenv("TRELLO_BOARD_ID"),
        to_do_list_id=os.getenv("TRELLO_TO_DO_LIST_ID"),
        in_progress_list_id=os.getenv("TRELLO_IN_PROGRESS_LIST_ID"),
        done_list_id=os.getenv("TRELLO_DONE_LIST_ID")
    )
    print("Trello分析MCPサーバーを起動中: http://localhost:8113")
    server.start()
```

### コードの説明
- **get_cards**：ボードのカード情報を取得（第2章から再利用）。
- **get_card_actions**：カードのアクション履歴を取得し、作成日や更新日を抽出。
- **analyze_tasks**：カードデータを解析し、完了率、平均完了時間、ボトルネックを計算。
  - 完了率：`Done`リストのカード数を全体で割る。
  - 平均完了時間：カードの作成日から最終更新日までの時間を計算。
  - ボトルネック：期限切れの`In Progress`カードを特定。
- **register_resource**：タスク分析をリソースとして登録。

### 前提条件
- Trelloボードに`To Do`、`In Progress`、`Done`リストが存在。
- カードに期限や移動履歴がある。
- `.env`ファイルに正しい`TRELLO_API_KEY`、`TRELLO_TOKEN`、`TRELLO_BOARD_ID`、`TRELLO_TO_DO_LIST_ID`、`TRELLO_IN_PROGRESS_LIST_ID`、`TRELLO_DONE_LIST_ID`が設定済み。

## サーバーのテスト

サーバーが正しく動作するか確認します：

1. **サーバー起動**：
   ```bash
   python trello_analysis_server.py
   ```
   コンソールに「Trello分析MCPサーバーを起動中: http://localhost:8113」と表示。

2. **タスク分析のテスト**：
   Pythonでリクエストを送信：
   ```python
   import requests
   import json

   url = "http://localhost:8113"
   payload = {
       "jsonrpc": "2.0",
       "method": "analyze_tasks",
       "params": {},
       "id": 1
   }
   response = requests.post(url, json=payload)
   print(json.dumps(response.json(), indent=2, ensure_ascii=False))
   ```
   期待されるレスポンス：
   ```json
   {
     "jsonrpc": "2.0",
     "result": {
       "status": "success",
       "analysis": {
         "completion_rate": "40.00%",
         "avg_completion_time_hours": "24.50",
         "to_do_count": 2,
         "in_progress_count": 3,
         "done_count": 2,
         "bottlenecks": [
           {
             "card_id": "card126",
             "name": "コードレビュー",
             "due": "2025-04-20T10:00:00Z"
           }
         ]
       }
     },
     "id": 1
   }
   ```

## Claude Desktopとの接続

サーバーをClaude Desktopに接続します：

1. **設定ファイルの編集**：
   Claude Desktopの設定ファイル（例：`claude_desktop_config.json`）に以下を追加：
   ```json
   {
     "mcp_servers": [
       {
         "name": "TrelloAnalysisServer",
         "url": "http://localhost:8113",
         "auth": "none"
       }
     ]
   }
   ```

2. **Claudeでテスト**：
   Claude Desktopを起動し、プロンプトを入力：
   ```
   プロジェクトの進捗を分析してください。
   ```
   レスポンス例：
   ```
   プロジェクト進捗分析：
   - 完了率：40.00%
   - 平均完了時間：24.50時間
   - To Do：2タスク
   - In Progress：3タスク
   - Done：2タスク
   - ボトルネック：コードレビュー（期限：2025-04-20）
   ```

## 実装のコツと注意点

- **データ品質**：カードに期限やアクション履歴がない場合、分析結果が制限される。
- **レートリミティング**：Trello APIの制限（通常100リクエスト/10秒）に注意。
- **セキュリティ**：本番環境では、`auth: none`を避け、トークン認証を導入。
- **パフォーマンス**：大量のカードやアクションを処理する場合、キャッシュ（例：Redis）を検討。
- **テスト**：テスト用ボードを作成し、本番データに影響を与えない。

## 試してみよう：挑戦課題
以下の機能を追加して、エージェントを強化してみてください：
- メンバーごとのタスク完了率を分析（カードの`idMembers`を使用）。
- ボトルネックカードに自動でコメントを追加するツール。
- 分析結果をCSVファイルにエクスポートする機能。

## まとめと次のステップ

この第3章では、Trelloのカードデータを活用してタスク分析エージェントを構築しました。完了率やボトルネックを分析することで、AIがチームのパフォーマンスを評価し、プロセス改善のインサイトを提供できるようになりました。

次の第4章では、TrelloのWebhookを活用して**リアルタイム管理AI**を構築します。たとえば、AIがカードの移動や期限変更をリアルタイムで検知し、通知やコメントを生成します。リアルタイム管理AIに興味がある方は、ぜひお楽しみに！

---

役に立ったと思ったら、「いいね」や「ストック」をしていただけると嬉しいです！次の章でまたお会いしましょう！