はじめに
第1章では、GitHubと**Model Context Protocol(MCP)**の基本を学び、GitHubリポジトリからIssueとコミットデータを取得するMCPサーバーを構築しました。これにより、AIがリポジトリの情報を取得できるようになりました。今回は、この基盤を進化させ、GitHubにIssueを作成したり、Pull Request(PR)にコメントしたりする機能を実装します。これにより、タスクを自動化するエージェントを構築します。
この第2章では、MCPサーバーを通じてAIがIssueにラベルを付けたり、PRにコメントを追加したりできるようにします。たとえば、ユーザーが特定のキーワードを含むIssueを作成すると、AIが自動で適切なラベル(例:「bug」)を付けることができます。コード例とステップごとのガイドで、開発タスク自動化の可能性を体感しましょう。さあ、始めましょう!
タスク自動化エージェントとは?
タスク自動化エージェントは、GitHubのIssueやPRを操作し、開発プロセスを効率化するAIです。MCPサーバーを介して、以下のような機能を実現できます:
- Issue管理:Issueの作成、ラベル付与、コメント追加。
- PR操作:PRへのコメント追加、レビューリクエスト。
- 自動化ルール:特定の条件(例:キーワードやユーザー)に基づいてアクションを実行。
ユースケース
- バグ管理:AIが「エラー」キーワードを含むIssueに「bug」ラベルを自動付与。
- コードレビュー:AIがPRに初期コメントを追加し、レビュアーに通知。
- プロジェクト管理:AIが期限付きIssueを作成し、チームに割り当て。
開発環境の準備
第1章の環境を基に、以下の準備を行います:
- Python 3.8以降、mcpライブラリ、requestsライブラリ、Claude Desktop:第1章と同じ。
- python-dotenv:環境変数の管理(既にインストール済み)。
- GitHubリポジトリ:IssueやPRを操作するための設定。
GitHubのセットアップ
-
GitHub Personal Access Tokenの拡張:
- 第1章のトークンを使用。
- スコープを確認:
repo
(Issue、PR、コミット操作)、必要に応じてadmin:repo_hook
(Webhook用)。 - トークンがIssueとPRの書き込み権限を持つことを確認。
-
リポジトリ準備:
- 第1章のリポジトリ(例:
yourusername/mcp-test-repo
)を使用。 - 新しいブランチを作成し、PRを1つ作成(例:「機能追加」ブランチ)。
- Issueラベルを追加(例:「bug」「enhancement」)。
- 第1章のリポジトリ(例:
-
環境変数:
第1章の.env
ファイル(GITHUB_TOKEN
、GITHUB_REPO
)を再利用:GITHUB_TOKEN=your_token GITHUB_REPO=yourusername/mcp-test-repo
コード例:タスク自動化用MCPサーバー
以下のMCPサーバーは、GitHubからIssueやコミットを取得し、Issue作成やPRコメント追加の機能を提供します。
from mcp import MCPServer
import os
from dotenv import load_dotenv
import requests
class GitHubTaskServer(MCPServer):
def __init__(self, host, port, token, repo):
super().__init__(host, port)
self.token = token
self.repo = repo
self.base_url = "https://api.github.com"
self.headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/vnd.github.v3+json"
}
self.register_resource("get_issues", self.get_issues)
self.register_tool("create_issue", self.create_issue)
self.register_tool("add_pr_comment", self.add_pr_comment)
def get_issues(self, params):
try:
url = f"{self.base_url}/repos/{self.repo}/issues"
query = {"state": params.get("state", "open"), "per_page": params.get("limit", 10)}
response = requests.get(url, headers=self.headers, params=query)
response.raise_for_status()
issues = response.json()
issue_list = [
{
"title": issue["title"],
"number": issue["number"],
"state": issue["state"],
"creator": issue["user"]["login"],
"created_at": issue["created_at"]
}
for issue in issues
]
return {"status": "success", "issues": issue_list}
except Exception as e:
return {"status": "error", "message": str(e)}
def create_issue(self, params):
try:
title = params.get("title", "")
body = params.get("body", "")
labels = params.get("labels", [])
if not title:
return {"status": "error", "message": "タイトルが必要です"}
url = f"{self.base_url}/repos/{self.repo}/issues"
payload = {
"title": title,
"body": body,
"labels": labels
}
response = requests.post(url, headers=self.headers, json=payload)
response.raise_for_status()
issue = response.json()
return {"status": "success", "issue_number": issue["number"]}
except Exception as e:
return {"status": "error", "message": str(e)}
def add_pr_comment(self, params):
try:
pr_number = params.get("pr_number", 0)
comment = params.get("comment", "")
if not pr_number or not comment:
return {"status": "error", "message": "PR番号とコメントが必要です"}
url = f"{self.base_url}/repos/{self.repo}/issues/{pr_number}/comments"
payload = {"body": comment}
response = requests.post(url, headers=self.headers, json=payload)
response.raise_for_status()
comment = response.json()
return {"status": "success", "comment_id": comment["id"]}
except Exception as e:
return {"status": "error", "message": str(e)}
if __name__ == "__main__":
load_dotenv()
server = GitHubTaskServer(
host="localhost",
port=8128,
token=os.getenv("GITHUB_TOKEN"),
repo=os.getenv("GITHUB_REPO")
)
print("GitHubタスクMCPサーバーを起動中: http://localhost:8128")
server.start()
コードの説明
- get_issues:第1章から再利用。リポジトリのIssueを取得。
- create_issue:新しいIssueを作成。タイトル、本文、ラベルを指定。
- add_pr_comment:指定したPRにコメントを追加。PR番号とコメント内容を指定。
- register_resource/tool:Issue取得をリソース、Issue作成・PRコメントをツールとして登録。
前提条件
- GitHubトークンに
repo
スコープが付与されている。 - リポジトリにPRとラベル(例:「bug」「enhancement」)が存在。
-
.env
ファイルに正しいGITHUB_TOKEN
とGITHUB_REPO
が設定済み。
サーバーのテスト
サーバーが正しく動作するか確認します:
-
サーバー起動:
python github_task_server.py
コンソールに「GitHubタスクMCPサーバーを起動中: http://localhost:8128」と表示。
-
Issue作成のテスト:
Pythonでリクエストを送信:import requests import json url = "http://localhost:8128" payload = { "jsonrpc": "2.0", "method": "create_issue", "params": { "title": "新しいバグ報告", "body": "アプリがクラッシュする問題が発生。", "labels": ["bug"] }, "id": 1 } response = requests.post(url, json=payload) print(json.dumps(response.json(), indent=2, ensure_ascii=False))
期待されるレスポンス:
{ "jsonrpc": "2.0", "result": { "status": "success", "issue_number": 3 }, "id": 1 }
-
PRコメント追加のテスト:
payload = { "jsonrpc": "2.0", "method": "add_pr_comment", "params": { "pr_number": 1, "comment": "コードレビュー:良好ですが、ドキュメントを追加してください。" }, "id": 2 } response = requests.post(url, json=payload) print(json.dumps(response.json(), indent=2, ensure_ascii=False))
期待されるレスポンス:
{ "jsonrpc": "2.0", "result": { "status": "success", "comment_id": 123456789 }, "id": 2 }
Claude Desktopとの接続
サーバーをClaude Desktopに接続します:
-
設定ファイルの編集:
Claude Desktopの設定ファイル(例:claude_desktop_config.json
)に以下を追加:{ "mcp_servers": [ { "name": "GitHubTaskServer", "url": "http://localhost:8128", "auth": "none" } ] }
-
Claudeでテスト:
Claude Desktopを起動し、プロンプトを入力:リポジトリに「新しいバグ報告」というIssueを作成し、「bug」ラベルを付けてください。
レスポンス例:
Issue #3「新しいバグ報告」を作成し、「bug」ラベルを付けました。
別のプロンプト:
PR #1に「コードレビュー:良好ですが、ドキュメントを追加してください。」とコメントしてください。
レスポンス例:
PR #1にコメントを追加しました。
実装のコツと注意点
- エラーハンドリング:無効なPR番号やラベルが存在しない場合のエラーを適切に処理。
- レートリミティング:GitHub APIの制限(例:5000リクエスト/時間)に注意。
-
セキュリティ:本番環境では、
auth: none
を避け、トークン認証を導入。 - テスト:テスト用リポジトリを作成し、本番データに影響を与えない。
- 拡張性:大量のIssueやPRを処理する場合、キャッシュ(例:Redis)を検討。
試してみよう:挑戦課題
以下の機能を追加して、エージェントを強化してみてください:
- 特定のキーワード(例:「エラー」)を含むIssueに自動で「bug」ラベルを付ける機能。
- PRにレビュアーを割り当てるツール。
- Issueをクローズする機能。
まとめと次のステップ
この第2章では、GitHubにIssueを作成し、PRにコメントを追加するMCPサーバーを構築し、開発タスク自動化エージェントを実現しました。AIがIssueやPRを操作できるようになり、チームの効率が向上しました。
次の第3章では、GitHubのコミットデータを活用してコード分析エージェントを構築します。たとえば、AIがコミット履歴から変更パターンを分析し、コード品質のインサイトを提供します。コード分析AIに興味がある方は、ぜひお楽しみに!
役に立ったと思ったら、「いいね」や「ストック」をしていただけると嬉しいです!次の章でまたお会いしましょう!