Skip to main content
Glama
README.md
# Jira MCP

Локальный MCP-сервер для Jira Server/Data Center. Дает Claude и Codex доступ к
задачам, комментариям, вложениям, статусам и переходам, worklog, связям,
доскам, спринтам, эпикам, версиям и компонентам.

Сервер работает через Jira REST API v2 и Agile API 1.0 с Basic Auth. Токен не
нужен.

## Статус

- **64 инструмента в 18 разделах** (см. «Инструменты»). Покрыта повседневная
  работа с задачами, кроме администрирования Jira.
- **Проверено на Jira Server 8.8 с русской локализацией.**
  - Все инструменты чтения проверены на реальных данных. Версии,
    компоненты, избранные фильтры и worklog проверены только на пустых
    списках, потому что таких данных в тестовом проекте не было.
  - Изменяющие инструменты для задач проверены на временных задачах: создание,
    правка, назначение, комментарии, вложения, worklog, наблюдатели, связи и
    удаленные ссылки, смена статуса.
  - Инструменты, которые меняют общие доски и проект (спринты, ранжирование,
    эпики, версии, компоненты), покрыты только автотестами.
- **Тесты:** 123 теста, покрытие строк и ветвлений 99%. Тесты не обращаются к
  сети и к Jira, поэтому их безопасно запускать где угодно, в том числе с
  заполненным `.env`.

Особенности Jira, которые учитывает сервер:

- имена типов задач и статусов локализованы, а часть API Jira понимает только
  исходные (английские) имена. `get_create_fields` принимает видимое имя типа,
  а `get_issue_history` показывает статусы так, как они называются в Jira
  сейчас. `get_project_statuses` отдает ответ Jira как есть, поэтому типы
  задач в нем могут быть на английском (`Task` вместо «Задача»);
- на переходах без экрана Jira молча отбрасывает комментарий.
  `change_status` в этом случае добавляет комментарий отдельным запросом;
- у канбан-досок нет спринтов и бэклога: `list_sprints` и `get_backlog`
  работают только со скрам-досками;
- `notify_issue` требует настроенной исходящей почты (SMTP) в Jira.

Пока не реализовано:

- удаление, клонирование и массовое создание задач, голоса;
- правка и удаление спринтов, версий и компонентов, создание и правка
  сохраненных фильтров;
- комментарии с ограниченной видимостью (по роли или группе);
- администрирование Jira (схемы, workflow, пользователи) — не планируется.

## Различия ОС

Команды ниже даны в двух вариантах: **Linux/macOS** (bash/zsh) и **Windows**
(PowerShell). Главное отличие — расположение файлов в виртуальном окружении:

|                        | Linux/macOS                 | Windows                          |
|------------------------|-----------------------------|----------------------------------|
| Создать окружение      | `python3 -m venv .venv`     | `python -m venv .venv` или `py -m venv .venv` |
| Python окружения       | `.venv/bin/python`          | `.venv\Scripts\python.exe`       |
| pip окружения          | `.venv/bin/pip`             | `.venv\Scripts\pip.exe`          |
| Перенос строки команды | `\`                         | `` ` `` (обратная кавычка)       |
| Пример абсолютного пути | `/home/me/jira-mcp`        | `C:\Users\me\jira-mcp`           |

В JSON-файлах (Claude Desktop, `.mcp.json`) пути Windows пишите с прямыми
слэшами (`C:/Users/me/jira-mcp/main.py`) или удваивайте обратные
(`C:\\Users\\me\\jira-mcp\\main.py`). В TOML (Codex) используйте строки в
одинарных кавычках: `'C:\Users\me\jira-mcp\main.py'`.

## Установка

Нужны Python 3.10 или новее и сетевой доступ к Jira (внутренняя сеть или VPN).

Linux/macOS:

```bash
git clone <URL_РЕПОЗИТОРИЯ> jira-mcp
cd jira-mcp

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python -m unittest -v
```

Windows:

```powershell
git clone <URL_РЕПОЗИТОРИЯ> jira-mcp
cd jira-mcp

python -m venv .venv
.venv\Scripts\pip install -r requirements.txt
.venv\Scripts\python.exe -m unittest -v
```

Активировать окружение (`activate`) не нужно: MCP-клиент запускает
`python` из `.venv` по полному пути.

## Настройки

Сервер читает настройки из переменных окружения:

| Переменная         | Обязательна | По умолчанию | Описание                          |
|--------------------|-------------|--------------|-----------------------------------|
| `JIRA_URL`         | да          |              | `http://jira.company.local:8080`  |
| `JIRA_USER`        | да          |              | логин Jira                        |
| `JIRA_PASSWORD`    | да          |              | пароль Jira                       |
| `JIRA_VERIFY_SSL`  | нет         | `true`       | проверять TLS-сертификат          |
| `JIRA_TIMEOUT`     | нет         | `20`         | таймаут запроса, секунды          |
| `JIRA_MAX_RESULTS` | нет         | `50`         | потолок `max_results` в списках   |

Обычно их передает MCP-клиент при подключении сервера: `-e` в
`claude mcp add`, блок `env` в JSON/TOML-конфигурации. Так у каждого проекта
или подключения могут быть свои Jira и учётная запись. Каждое подключение
запускает отдельный процесс сервера со своими значениями. Примеры ниже.

Для запуска без клиента или как общие значения по умолчанию можно создать
`.env` рядом с `main.py`.

Linux/macOS:

```bash
cp .env.example .env
chmod 600 .env
```

Windows:

```powershell
Copy-Item .env.example .env
```

Переменные, переданные клиентом, имеют приоритет над `.env`. Файлы `.env` и
`.env.*` (кроме `.env.example`) находятся в `.gitignore`. Не коммитьте их.

## Claude Code

### Для одного проекта (рекомендуется)

Запустите из каталога **проекта**, в котором нужна Jira. `--scope local`
сохраняет сервер только для этого проекта и только у вас.

Linux/macOS:

```bash
MCP_DIR="/ABSOLUTE/PATH/jira-mcp"

claude mcp add \
  --transport stdio \
  --scope local \
  -e JIRA_URL=http://jira.company.local:8080 \
  -e JIRA_USER=firstname.lastname \
  -e JIRA_PASSWORD=your-password \
  jira -- \
  "$MCP_DIR/.venv/bin/python" \
  "$MCP_DIR/main.py"
```

Windows:

```powershell
$MCP_DIR = "C:\ABSOLUTE\PATH\jira-mcp"

claude mcp add `
  --transport stdio `
  --scope local `
  -e JIRA_URL=http://jira.company.local:8080 `
  -e JIRA_USER=firstname.lastname `
  -e JIRA_PASSWORD=your-password `
  jira -- `
  "$MCP_DIR\.venv\Scripts\python.exe" `
  "$MCP_DIR\main.py"
```

### Общий `.mcp.json` в репозитории проекта

Чтобы подключение было у всей команды (`--scope project`), не записывайте в
`.mcp.json` пароль и пути, зависящие от ОС. Claude Code подставит значения
`${VAR}` из окружения каждого пользователя:

```json
{
  "mcpServers": {
    "jira": {
      "command": "${JIRA_MCP_PYTHON}",
      "args": ["${JIRA_MCP_DIR}/main.py"],
      "env": {
        "JIRA_URL": "http://jira.company.local:8080",
        "JIRA_USER": "${JIRA_USER}",
        "JIRA_PASSWORD": "${JIRA_PASSWORD}"
      }
    }
  }
}
```

Каждый участник один раз задает переменные у себя.

Linux/macOS (добавьте в `~/.bashrc` или `~/.zshrc`):

```bash
export JIRA_MCP_DIR="/ABSOLUTE/PATH/jira-mcp"
export JIRA_MCP_PYTHON="$JIRA_MCP_DIR/.venv/bin/python"
export JIRA_USER="firstname.lastname"
export JIRA_PASSWORD="your-password"
```

Windows (сохраняется для пользователя, действует в новых терминалах):

```powershell
setx JIRA_MCP_DIR "C:/ABSOLUTE/PATH/jira-mcp"
setx JIRA_MCP_PYTHON "C:/ABSOLUTE/PATH/jira-mcp/.venv/Scripts/python.exe"
setx JIRA_USER "firstname.lastname"
setx JIRA_PASSWORD "your-password"
```

После `setx` перезапустите терминал и Claude Code.

### Для всех проектов

Если настройки везде одинаковые, заполните `.env` рядом с `main.py` и
подключите сервер глобально.

Linux/macOS:

```bash
MCP_DIR="/ABSOLUTE/PATH/jira-mcp"

claude mcp add --transport stdio --scope user \
  jira -- "$MCP_DIR/.venv/bin/python" "$MCP_DIR/main.py"
```

Windows:

```powershell
$MCP_DIR = "C:\ABSOLUTE\PATH\jira-mcp"

claude mcp add --transport stdio --scope user `
  jira -- "$MCP_DIR\.venv\Scripts\python.exe" "$MCP_DIR\main.py"
```

Сервер с тем же именем в `local` или `project` перекрывает глобальный.

Проверка (одинаково на всех ОС):

```bash
claude mcp get jira
claude mcp list
```

В новой сессии Claude Code выполните `/mcp`.

## Claude Desktop

Откройте **Settings → Developer → Edit Config**. Откроется файл:

- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`

Добавьте сервер.

macOS:

```json
{
  "mcpServers": {
    "jira": {
      "command": "/ABSOLUTE/PATH/jira-mcp/.venv/bin/python",
      "args": ["/ABSOLUTE/PATH/jira-mcp/main.py"],
      "env": {
        "JIRA_URL": "http://jira.company.local:8080",
        "JIRA_USER": "firstname.lastname",
        "JIRA_PASSWORD": "your-password"
      }
    }
  }
}
```

Windows:

```json
{
  "mcpServers": {
    "jira": {
      "command": "C:/ABSOLUTE/PATH/jira-mcp/.venv/Scripts/python.exe",
      "args": ["C:/ABSOLUTE/PATH/jira-mcp/main.py"],
      "env": {
        "JIRA_URL": "http://jira.company.local:8080",
        "JIRA_USER": "firstname.lastname",
        "JIRA_PASSWORD": "your-password"
      }
    }
  }
}
```

Блок `env` можно не указывать, если заполнен `.env` рядом с `main.py`. Для
нескольких Jira добавьте несколько серверов с разными именами (`jira-alpha`,
`jira-beta`) и своим `env`.

Если в файле уже есть другие серверы, добавьте только нужную секцию, не
перезаписывая остальную конфигурацию. После изменения полностью закройте
Claude Desktop (на Windows — также из трея) и откройте снова.

## Codex CLI

Linux/macOS:

```bash
MCP_DIR="/ABSOLUTE/PATH/jira-mcp"

codex mcp add jira \
  --env JIRA_URL=http://jira.company.local:8080 \
  --env JIRA_USER=firstname.lastname \
  --env JIRA_PASSWORD=your-password \
  -- \
  "$MCP_DIR/.venv/bin/python" \
  "$MCP_DIR/main.py"
```

Windows:

```powershell
$MCP_DIR = "C:\ABSOLUTE\PATH\jira-mcp"

codex mcp add jira `
  --env JIRA_URL=http://jira.company.local:8080 `
  --env JIRA_USER=firstname.lastname `
  --env JIRA_PASSWORD=your-password `
  -- `
  "$MCP_DIR\.venv\Scripts\python.exe" `
  "$MCP_DIR\main.py"
```

Конфигурация Codex общая для всех проектов: `~/.codex/config.toml`
(на Windows — `%USERPROFILE%\.codex\config.toml`). Для разных Jira добавьте
серверы с разными именами (`jira-alpha`, `jira-beta`) и своими `--env`.

Проверка (одинаково на всех ОС):

```bash
codex mcp get jira
codex mcp list
```

В новой сессии Codex выполните `/mcp`.

## Codex Desktop

Codex Desktop, Codex CLI и IDE-расширение используют общий `config.toml`
(путь см. выше). Если сервер уже добавлен через `codex mcp add`, повторная
настройка не нужна: перезапустите приложение.

Также сервер можно добавить через **Settings → MCP servers → Add server**:

- Name: `jira`
- Type: `STDIO`
- Command: абсолютный путь к Python окружения (см. «Различия ОС»)
- Args: абсолютный путь к `main.py`
- переменные окружения `JIRA_URL`, `JIRA_USER`, `JIRA_PASSWORD`

Ручная конфигурация, Linux/macOS:

```toml
[mcp_servers.jira]
command = "/ABSOLUTE/PATH/jira-mcp/.venv/bin/python"
args = ["/ABSOLUTE/PATH/jira-mcp/main.py"]
env = { JIRA_URL = "http://jira.company.local:8080", JIRA_USER = "firstname.lastname", JIRA_PASSWORD = "your-password" }
```

Windows:

```toml
[mcp_servers.jira]
command = 'C:\ABSOLUTE\PATH\jira-mcp\.venv\Scripts\python.exe'
args = ['C:\ABSOLUTE\PATH\jira-mcp\main.py']
env = { JIRA_URL = "http://jira.company.local:8080", JIRA_USER = "firstname.lastname", JIRA_PASSWORD = "your-password" }
```

## Проверка Jira

После подключения попросите агента:

```text
Покажи текущего пользователя Jira и доступные проекты.
```

Если MCP подключен, но Jira не отвечает, проверьте:

- доступ к внутренней сети или VPN;
- `JIRA_URL`, логин и пароль в `env` подключения MCP или в `.env`;
- права пользователя в нужном проекте;
- статус сервера через `/mcp`;
- что путь к Python указывает на окружение проекта: `.venv/bin/python` на
  Linux/macOS, `.venv\Scripts\python.exe` на Windows.

## Инструменты

| Раздел        | Чтение                                                            | Изменения                                          |
|---------------|-------------------------------------------------------------------|----------------------------------------------------|
| `users`       | `get_myself`, `find_users`, `find_assignable_users`, `get_my_permissions` |                                            |
| `projects`    | `list_projects`, `get_project_issue_types`, `get_create_fields`   |                                                    |
| `statuses`    | `get_project_statuses`, `get_all_statuses`                        |                                                    |
| `reference`   | `get_priorities`, `get_resolutions`, `get_issue_types`            |                                                    |
| `fields`      | `get_fields`                                                      |                                                    |
| `issues`      | `get_ticket`, `search_tickets`, `get_edit_fields`, `get_issue_history` | `create_ticket`, `update_ticket`, `assign_ticket`, `notify_issue` |
| `comments`    | `get_comments`                                                    | `add_comment`, `delete_comment`                    |
| `attachments` | `download_attachment`                                             | `add_attachment`, `delete_attachment`              |
| `transitions` | `list_transitions`                                                | `change_status`                                    |
| `worklogs`    | `get_worklogs`                                                    | `add_worklog`, `update_worklog`, `delete_worklog`  |
| `links`       | `get_link_types`, `get_remote_links`                              | `link_tickets`, `delete_link`, `add_remote_link`, `delete_remote_link` |
| `watchers`    | `get_watchers`                                                    | `add_watcher`, `remove_watcher`                    |
| `filters`     | `list_favourite_filters`, `run_filter`                            |                                                    |
| `boards`      | `list_boards`, `get_board_config`, `get_board_issues`, `get_backlog` | `rank_issues`                                   |
| `sprints`     | `list_sprints`, `get_sprint_issues`                               | `move_to_sprint`, `move_to_backlog`, `create_sprint`, `start_sprint`, `close_sprint` |
| `epics`       | `list_epics`, `get_epic_issues`                                   | `add_to_epic`                                      |
| `versions`    | `list_versions`                                                   | `create_version`, `release_version`                |
| `components`  | `list_components`                                                 | `create_component`                                 |

Перед созданием задачи или сменой статуса агент должен сначала проверить
доступные типы, поля и переходы:

- `get_fields` сопоставляет `customfield_XXXXX` с человеческими именами и
  JQL-именами;
- `get_edit_fields` показывает, какие поля задачи можно менять и какими
  операциями. `update_ticket` принимает `fields` (замена значения) и `update`
  (операции `add`/`remove`/`set`, например добавить метку, не трогая
  остальные);
- `list_transitions` показывает поля экрана перехода. Обязательные поля,
  чаще всего `resolution` при закрытии, передаются в `change_status` через
  `fields`, а комментарий к переходу через `comment`.

Списки (`get_comments`, `get_worklogs`) возвращаются постранично:
`{items, start_at, max_results, total, next_start_at}`. Для следующей
страницы передайте `next_start_at` как `start_at`. `get_issue_history`
показывает, кто, когда и что менял в задаче, с фильтром по полю, например
`field="status"`. Для назначения задачи используйте `find_assignable_users`:
`find_users` находит и тех, на кого назначить нельзя. Если Jira отклонила
действие, `get_my_permissions` покажет, каких прав не хватает.

Доски, спринты и эпики работают через Agile API (`/rest/agile/1.0`, нужен
Jira Software):

- колонка доски и статус — разные вещи. `get_board_config` показывает, какие
  статусы попадают в каждую колонку;
- у канбан-досок нет спринтов и бэклога: `list_sprints` и `get_backlog`
  работают только со скрам-досками, для канбана Jira вернет ошибку;
- групповые операции (`move_to_sprint`, `move_to_backlog`, `add_to_epic`,
  `rank_issues`) принимают до 50 задач за вызов.

Списки досок, спринтов, эпиков и задач на них тоже постраничные, в том же
формате `{items, ..., next_start_at}`.

## Структура

```text
main.py                         # точка входа для MCP-клиентов
src/jira_mcp/
  app.py                        # экземпляр FastMCP
  settings.py                   # настройки из env / .env
  client.py                     # HTTP-сессия Jira и общие хелперы
  formatting.py                 # компактный вид задач в Agile-списках
  server.py                     # регистрация инструментов и запуск
  tools/<раздел>/<команда>.py   # по одному файлу на инструмент
tests/                          # тесты по разделам
```

Сервер также запускается как модуль.

Linux/macOS:

```bash
PYTHONPATH=src .venv/bin/python -m jira_mcp
```

Windows:

```powershell
$env:PYTHONPATH = "src"; .venv\Scripts\python.exe -m jira_mcp
```

Чтобы добавить инструмент:

1. Создайте `src/jira_mcp/tools/<раздел>/<команда>.py` с функцией под
   `@mcp.tool()`. Запросы к Jira делайте через `client.request(...)`:
   - по умолчанию запрос идет в `/rest/api/2`; для досок, спринтов и эпиков
     передайте `api="agile"` (`/rest/agile/1.0`);
   - для списков используйте `client.page(path, items_key, start_at=...,
     max_results=...)`. Он возвращает одну страницу в едином формате
     `{items, start_at, max_results, total, next_start_at}` для обоих API.
     Чтобы получить следующую страницу, передайте `next_start_at` как
     `start_at`; на последней странице он равен `null`.
2. Импортируйте модуль в `src/jira_mcp/tools/<раздел>/__init__.py`. Для нового
   раздела добавьте его в `src/jira_mcp/tools/__init__.py`.
3. Добавьте имя в `EXPECTED_TOOLS` в `tests/test_server.py`, а тест — в
   `tests/test_<раздел>.py`. В тестах подменяйте `jira_mcp.client.request`.

## Обновление

Linux/macOS:

```bash
git pull
.venv/bin/pip install -r requirements.txt
.venv/bin/python -m unittest -v
```

Windows:

```powershell
git pull
.venv\Scripts\pip install -r requirements.txt
.venv\Scripts\python.exe -m unittest -v
```

Повторно добавлять MCP не нужно, пока путь к каталогу не изменился. Но уже
запущенные сессии продолжают работать на старом коде: перезапустите сервер
через `/mcp` или откройте новую сессию.

Если раньше настройки лежали в `config.py`, перенесите значения в `.env` (те
же имена, формат `JIRA_URL=...`) или в `env` подключения MCP. Затем удалите
`config.py`: сервер его больше не читает. Если вы вручную создавали
`src/jira_mcp/config.py`, тоже удалите его. Git его не игнорирует, и файл с
паролем можно случайно закоммитить.

## Ссылки

Документация по клиентам:

- [Claude Code MCP](https://code.claude.com/docs/en/mcp)
- [Codex MCP](https://learn.chatgpt.com/docs/extend/mcp)

Maintenance

ActivityMaintained
ResponsivenessNo issues