Skip to main content
Glama
README.md
# jira-mcp-ai

An [MCP](https://modelcontextprotocol.io) server for **Jira Cloud**: it gives an
MCP-capable agent (Claude Code, Claude Desktop, or any other client) tools to
search, read and — behind an explicit gate — write Jira issues, using your own
Atlassian account and API token.

Two things shape the design:

- **Writes are gated.** Write tools default to describing what they *would* do
  instead of doing it. Executing requires both an opt-in configuration and an
  explicit flag on the call. See [`docs/THREAT-MODEL.md`](docs/THREAT-MODEL.md).
- **Jira content is untrusted input.** Issue text arrives from whoever filed the
  ticket. It is labelled as data, never merged into the agent's instructions.

> **Status: published, pre-1.0.** The specification in [`docs/`](docs/README.md)
> is normative and the code ships with it; drift is a bug. `jira-mcp-ai` is on
> npm with provenance, so the registration example below resolves as written.
> The version stays below 1.0.0 because 12 of the 52 tools have not yet been run
> against a real Jira site — see [the roadmap](docs/IMPLEMENTATION-PLAN.md) and
> [`CHANGELOG.md`](CHANGELOG.md).

## Requirements

- Node.js ≥ 22 (env files are read with `process.loadEnvFile()`, not dotenv)
- A Jira Cloud site and an Atlassian API token

## Registration

Put this in `.mcp.json` (project scope), or paste the inner `"jira"` object
into `claude mcp add-json jira '<object>'` — `claude mcp add` takes CLI
arguments, not JSON.

```json
{
  "mcpServers": {
    "jira": {
      "command": "npx",
      "args": ["-y", "jira-mcp-ai@0.9.4"],
      "env": {
        "JIRA_SITE": "mycompany",
        "JIRA_EMAIL": "me@example.com",
        "JIRA_API_TOKEN": "<api-token>",
        "JIRA_WRITE_MODE": "plan"
      }
    }
  }
}
```

The version is pinned on purpose: an unpinned `npx -y` re-resolves to whatever is
newest at spawn time, so a fresh publish could start running new code inside an
agent session with no review step. Bump the pin once you have read the changelog.

Before wiring the server into a client, run
`npx -y jira-mcp-ai@0.9.4 doctor` with the same environment variables set: it
runs the configuration and credential probes from a plain terminal and prints a
report — the fastest way to learn whether the site, email and token actually
work. `--help` and `--version` are also available.

**If the server does not appear, it is almost always PATH.** Claude Desktop
launches MCP servers from a minimal environment that does not include your
shell's PATH, so a `node`/`npx` installed by nvm, Homebrew or fnm is invisible to
it and the launch fails inside the client, before this server runs — you get the
client's generic "server failed" message and nothing on this server's stderr,
because there was no process. Fix it by giving an absolute path:
`"command": "/usr/local/bin/npx"` (`which npx` prints yours). Claude Code, run
from a terminal, inherits your PATH and is not affected.

Every diagnostic this server writes goes to **stderr**, never stdout — stdout is
the MCP protocol. Claude Code keeps it in `~/.claude/logs/`; Claude Desktop in
`~/Library/Logs/Claude/mcp*.log` (macOS) or `%APPDATA%\Claude\logs\` (Windows).
That is where the startup report and any `JIRA_*` configuration error will be.

## Configuration

Every setting is an environment variable with the `JIRA_` prefix. The full table
— names, defaults, required-ness, and where credentials may live — is in
[`docs/CONFIGURATION.md`](docs/CONFIGURATION.md); [`.env.example`](.env.example)
is a fill-in-the-blanks copy.

## Tools

<!-- GENERATED:TOOLS:START -->

<!-- Generated by scripts/generate-readme.mjs from the tool manifest.
     Do not edit by hand — run `npm run readme`. -->

52 tools in 10 packages, 25 of them write tools
behind the plan/apply gate. `JIRA_TOOL_PACKAGES`, `JIRA_PACKAGES_DENY` and
`JIRA_PACKAGES_READONLY` decide which of them a session actually sees; the
`core` package is always registered. Full input and output shapes are in
[`docs/TOOLS.md`](docs/TOOLS.md).

### Core — `core`

Server self-description and credential check — always registered, even when every other package is denied.

| Tool | Title | Access | What it does |
| --- | --- | --- | --- |
| `jira_capabilities` | Describe this server | read-only | Describe this server without calling Jira: the packages and tools that are registered, the site, the active profile, the write mode (plan vs apply) and the per-call limits. |
| `jira_get_myself` | Get authenticated user | read-only | Verify the configured credentials and return the account they belong to: accountId, displayName, active, accountType, timeZone and locale. |

### Search — `search`

JQL search over issues, approximate result counts, and the saved filters that store reusable JQL — one page per call.

| Tool | Title | Access | What it does |
| --- | --- | --- | --- |
| `jira_search` | Search issues | read-only | Run JQL and return ONE page of issues plus data.nextPageToken — pass it back to read the next page. There is no total; use jira_count. |
| `jira_count` | Count issues | read-only | Count the issues a JQL matches without fetching any of them. |
| `jira_list_filters` | List saved filters | read-only | Finds saved filters — named, stored JQL — by name substring or owner, and returns each one with its jql. |
| `jira_get_filter` | Get saved filter | read-only | Reads one saved filter by numeric id (from jira_list_filters): name, description, owner, the JQL it stores and whether you favourited it. |

### Issues (read) — `issues`

One issue and its comments, available transitions, change history and worklogs — reads only; the matching writes live in issues-write.

| Tool | Title | Access | What it does |
| --- | --- | --- | --- |
| `jira_get_issue` | Get issue | read-only | Read one Jira issue by key or id. Name the fields you need — omitting fields returns Jira's whole navigable set and burns the result budget. |
| `jira_get_comments` | Get comments | read-only | List the comments on an issue, newest first by default (orderBy -created; Jira's own default is oldest first). |
| `jira_get_transitions` | Get transitions | read-only | List the workflow transitions available from this issue's CURRENT status: id, name and target status. |
| `jira_get_changelog` | Get changelog | read-only | Read an issue's change history — field, from → to, author, created. |
| `jira_get_worklogs` | Get worklogs | read-only | List the work logged on an issue: timeSpentSeconds, timeSpent, started, author and the flattened comment. Sum timeSpentSeconds rather than parsing timeSpent strings. |

### Issues (write) — `issues-write`

Issue changes: creation, fields, workflow transitions, comments and comment edits, assignee, worklogs and links — every tool is plan-gated.

| Tool | Title | Access | What it does |
| --- | --- | --- | --- |
| `jira_create_issue` | Create issue | write · standard | Create one issue. project and issueType are instance-specific — resolve them with jira_list_projects and jira_get_create_meta, which also names the custom fields this project requires. |
| `jira_update_issue` | Update issue | write · standard | Update fields on one issue. REPLACE semantics: description (text or ADF) replaces the WHOLE rich-text field, so tables and panels in the old value are lost — never "append" a paragraph this way. |
| `jira_transition_issue` | Transition issue | write · standard | Move one issue through its workflow. |
| `jira_add_comment` | Add comment | write · standard | Add a comment to one issue. body takes plain text (converted to ADF) or a raw ADF document; format: "markdown" parses a string body as the markdown subset. |
| `jira_update_comment` | Update comment | write · standard | Edit one existing comment. |
| `jira_assign_issue` | Assign issue | write · standard | Set or clear the assignee of one issue. Pass exactly one of accountId (assign) or unassign: true (clear) — both together is rejected as ambiguous, neither is rejected as intentless. |
| `jira_add_worklog` | Add worklog | write · standard | Log work against one issue. Pass exactly one of timeSpentSeconds (preferred) or timeSpent ("2h 30m"). |
| `jira_link_issues` | Link issues | write · standard | Link two issues. linkType is the link type NAME ("Blocks", "Relates"), and those names are instance-specific — read them from jira_list_link_types and spell them exactly. |

### Issues (delete) — `issues-delete`

Irreversible deletions: an issue, a comment, a worklog entry. Every tool is plan-gated AND needs JIRA_ALLOW_IRREVERSIBLE; every plan shows what would be destroyed.

| Tool | Title | Access | What it does |
| --- | --- | --- | --- |
| `jira_delete_issue` | Delete issue | write · irreversible | Permanently delete one issue. IRREVERSIBLE: Jira has no undo and no trash for this, the issue and its comments, worklogs and attachments are gone. |
| `jira_delete_comment` | Delete comment | write · irreversible | Permanently delete one comment from an issue. IRREVERSIBLE: the comment is not recoverable and the deletion is not recorded in the issue changelog. |
| `jira_delete_worklog` | Delete worklog | write · irreversible | Permanently delete one worklog entry from an issue. IRREVERSIBLE: the logged time is gone and Jira gives it back to the remaining estimate (its default adjustment). |

### Attachments — `attachments`

Files on issues: list what is attached, download one into the server's media directory, and attach a file from it. The two byte-moving tools need JIRA_MEDIA_DIR and never touch anything outside it.

| Tool | Title | Access | What it does |
| --- | --- | --- | --- |
| `jira_list_attachments` | List attachments | read-only | Lists the files attached to one issue: id, filename, size in bytes, mime type, author and creation time. Metadata only — no bytes are transferred and no local directory is needed. |
| `jira_download_attachment` | Download attachment | read-only | Downloads one attachment INTO THIS SERVER'S media directory and returns the local path — the bytes never pass through the conversation. |
| `jira_upload_attachment` | Upload attachment | write · standard | Attaches a file from this server's media directory to an issue. |

### Watchers, votes & project setup — `collab`

The surface around an issue: who watches it, who voted for it, and the components and versions a project files work under — including cutting a release. Reversible writes only; nothing here deletes anything.

| Tool | Title | Access | What it does |
| --- | --- | --- | --- |
| `jira_list_watchers` | List watchers | read-only | Lists the accounts watching an issue, with the watch count and whether this server's own account is among them. |
| `jira_add_watcher` | Add watcher | write · standard | Makes an account watch an issue, so Jira notifies it of every change. Adding an account that already watches changes nothing. |
| `jira_remove_watcher` | Remove watcher | write · standard | Stops an account watching an issue — it no longer gets notifications. Nothing is deleted: the watch is a link, jira_add_watcher puts it back with the same accountId, and no issue content changes. |
| `jira_add_vote` | Vote for issue | write · standard | Casts THIS SERVER'S OWN vote for an issue. There is no way to vote on behalf of another account — the endpoint takes no accountId — so a request to record someone else's vote cannot be honoured. |
| `jira_remove_vote` | Withdraw vote | write · standard | Withdraws THIS SERVER'S OWN vote from an issue; other people's votes are untouched and unreachable. Nothing is deleted beyond the vote itself, and jira_add_vote casts it again. |
| `jira_list_components` | List components | read-only | Lists a project's components — the sub-areas an issue's `components` field points at — with their id, name, description, lead and default assignee rule. |
| `jira_create_component` | Create component | write · standard | Creates a component in a project — a sub-area issues can be filed under. Takes the project KEY (jira_create_version takes a numeric id instead; that asymmetry is Jira's). |
| `jira_update_component` | Update component | write · standard | Changes a component. This is a PARTIAL update, unlike jira_update_issue: only the fields you pass are changed and everything you omit keeps its current value. |
| `jira_list_versions` | List versions | read-only | Lists a project's versions (releases) — the values an issue's fixVersions and affectedVersions fields point at — with their id, name, dates and whether they are released or archived. |
| `jira_create_version` | Create version | write · standard | Creates a version (a release) in a project — a value issues can then use in fixVersions. Takes the NUMERIC projectId, not the key (jira_create_component takes a key; the asymmetry is Jira's). |
| `jira_update_version` | Update version | write · standard | Changes a version — this is how a release is cut (released: true) and how it is un-cut (released: false). |
| `jira_list_project_roles` | List project roles | read-only | Lists a project's roles (Administrators, Developers, …) with their ids, and — when you pass a roleId — the accounts and groups in that one role. |

### Metadata & discovery — `meta`

Projects, fields, create metadata, statuses and link types — the reads that turn names into the ids every other package needs.

| Tool | Title | Access | What it does |
| --- | --- | --- | --- |
| `jira_list_projects` | List projects | read-only | Lists the Jira projects you can see — id, key, name, project type and lead. This is how a project NAME becomes the KEY every other tool wants. |
| `jira_get_project` | Get project | read-only | Reads one project in detail: description, lead, issue types, components and versions — what you need before creating an issue, because issue type ids and component/version names are per-project. |
| `jira_list_fields` | List fields | read-only | THE discovery tool for field ids: every field with id, name, schema type and the custom flag, so "Story Points" resolves to customfield_10016 and back. |
| `jira_get_create_meta` | Get create metadata | read-only | Reads what jira_create_issue accepts for a project. |
| `jira_list_statuses` | List statuses | read-only | Lists workflow statuses — id, name, category and scope — so JQL like status = "In Review" names a status that really exists on this site. |
| `jira_list_link_types` | List issue link types | read-only | Lists the issue link types configured on this site with their inward and outward phrases (for example "blocks" / "is blocked by"). |

### User lookup — `users`

Finding people by name or email — the one path from a human name to the accountId every other tool requires.

| Tool | Title | Access | What it does |
| --- | --- | --- | --- |
| `jira_search_users` | Search users | read-only | Finds Jira users by display name or email and returns their accountId — the id every other tool takes, since Cloud has no usernames. |

### Boards & sprints — `agile`

Jira Software boards, sprints and their issues, the two moves (into a sprint, out to the backlog) and the sprint lifecycle — the only tools that speak the Agile API rather than the platform one.

| Tool | Title | Access | What it does |
| --- | --- | --- | --- |
| `jira_list_boards` | List boards | read-only | Lists the Jira Software boards you can see — id, name, type and the project each belongs to. The board id is what jira_list_sprints takes, so this is the first call of any sprint workflow. |
| `jira_list_sprints` | List sprints | read-only | Lists a board's sprints with their id, name, state, goal and dates. Filter with state ("active" for the sprint in flight, "future" for the ones planned). |
| `jira_get_sprint_issues` | Get sprint issues | read-only | Lists the issues in one sprint, flattened exactly like jira_search: rich text as plain text, users as accountId + displayName. |
| `jira_move_to_sprint` | Move issues to sprint | write · standard | Moves up to 50 issues into a sprint — the only way to set a sprint, which is not an editable field on jira_update_issue. |
| `jira_move_to_backlog` | Move issues to backlog | write · standard | Sends up to 50 issues back to the backlog — Jira defines it as "remove the future and active sprints from these issues", so it is the inverse of jira_move_to_sprint and the only way to clear a sprint… |
| `jira_create_sprint` | Create sprint | write · standard | Creates a sprint on a Scrum board and returns its id. The sprint is created in the "future" state — this does NOT start it, jira_start_sprint does, and only a started sprint is the work in flight. |
| `jira_start_sprint` | Start sprint | write · standard | Starts a sprint: "future" becomes "active", which is what makes its issues the work in flight and what every board report measures from. |
| `jira_close_sprint` | Close sprint | write · standard | Completes the active sprint. |

<!-- GENERATED:TOOLS:END -->

## Data handling

What leaves your machine, what is written to disk, what is redacted from logs,
and what the write gate does and does not promise are documented in
[`docs/THREAT-MODEL.md`](docs/THREAT-MODEL.md). Credential storage and lifecycle
are in [`docs/AUTH.md`](docs/AUTH.md).

To report a vulnerability, see [`SECURITY.md`](SECURITY.md).

## Development

```sh
npm install
npm run check   # typecheck, lint, format, build, tarball, test, docs-lint, prod audit
```

[`CONTRIBUTING.md`](CONTRIBUTING.md) is the contributor entry point: the
`npm run check` gate, the rules a PR cannot break, and how to point the server
at a real Jira site without endangering anyone's tenant.
[`docs/README.md`](docs/README.md) is the index to the specification and
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) is the place to start; the test
taxonomy and the coverage gate are in [`docs/TESTING.md`](docs/TESTING.md).
Participation is governed by the [Code of Conduct](CODE_OF_CONDUCT.md).

## License

[MIT](LICENSE).

Jira and Atlassian are trademarks of Atlassian Pty Ltd. This project is an
independent, unofficial client and is not affiliated with or endorsed by
Atlassian.

TDQS

A4.1/5.0

Scored across 52 tools

Disambiguation5/5

Every tool maps to a distinct resource/action pair, and the verbose descriptions actively disambiguate near-neighbors: jira_get_sprint_issues is scoped by sprint, jira_search by JQL, and jira_get_create_meta is separated from jira_list_fields by focusing on the create screen. Overlap exists only where Jira itself exposes similar concepts, and the descriptions handle it.

Naming Consistency4/5

All 52 tools use the jira_ prefix and snake_case, and most follow a clear verb_noun pattern: get_issue, list_sprnts, create_component, delete_worklog. The exceptions—jira_search, jira_count, and jira_capabilities—deviate slightly from that pattern, but the overall convention is highly predictable.

Tool Count1/5

52 tools is an extreme surface for one MCP server, crossing the rubric's 50+ threshold. Even though Jira is a broad domain, the sheer number of resource/action pairs makes selection heavy and increases the chance of mispicks.

Completeness4/5

The core issue lifecycle is well covered: create, get, update, delete, transition, assign, link, comments, worklogs, attachments, watchers, votes, and sprint management. Gaps like no component/version delete, no filter create/update/delete, and no worklog update are present but mostly affect secondary workflow edges rather than blocking primary use.

Maintenance

ActivityMaintained
ResponsivenessNo issues