はじめに
第1章では、Jiraと**Model Context Protocol(MCP)**の基本を学び、JiraプロジェクトからTicketやSprintデータを取得するMCPサーバーを構築しました。これにより、AIがプロジェクトの情報を取得できるようになりました。今回は、この基盤を進化させ、JiraにTicketを作成したり、コメントを追加したりする機能を実装します。これにより、タスクを自動化するエージェントを構築します。
この第2章では、MCPサーバーを通じてAIがTicketに優先度を付けたり、コメントを追加したりできるようにします。たとえば、ユーザーが特定のキーワードを含むTicketを作成すると、AIが自動で「High」優先度を付けることができます。コード例とステップごとのガイドで、プロジェクトタスク自動化の可能性を体感しましょう。さあ、始めましょう!
タスク自動化エージェントとは?
タスク自動化エージェントは、JiraのTicketやコメントを操作し、プロジェクト管理を効率化するAIです。MCPサーバーを介して、以下のような機能を実現できます:
- Ticket管理:Ticketの作成、優先度設定、コメント追加。
- 自動化ルール:特定の条件(例:キーワードやステータス)に基づいてアクションを実行。
- チーム支援:Ticketの割り当てや通知を最適化。
ユースケース
- バグ管理:AIが「エラー」キーワードを含むTicketに「High」優先度を自動付与。
- コミュニケーション:AIがTicketに初期コメントを追加し、担当者に指示。
- ワークフロー最適化:AIが期限付きTicketを作成し、チームに割り当て。
開発環境の準備
第1章の環境を基に、以下の準備を行います:
- Python 3.8以降、mcpライブラリ、requestsライブラリ、Claude Desktop:第1章と同じ。
- python-dotenv:環境変数の管理(既にインストール済み)。
- Jiraプロジェクト:Ticket操作のための設定。
Jiraのセットアップ
-
Jira APIトークンの確認:
- 第1章のトークンを使用。
- 権限を確認:プロジェクトでのTicket作成、編集、コメント追加が可能。
-
プロジェクト準備:
- 第1章のプロジェクト(例:
MCP-TEST
、キー:MCP
)を使用。 - Ticketタイプ(例:Bug、Task)と優先度(例:High、Medium、Low)を設定。
- テスト用ユーザーをプロジェクトに追加(コメントや割り当て用)。
- 第1章のプロジェクト(例:
-
環境変数:
第1章の.env
ファイル(JIRA_URL
、JIRA_EMAIL
、JIRA_API_TOKEN
、JIRA_PROJECT_KEY
)を再利用:JIRA_URL=https://your-domain.atlassian.net JIRA_EMAIL=your_email@example.com JIRA_API_TOKEN=your_jira_api_token JIRA_PROJECT_KEY=MCP
コード例:タスク自動化用MCPサーバー
以下のMCPサーバーは、JiraからTicketデータを取得し、Ticket作成やコメント追加の機能を提供します。
from mcp import MCPServer
import os
from dotenv import load_dotenv
import requests
from requests.auth import HTTPBasicAuth
class JiraTaskServer(MCPServer):
def __init__(self, host, port, url, email, api_token, project_key):
super().__init__(host, port)
self.url = url
self.email = email
self.api_token = api_token
self.project_key = project_key
self.base_url = f"{url}/rest/api/3"
self.auth = HTTPBasicAuth(email, api_token)
self.headers = {
"Accept": "application/json",
"Content-Type": "application/json"
}
self.register_resource("get_tickets", self.get_tickets)
self.register_tool("create_ticket", self.create_ticket)
self.register_tool("add_comment", self.add_comment)
def get_tickets(self, params):
try:
url = f"{self.base_url}/search"
query = {
"jql": f"project={self.project_key} AND status={params.get('status', 'Open')}",
"maxResults": params.get("limit", 10)
}
response = requests.get(url, headers=self.headers, auth=self.auth, params=query)
response.raise_for_status()
issues = response.json()["issues"]
ticket_list = [
{
"key": issue["key"],
"summary": issue["fields"]["summary"],
"status": issue["fields"]["status"]["name"],
"creator": issue["fields"]["creator"]["displayName"],
"created": issue["fields"]["created"]
}
for issue in issues
]
return {"status": "success", "tickets": ticket_list}
except Exception as e:
return {"status": "error", "message": str(e)}
def create_ticket(self, params):
try:
summary = params.get("summary", "")
description = params.get("description", "")
issue_type = params.get("issue_type", "Task")
priority = params.get("priority", "Medium")
if not summary:
return {"status": "error", "message": "サマリーが必要です"}
url = f"{self.base_url}/issue"
payload = {
"fields": {
"project": {"key": self.project_key},
"summary": summary,
"description": description,
"issuetype": {"name": issue_type},
"priority": {"name": priority}
}
}
response = requests.post(url, headers=self.headers, auth=self.auth, json=payload)
response.raise_for_status()
issue = response.json()
return {"status": "success", "ticket_key": issue["key"]}
except Exception as e:
return {"status": "error", "message": str(e)}
def add_comment(self, params):
try:
ticket_key = params.get("ticket_key", "")
comment = params.get("comment", "")
if not ticket_key or not comment:
return {"status": "error", "message": "Ticketキーとコメントが必要です"}
url = f"{self.base_url}/issue/{ticket_key}/comment"
payload = {"body": comment}
response = requests.post(url, headers=self.headers, auth=self.auth, 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 = JiraTaskServer(
host="localhost",
port=8133,
url=os.getenv("JIRA_URL"),
email=os.getenv("JIRA_EMAIL"),
api_token=os.getenv("JIRA_API_TOKEN"),
project_key=os.getenv("JIRA_PROJECT_KEY")
)
print("JiraタスクMCPサーバーを起動中: http://localhost:8133")
server.start()
コードの説明
- get_tickets:第1章から再利用。プロジェクトのTicketを取得。
- create_ticket:新しいTicketを作成。サマリー、説明、課題タイプ、優先度を指定。
- add_comment:指定したTicketにコメントを追加。Ticketキーとコメント内容を指定。
- register_resource/tool:Ticket取得をリソース、Ticket作成・コメント追加をツールとして登録。
前提条件
- Jira APIトークンにプロジェクトへの書き込み権限がある。
- プロジェクトに課題タイプ(例:Bug、Task)と優先度(例:High、Medium、Low)が設定済み。
-
.env
ファイルに正しいJIRA_URL
、JIRA_EMAIL
、JIRA_API_TOKEN
、JIRA_PROJECT_KEY
が設定済み。
サーバーのテスト
サーバーが正しく動作するか確認します:
-
サーバー起動:
python jira_task_server.py
コンソールに「JiraタスクMCPサーバーを起動中: http://localhost:8133」と表示。
-
Ticket作成のテスト:
Pythonでリクエストを送信:import requests import json url = "http://localhost:8133" payload = { "jsonrpc": "2.0", "method": "create_ticket", "params": { "summary": "新しいバグ報告", "description": "アプリがクラッシュする問題が発生。", "issue_type": "Bug", "priority": "High" }, "id": 1 } response = requests.post(url, json=payload) print(json.dumps(response.json(), indent=2, ensure_ascii=False))
期待されるレスポンス:
{ "jsonrpc": "2.0", "result": { "status": "success", "ticket_key": "MCP-3" }, "id": 1 }
-
コメント追加のテスト:
payload = { "jsonrpc": "2.0", "method": "add_comment", "params": { "ticket_key": "MCP-3", "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": "10001" }, "id": 2 }
Claude Desktopとの接続
サーバーをClaude Desktopに接続します:
-
設定ファイルの編集:
Claude Desktopの設定ファイル(例:claude_desktop_config.json
)に以下を追加:{ "mcp_servers": [ { "name": "JiraTaskServer", "url": "http://localhost:8133", "auth": "none" } ] }
-
Claudeでテスト:
Claude Desktopを起動し、プロンプトを入力:プロジェクトに「新しいバグ報告」というBug Ticketを作成し、優先度を「High」にしてください。
レスポンス例:
Ticket MCP-3「新しいバグ報告」を作成し、優先度を「High」に設定しました。
別のプロンプト:
Ticket MCP-3に「問題を確認しました。詳細を教えてください。」とコメントしてください。
レスポンス例:
Ticket MCP-3にコメントを追加しました。
実装のコツと注意点
- エラーハンドリング:無効なTicketキーや優先度が存在しない場合のエラーを適切に処理。
- レートリミティング:Jira APIの制限(例:600リクエスト/分、クラウドインスタンスによる)に注意。
-
セキュリティ:本番環境では、
auth: none
を避け、トークン認証を導入。 - テスト:テスト用プロジェクトを作成し、本番データに影響を与えない。
- 拡張性:大量のTicketを処理する場合、キャッシュ(例:Redis)を検討。
試してみよう:挑戦課題
以下の機能を追加して、エージェントを強化してみてください:
- 特定のキーワード(例:「エラー」)を含むTicketに自動で「High」優先度を付ける機能。
- Ticketに担当者を割り当てるツール。
- Ticketのステータスを更新(例:Open → In Progress)する機能。
まとめと次のステップ
この第2章では、JiraにTicketを作成し、コメントを追加するMCPサーバーを構築し、プロジェクトタスク自動化エージェントを実現しました。AIがTicketを操作できるようになり、チームの効率が向上しました。
次の第3章では、JiraのTicketデータを活用してプロジェクト分析エージェントを構築します。たとえば、AIがSprintの完了率やチームのパフォーマンスを分析し、プロジェクトのインサイトを提供します。プロジェクト分析AIに興味がある方は、ぜひお楽しみに!
役に立ったと思ったら、「いいね」や「ストック」をしていただけると嬉しいです!次の章でまたお会いしましょう!