mcp-jira
# JIRA MCP Server (Async)
[](https://www.python.org/downloads/)
[](https://modelcontextprotocol.io)
[](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
Scored across 6 tools
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.
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.
Six tools cover the core Jira issue lifecycle without being excessive. The count is well-scoped for a focused issue management server.
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.