(спойлер: в конце будет ссылка на GitHub)
Таск-менеджеры вроде Jira — хороший инструмент для ведения проектов. Вот только есть одна проблема — на них очень быстро забивают. В первую очередь — проектные менеджеры. Когда проект стартует, менеджер с командой, как правило, делают волевую попытку декомпозировать его на эпики и задачи. Каждая задача получает красивое описание, а иногда даже назначенных исполнителей и дедлайны.
Потом проект стартует…
Внезапно меняются требования и бэклог, появляются дополнительные зависимости. Часть задач внезапно оказывается ненужной, ещё более внезапно меняются менеджеры и ключевые участники. Рано или поздно таски начинают зарастать мхом: апдейты не комментируются, статусы не двигаются.
В какой-то момент наиболее ответственный член команды решает устроить субботник и позакрывать то, что уже сделано. Отсюда — популярность следующих вопросов в поддержке Jira:
Он очевиден — лень. И это, вообще, нормальная человеческая реакция. После того как изменения в задачах обсудили в чате или на встрече, нужно суммировать договорённости и внести обновления в трекер. Это требует мыслительного ресурса, а «договаривание» обычно бывает интенсивным. Поэтому последнюю часть часто оставляют «на потом»: мол, всё и так зафиксировано в чате. «Потом» зачастую так и не наступает.
В итоге — в трекере бардак. Мы упускаем возможность строить аналитику, улучшать планирование и делать ещё много полезного, о чём мечтательно вздыхают на планёрках старшие менеджеры. А если серьёзно — в нынешней действительности с 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К+ звёздами.
Крутотень! Сразу два.
Но… с обоими возникли проблемы.
Сначала — про официальный. У него такой алгоритм подключения:
Ключевой пункт — №2. Предполагается, что на локальной машине откроется браузер и предложит авторизоваться. Так и произошло, когда я подключил этот MCP к Cursor’у.
И это проблема: чат-бот я собирался запускать на удалённом сервере, а не на ноутбуке — и не для одного пользователя, а для любого. Официальный Remote MCP готов работать только с локальными клиентами. Значит, он выбывает.
Что с неофициальным?
Коротко — та же беда: авторизация. Есть три варианта. Но первые два (API Token Authentication, Personal Access Token) означают, что MCP будет авторизован подо мной и работать только с теми проектами, к которым есть личный доступ. Это не то, что нужно. Нам надо, чтобы любой пользователь смог авторизоваться в Jira со своего компьютера и выдать чат-боту право хотя бы на чтение своих проектов. Иначе смысла нет.
Третий способ — OAuth 2.0 Authentication. Тут всё ок, кроме того, что токен, полученный при авторизации на локальном компе, нужно занести в .env
или конфиг на сервере. То есть опять только один пользователь авторизован. Чуть ниже описания этого метода я обнаружил интригующую заметку:
Ок, поднял этот 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 выглядит так:
В девелоперской консоли создаём приложение. Я назвал его BriefChief1.0.
В секции Authorization выбираем OAuth 2.0 и указываем ссылку, куда придёт callback с кодом после того, как пользователь авторизуется и выдаст приложению права делать что-то от его имени в Jira. В ответ генерируется ссылка, по которой нужно пользователя вести на авторизацию.
Пользователь переходит по ссылке и авторизуется.
Atlassian шлёт callback на указанный URL. В моём случае — https://www.briefchief.ai/auth/callback
.
Значит, нам нужен не только чат-бот (о нём было выше), но и авторизационный сервер для Atlassian-приложения, который будет хранить токены пользователей.
У сервера две задачи:
Обрабатывать коллбэки, получать токены и сохранять их.
Токены, кстати, протухают за час. Чтобы этого не происходило, можно прикрутить автообновление. Я этого не делал — не из лени, а из соображений безопасности. На UX это почти не влияет: авторизоваться раз в час не слишком раздражает (личный опыт).
Общаться с чат-ботом. Я держу бота и сервер авторизации на разных машинах: сервер честно развернул в облаке, а бота отлаживаю на ноутбуке — так удобнее.
Авторизационный сервер по запросу бота выдаёт токен текущего пользователя (с которым идёт диалог) или сообщает, что пользователь не авторизован, и генерирует ссылку для авторизации.
Полностью процесс авторизации выглядит так:
┌─────────────────┐ /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 использовал тестовый проект, сгенерированный по умолчанию при создании аккаунта.
С точки зрения пользователя взаимодействие с briefchiefbot в Telegram выглядит так:
В итоге я решил, что автоматически вносить правки в Jira — слишком рискованно (нейросети, как мы знаем, умеют удалять прод-базы). Ограничился генерацией комментариев, которые можно просто Ctrl-C-Ctrl-V'шнуть в Jira — рядом даю ссылки на таски.
Мне, как ленивому менеджеру с полутора десятками лет опыта, это видится норм. Но особо горячие головы (и, очевидно, ещё более ленивые) небольшой правкой промпта и прав, выданных Atlassian-приложению, могут сделать систему полностью автоматической.
На всякий случай: BriefChiefBot в Telegram существует, но сейчас не работает. Подумываю сделать его публичным, но нужно допилить код и решить, готов ли я платить за запросы к ChatGPT. Даже если это будет gpt-5-nano
, это всё же деньги :)
Весь код проекта — тут:
https://github.com/vladmiron85/BriefChief
Надеюсь, этот текст вдохновит кого-нибудь сделать инструмент покруче моего! Область оптимизации работы проектного менеджера с помощью GenAI на момент написания этой статьи выглядит сильно недоинвестированной.