jira-cli
Agent-first CLI for legacy Jira Server 8.13.5. Rust, single binary, no daemon, TOML config.
Targets Jira Server/DC 8.13.5 specifically — no Cloud, no PAT (PAT ships 8.14+). Uses Basic Auth or cookie session (/rest/auth/1/session).
Why
Modern Jira CLIs assume Cloud or newer Server versions. For teams stuck on 8.13.5, options are thin. This tool:
- Speaks Jira 8.13.5's native REST v2 + Agile 1.0 exactly
- JSON/JSONL output by default (agent-friendly, no HTML table noise)
- Typed errors with stable exit codes + actionable
hint field
schema self-introspection so agents can discover the CLI
- Field aliases + renames for messy customfield landscapes
- TOML config with defaults, JQL aliases, per-command field projections
Why a CLI and not an MCP server?
A Jira MCP server and jira-cli cover the same ground from an agent's perspective. We went CLI because of process model economics:
- MCP = long-lived daemon. Every concurrent Claude Code / agent session spawns its own MCP child process and keeps it resident. A typical Node or Python MCP stays 30–80 MiB RSS idle per instance. Five agent sessions on one laptop → 150–400 MiB just holding idle connections. IPC buffers, language runtime, cached TLS context — none of it freeable while the session lives.
- CLI = fork-exec, short-lived.
jira-cli uses memory only during the invocation. Peak ~4 MiB per call (see benchmarks), freed on exit. A burst of 20 concurrent calls peaks under 100 MiB total and returns to zero when the work's done.
- Startup cost is negligible for the usage pattern. Agents run a jira command, read the JSON, move on — not a tight inner loop where 10–20 ms cold start would matter. Wall-clock on real Jira is dominated by ~450 ms of network RTT regardless of tool.
- Composable by default. Pipe into
jq, feed into xargs, redirect to file, run in CI — nothing special. An MCP needs a bespoke client per consumer.
- Zero protocol lock-in. Jira-ccli speaks JSON-over-stdout; any agent runtime (Claude Code, Codex, Copilot CLI, a shell script) can use it. MCP requires the host to implement the MCP protocol.
- Observable.
-vv gives structured tracing; time -l measures usage; binaries signed and checksummed. Debugging an MCP means debugging its host's protocol stack.
When an MCP would make more sense: when you need persistent state across calls (cached auth tokens with refresh logic, streaming subscriptions to Jira webhooks, multi-step workflows with inter-call coordination). None of those apply to the workflows we target.
For the rare case where an agent really wants structured tool semantics instead of shelling out, the schema command + stable JSON contract make a thin MCP wrapper around this binary trivial (~50 lines of code) — without baking one into the distribution.
Install
Homebrew (macOS + Linux)
brew install zhiyue/tap/jira-cli
The tap-qualified name is required because homebrew-core already ships a different tool named jira-cli (the Go one by ankitpokhrel); a plain brew install jira-cli would fetch that instead. You can also tap first if you prefer:
brew tap zhiyue/tap
brew install zhiyue/tap/jira-cli
Upgrade / uninstall:
brew upgrade zhiyue/tap/jira-cli
brew uninstall zhiyue/tap/jira-cli
Install script (macOS + Linux)
curl -sSL https://raw.githubusercontent.com/zhiyue/jira-cli/main/install.sh | sh
Options: install.sh -v v0.1.0, -d /usr/local/bin, -b https://internal-mirror.example.com/....
Install script (Windows PowerShell)
iwr -useb https://raw.githubusercontent.com/zhiyue/jira-cli/main/install.ps1 | iex
cargo install (any platform with Rust ≥ 1.88)
cargo install --git https://github.com/zhiyue/jira-cli --locked
Manual
Download the tarball for your platform from the Releases page, extract, put jira-cli on your PATH.
Quickstart
# one-time
jira-cli config init \
--url https://jira.internal.example.com \
--user alice \
--password "$JIRA_PASSWORD"
jira-cli ping
jira-cli whoami
jira-cli issue get MGX-1 --pretty
jira-cli search "project = MGX AND status = Open" --max 20 --keys-only
Configuration
Default path: $XDG_CONFIG_HOME/jira-cli/config.toml (typically ~/.config/jira-cli/config.toml). Mode 0600 enforced.
Precedence for resolved values: CLI flag > env var > config file > built-in default.
Full example:
# basic connection
url = "https://jira.internal.example.com"
user = "alice"
password = "your-password-or-token"
insecure = false
timeout_secs = 30
concurrency = 4
# optional: used by `issue create` when --project is omitted
default_project = "MGX"
# auth_method = "cookie" # optional; default "basic"
# session_cookie = "JSESSIONID=..." # required if cookie auth