jira-mcp-ai pre-1.0
Model Context Protocol server

jira-mcp-ai

Give your AI assistant a real seat in Jira Cloud — JQL search, issue reads, transitions, comments, worklogs, boards and sprints. It runs on your machine, with your API token, fenced to a single host, and every write is disarmed until you say otherwise.

TypeScript MIT Node 22+ Jira Cloud REST v3 58 tools · 10 packages pre-1.0 · on npm
58tools in 10 packages
28 / 30read tools / write tools
1host the process may reach
0telemetry calls, by design

Status, honestly. The surface is complete and green offline: all 58 tools, the write gate, the error catalog and the corner cases are implemented against the spec in docs/, which stays normative — 1,700+ hermetic tests behind a network fence, with layering, coverage floors and docs consistency enforced in CI. The package is on npm as jira-mcp-ai, and two runs against a real Atlassian tenant have proven 40 of the 58 tools live. The 18 still unproven — 17 writes and the bulk queue-status read — are why the version stays below 1.0.0.

Install

Three steps

No developer app, no consent screen, no App Review — a Jira Cloud site and an API token are the whole setup; OAuth 2.0 is an opt-in, never a requirement. Node 22 or newer.

On npm as jira-mcp-ai@0.9.4, and pre-1.0 on purpose. The surface is complete, the offline gate is green, and the build has now been run against a real Atlassian tenant — 40 of the 58 tools have been proven live, and the three bugs that run found are fixed in this version. Of the 18 still unproven, most need a permission nobody has pointed at it yet — project administrator for the older ones, the site-wide Make bulk changes for the three bulk tools that landed after that run — so the number stays below 1.0.0 until they are covered too. The registration below resolves as written; it installs the published package, provenance and all.

Mint an API token

In your Atlassian profile under Security → API tokens. The token inherits exactly your permissions — nothing more. Cloud tokens expire (a year at most), so note the date: set JIRA_TOKEN_EXPIRES and the server warns you 30 days ahead instead of failing cold one morning.

Register the server

.mcp.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 deliberately: an unpinned npx -y jira-mcp-ai re-resolves to whatever is newest at spawn time, which lets a published package start running new code inside an agent session with no review step. Bump the pin when you have read the changelog. Prefer keeping the token out of project files — the server also loads ~/.config/jira-mcp-ai/.env via Node's own process.loadEnvFile(); there is no dotenv in the chain, because dotenv ≥ 17 prints a banner to stdout, and stdout belongs to the MCP protocol.

Stay read-only until you mean it

Out of the box every write describes instead of executing. Narrow the surface further, or open the gate, with three variables:

env
JIRA_WRITE_MODE=plan       # default — writes return a plan, nothing executes
JIRA_TOOL_PACKAGES=reader  # reads only — write tools are never registered
JIRA_WRITE_MODE=apply      # writes execute, when a call also passes apply:true
JIRA_ALLOW_IRREVERSIBLE=true # and only this adds the deletes and bulk writes; apply alone never does
Capabilities

Ten packages, 58 tools

Packages are the unit of exposure: JIRA_TOOL_PACKAGES picks a profile (core, reader, all — the default) or an explicit list, JIRA_PACKAGES_DENY removes one regardless, and JIRA_PACKAGES_READONLY keeps a package's reads while dropping its writes. core is always on.

Package Tools Write mode What it covers
core 2 read — jira_capabilities self-describes the running surface; jira_get_myself verifies auth. Always registered — even a deny list cannot remove it.
search 4 read — JQL search and approximate count over the current /rest/api/3/search/jql endpoint — the legacy search API Atlassian removed in 2025 is never called — plus the saved-filter reads that turn a filter into the JQL behind it.
issues 6 read — One issue with ADF flattened to plain text (raw on request), comments, transitions, changelog, worklogs, and the status of a queued bulk operation.
issues-write 8 write plan Create, update, transition, comment, edit a comment, assign, log work, link — every one behind the plan → apply gate.
issues-delete 8 irreversible plan + opt-in Delete an issue, a comment, a worklog, a component, a version or a sprint — or bulk-edit and bulk-delete up to 1,000 issues at once. The one package that is not covered by JIRA_WRITE_MODE=apply alone — it also needs JIRA_ALLOW_IRREVERSIBLE=true, set on purpose.
attachments 2 read 1 write plan List, download and upload attachments. Bytes only ever cross the boundary through JIRA_MEDIA_DIR; with no directory set the binary tools refuse, and file contents never enter a tool result.
collab 4 read 8 write plan Watchers, votes, components, versions and project roles — the project-shaping surface around an issue rather than the issue itself.
meta 6 read — Projects, fields, create-meta, statuses and link types — the discovery calls that make writes land on the first try.
users 1 read — User search: the only path from a human name to the accountId every other tool requires. Emails stay hidden unless you opt in.
agile 3 read 5 write plan Boards, sprints and sprint issues; the writes move issues into a sprint or the backlog and create, start and close a sprint. The one package that speaks the Agile API rather than the platform one.

What it deliberately does not do

No deleting a project, no admin surface, no free-form bulk — the bulk delete and bulk edit are two fixed tools inside the irreversible tier — excluded by decision, not by omission. No Confluence, no Jira Service Management, no Data Center. A tool that does not exist cannot be talked into running.

Built for 2026 Jira

v3 REST only: ADF documents in, readable plain text out. Users are addressed exclusively by accountId — the GDPR-era contract. Search paginates by nextPageToken, and jira_count returns Jira's approximate count and labels it as such instead of pretending it is exact.

The full 55-tool catalog — input schemas, hints and the error contract per tool — lives in docs/TOOLS.md.

Safety

A write model you can reason about

Every tool declares a tier. The tier — not the tool, and not the model's confidence — decides what has to happen before your Jira site is touched.

read

28 tools

Never mutates anything. Safe to expose first, and to leave on.

standard

22 tools

Every reversible write. Governed by JIRA_WRITE_MODE: under plan — the default — the tool returns exactly what it would have sent and performs zero network mutations; under apply it executes, and only when the call itself also opts in.

irreversible

8 tools

Deleting an issue, a comment, a worklog, a component, a version or a sprint, and bulk-editing or bulk-deleting up to 1,000 issues at once. These need a second, separate switch — JIRA_ALLOW_IRREVERSIBLE=true — on top of everything the standard tier already requires, because an operator who turned writes on to move a ticket did not thereby agree to lose one.

The plan → apply contract

In plan mode a write returns the method, path and redacted body it would have sent, plus a single-use plan_id — and its first line is, literally, NOT performed — plan mode. Executing the same call requires all three: the server started with JIRA_WRITE_MODE=apply, the call passing apply: true, and a plan_id minted for identical arguments — change one field and the fingerprint no longer matches.

Plans live in memory only. A restart voids them; nothing can be armed in advance and fired later.

Ambiguous failures never replay

When a timeout or a dropped socket makes it unknowable whether a write reached Jira, the server refuses to guess: the call fails as ambiguous_write, marked non-retryable, with the remediation to read current state first. A comment posted twice is a mess a human cleans up — this server would rather fail honestly than tidy over it.

Defence in depth

  • One host, and no others. The HTTP layer refuses any request that resolves outside your site — including redirects that try to leave it. Extra hosts need an explicit allowlist entry: exact name or anchored regex, never a suffix match.
  • No telemetry, no phone-home. The only outbound traffic is the Jira call you asked for.
  • Secrets never surface. The API token is registered with a redactor at startup; one choke point scrubs logs, errors and results, and Authorization header echoes are stripped.
  • Jira text is data, not instructions. Every content-bearing read comes back inside ⟦BEGIN UNTRUSTED CONTENT⟧ … ⟦END UNTRUSTED CONTENT⟧ markers, so a ticket that says "ignore your instructions" reads as a ticket, not as instructions.
  • stdout belongs to the protocol. Diagnostics go to stderr through a structured logger, and a stray console.log is redirected before it can corrupt a JSON-RPC frame.
  • Writes can be journalled. Set JIRA_JOURNAL_PATH for an append-only JSONL record of every write call: tool, argument hash, result, timestamp.
  • Attachment bytes stay out of the conversation. Downloads and uploads pass through JIRA_MEDIA_DIR and nowhere else; with no directory configured the binary tools refuse, and a file's contents never land in a tool result.
  • The HTTP transport binds loopback only. stdio is the default; selecting http binds 127.0.0.1 only, demands a bearer token on every request and refuses to start without one — no other interface is ever listened on.
your-site.atlassian.net

That pill is the entire default egress surface — one origin, resolved once at startup.

Architecture

Four layers, one direction

Imports point leftward only — core ← api ← mcp ← tools — and the rule is enforced twice in eslint, as import zones and as string patterns, so it never depends on how modules happen to resolve.

tools One file per package exporting its tool specs; thin glue from validated input to API call to shaped result.
mcp Protocol plumbing: defineTool with import-time assertions, the registry, the result envelope, taint marking, the write gate, transports.
api Typed wrappers over Jira REST, one module per domain — search, filters, issues, meta, users, collab, attachments, agile. ADF flattening lives here.
core Config, host resolution, errors, redaction, logging, clock — and the HTTP client, the only module in the repository allowed to touch the network.

Typed without codegen

Atlassian's OpenAPI spec is enormous, churns constantly, and knows nothing about your customfield_10xxx. So no generated optimism: wire data enters as unknown, is narrowed by minimal hand-written guards at the API boundary, and a guard failure surfaces as a typed error naming the unexpected shape — never a TypeError five frames deep.

Deterministic by injection

Time comes from an injected clock, retry jitter from an injected RNG, and fetch is read off globalThis at call time. Backoff sequences are asserted exactly in tests, and a network fence turns any accidental real socket into a test failure.

Configuration

Credentials and environment

Headless by design: Basic auth with your Atlassian account email and an API token, nothing to click through — it works from cron, CI and remote boxes, which is the main reason this exists next to Atlassian's official remote MCP server. OAuth 2.0 (3LO) is there as an opt-in for the accounts that need it: one browser login, then the server refreshes on its own.

Variable Required What it does
JIRA_SITE yes "mycompany", "mycompany.atlassian.net" or a full URL — resolved once into the single origin the allowlist then pins.
JIRA_EMAIL yes Atlassian account email for Basic auth.
JIRA_API_TOKEN yes Secret. Registered with the redactor before anything else gets a chance to log it.
JIRA_TOKEN_EXPIRES no ISO date of the token's expiry — Cloud tokens live a year at most. When set, startup and doctor warn 30 days out.
JIRA_ALLOWED_HOSTS no Extra allowed hosts for Server/DC or vanity domains: exact host or anchored regex. Suffix matching is banned.
The full environment surface
Variable Default Description
JIRA_ENV_FILE — Explicit env-file path; wins over ~/.config/jira-mcp-ai/.env and the project-local .env.
JIRA_SITE — Site name, host or URL. Required.
JIRA_EMAIL — Account email for Basic auth. Required.
JIRA_API_TOKEN — Secret. API token. Required.
JIRA_TOKEN_EXPIRES — ISO expiry date; warning 30 days out when set.
JIRA_ALLOWED_HOSTS — Comma list of extra allowed hosts — exact or anchored regex.
JIRA_PROFILE_<NAME>_SITE / _EMAIL / _API_TOKEN — Named profile credentials for multi-site setups.
JIRA_ACTIVE_PROFILE — Profile used when a call does not name one.
JIRA_LOCK_PROFILE true Per-call profile switching is rejected by default — a model that can pick the tenant per call can leak issue text across tenants, so unlocking is a deliberate act.
JIRA_TOOL_PACKAGES all Profile (core, reader, all) or explicit comma list of packages.
JIRA_PACKAGES_DENY — Deny list; wins over selection; core is force-re-added.
JIRA_PACKAGES_READONLY — Packages whose write-tier tools are dropped; reads stay.
JIRA_WRITE_MODE plan plan = writes describe instead of execute; apply = writes execute when the call passes apply: true.
JIRA_ALLOW_IRREVERSIBLE false Opt-in for the irreversible tier. Without it the deletes and the bulk writes refuse even under apply — blanket write mode never covers them.
JIRA_REQUEST_TIMEOUT_MS 30000 Per-request timeout.
JIRA_CALL_BUDGET_MS 120000 Wall-clock budget for one tool call's total HTTP activity — retry waits and queueing count against it.
JIRA_HOST_CONCURRENCY 4 Per-host semaphore slots.
JIRA_RETRY_ATTEMPTS 3 Max retry attempts — for requests that are safe to retry. Ambiguous write outcomes are never replayed.
JIRA_MAX_RESULT_CHARS 25000 Truncation budget for tool results; whole items are dropped so output stays valid JSON.
JIRA_MAX_PAGES 20 Loop guard for paginated fetches.
JIRA_MEDIA_DIR — Directory attachment downloads land in and uploads are read from. Unset, the binary attachment tools refuse; listing metadata needs no directory.
JIRA_TRANSPORT stdio stdio (default) or http — the loopback Streamable HTTP transport.
JIRA_HTTP_PORT 3334 Loopback port the http transport binds — 127.0.0.1 only, never another interface.
JIRA_HTTP_TOKEN — Secret. Bearer token required on every http request; without it the server refuses to start.
JIRA_LOG_LEVEL info Stderr log verbosity: debug, info, warn, error.
JIRA_JOURNAL_PATH — Optional write journal — JSONL of every write tool call: tool, argument hash, result, timestamp.

The defaults are chosen so that an environment holding nothing beyond the three credentials is already a sensible posture: every package registered, every write disarmed, exactly one host reachable. The normative table, with validation ranges and edge cases, is docs/CONFIGURATION.md.

Roadmap

Where it stands

The spec was written first, reviewed, and revised before serious code — so the phases below are gates with exit criteria, not vibes. All eight are closed, and the package is on npm. What is left before 1.0.0 is mostly not code either: one more gate run for the sprint tools, and a Jira site where the test account may administer a project for the rest.

Phase Status Exit gate
0 · Scaffold done Repo furniture, the full docs corpus and the initial core/api skeleton committed.
0.5 · Spec revision done External review-panel findings folded back into the spec; both exit gates met on the spec side.
1 · Core done Config, host pinning, errors, redaction, logging and the one HTTP module; wire-tier policy tests green.
2a · MCP layer + search done defineTool, the registry, the result envelope, taint marking — and JQL search over the current endpoint.
2b · ADF + issue read done Issue reads with ADF flattening proven against recorded fixtures.
3 · Full read surface done Every read tool implemented; coverage floors enforced by the gate from here on.
4 · Writes done The plan → apply gate proven in both modes, plan fingerprinting, the optional write journal.
5 · Hardening & release prep done Every corner case traceable to a named test; the publish pipeline built and left inert by construction.
6 · v1.5 pulled forward done Markdown ↔ ADF, the agile write surface, saved filters, comment editing.
7 · v2 subset pulled forward done Attachments, the collaboration surface, and the irreversible tier with its own opt-in.
Hardening waves 8–13 done Adversarial passes over the shipped tarball rather than the source, release mechanics, and a live-verification driver rehearsed offline.
Live verification · read half done First contact with a real Atlassian tenant, 2026-08-17. Every one of the 27 read tools proven against the live API, and three bugs found that no fixture could have produced — all three fixed in 0.9.4.
Live verification · write half partial Run 2026-08-18 against a sandbox project: 13 write tools applied successfully, taking the live-proven surface to 40 — of today's 55 tools. Seven of the writes still unproven wait on permissions the test account does not hold — both watcher writes, both version writes, both component writes and issue delete, each answering with a correctly shaped refusal rather than a result. Five are the sprint writes, which the run never reached: the gate asked Jira for a sprint name past a length cap Atlassian does not document — that was the harness, not the server, and it is fixed here. The last three, the component, version and sprint deletes, landed after this run and have never been sent at all.
0.9.4 on npm done Published from a tag with provenance. Still on the one-run bootstrap token, because npm cannot register a trusted publisher for a package that does not exist yet and the switch has not been made.
1.0.0 on npm planned The 15 remaining tools proven — the sprint five on any site with a Scrum board, the seven permission-gated writes and the component and version deletes on a site where the account may administer a project, the sprint delete where it may manage sprints — and the semver promise made: from then on OIDC trusted publishing, no token in the repository.

The full plan, with per-phase exit gates and open decisions, is docs/IMPLEMENTATION-PLAN.md; the longer horizon — a Data Center adapter, parked until a real host exists — is docs/ROADMAP.md.

FAQ

Questions worth asking first

Is jira-mcp-ai affiliated with Atlassian?

No. This is an independent, community-built project and is not affiliated with, endorsed by, or sponsored by Atlassian Pty Ltd. Jira, Atlassian and related marks are trademarks of Atlassian Pty Ltd, used here only nominatively to indicate compatibility.

Why not Atlassian's official remote MCP server?

The official server is remote and OAuth-based: fine for interactive desktop use, unusable anywhere nobody can click through a browser consent screen. jira-mcp-ai is headless by default — Basic auth with your own API token, with OAuth 2.0 (3LO) as an opt-in for accounts that need it — so it runs from cron, CI and remote sessions, keeps all traffic between your machine and your Jira site, and adds a plan-and-apply write gate the official server does not have.

If a hosted service fits your setup, use the official one; this exists for everyone else.

Which credentials does it need?

Three environment variables: JIRA_SITE, JIRA_EMAIL and JIRA_API_TOKEN — the token is minted in your Atlassian profile under Security → API tokens and inherits exactly your permissions, nothing more. Jira Cloud tokens expire (a year at most); set JIRA_TOKEN_EXPIRES and the server warns you 30 days ahead instead of failing cold.

Is it safe to let an AI assistant write to my Jira site?

Writes ship disarmed. In the default plan mode a write tool returns the exact method, path and redacted body it would have sent, plus a single-use plan_id — its first line is, literally, NOT performed — plan mode. Executing requires all three: the server started with JIRA_WRITE_MODE=apply, the call passing apply: true, and a plan_id minted for identical arguments.

The irreversible tier — the six deletes (issue, comment, worklog, component, version, sprint) and the two bulk writes (delete, edit) — needs a fourth thing, JIRA_ALLOW_IRREVERSIBLE=true, because blanket write mode must never cover it. A write whose outcome is unknowable — a timeout mid-flight — is never retried: the server asks you to check state instead of guessing.

What actually works today?

The whole surface, offline. All 58 tools across 10 packages are implemented, along with the plan-and-apply write gate, the error catalog and the corner cases — the spec in docs/ stays normative and the code is checked against it by 1,700+ hermetic tests behind a network fence, with layering, coverage floors and docs consistency all enforced in CI.

And now online too, in part. Two runs against a real Atlassian tenant have proven 40 of the 58 tools against the live API — 27 of the 28 reads, and 13 of the 30 writes: issue create and update, comments and comment edit, worklogs, transitions, links, assignment, votes, attachment upload and the comment and worklog deletes. Of the 18 still unproven, seven need a project administrator — the watcher pair, the version pair, the component pair and issue delete — five are the sprint writes, which that run never reached because the gate itself asked Jira for an over-long sprint name, three are the component, version and sprint deletes, which landed after the last live run, and three are the bulk operations — bulk edit, bulk delete and the queue-status read — which landed after it too and additionally need the site-wide Make bulk changes permission. All 18 are implemented and tested offline; the sprint five need only another run, and the rest need a site where the account holds the permission.

Is it on npm?

Yes — jira-mcp-ai, currently 0.9.4. It is published from a git tag by GitHub Actions with provenance attestation, so the artifact on npm is verifiably built from this repository; npm audit signatures will say so.

The version is deliberately below 1.0.0 and will stay there until the live verification above is complete. Pin the exact version in your client configuration — the changelog is written for someone deciding whether to move that pin.

Which MCP clients does it work with?

Any client that speaks the Model Context Protocol — Claude Code, Claude Desktop, VS Code and Cursor among them. stdio is the default transport; a loopback-only Streamable HTTP transport can be selected instead, binding 127.0.0.1 only and requiring a bearer token on every request — without the token the server refuses to start.

How can I support the project?

jira-mcp-ai is MIT-licensed and free, with no paid tier. It is maintained by one person in their own time, so donations are welcome — see Support below. Donating buys no priority support and no SLA; starring the repository or filing a good bug report helps just as much.

Support

Free, MIT, and built in spare time

There is no paid tier and no hosted version. If this saves you an afternoon, a donation keeps the coffee flowing — but a star, a bug report or a fix helps just as much.

Found a bug?

Open an issue with what you asked the assistant to do, the tool call it made, and the ok: false envelope it returned — the error's kind and the hints answer most of the first round of questions.

Open an issue →

Found a security problem?

Please report it privately through GitHub's private vulnerability reporting rather than in a public issue — for a security problem, opening the issue is the disclosure. If that button is not there, email ivanbbaev@gmail.com with jira-mcp-ai security in the subject; both routes reach the same person.

Security policy →