Sign inSign up

nerd4ever/jira-mcp

By nerd4ever

•Updated 3 months ago

Jira MCP Server

Image
0

218

nerd4ever/jira-mcp repository overview

⁠jira-mcp

MCP server that integrates AI agents with Jira Server 8.16.1 — search/create/update issues, manage sprints, boards, versions and workflow transitions through MCP tools.

⁠Requirements

  • Python 3.13+
  • uv⁠
  • A Jira Server/Data Center instance (8.14+ if using Personal Access Tokens)

⁠Setup

uv sync
cp .env.example .env   # then fill in JIRA_BASE_URL and, for stdio mode, credentials

⁠Running modes

The server supports two transports, controlled by MCP_TRANSPORT. They target different use cases and authenticate differently.

⁠stdio (default) — local, single user

Your MCP client (Claude Desktop, Claude Code, etc.) spawns jira-mcp as a local subprocess and talks to it over stdin/stdout. There's no network involved, so this only works on the same machine as the client.

MCP_TRANSPORT=stdio
JIRA_USERNAME=you
JIRA_PASSWORD=your-password-or-pat

JIRA_USERNAME/JIRA_PASSWORD are required in this mode — the server runs as that one Jira identity for every tool call. Run it with:

make run
⁠streamable-http — remote, multi-user

The server runs as an HTTP service (e.g. in Docker, Kubernetes, or a Portainer stack) and any number of MCP clients connect to it over the network at http://<host>:8000/mcp.

There is no shared Jira credential in this mode. Every request must carry its own Jira username + password/PAT via HTTP Basic auth:

Authorization: Basic base64(jira_username:jira_password_or_pat)

The server decodes that header per request and forwards those exact credentials to Jira, so every tool call runs with the caller's own Jira permissions — nobody borrows anybody else's access, and nothing is shared. A request without a valid Authorization header is rejected with 401 before it ever reaches Jira. JIRA_USERNAME/JIRA_PASSWORD in .env are ignored in this mode — only JIRA_BASE_URL (plus the optional JIRA_AUTH_METHOD, LOG_LEVEL, OTEL_* settings) matters.

JIRA_AUTH_METHOD still controls how the decoded credentials are sent to Jira: basic (default) forwards them as HTTP Basic; bearer sends the secret half as Authorization: Bearer <token> (required by most Jira Server/Data Center 8.14+ instances when using a PAT).

⁠Getting a Jira Personal Access Token

In Jira, go to your avatar → Personal Access Tokens → Create token. Use your Jira username together with that token as the Basic auth credentials above (not your account password).

⁠Configuring an MCP client to connect remotely

Point the client at http://<host>:8000/mcp and set a custom Authorization header (or username/password, if the client offers a Basic auth field) to Basic base64(username:token). Example of building that header value:

printf '%s' "your-username:your-pat" | base64

⁠Deploying with Docker / Portainer / Kubernetes

A Dockerfile and a jira-mcp service in docker-compose.yml are included, pre-configured for streamable-http mode (MCP_TRANSPORT=streamable-http, FASTMCP_HOST=0.0.0.0, listening on port 8000).

docker compose build jira-mcp
docker compose up -d jira-mcp

In Portainer: Stacks → Add stack, point it at this repo (or paste docker-compose.yml), and set JIRA_BASE_URL as an environment variable on the stack — no Jira username/password/PAT needs to live on the server, since each caller supplies their own. The same image runs unchanged on Kubernetes; just set JIRA_BASE_URL and MCP_TRANSPORT=streamable-http on the container and expose port 8000.

Health endpoints (unauthenticated, for liveness/readiness probes):

  • GET /health/live — process is up.
  • GET /health/ready — Jira is reachable (GET /status, no auth needed in this mode since there's no service-level credential to check).

⚠️ The MCP endpoint itself has no transport-level encryption on its own — put it behind TLS (reverse proxy / ingress) before exposing it beyond a trusted network, since Basic auth credentials travel in cleartext over plain HTTP.

⁠jira-ops Claude Code plugin

This repo also hosts a jira-ops Claude Code plugin (.claude-plugin/marketplace.json

  • plugins/jira-ops/) — a skill for interacting with a running jira-mcp server from any project, without copying files. It supports two modes:
  • Command mode: free-form Jira instructions ("create a bug for X", "list the sprints on board 3", "transition this issue to done"), mapped to the appropriate jira_* MCP tool calls.
  • OpenSpec-sync mode: reads an OpenSpec change's proposal.md/design.md/ tasks.md and creates/updates a Jira Epic plus one Story/Task per task, tracking the mapping in a jira.md file inside the change directory so re-running sync updates existing issues instead of duplicating them.

To install it in another project (which must already have an MCP client configured against a jira-mcp server — the plugin itself doesn't start or configure one):

/plugin marketplace add if-sb/jira-mcp
/plugin install jira-ops

See plugins/jira-ops/skills/jira-ops/SKILL.md for the full behavior.

⁠Testing

make test              # unit tests
make test-integration  # against a real Jira instance, see docs/integration-testing.md
make lint
make format

⁠Observability

Traces and logs are emitted via OpenTelemetry; point OTEL_EXPORTER_OTLP_ENDPOINT at a collector (see docker-compose.yml's otel-collector service, profile observability).

Tag summary

Content type

Image

Digest

sha256:cef08904a…

Size

63.7 MB

Last updated

3 months ago

docker pull nerd4ever/jira-mcp