Skip to main content
Glama
README.md
# JIRA MCP Server (Async)

[![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)
[![MCP Compatible](https://img.shields.io/badge/MCP-compatible-green.svg)](https://modelcontextprotocol.io)
[![UV](https://img.shields.io/badge/package%20manager-uv-blue)](https://docs.astral.sh/uv/)

An async Model Context Protocol (MCP) server for JIRA integration via stdio transport. Supports both Atlassian Cloud and Server/DC instances.

## MCP Tools

6 tools covering the full issue lifecycle, plus 2 prompt templates:

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `jira_search_issues` | Search issues using JQL (paginated) | `jql`, `max_results`, `start_at` |
| `jira_get_issue` | Get issue details, comments, links; optionally subtasks and transitions | `issue_key`, `include_subtasks`, `include_transitions` |
| `jira_create_issue` | Create a new issue | `project_key`, `summary`, `description`, `issue_type_name` |
| `jira_update_issue` | Update fields on an existing issue, optionally add a comment | `issue_key`, `summary`, `description`, `assignee`, `priority`, `labels`, `comment` |
| `jira_transition_issue` | Move an issue through a workflow transition | `issue_key`, `transition_id`, `comment` |
| `jira_get_create_meta` | Get required fields and allowed values before creating an issue | `project_key`, `issue_type` |

## Features

- **Cloud + Server/DC**: Auto-detects deployment type via `JIRA_USER_EMAIL` env var
- **Token optimization**: API responses transformed to 40-60% fewer tokens
- **ADF support**: Reads and writes Atlassian Document Format (Cloud v3)
- **Connection pooling**: `aiohttp` with configurable pool size
- **Rate limiting**: Built-in throttling with exponential backoff on 429s
- **Testable**: Injectable client via `_set_client()`, session injection for HTTP-level tests, 113 unit tests

## Setup

### Prerequisites

- Python 3.13+
- [uv](https://docs.astral.sh/uv/) package manager
- JIRA API token

### Installation

```bash
git clone https://github.com/judexzhu/mcp-jira.git
cd mcp-jira
uv sync
cp config.env.example .env
# Edit .env with your JIRA credentials
```

### Environment Variables

| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `JIRA_SERVER_URL` | Your JIRA instance URL | — | Yes |
| `JIRA_API_TOKEN` | Your JIRA API token | — | Yes |
| `JIRA_USER_EMAIL` | Email for Cloud Basic Auth (enables Cloud mode) | — | Cloud only |
| `MAX_CONCURRENT_REQUESTS` | Max concurrent requests & rate limit (req/sec) | `2` | No |
| `REQUEST_TIMEOUT` | HTTP request timeout (seconds) | `30` | No |
| `CONNECT_TIMEOUT` | HTTP connection timeout (seconds) | `10` | No |
| `LOG_LEVEL` | Logging level | `ERROR` | No |
| `LOG_TO_STDOUT` | Enable stdout logging (breaks MCP stdio) | `false` | No |

### Claude Desktop

Add to your Claude Desktop MCP config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):

```json
{
  "mcpServers": {
    "jira": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/mcp-jira", "python", "jira_mcp_server.py"],
      "env": {
        "JIRA_SERVER_URL": "https://your-company.atlassian.net",
        "JIRA_API_TOKEN": "your_api_token",
        "JIRA_USER_EMAIL": "you@company.com"
      }
    }
  }
}
```

### Claude Code

Add to your Claude Code MCP settings (`.claude/settings.json` or global `~/.claude/settings.json`):

```json
{
  "mcpServers": {
    "jira": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/mcp-jira", "python", "jira_mcp_server.py"],
      "env": {
        "JIRA_SERVER_URL": "https://your-company.atlassian.net",
        "JIRA_API_TOKEN": "your_api_token",
        "JIRA_USER_EMAIL": "you@company.com"
      }
    }
  }
}
```

Or add via CLI:

```bash
claude mcp add jira \
  -e JIRA_SERVER_URL=https://your-company.atlassian.net \
  -e JIRA_API_TOKEN=your_api_token \
  -e JIRA_USER_EMAIL=you@company.com \
  -- uv run --directory /path/to/mcp-jira python jira_mcp_server.py
```

Alternatively, skip the `-e` flags and put credentials in a `.env` file inside the mcp-jira directory — `load_dotenv()` picks them up automatically.

## Testing

```bash
# Unit tests (no credentials needed)
uv sync --group dev
uv run pytest tests/ -v
```

## Architecture

Two-file core:

- **`jira_mcp_server.py`** — 6 MCP tool functions + 2 prompt templates, each a thin wrapper delegating to the client
- **`jira_client.py`** — `AsyncJiraClient` with `JiraClientProtocol` seam, `_CloudFormat`/`_ServerFormat` adapters, auth, connection pooling, rate limiting, retry, and response transformation

Cloud vs Server/DC is detected by the presence of `JIRA_USER_EMAIL`. See `docs/adr/0001-cloud-detection-via-email.md` for the rationale.

TDQS

A4.5/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a distinct operation: search, get, create, update, transition, and metadata. No overlap exists; search returns lists while get returns single issue details, and transition handles workflow state changes.

Naming Consistency5/5

All tool names follow the jira_verb_noun pattern consistently (jira_search_issues, jira_get_issue, etc.). The one compound verb 'get_create_meta' still follows the verb_noun convention.

Tool Count5/5

Six tools cover the core Jira issue lifecycle without being excessive. The count is well-scoped for a focused issue management server.

Completeness4/5

Core CRUD and workflow transitions are covered: search, get, create, update, transition, and create metadata. Minor gaps include no delete issue or dedicated comment tool, but comments can be added via update/transition.

Maintenance

ActivitySlowing
ResponsivenessNo issues