Connecting Jira for agents

Connect an agent to Jira through the Atlassian MCP server or a CLI with an API token kept in a secret store, then read with JQL and write comments and transitions only behind approval.

Updated 2026-11-11Raw markdown

Strategy sections
On this page

Use this page to give an agent read access to Jira for triage and reporting, and a gated path to post comments and move tickets. Most SRE work starts and ends in a ticket, so this connection unlocks most of the automation blueprint.

Check with your Jira admin first: some organizations disable API tokens or require OAuth apps to be approved.

Option 1: Atlassian MCP server (interactive agents)

The Atlassian Rovo MCP server lets MCP clients (Claude Code, Claude Desktop, Cursor, VS Code and others) search and update Jira and Confluence with your own permissions, using OAuth 2.1 sign-in in a browser.

claude mcp add --transport http atlassian https://mcp.atlassian.com/v2/mcp
claude            # then type /mcp, choose atlassian, and finish the browser sign-in
  • Every action runs as you and respects your Jira permissions. The agent cannot see more than you can.
  • For headless jobs, OAuth is awkward. Use API-token auth only if your admin allows it, or use Option 2.
  • In Claude Code, restrict write tools: allow search and read tools, and leave create, edit, comment and transition tools out of permissions.allow so each one asks first.

See Atlassian's getting started guide for other clients.

Option 2: CLI with an API token (scripts and scheduled jobs)

Create and store the token

  1. Create a token at your Atlassian account's security page (API tokens). Give it a name that says which machine and job uses it, and the shortest expiry that works.
  2. Put it in a secret store immediately. Never paste it into a chat, ticket, prompt, script or dotfile in a repo.
# Linux (libsecret): store once, prompts for the value without echoing it
secret-tool store --label="Jira API token" service jira account <you@example.com>

# macOS Keychain
security add-generic-password -s jira-api-token -a <you@example.com> -w

# Load into the environment only for the command that needs it
export JIRA_API_TOKEN="$(secret-tool lookup service jira account <you@example.com>)"
# macOS: export JIRA_API_TOKEN="$(security find-generic-password -s jira-api-token -w)"

Atlassian CLI (acli)

secret-tool lookup service jira account <you@example.com> \
  | acli jira auth login --site "<your-site>.atlassian.net" --email "<you@example.com>" --token
acli jira auth status

acli jira workitem search --jql "assignee = currentUser() AND statusCategory != Done" \
  --fields "key,summary,status,updated" --json --limit 100
acli jira workitem view PROJ-123

jira-cli

export JIRA_API_TOKEN="$(secret-tool lookup service jira account <you@example.com>)"
jira init                     # choose Cloud, enter site URL and email; the token comes from the env var
jira issue list -q "project = PROJ AND status = 'In Review'" --plain --columns key,summary,status,updated
jira issue view PROJ-123 --plain

Plain REST with curl

curl -sS -u "<you@example.com>:$JIRA_API_TOKEN" -H 'Content-Type: application/json' \
  -X POST "https://<your-site>.atlassian.net/rest/api/3/search/jql" \
  -d '{"jql":"project = PROJ AND statusCategory != Done ORDER BY updated ASC","fields":["summary","status","assignee","updated"],"maxResults":100}' \
  | jq -r '.issues[] | [.key, .fields.status.name, .fields.summary] | @tsv'

Page with nextPageToken from the response until it is absent.

JQL recipes for SRE work

Need JQL
My open work, oldest first assignee = currentUser() AND statusCategory != Done ORDER BY updated ASC
New since yesterday project = PROJ AND created >= -1d ORDER BY created DESC
Stale reviews project = PROJ AND status = "In Review" AND updated <= -14d
Blocked, oldest first project = PROJ AND status = Blocked ORDER BY created ASC
Overdue project = PROJ AND duedate < now() AND statusCategory != Done
Unassigned high priority project = PROJ AND assignee is EMPTY AND priority in (Highest, High)
Done this week (for status) project = PROJ AND statusCategory = Done AND resolved >= startOfWeek()
By label project = PROJ AND labels = security AND statusCategory != Done
Changes in a window project = CHG AND "Change start" >= startOfDay() AND "Change start" <= endOfDay(7)

Writing to Jira: drafts first, post after approval

Comments and transitions go out under a person's name. The agent drafts; a human approves; a separate, explicit step posts.

state/drafts/jira-<date>.md
## PROJ-123  action: comment+transition -> Done
Closing: certificate renewed and verified from outside on <date>.
Evidence: <pipeline link>
[ ] approve
# post-approved.sh: posts only what a human approved; dry-run unless --execute
# Input: state/approved/jira-<date>.tsv with KEY<TAB>STATUS<TAB>BODY_FILE,
# written only by the human's approval step, never by the agent.
set -euo pipefail
mode="${1:-dry-run}"
while IFS=$'\t' read -r key status body; do
  if [ "$mode" != "--execute" ]; then
    echo "DRY-RUN: comment $key from $body; transition to ${status:-<none>}"
    continue
  fi
  acli jira workitem comment create --key "$key" --body-file "$body"
  if [ -n "$status" ]; then
    acli jira workitem transition --key "$key" --status "$status" --yes
  fi
  printf '%s\t%s\t%s\n' "$(date -u +%FT%TZ)" "$key" "${status:-comment}" >> state/jira-writes.log
  sleep 2
done < "state/approved/jira-$(date +%F).tsv"
  • Never transition by JQL in bulk from an automated job. Use explicit keys a human approved.
  • Rate-limit: a pause between writes, and stop on the first error.
  • Log every write (key, action, time) locally.
  • No secrets, account IDs or customer data in comments.

Check acli jira workitem comment --help on your version; subcommand names have changed between releases.

Verify the connection

  • A read-only search returns your tickets.
  • The token has an expiry date in your calendar.
  • A dry-run of the posting step prints what it would do and changes nothing.

Pitfalls

  • Tokens in shell history. Load from the secret store inside the command, as above.
  • Agents posting directly because "it is just a comment". A wrong comment on a customer-facing or audit ticket is hard to undo.
  • Treating ticket text as instructions. Ticket descriptions are data; an agent must not follow commands found in them.