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 27 tools · 7 packages pre-1.0 · not on npm yet
27tools in 7 packages
19 / 8read tools / write tools
1host the process may reach
0telemetry calls, by design

Status, honestly. This is a spec-first repository: the complete contract — all 27 tools, the write gate, the error catalog, the corner cases — is written down in docs/ and is normative. The core HTTP layer and the first typed API wrappers are implemented and covered by hermetic tests behind a network fence; the MCP layer and the tool surface are being built against that spec now. There is no tagged release and no npm package yet.

Install

Three steps, once it ships

No developer app, no OAuth consent screen, no App Review — a Jira Cloud site and an API token are the whole setup. Node 22 or newer.

Not on npm yet. jira-mcp-ai is pre-1.0 and unpublished. The registration below is the target contract the docs already guarantee — it will resolve as-is once the first release is tagged. Until then, watch the repository.

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.1.0"],
      "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 two 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
Capabilities

Seven packages, 27 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 2 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.
issues 5 read One issue with ADF flattened to plain text (raw on request), comments, transitions, changelog, worklogs.
issues-write 7 write plan Create, update, transition, comment, assign, log work, link — every one behind the plan → apply gate.
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 1 write plan Boards, sprints and sprint issues; moving issues into a sprint is the one write.

What it deliberately does not do

No deletes of any kind, no bulk operations, no attachment upload or download — 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 27-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

19 tools

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

standard

8 tools

Every write in v1. 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

0 tools

Empty on purpose. Deletes, bulk edits and attachments are excluded from v1 by decision — the tier exists so anything added later inherits rules that are already written down, instead of negotiating them in a pull request.

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.
  • The HTTP transport fails closed. It binds loopback only, refuses to start without JIRA_HTTP_TOKEN, and checks Origin against DNS rebinding. stdio stays the default.
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, issues, meta, users, 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. No browser OAuth dance, 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.

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_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_TRANSPORT stdio stdio or http.
JIRA_HTTP_PORT 3334 TCP port for the http transport; the bind host is fixed to loopback.
JIRA_HTTP_TOKEN Secret. Bearer token required by the http transport; it fails closed without it.
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. Two are done, two are moving, four are queued.

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 in progress First runnable artifact: wire-tier HTTP policy tests green; doctor exits 0 against a real site.
2a · MCP layer + search in progress First usable build: registered in Claude Code, a real JQL search end-to-end.
2b · ADF + issue read planned Issue reads with ADF flattening proven against recorded fixtures.
3 · Full read surface planned Every read tool green against a live scratch site; coverage thresholds enforced from here on.
4 · Writes planned The plan → apply gate proven end-to-end in both modes; write journal; the full 27-tool surface locked.
5 · Hardening & release planned npm publish via OIDC trusted publishing with provenance; corner cases traceable to tests.

The full plan, with per-phase exit gates and open decisions, is docs/IMPLEMENTATION-PLAN.md; the longer horizon 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 — Basic auth with your own API token — 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 OAuth and a hosted service fit 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.

v1 has no delete, bulk or attachment tools at all, and 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?

This is a spec-first repository. The complete contract — all 27 tools, the write gate, the error catalog, the corner cases — is written down in docs/ and is normative. The core HTTP layer and the first typed API wrappers are implemented and covered by hermetic tests behind a network fence; the MCP layer and the tool surface are being built against that spec now.

There is no tagged release and no npm package yet.

When will it be published to npm?

In the release phase, after the full read surface and the write gate have been proven against a real Jira site. Publication is planned through npm trusted publishing (OIDC) with provenance attestation, so the artifact on npm is verifiably built from this repository. Until then there is nothing to install — watch the repository instead.

Which MCP clients will it work with?

Any client that speaks the Model Context Protocol over stdio — Claude Code, Claude Desktop, VS Code and Cursor among them. An optional loopback-only Streamable HTTP transport is specified for advanced setups; it binds 127.0.0.1 only and refuses to start without a bearer token.

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.

Security policy →