Skip to main content
Glama
YusufKaracSimply

jira-worktrack-mcp

README.md
# jira-worktrack-mcp

A zero-dependency MCP server that answers the questions people actually ask about work in
Jira — *what is on my plate, what did I do yesterday, where is the sprint bleeding, which
tickets are not ready for development, what has been waiting too long* — instead of
returning raw issue JSON to sort through.

Jira is the single source of truth; nothing is stored locally except downloaded
attachments. Everything is read-only apart from `upload_attachments`, which is the single
tool that changes anything.

The installer offers to write the matching permission rules, so reading a ticket's
screenshots does not prompt on every call while the one writing tool still does:

```json
{
  "permissions": {
    "allow": ["mcp__jira-worktrack"],
    "ask": ["mcp__jira-worktrack__upload_attachments"]
  }
}
```

An `ask` rule outranks an `allow` rule, so the two hold together. Decline the question, or
set `JIRA_NO_PERMS=1`, and nothing is written to `~/.claude/settings.json`.

## Install

```bash
curl -fsSL https://raw.githubusercontent.com/YusufKaracSimply/jira-worktrack-mcp/main/bootstrap.sh | bash -s -- acme
```

The argument is the Jira site, so the command your team shares already carries the company
name: `acme` becomes `https://acme.atlassian.net`, and a full URL works too. Leave it out
and the installer asks for it.

Credentials you already have on this machine — from Claude Code, Cursor or Claude Desktop —
are found first and offered for reuse, so you may not be asked for anything else. Otherwise
it asks for your Atlassian e-mail and an API token (create one at
https://id.atlassian.com/manage-profile/security/api-tokens).

## Tools

You normally do not need to name a tool. Ask the question in your own words — *what did I do
yesterday*, *what is in this ticket's attachment*, *why is CON-123 taking so long* — and
Claude picks the right one. This is most true of the attachment tools: mention an issue key
and say you want to see the file, and it lists, downloads, renders or extracts as needed
without being told which step to run.

### For developers

| Tool | Answers |
| --- | --- |
| `my_work` | What is assigned to me, grouped by status, with anything untouched for days flagged. |
| `standup` | What I moved or closed since yesterday, what I am on now, what I am waiting for — read from the change history, not from memory. |
| `next_up` | What to pick up next, ranked by started/priority/sprint/age, with the reasoning shown. |

### For scrum masters

| Tool | Answers |
| --- | --- |
| `sprint_health` | Status split, work in progress per person, unassigned items, items stuck too long, share of the sprint actually done. |
| `flow_metrics` | Cycle time and lead time (median and p90), where the time goes per status, and the slowest tickets. |
| `stale_issues` | Two kinds of silence: nobody updated it, and it never left this status. |
| `workload` | Open issues per person, split by in progress and waiting, with story points when the project uses them. |

### For BAs

| Tool | Answers |
| --- | --- |
| `intake_check` | Which tickets lack a description, acceptance criteria, an attachment, a customer or an estimate. |
| `waiting_on_customer` | What is parked outside the team, how long, and who spoke last. |
| `duplicate_scan` | Tickets whose summaries overlap — the same request arriving twice. |

### Attachments

| Tool | Answers |
| --- | --- |
| `list_attachments` | What is attached, and which comment each file was posted with. |
| `download_attachments` | Fetches them; `inline: true` shows the images straight in the reply. |
| `render_pdf` | Renders PDF pages to images, plus any annotation text — no poppler needed on macOS. |
| `extract_attachment_text` | Text out of .xlsx/.docx/.pptx, text files and text-bearing PDFs. |
| `download_attachments_by_jql` | Every attachment across the issues a query matches. |
| `upload_attachments` | Attaches local files. **The only tool that writes to Jira.** |

### For everyone

| Tool | Answers |
| --- | --- |
| `issue_timeline` | One ticket's life: every status change, how long it stayed, who moved it. |
| `team_report` | Created versus resolved over a period, throughput per person, breakdown by type. |
| `whoami` | Verifies the credentials. |

## How the numbers are worked out

- **Status categories over status names.** Workflows differ per project — this site alone
  has `in progress`, `Code_Review`, `ready_for_test` and `Ready To Release`. Anything
  structural keys off Jira's `statusCategory` (new / indeterminate / done); the name is only
  used for display and for spotting "waiting" states.
- **Time in status** is rebuilt from each issue's changelog, requested with
  `expand: changelog` on the search itself — one call for a hundred issues rather than a
  hundred calls.
- **Cycle time** starts at the first move into a status that is neither backlog nor done. A
  ticket taken straight from the backlog to closed never started, so it has no cycle time
  and is reported separately instead of being counted as zero.
- **Duplicate scan** compares normalised summary words (Jaccard). Pairs that share a parent,
  and story/test pairs, are skipped — those repeat a summary on purpose.
- **Caps are reported, never silent**: when a tool stops at its issue limit it says so.

## Configuration

| Env var | Default | Meaning |
| --- | --- | --- |
| `JIRA_BASE_URL` | — | e.g. `https://your-site.atlassian.net` |
| `JIRA_EMAIL` | — | Atlassian account e-mail |
| `JIRA_API_TOKEN` | — | Atlassian API token |
| `JIRA_TIMEOUT_MS` | `30000` | Request timeout |
| `JIRA_MAX_RETRIES` | `3` | Retries on timeout, 429 and 5xx (honouring `Retry-After`) |
| `JIRA_DOWNLOAD_DIR` | `~/.cache/jira-worktrack` | Where attachments are written, one directory per issue key |
| `JIRA_MAX_BYTES` | `52428800` | Attachments larger than this are skipped |
| `JIRA_CACHE_DAYS` | `14` | Downloaded files older than this are deleted; `0` keeps everything |

Custom field ids differ per site, so Story Points, Sprint and the customer field are looked
up by name once per session and cached.

## Contributing

MIT licensed, so fork it and change whatever you like — a tool that only fits your own way
of working belongs in your own copy.

If the change would help everyone, open a pull request instead. `main` takes no direct
pushes: branch off, push the branch, open the PR. Every file is code-owned, so the review
request reaches the maintainer automatically, and the PR merges once it is approved.

## Notes

- The API token is stored in `~/.claude.json` in plain text, like every other MCP env var.
- Everything is scoped to what your own Jira account can see.
- Downloaded attachments are customer files sitting unencrypted in the cache directory.
  They are swept once per session: anything older than `JIRA_CACHE_DAYS` goes, along with
  the directories left empty. A cache directory you named yourself is never swept.
- This supersedes [jira-attachments-mcp](https://github.com/YusufKaracSimply/jira-attachments-mcp).
  Everything that server did is here: five tools keep their names, `download_by_jql` became
  `download_attachments_by_jql` and `jira_whoami` became `whoami`. Running both registers
  those five twice, so the installer offers to remove the old one, and the first run moves
  its download cache over.
- Uninstall with `claude mcp remove jira-worktrack --scope user`.

Maintenance

ActivitySlowing
ResponsivenessNo issues