Таск-менеджеры вроде Jira — хороший инструмент для ведения проектов. Вот только есть одна проблема — на них очень быстро забивают. В первую очередь — проектные менеджеры (на всякий случай: я тоже забиваю). Когда проект стартует, менеджер с командой, как правило, делают волевую попытку декомпозировать его на эпики и задачи. Каждая задача получает красивое описание, а иногда даже назначенных исполнителей и дедлайны.

Потом проект стартует…

Внезапно меняются требования и бэклог, появляются дополнительные зависимости. Часть задач внезапно оказывается ненужной, ещё более внезапно меняются менеджеры и ключевые участники. Рано или поздно таски начинают зарастать мхом: апдейты не комментируются, статусы не двигаются.

В какой-то момент наиболее ответственный член команды решает устроить субботник и позакрывать то, что уже сделано. Отсюда — популярность следующих вопросов в поддержке Jira:

Issues not updated in a certain timeframe
Issues not updated in a certain timeframe

Корень зла

Он очевиден — лень. И это, вообще, нормальная человеческая реакция. После того как изменения в задачах обсудили в чате или на встрече, нужно суммировать договорённости и внести обновления в трекер. Это требует мыслительного ресурса, а «договаривание» обычно бывает интенсивным. Поэтому последнюю часть часто оставляют «на потом»: мол, всё и так зафиксировано в чате. «Потом» зачастую так и не наступает.

В итоге — в трекере бардак. Мы упускаем возможность строить аналитику, улучшать планирование и делать ещё много полезного, о чём мечтательно вздыхают на планёрках старшие менеджеры. А если серьёзно — в нынешней действительности с GenAI здорово иметь артефакт в виде подробного трекинга изменений по проекту. Это открывает практически бесконечные возможности для оптимизации процессов.

Как победить лень?

А никак. За почти 20 лет менеджмента в IT я видел много компаний и команд. Отдельные менеджеры на морально-волевых вытягивают качество проектных артефактов, но это скорее исключения. Массово качество ведения документации не лечится ни тренингами, ни административным давлением.

Итого, принимаем лень за константу: средний живой человек не будет аккуратно заносить изменения в трекер и передвигать таски по статусам.

Ок, давайте избавим его от этой работы. К счастью, это достижимо. Фактически у нас есть все договорённости — они зафиксированы в проектном чате. Ну или в живой беседе на дейли-митинге. С живыми беседами чуть сложнее — их нужно оцифровывать. Это решаемо (Zoom, например, умеет «из коробки», Яндекс.Телемост — тоже) и может быть полностью автоматизировано (помним про лень).

В этом упражнении оставим живые разговоры за скобками: после оцифровки они не отличаются от текстового чата. Сосредоточимся на последнем.

Идеальная схема

На входе: рабочий чат, посвящённый проекту. Коллеги обсуждают там задачи, но могут и пофлудить.
На выходе: все договорённости автоматически регистрируются нейросетью и переносятся в таски, а флуд игнорируется.

Для простоты эксперимента возьмём в качестве мессенджера Telegram, а в качестве трекера — Jira. В роли нейросети — OpenAI GPT-4o (можно заменить на что угодно). Менять трекер и мессенджер сложнее. Код пишем на Python.

Трудности реализации

1) Настраиваем чат-бота

Очевидно: для автоматического управления телеграм-чатиком нужен бот. И тут первая проблема — как прочитать историю сообщений? По умолчанию ботам это недоступно.

Беглый гуглеж приводит к Telethon.

Супер, наш бот теперь умеет читать историю. Я решил читать последние 50 сообщений, но несложно прикрутить более изощрённую логику при желании. У меня желания не было. Помним про лень!

client.iter_messages(update.effective_chat.id, limit=50)

2) Подключаем GPT-4o в режиме агента к MCP Jira

С агентским режимом проблем нет: используем библиотеку LangChain.

Чуть сложнее с Jira. Мы хотим как минимум уметь читать таски (а, может и писать).

Сложность — в подключении к MCP Atlassian. Я нашёл два варианта:

— официальный Atlassian Remote MCP;
— GitHub-проект mcp-atlassian с 3К+ звёздами.

Крутотень! Сразу два.
Но… с обоими возникли проблемы.

Сначала — про официальный. У него такой алгоритм подключения:

из официальной документации Atlassian
из официальной документации Atlassian

Ключевой пункт — №2. Предполагается, что на локальной машине откроется браузер и предложит авторизоваться. Так и произошло, когда я подключил этот MCP к Cursor’у.

И это проблема: чат-бот я собирался запускать на удалённом сервере, а не на ноутбуке — и не для одного пользователя, а для любого. Официальный Remote MCP готов работать только с локальными клиентами. Значит, он выбывает.

Что с неофициальным?

Коротко — та же беда: авторизация. Есть три варианта. Но первые два (API Token Authentication, Personal Access Token) означают, что MCP будет авторизован подо мной и работать только с теми проектами, к которым есть личный доступ. Это не то, что нужно. Нам надо, чтобы любой пользователь смог авторизоваться в Jira со своего компьютера и выдать чат-боту право хотя бы на чтение своих проектов. Иначе смысла нет.

Третий способ — OAuth 2.0 Authentication. Тут всё ок, кроме того, что токен, полученный при авторизации на локальном компе, нужно занести в .env или конфиг на сервере. То есть опять только один пользователь авторизован. Чуть ниже описания этого метода я обнаружил интригующую заметку:

из README.md на гитхабе
из README.md на гитхабе

Ок, поднял этот MCP у себя на компе и попробовал поискать таски в тестовом проекте BriefChiefTest:

Invoking: `jira_search` with `{'jql': 'project = BriefChiefTest', 'fields': 'summary,status,assignee', 'limit': 50}`

MCP авторизовался, но выдал ошибку:

ERROR - mcp-jira - Error fetching metadata for JQL 'project = BriefChiefTest': The requested API has been removed. Please migrate to the /rest/api/3/search/jql API. A full migration guideline is available at https://developer.atlassian.com/changelog/#CHANGE-2046

Полез разбираться. Оказалось, проблему уже зарепортили: https://github.com/sooperset/mcp-atlassian/issues/720

И её благополучно игнорируют. Я решил починить и написал крутую строчку кода (заменяющую search на search/jql), но при попытке протестировать локально упёрся в следующую зарепорченную проблему:
https://github.com/sooperset/mcp-atlassian/issues/721

На этом решил, что полагаться на mcp-atlassian не готов. Тратить время на его починку — тем более, учитывая, что автор проекта sooperset пару месяцев там ничего не трогал и игнорировал PR’ы. Ага, помним про лень.

Ну и Cursor к этому моменту раз пять подсказывал что-то вроде: «Братан, тебе же всего 3 метода нужны, давай я тебе свой MCP напишу, а?»
Я сказал: «А давай» — и получил 223 строки работающего и читаемого кода. Не с первой попытки, конечно. Но — ура!

Я завернул свой мини-MCP в функцию create_jira_langchain_tools — на случай, если потом подключим что-то более классное и поддерживаемое.

Дальше — к авторизации в Jira из Telegram.

3) Авторизуемся в Jira из Telegram

Это самый неприятный с точки зрения UX элемент всей системы. Как было бы здорово, если бы Telegram умел открывать модальное окно прямо в чате, сделать там всё, что надо, и нативно вернуться обратно!

Но нет. Поэтому авторизовываться придётся так: уводим пользователя в браузер и просим вернуться в чат самостоятельно.

OAuth 2.0-авторизация в Atlassian выглядит так:

  1. В девелоперской консоли создаём приложение. Я назвал его BriefChief1.0.

  2. В секции Authorization выбираем OAuth 2.0 и указываем ссылку, куда придёт callback с кодом после того, как пользователь авторизуется и выдаст приложению права делать что-то от его имени в Jira. В ответ генерируется ссылка, по которой нужно пользователя вести на авторизацию.

    интерфейс девелоперской консоли Atlassian
    интерфейс девелоперской консоли Atlassian
  3. Пользователь переходит по ссылке и авторизуется.

  4. Atlassian шлёт callback на указанный URL. В моём случае — https://www.briefchief.ai/auth/callback.

Значит, нам нужен не только чат-бот (о нём было выше), но и авторизационный сервер для Atlassian-приложения, который будет хранить токены пользователей.

У сервера две задачи:

  1. Обрабатывать коллбэки, получать токены и сохранять их.
    Токены, кстати, протухают за час. Чтобы этого не происходило, можно прикрутить автообновление. Я этого не делал — не из лени, а из соображений безопасности. На UX это почти не влияет: авторизоваться раз в час не слишком раздражает (личный опыт).

  2. Общаться с чат-ботом. Я держу бота и сервер авторизации на разных машинах: сервер честно развернул в облаке, а бота отлаживаю на ноутбуке — так удобнее.
    Авторизационный сервер по запросу бота выдаёт токен текущего пользователя (с которым идёт диалог) или сообщает, что пользователь не авторизован, и генерирует ссылку для авторизации.

Полностью процесс авторизации выглядит так:

┌─────────────────┐    /auth      ┌─────────────────┐
│   Telegram Bot  │ ────────────► │  Auth Server    │
│                 │               │                 │
│ 1. User sends   │               │ 2. Generates    │
│    /auth        │               │    auth URL and │
│    command      │               │    returns JSON │
│                 │               │    response     │
└─────────────────┘               └─────────────────┘
         │                                 │
         │ JSON response                   │
         │ {auth_url: "...",               │
         │  telegram_user_id: "123"}       │
         ▼                                 │
┌─────────────────┐               ┌─────────────────┐
│   Telegram Bot  │               │      Jira       │
│                 │               │                 │
│ 3. Shows button │               │ 4. Displays     │
│    with         │               │    authorization│
│    auth_url     │               │    form         │
└─────────────────┘               └─────────────────┘
         │                                 │
         │ user clicks button              │
         ▼                                 │
┌─────────────────┐               ┌─────────────────┐
│   Web Browser   │ ◄─────────────│      Jira       │
│                 │               │                 │
│ 6. User         │               │ 5. Displays     │
│    authorizes   │               │    authorization│
│    in Jira      │               │    form         │
└─────────────────┘               └─────────────────┘
                                           │
                                           │ callback
                                           ▼
┌─────────────────┐               ┌─────────────────┐
│   Auth Server   │ ◄─────────────│      Jira       │
│                 │               │                 │
│ 8. Receives     │               │ 7. Sends        │
│    code + state │               │    code + state │
│    with user_id │               │    (user_id)    │
└─────────────────┘               └─────────────────┘
         │
         │ exchange code for token
         ▼
┌─────────────────┐
│      Jira       │
│                 │
│ 9. Exchanges    │
│    code for     │
│    access_token │
└─────────────────┘
         │
         │ token response
         ▼
┌─────────────────┐
│   Auth Server   │
│                 │
│ 10. Encrypts    │
│     and saves   │
│     token for   │
│     telegram_id │
└─────────────────┘
         │
         │ success page
         ▼
┌─────────────────┐
│   Web Browser   │
│                 │
│ 11. Shows       │
│     success and │
│     auto-closes │
└─────────────────┘

┌─────────────────┐    /brief     ┌─────────────────┐
│   Telegram Bot  │ ────────────► │  Auth Server    │
│                 │               │                 │
│ 12. User uses   │               │ 13. Verifies    │
│     /brief      │               │    authorization│
│     command     │               │     by user_id  │
└─────────────────┘               └─────────────────┘
         │
         │ if authenticated
         ▼
┌─────────────────┐
│   Telegram Bot  │
│                 │
│ 14. Executes    │
│     command     │
│     with token  │
└─────────────────┘

ЧТО В ИТОГЕ

Связка из бота и авторизационного сервера заработала. Я протестировал её на паре чатиков и добавил режим /test, когда вместо реального чата подсовываю симулированный диалог, сгенерированный ChatGPT. С помощью этих симуляций я отлаживал промпт. В Jira использовал тестовый проект, сгенерированный по умолчанию при создании аккаунта.

тестовый проект по умолчанию в Jira
тестовый проект по умолчанию в Jira

С точки зрения пользователя взаимодействие с briefchiefbot в Telegram выглядит так:

пример использования BriefChiefBot
пример использования BriefChiefBot

В итоге я решил, что автоматически вносить правки в Jira — слишком рискованно (нейросети, как мы знаем, умеют удалять прод-базы). Ограничился генерацией комментариев, которые можно просто Ctrl-C-Ctrl-V'шнуть в Jira — рядом даю ссылки на таски.

Мне, как ленивому менеджеру с полутора десятками лет опыта, это видится норм. Но особо горячие головы (и, очевидно, ещё более ленивые) небольшой правкой промпта и прав, выданных Atlassian-приложению, могут сделать систему полностью автоматической.

На всякий случай: BriefChiefBot в Telegram существует, но сейчас не работает. Подумываю сделать его публичным, но нужно допилить код и решить, готов ли я платить за запросы к ChatGPT. Даже если это будет gpt-5-nano, это всё же деньги :-)

Весь код проекта — тут

Надеюсь, этот текст вдохновит кого-нибудь сделать инструмент покруче моего! Область оптимизации работы проектного менеджера с помощью GenAI на момент написания этой статьи выглядит сильно недоинвестированной.