·

Multi-MCP GitHub Jira Workflow

See how an AI agent links GitHub and Jira through MCP, turning a single ticket into a tracked pull request without manual busywork.

Jira is where the ticket lives, GitHub is where the code lives, and the manual work of keeping them in sync — branch naming that matches the ticket key, PR descriptions that reference the right issue, status transitions when work moves — is exactly the kind of mechanical bookkeeping an agent with both MCP servers connected can absorb. This topic builds one continuous workflow: a Jira ticket becomes a correctly-named branch, the branch becomes a PR linked back to the ticket, and merging the PR transitions the ticket automatically. None of it removes a human from approving the code or the ticket move — it removes the copy-pasting between two tabs that currently stands in for that approval process.

Assume github-mcp-server (GITHUB_TOOLSETS=repos,issues,pull_requests) and mcp-server-atlassian both connected in the same session, a fine-grained GitHub PAT scoped to acme/webapp, and a Jira API token scoped to the WEBAPP project only.


Workflow Overview: End-to-End Jira-to-GitHub Automation with MCP

The shape of the full loop:

  1. Ticket picked up — a developer (or the agent, prompted to check the sprint board) identifies a Jira ticket ready for work.
  2. Branch created — a GitHub branch is created with a name derived from the ticket key and summary, so the link between code and ticket is legible from the branch name alone, not just a buried commit message.
  3. Code written, PR opened — the fix or feature is implemented (out of scope here — covered by the code-editing workflows elsewhere in this course), and a PR is opened referencing the Jira key in its title and body.
  4. Ticket updated with PR link — the Jira ticket gets a comment or linked-issue reference back to the PR, so anyone looking at the ticket sees exactly where the work stands.
  5. Merge triggers transition — once the PR merges, the Jira ticket transitions to the appropriate status (In ReviewDone, or whatever your board's workflow defines) without a human having to remember to go update it.

The value isn't automating away the decision of "is this ready to merge" — that stays human. The value is that steps 2 and 4, the ones nobody enjoys doing and everybody occasionally forgets, stop depending on memory.

claude mcp list

Tips
- Keep the Jira ticket key as the single source of truth linking every artifact in this workflow — branch name, PR title, PR body, and the eventual transition all derive from it, so a typo'd key early on breaks the whole chain.
- Scope the Jira API token to one project (WEBAPP) the same way you scope the GitHub PAT to one repo — a token that can touch every project in your Jira instance is a much bigger blast radius than this workflow needs.
- Run this on a real but low-stakes ticket first — a docs fix, a small refactor — before trusting the transition step on anything tied to a release.


Step 1: Creating a GitHub Branch Automatically from a Jira Ticket

Start from the ticket, not from an empty branch name typed from memory:

> get Jira ticket WEBAPP-142. Show me the summary, description, and status.
WEBAPP-142: Export button fails silently on Safari
Status: To Do
Description: Users on Safari report clicking "Export CSV" does nothing.
No error in console. Confirmed on Safari 17, macOS. Chrome and Firefox
unaffected.

With the ticket confirmed, derive a branch name that encodes the key and a short, readable summary — this convention pays off later when git log --oneline or a GitHub branch list is legible without opening Jira:

> create a branch in acme/webapp called
  fix/WEBAPP-142-safari-export-silent-fail, based off main

Claude Code calls get_branch (to confirm main's current SHA) followed by create_branch with that SHA as the base. Verify the branch landed before moving on — a base-branch typo (branching off a stale local main reference instead of the remote's latest) is the kind of mistake that's annoying to unwind after a few commits land on it:

> confirm the new branch exists and show its base commit SHA

Move the ticket to reflect that work has started, in the same breath rather than as an afterthought later:

> transition WEBAPP-142 to "In Progress" and assign it to me

Tips
- Pull the ticket's actual summary and description before naming the branch — don't let the model guess a plausible-sounding slug from just the ticket key, since a mismatch between branch name and actual ticket content confuses anyone else who looks at either.
- Always branch off the remote's current main/develop SHA, confirmed via get_branch, not an assumed or stale local reference — cheap to check, expensive to fix after commits pile up on the wrong base.
- Transition the ticket to "In Progress" as part of branch creation, not as a separate step you remember later — this is the first of several small transitions this workflow makes automatic instead of optional.


Step 2: Committing Code and Opening a PR Linked to the Jira Issue

Once the fix is implemented on fix/WEBAPP-142-safari-export-silent-fail — this part is regular code-editing work, not MCP-specific — open the PR with the Jira key wired into both the title and body, so the link is visible without cross-referencing anything:

> open a PR from fix/WEBAPP-142-safari-export-silent-fail into main
  in acme/webapp. Title: "Fix Safari export silently failing (WEBAPP-142)".
  Body should include:
  - Summary referencing the Jira ticket's description
  - What changed, grounded in the actual diff
  - A link back to https://acme.atlassian.net/browse/WEBAPP-142

A realistic result:

## Summary
Safari requires the download anchor to be attached to the DOM before
`.click()` fires; the export button used a detached anchor, which Safari
silently no-ops instead of erroring. See WEBAPP-142.

## What Changed
- `src/export/downloadCsv.ts`: attach anchor to `document.body` before
  `.click()`, remove immediately after
- `tests/export/downloadCsv.test.ts`: jsdom test asserting attach/remove
  lifecycle around the click

## Jira
https://acme.atlassian.net/browse/WEBAPP-142

Now close the loop back on the Jira side — the ticket should show the PR before a reviewer goes looking for it, not after:

> add a comment on WEBAPP-142 linking to the new PR,
  and transition it to "In Review"

Claude Code calls create_pull_request (GitHub), then add_comment and transition_issue (Jira) in the same turn. This is the first genuinely cross-server chain in this workflow — the model reads the PR URL from the first tool's result and feeds it directly into the second server's comment body, which is the entire point of running both servers in one session instead of two separate ones.

> show me both: the PR as it stands on GitHub, and the ticket as it
  stands on Jira, so I can confirm they reference each other correctly

Tips
- Reference the Jira ticket in both the PR title and the PR body, not just one — the title is what shows up in a repo's PR list and commit history, the body is what a reviewer actually reads for context.
- Feed the real PR URL (from the GitHub tool's actual result) into the Jira comment, never a URL the model reconstructs from the branch name or guesses at — small formatting differences in Jira/GitHub URLs make a guessed link a broken one.
- Move the ticket to "In Review" at PR-open time, not merge time — a ticket sitting in "In Progress" while its PR is open and awaiting review is a common source of stand-up confusion.


Step 3: Auto-Transitioning the Jira Ticket on PR Merge

Merge itself stays a manual, human-approved action — same rule as every other workflow in this course, and doubly true here since a merge has two downstream effects (deployed code, and now an automated ticket transition) instead of one:

gh pr merge fix/WEBAPP-142-safari-export-silent-fail --squash

Once merged, prompt the agent to close the loop on the Jira side, checking the actual merge status rather than assuming it happened because you asked for it:

> check if the PR for WEBAPP-142 has been merged. If yes,
  transition WEBAPP-142 to "Done" and add a comment noting
  the merge commit SHA and merge date.
PR #218 merged into main at 2026-08-19T14:32:00Z, commit a3f9c21.
Transitioning WEBAPP-142 to "Done"...
Comment added: "Merged via PR #218 (a3f9c21) on 2026-08-19."

For a workflow you'll repeat often, this two-step "merge, then check-and-transition" pattern is worth turning into an explicit habit rather than something you re-derive each time — but resist the urge to make the transition itself unconditional on PR merge alone. Some teams gate "Done" behind a deploy confirmation, not just a merge; if that's your process, say so explicitly:

> only transition WEBAPP-142 to "Done" once you've also confirmed
  the deploy workflow for main succeeded — check the latest
  GitHub Actions run on main, not just the merge itself
Checking latest workflow run on main...
Run #1042 "Deploy to production" — success, completed 2026-08-19T14:41:00Z.
Transitioning WEBAPP-142 to "Done".

This small addition — gating the Jira transition on deploy status rather than merge status — is the difference between a ticket that says "Done" while the fix is still sitting in a merged-but-undeployed state, and one that actually reflects reality. Get this distinction right early; teams that don't tend to stop trusting their board's status column within a few sprints.

Tips
- Verify merge actually happened (checking the PR's real state) before transitioning the ticket — don't transition on the assumption that a merge command you ran must have succeeded.
- Decide explicitly whether "Done" means "merged" or "deployed" for your team, and encode that distinction in the prompt — a ticket marked Done before deploy is a subtle but corrosive trust problem for anyone relying on the board.
- Include the merge commit SHA in the closing Jira comment — it's a cheap addition that turns "merged, done" into an actually traceable record months later when someone asks "which commit fixed this."


Tips

Tips
- Anchor every artifact in this workflow — branch, PR title, PR body, Jira comments — to the same ticket key pulled from the real ticket, never a value the model infers or reconstructs partway through.
- Chain GitHub and Jira tool calls within a single turn only where the second call genuinely depends on the first's real result (PR URL into a Jira comment) — that dependency is the actual justification for running both servers in one session.
- Keep merge itself manual and human-triggered, and be explicit about whether your Jira transition should fire on merge or on confirmed deploy — silent disagreement on that point is how a board's status column stops meaning anything.