·

Quy trình Đa MCP: GitHub & Jira

Xem cách AI agent kết nối GitHub và Jira qua MCP, biến một ticket thành pull request được theo dõi mà không cần thao tác thủ công.

Cặp GitHub + Jira là combo multi-MCP phổ biến nhất trong thực tế, vì nó khớp thẳng với quy trình làm việc của gần như mọi team engineering: ticket sống ở Jira, code sống ở GitHub, và không có gì tự động nối hai thế giới đó lại — trừ khi bạn dựng nó. Bài này đi qua toàn bộ vòng đời một ticket: từ lúc AI agent đọc Jira ticket, tự tạo branch, viết code, mở PR có link ngược lại ticket, đến lúc PR merge và ticket tự chuyển trạng thái. Đây là ví dụ rõ nhất cho thấy giá trị thật của MCP không nằm ở một server đơn lẻ, mà ở việc nối nhiều server để loại bỏ các bước tay chân lặp đi lặp lại.

Tổng Quan Workflow: Tự Động Hóa Toàn Trình Từ Jira Sang GitHub Với MCP

Trước khi vào chi tiết từng bước, cần hình dung rõ luồng dữ liệu chảy giữa hai server:

Jira MCP server                         GitHub MCP server
──────────────────                      ──────────────────
PROJ-123 "Fix null pointer   ──read──►  agent phân tích ticket
  in checkout total"                    
                                         agent tạo branch
                              ◄─write──  fix/proj-123-checkout-npe

                                         agent commit code + mở PR
                              ◄─write──  PR #456, description có
                                         "Closes PROJ-123"

PROJ-123 chuyển "In Review"  ◄─write──  (transition ticket khi PR mở)

                                         PR #456 được merge
PROJ-123 chuyển "Done"       ◄─write──  (transition ticket khi PR merge,
                                         qua webhook hoặc agent tự check)

Có hai cách triển khai workflow này: agent-driven (bạn ra lệnh, agent gọi tool lần lượt trong một session) hoặc event-driven (webhook từ GitHub kích hoạt agent tự động, không cần người gõ lệnh). Bài này tập trung vào agent-driven vì đó là cách bắt đầu thực tế nhất, nhưng phần cuối mỗi bước sẽ ghi chú cách chuyển sang event-driven khi bạn đã quen.

Điểm mấu chốt cần nắm: agent phải giữ được "sợi chỉ" nối 3 định danh xuyên suốt cả flow — Jira ticket key (PROJ-123), Git branch name, và PR number — vì đây là cách duy nhất để bước sau (transition ticket khi merge) biết phải tác động lên ticket nào.

Mẹo: Ngay từ bước đầu, ép agent đặt tên branch theo pattern cố định chứa ticket key (fix/proj-123-..., feature/proj-456-...). Đừng để agent tự do đặt tên branch mô tả — pattern cố định là cách rẻ nhất để bước cuối (transition ticket) tìm lại đúng ticket mà không cần lưu trạng thái riêng.

Bước 1: Tự Động Tạo Branch GitHub Từ Jira Ticket

Bắt đầu bằng việc yêu cầu agent đọc chi tiết ticket qua Jira MCP server, sau đó dùng chính nội dung đó để tạo branch có tên rõ nghĩa qua GitHub MCP server:

Đọc chi tiết ticket PROJ-123 trong Jira project CHECKOUT.
Dựa trên summary và description, tạo một branch mới trong repo
acme/checkout-service từ base branch main, tên branch theo pattern
fix/proj-123-<slug-ngắn-mô-tả-lỗi>.

Agent sẽ gọi tool Jira trước (thường là getJiraIssue hoặc tương đương) để lấy summary, description, issueType. Với ticket type là Bug, agent nên tự suy ra prefix fix/; với Story/Task, dùng feature/. Đây là điểm bạn nên chuẩn hoá bằng system prompt hoặc slash command, không để agent tự quyết mỗi lần khác nhau:

<!-- .claude/commands/start-ticket.md -->
Đọc ticket Jira $1 (project CHECKOUT). Xác định branch prefix:
- issueType "Bug" → prefix "fix/"
- issueType "Story" hoặc "Task" → prefix "feature/"
Tạo branch trong repo acme/checkout-service, tên:
<prefix><ticket-key-lowercase>-<3-5 từ khoá từ summary, cách nhau bằng gạch ngang>
Base branch: main.
Sau khi tạo branch, chuyển trạng thái ticket $1 sang "In Progress".

Gọi bằng /start-ticket PROJ-123. Lưu ý bước cuối trong command — chuyển trạng thái Jira ngay khi bắt đầu code, không phải chờ tới lúc mở PR. Đây là chi tiết dễ bị bỏ qua nhưng quan trọng cho tính minh bạch: người quản lý nhìn board Jira phải biết ticket đang được xử lý, không chỉ biết khi nó xong.

Về mặt kỹ thuật, tool tạo branch của GitHub MCP server thường cần bạn chỉ rõ SHA của base branch (không phải chỉ tên "main") để tránh race condition khi nhiều agent/nhiều người cùng tạo branch từ main đồng thời — agent nên gọi tool lấy ref của main trước, lấy SHA, rồi mới tạo branch từ SHA đó.

Mẹo: Đừng để agent tạo branch trực tiếp từ tên nhánh tự nhiên ngữ (ví dụ "sửa lỗi null pointer ở checkout") — luôn ép qua một bước "slugify" (chuẩn hoá thành chuỗi không dấu, không khoảng trắng, nối gạch ngang) tường minh trong prompt. Branch name có khoảng trắng hoặc ký tự lạ là lỗi runtime âm thầm khó chịu nhất khi tự động hoá Git.

Bước 2: Commit Code Và Mở PR Gắn Liên Kết Với Jira Issue

Sau khi có branch, để agent viết code sửa lỗi/feature (phần này dùng tool file-editing thông thường của agent, không qua MCP), rồi commit và push qua GitHub MCP server, cuối cùng mở PR với description chứa liên kết ngược về Jira:

Commit các thay đổi hiện tại vào branch fix/proj-123-checkout-npe
với message: "fix(checkout): guard against null cart total (PROJ-123)".
Push branch lên remote.
Mở PR từ fix/proj-123-checkout-npe vào main, title:
"Fix: null pointer khi cart total rỗng (PROJ-123)"
Description PR gồm:
- Tóm tắt thay đổi (2-3 câu)
- Liên kết: "Closes PROJ-123" và link đầy đủ tới ticket Jira
- Checklist: [ ] Unit test đã thêm, [ ] Đã test local

Chuỗi "Closes PROJ-123" trong PR description không tự động làm gì ở phía Jira — khác với GitHub issue (nơi từ khoá "Closes #123" tự đóng issue), Jira cần một tích hợp riêng (Jira/GitHub Integration app, hoặc chính agent của bạn) để đọc PR và transition ticket. Nếu team đã cài GitHub for Jira app, cụm "PROJ-123" xuất hiện trong PR title/commit message là đủ để Jira tự động hiện "linked PR" trên ticket — nhưng transition trạng thái (In Review, Done) vẫn cần rule riêng hoặc agent tự làm ở Bước 3.

Một chi tiết dễ bỏ sót: PR description nên trỏ về ticket bằng URL đầy đủ, không chỉ mã ticket, vì không phải mọi nơi hiển thị PR (Slack notification, email digest) đều tự động link hoá "PROJ-123" thành URL clickable:

## Liên kết
Closes PROJ-123 — https://acme.atlassian.net/browse/PROJ-123

Yêu cầu agent lấy diff thực tế qua GitHub MCP tool (get_pull_request_diff hoặc tương đương) trước khi tự viết tóm tắt PR description, thay vì tự bịa dựa vào "nhớ" những gì nó vừa sửa trong session — cách này giảm hẳn rủi ro description không khớp code thật, đặc biệt khi agent đã sửa qua vài lần chỉnh sau đó.

Mẹo: Luôn yêu cầu agent đọc lại PR diff bằng tool (không dựa vào trí nhớ trong context) ngay trước khi generate PR description cuối cùng — một agentic session dài có thể đã sửa code qua 4-5 lượt chỉnh, và mô tả PR viết từ context cũ dễ lệch với code thật ở commit cuối.

Bước 3: Tự Động Chuyển Trạng Thái Jira Ticket Khi PR Merge

Đây là bước nhiều team bỏ qua vì nó nằm ở "sau" — không xảy ra trong cùng session mở PR, mà xảy ra (có thể) vài giờ hoặc vài ngày sau, khi reviewer approve và merge. Có hai cách triển khai:

Cách 1 — Agent tự kiểm tra định kỳ (đơn giản, phù hợp khi mới bắt đầu):

Kiểm tra trạng thái PR #456 trong acme/checkout-service.
Nếu đã merged: chuyển Jira ticket PROJ-123 sang "Done" và
thêm comment vào ticket: "PR #456 đã merge vào main lúc <thời gian>."
Nếu chưa merged nhưng đã approved: chuyển ticket sang "Ready to Merge".
Nếu vẫn đang review: không làm gì.

Bạn có thể chạy lệnh này thủ công, hoặc lên schedule (cron job gọi agent) chạy mỗi 30 phút để quét toàn bộ PR đang mở có liên kết Jira.

Cách 2 — Event-driven qua webhook (đáng đầu tư khi đã có nhiều ticket/tuần):

GitHub gửi webhook pull_request.closed (với merged: true) tới một service nhỏ, service đó parse PR body tìm mã ticket theo regex [A-Z]+-\d+, rồi gọi agent (hoặc gọi trực tiếp Jira MCP server không qua LLM, vì đây là logic xác định, không cần suy luận) để transition ticket:

// webhook-handler.js — service nhẹ chạy độc lập, không nhất thiết cần LLM ở bước này
app.post('/github-webhook', async (req, res) => {
  const { action, pull_request, merged } = req.body;
  if (action === 'closed' && pull_request.merged) {
    const match = pull_request.body.match(/([A-Z]+-\d+)/);
    if (match) {
      await transitionJiraTicket(match[1], 'Done'); // gọi Jira REST API hoặc Jira MCP server
      await addJiraComment(match[1], `PR #${pull_request.number} merged into main.`);
    }
  }
  res.sendStatus(200);
});

Lưu ý quan trọng: bước transition trạng thái không cần LLM nếu logic là "regex tìm mã ticket, rồi map merged → Done" thuần tuý — dùng agent/LLM ở đây chỉ tốn thêm latency và token không cần thiết. Chỉ nên đưa LLM vào lại nếu bạn muốn agent viết comment tóm tắt thông minh hơn (ví dụ tóm tắt review feedback trước khi đóng ticket) chứ không chỉ transition trạng thái máy móc.

Mẹo: Đừng để mọi bước trong workflow đều chạy qua agent/LLM chỉ vì "đang làm MCP thì dùng agent cho đồng bộ". Bước transition trạng thái đơn giản dựa trên rule cố định nên tách thành script/webhook thuần, dùng Jira MCP server hoặc REST API trực tiếp — dành ngân sách LLM cho những bước thật sự cần suy luận (đọc ticket, viết code, viết PR description).

Vài Lưu Ý Thêm

  • Chuẩn hoá pattern branch name chứa ticket key ngay từ đầu — đây là "khoá ngoại" nối toàn bộ workflow, sai một lần là mất liên kết cả chuỗi.
  • Luôn dùng URL đầy đủ khi trỏ PR về Jira ticket, không chỉ mã ticket viết tay.
  • Bắt agent đọc lại diff thật qua tool trước khi viết PR description, không dựa vào trí nhớ context.
  • Tách phần logic xác định (transition trạng thái theo rule cố định) ra khỏi phần cần LLM (đọc hiểu, viết mô tả) để tối ưu chi phí và độ tin cậy.
  • Khi chuyển từ agent-driven sang event-driven, giữ nguyên convention đặt tên/liên kết đã dùng ở giai đoạn thủ công — đổi convention giữa đường sẽ làm webhook parser cũ không còn khớp.

Mẹo: Chạy thử toàn bộ 3 bước trên một ticket "nháp" không quan trọng trước, quan sát kỹ tên branch, PR description, và comment Jira mà agent tạo ra — chỉnh prompt/command cho đến khi output ổn định và đúng convention team, rồi mới áp dụng cho ticket thật. Sửa prompt sau khi đã chạy trên ticket thật tốn công dọn dẹp hơn nhiều so với test trước trên ticket nháp.