TeamStorm MCP
# TeamStorm MCP
Интеграция TeamStorm с AI-агентами через протокол MCP. Сервер реализован на
[FastMCP 3](https://gofastmcp.com/) и работает через STDIO.
Сервер предоставляет небольшой типизированный набор инструментов для чтения
задач TeamStorm и связанного с ними контекста. Операции записи намеренно
ограничены созданием задач и подзадач, добавлением комментария и изменением
названия, описания или статуса задачи. Инструменты удаления отсутствуют.
## Возможности
- разбор ключей задач вида `TS-123` и `BACKEND-42`;
- чтение задачи, пользовательских атрибутов, комментариев, метаданных вложений,
связей и непосредственных подзадач;
- получение страниц, связанных с задачей, по явному запросу пользователя;
- получение единого `TaskContext` с текстовым представлением для LLM и
структурированным MCP-ответом;
- добавление непустого комментария без небезопасных автоматических повторов;
- создание задач в указанной папке и подзадач по ключу родителя;
- изменение только полей `name`, `description` и `status` через типизированные
аргументы;
- формирование описания по единому HTML-шаблону с разделами «Суть задачи» и
«Что было сделано»;
- повтор безопасных `GET`-запросов при временных ошибках;
- преобразование ошибок TeamStorm и транспорта в короткие понятные MCP-ошибки.
## Требования
- Python 3.12 или новее;
- [uv](https://docs.astral.sh/uv/);
- доступный экземпляр TeamStorm;
- приватный токен с минимально необходимыми правами.
## Установка
### Из GitHub Releases
Скачайте wheel (`teamstorm_mcp-<версия>-py3-none-any.whl`) и
`teamstorm.env.example` из [последнего релиза](https://github.com/taaylor/TeamStorm-MCP/releases/latest).
Установите пакет, подставив имя скачанного файла:
```bash
uv tool install --python 3.12 ./teamstorm_mcp-0.2.0-py3-none-any.whl
cp teamstorm.env.example .env
```
Заполните `.env` и запускайте из его каталога `teamstorm-daemon`; MCP-клиенту
укажите команду `teamstorm-mcp`. Обе команды входят в один пакет. Для обновления
повторите установку с `--upgrade` и новым wheel. Для установки зависимостей
нужен доступ к PyPI; Python при необходимости загружает uv.
Релиз содержит wheel, архив исходников `.tar.gz`, пример окружения, README и
`SHA256SUMS`. Если скачаны все файлы релиза, проверьте их командой
`sha256sum -c SHA256SUMS`.
### Из исходников
```bash
git clone https://github.com/taaylor/TeamStorm-MCP.git teamstorm-mcp
cd teamstorm-mcp
uv sync
```
Пакет также можно установить непосредственно из GitHub:
```bash
uv tool install git+https://github.com/taaylor/teamstorm-mcp.git
```
## Получение токена TeamStorm
Создайте приватный токен в профиле пользователя TeamStorm в разделе
**Безопасность**. Запросы с токеном выполняются с правами пользователя, который
его создал. Подробнее — в официальной
[документации TeamStorm по аутентификации](https://docs.teamstorm.io/projects/api/overview/authentication/).
## Настройка окружения
Для локальной разработки скопируйте `.env.example` в `.env` либо экспортируйте
переменные в окружении процесса, который запускает сервер:
```env
TEAMSTORM_URL=https://teamstorm.example.com
TEAMSTORM_TOKEN=your-private-token
TEAMSTORM_TIMEOUT=30
TEAMSTORM_MAX_CONTEXT_ITEMS=200
```
`TEAMSTORM_URL` должен содержать корневой адрес экземпляра. Не добавляйте
`/cwm/public/api/v1`: клиент формирует API URL самостоятельно.
`TEAMSTORM_TOKEN` является секретом. Его нельзя добавлять в Git, логи или
непосредственно в конфигурационный файл Codex.
## Запуск
Локальный сервер запускается через STDIO:
```bash
uv run teamstorm-mcp
```
После установки через `uv tool install` используйте:
```bash
teamstorm-mcp
```
Процесс ожидает MCP-сообщения в стандартном потоке ввода. FastMCP banner
отключён, чтобы в STDOUT не попадали данные, не относящиеся к протоколу.
## Очередь и демон
Демон запускается отдельным процессом и продолжает работать после завершения
MCP-сессии:
```bash
uv run teamstorm-daemon
```
Настрой статусы и переходы в [шаблоне скилла](skills/teamstorm-workflow/SKILL.md)
и задай `TEAMSTORM_WORKFLOW_PATH` обоим процессам. Единственный YAML-блок в Markdown
валидируется и компилируется в LangGraph. По умолчанию карта отключена.
Ассистент получает её через `teamstorm_get_workflow`, выполняет работу и переводит
задачу по разрешённым MCP-переходам. Финальный переход выполняет только демон.
Если пользователь указал время закрытия, агент сразу вызывает `teamstorm_schedule_task_closure`:
```json
{"task_key": "TS-123", "close_at": "2026-09-17T18:00:00+05:00", "target_status": "Done"}
```
Сервер проверяет доступность задачи и сохраняет запись в SQLite. Время обязательно
содержит часовой пояс. Демон проверяет очередь каждые 30 секунд; просроченная
запись обрабатывается при ближайшей проверке. Очередь сохраняется после перезапуска.
Повтор идентичного запроса ничего не меняет, новый срок или целевой статус
заменяет прежнюю запись и сбрасывает сохранённый контекст.
С картой намерение хранится в состоянии `waiting` до достижения `trigger_state`.
Демон просматривает все доступные рабочие пространства и задачи с пагинацией,
включая ручные изменения. Ready раньше срока активирует очередь (`pending`) и
ожидает; Ready после срока закрывается при ближайшей успешной проверке.
Выход из Ready возвращает запись в `waiting`, сохраняя срок. Уже финальная задача
помечается `completed` без PATCH. Ошибки API повторяются на следующем цикле.
Без времени в промпте ассистент не создаёт расписание и не меняет существующее.
Без сохранённого срока демон пропускает задачу. Посмотреть запись можно через
`teamstorm_get_task_closure`, отменить — через `teamstorm_cancel_task_closure`.
Расписание связано с id, revision и отпечатком карты; изменение карты переводит
его в `suspended` до явного обновления расписания. После правки карты перезапусти
MCP и демон.
Перед финальной записью демон перечитывает статус и ревизию расписания. GET и PATCH
не атомарны: конкурентное изменение после проверки всё ещё возможно. Используй
один демон на общую очередь.
Без подключённой карты сохраняется прежний режим: по сроку демон только получает
контекст статуса (`context_ready`), автоматического перехода нет.
Настройки обоих процессов:
- `TEAMSTORM_QUEUE_PATH` — общий файл SQLite, по умолчанию
`~/.local/state/teamstorm-mcp/queue.sqlite3`;
- `TEAMSTORM_DAEMON_INTERVAL` — интервал проверки в секундах, по умолчанию `30`.
- `TEAMSTORM_WORKFLOW_PATH` — абсолютный путь к Markdown с картой, необязательный.
MCP и демон должны использовать одинаковые URL TeamStorm и абсолютный путь к
базе. Для разных экземпляров TeamStorm используйте разные базы. Если MCP
запускается через Codex с собственным путём базы, добавьте `TEAMSTORM_QUEUE_PATH`
и `TEAMSTORM_WORKFLOW_PATH` в его `env_vars`. Для постоянной работы процесс можно запускать под
systemd; SIGTERM и SIGINT завершают цикл после текущей обработки.
## Подключение к Codex
Codex читает конфигурацию MCP-серверов из `config.toml`. Актуальный формат
описан в [официальной документации OpenAI](https://developers.openai.com/codex/mcp).
Храните значения секретов в окружении, а в конфигурации указывайте только имена
переменных:
```toml
[mcp_servers.teamstorm]
command = "teamstorm-mcp"
env_vars = ["TEAMSTORM_URL", "TEAMSTORM_TOKEN", "TEAMSTORM_TIMEOUT", "TEAMSTORM_MAX_CONTEXT_ITEMS"]
default_tools_approval_mode = "writes"
```
Если пакет не установлен как CLI-инструмент, сервер можно запускать напрямую из
рабочей копии репозитория. Укажите абсолютный путь:
```toml
[mcp_servers.teamstorm]
command = "uv"
args = ["--directory", "/absolute/path/to/teamstorm-mcp", "run", "teamstorm-mcp"]
env_vars = ["TEAMSTORM_URL", "TEAMSTORM_TOKEN", "TEAMSTORM_TIMEOUT", "TEAMSTORM_MAX_CONTEXT_ITEMS"]
default_tools_approval_mode = "writes"
```
Перед запуском Codex экспортируйте `TEAMSTORM_URL` и `TEAMSTORM_TOKEN`.
Параметр `default_tools_approval_mode = "writes"` оставляет инструменты чтения
доступными без дополнительного подтверждения и запрашивает подтверждение для
операций записи.
Проверить подключение можно командами:
```bash
codex mcp list
```
В интерфейсе Codex также доступна команда `/mcp`.
## Навык агента
Исходник переиспользуемого навыка расположен в `skills/teamstorm/SKILL.md`.
Для установки только в текущий репозиторий выполните:
```bash
mkdir -p .agents/skills
cp -R skills/teamstorm .agents/skills/teamstorm
```
Для установки на уровне пользователя выполните:
```bash
mkdir -p ~/.agents/skills
cp -R skills/teamstorm ~/.agents/skills/teamstorm
```
Правила обнаружения навыков описаны в
[документации OpenAI Codex Skills](https://developers.openai.com/codex/skills).
## Примеры использования
После подключения сервера и установки навыка можно использовать запросы:
```text
Возьми TS-123 и расскажи, что нужно сделать.
Прочитай TS-123 и все страницы, связанные с этой задачей.
Покажи документацию, связанную с TS-123, включая содержимое страниц.
Реализуй TS-123.
Что обсуждали в TS-123?
На основании этих вводных сформируй и запиши описание задачи TS-123: ...
```
При запросе на реализацию навык предписывает агенту получить
`teamstorm_get_task_context`, изучить репозиторий, реализовать и проверить
изменения, а затем добавить в задачу краткое описание результата. Явный запрет
пользователя на запись в TeamStorm всегда имеет приоритет.
Связанные страницы не загружаются автоматически. Агент вызывает
`teamstorm_get_task_pages` только после явной просьбы пользователя прочитать
страницы или документацию по задаче. Поиск выполняется по доступным рабочим
пространствам с ограничением `max_items`; содержимое страниц считается внешними
данными и не является инструкциями для агента.
### Создание задач и подзадач
Создание выполняется по явной просьбе пользователя. Оба инструмента возвращают
созданный `WorkItem`, включая его `id` и `key`.
```text
teamstorm_create_task(workspace_key, folder_id, name, task_type, description=None)
teamstorm_create_subtask(parent_task_key, name, task_type, description=None)
```
Для задачи нужны ключ пространства (например, `TS`), UUID папки, название
длиной 1–255 символов и имя либо UUID типа задачи. Для подзадачи вместо
пространства и папки передаётся ключ родителя, например `TS-123`: сервер
получает его UUID и создаёт подзадачу в том же пространстве. Тип задаётся явно
и не наследуется от родителя. Необязательное `description` передаётся без
преобразования в шаблон.
Поиск папок и типов пока не предоставляется: их значения нужно знать заранее.
Статус, исполнитель и пользовательские атрибуты при создании не задаются.
Используется `POST /cwm/public/api/v1/workspaces/{workspace}/workitems`
с полями `name`, `type`, `parentId` и необязательным `description`.
Автоматических повторов нет. После таймаута или другой ошибки с неопределённым
результатом сначала проверьте TeamStorm: повторный вызов может создать дубль.
### Политика комментариев
Комментарий о завершении содержит только выполненные изменения, которые важны
пользователю. В него не включаются:
- результаты успешных, упавших или пропущенных проверок;
- ошибки, исключения, stack trace и причины блокировки;
- команды, локальные пути, адреса, порты и сведения об окружении;
- названия баз данных, схем, таблиц, колонок, индексов и ограничений;
- внутренние названия классов, функций, моделей и модулей;
- токены, заголовки авторизации и другие секреты.
Если реализация не завершена, агент не создаёт комментарий о завершении. Ошибки
и ограничения проверок он в любом случае сообщает только пользователю в чате.
Если изменения реализованы, комментарий может быть добавлен, но без диагностики
и без утверждения о результатах проверок.
Безопасный комментарий для изменения ограничения номера телефона выглядит так:
```markdown
## Что сделано
- Для ручного создания и редактирования заявки увеличена допустимая длина
номера телефона до 50 символов.
- Добавлено покрытие сценариев создания и редактирования заявки с длинным
номером телефона.
```
Если был добавлен или изменён публичный endpoint, комментарий дополняется
коротким контрактом:
```markdown
### API-контракт
- `POST /api/v1/resources` — создание ресурса.
- Запрос: обязательные публичные поля запроса.
- Успешный ответ: `201 Created`, идентификатор созданного ресурса.
```
Раздел `API-контракт` не добавляется, если endpoint не менялся. Тесты можно
упомянуть только как факт добавления покрытия, без названий тестов, команд,
результатов выполнения и диагностической информации.
### Шаблонное описание задачи
Для записи структурированного описания предназначен инструмент
`teamstorm_set_task_description`. Его контракт:
```text
task_key: str
task_summary: str
work_done: list[str] | null = null
```
- `task_key` — ключ существующей задачи, например `TS-123`;
- `task_summary` — обязательное непустое описание сути задачи обычным текстом;
- `work_done` — необязательный список только фактически выполненных изменений.
Инструмент полностью заменяет текущее поле `description` и формирует допустимый
для TeamStorm HTML:
```html
<h2>Суть задачи</h2>
<p>Добавить проверку прав доступа.</p>
<hr>
<h2>Что было сделано</h2>
<ul>
<li>Добавлена проверка роли пользователя.</li>
<li>Добавлены тесты.</li>
</ul>
```
Аргументы нужно передавать обычным текстом без HTML. Специальные символы
экранируются сервером. Если `work_done` не передан или содержит пустой список,
в описание добавляется нейтральный текст «Работы ещё не описаны». Пустой
`task_summary` и пустые элементы `work_done` отклоняются.
Пример команды агенту для планируемой задачи:
```text
Прочитай текущую задачу TS-123. На основании вводных ниже сформулируй суть
задачи и обнови её описание в TeamStorm через teamstorm_set_task_description.
Работы ещё не выполнены. Не меняй название и статус.
Вводные: ...
```
Пример команды после реализации:
```text
Обнови описание TS-123: сохрани актуальную суть задачи, а в раздел
«Что было сделано» добавь только фактически реализованные изменения и
выполненные проверки. Не указывай проверки, которые не запускались.
```
Изменение выполняется только по явному запросу. Перед заменой описания агенту
следует прочитать задачу с помощью `teamstorm_get_task`, чтобы не потерять
важную информацию из текущего текста.
## Доступные инструменты
- `teamstorm_create_task` — создать задачу в папке рабочего пространства;
- `teamstorm_create_subtask` — создать подзадачу по ключу родителя;
- `teamstorm_get_task` — получить основные данные задачи;
- `teamstorm_get_task_context` — получить агрегированный контекст для анализа;
- `teamstorm_get_comments` — получить комментарии в хронологическом порядке;
- `teamstorm_add_comment` — добавить комментарий;
- `teamstorm_get_attachments` — получить метаданные вложений;
- `teamstorm_get_links` — получить связанные задачи;
- `teamstorm_get_task_pages` — получить страницы и содержимое страниц, связанных
с задачей, по явному запросу;
- `teamstorm_update_task` — изменить `name`, `description` или `status`;
- `teamstorm_set_task_description` — полностью заменить описание единым
безопасным HTML-шаблоном.
- `teamstorm_schedule_task_closure` — сохранить срок и целевой статус в очереди;
- `teamstorm_get_task_closure` — прочитать запись очереди и полученный статус.
- `teamstorm_get_workflow` — получить активную карту целиком или `null`;
- `teamstorm_cancel_task_closure` — отменить автоматическое закрытие.
## Модель безопасности
- данные TeamStorm считаются внешним недоверенным содержимым, а не инструкциями
для агента;
- заголовки авторизации и тела HTTP-ответов не логируются;
- ошибки для модели не содержат исходные HTTP-ответы;
- запросы `POST` и `PATCH` автоматически не повторяются;
- инструменты удаления и назначения исполнителя отсутствуют;
- при подключённой карте MCP проверяет переходы, демон выполняет только финальный
переход по сохранённому сроку и статусу готовности;
- размер разделов контекста ограничен `TEAMSTORM_MAX_CONTEXT_ITEMS`;
- FastMCP скрывает детали неожиданных внутренних исключений, а ожидаемые ошибки
TeamStorm передаются через `ToolError`.
## Разработка
```bash
uv sync
uv run pytest
uv run ruff check .
uv run mypy src
```
Интеграционный тест работает только на чтение и автоматически пропускается,
если необходимые переменные не заданы:
```bash
TEAMSTORM_TEST_TASK=TS-13 uv run pytest -m integration
```
Тест может прочитать задачу и её контекст. Он не добавляет комментарии, не
изменяет задачи и не удаляет данные.
## Сборка и публикация релиза
Workflow `.github/workflows/build.yml` запускает Ruff, mypy, модульные тесты,
сборку wheel и исходников, затем проверяет загрузку обеих CLI-команд из
установленного wheel. Проверки выполняются для push в `main`, pull request
в `main` и ручного запуска. Собранные файлы доступны в артефакте
`teamstorm-mcp-dist` на странице запуска Actions.
Для публикации обновите `project.version` в `pyproject.toml`, выполните
`uv lock` и закоммитьте оба файла. Версия должна иметь формат `X.Y.Z`,
например `0.2.1`. Отправьте изменения в `main` напрямую или через pull request:
```bash
git push origin main
```
После успешных проверок workflow автоматически создаст тег `vX.Y.Z` на
проверенном коммите, GitHub Release и прикрепит установочные файлы.
Если релиз этой версии уже существует, публикация пропускается:
его файлы не перезаписываются. Если текущая версия ещё не опубликована,
ближайший успешный push в `main` выпустит её, даже без изменения версии.
Ручной запуск на `main` также может опубликовать отсутствующий релиз;
на других ветках выполняется только сборка.
Если тег уже указывает на другой коммит, публикация завершится ошибкой —
нужно повысить версию. Используется встроенный `GITHUB_TOKEN`,
отдельный секрет не нужен.
## Используемая архитектура
```text
src/teamstorm_mcp/
├── application/
│ ├── interfaces/ # Контракт доступа к TeamStorm
│ ├── services/ # Сценарии работы с задачами
│ ├── models.py # Модели приложения
│ ├── scheduling.py # Контракты очереди и сценарий постановки
│ ├── exceptions.py # Ошибки приложения
│ ├── parser.py
│ └── task_description.py
├── adapters/
│ ├── config.py # Настройки из окружения
│ ├── sqlite_closures.py # Постоянная очередь SQLite
│ └── teamstorm/ # REST-клиент на aiohttp и схемы ответов API
├── presentation/
│ └── fastmcp/ # MCP-ручки, схемы результатов и форматирование
├── bootstrap.py # Сборка зависимостей, lifespan и запуск
├── daemon.py # Отдельный процесс обработки очереди
└── __main__.py
```
Ручки FastMCP вызывают `TeamStormService`. Сервис зависит от интерфейса
`TeamStormGateway`, который реализует REST-адаптер `TeamStormClient`.
Слой `application` не зависит от FastMCP, aiohttp и настроек окружения.
`bootstrap.py` связывает слои и управляет общей HTTP-сессией: создаёт её
при запуске сервера и закрывает при завершении.
Прямые HTTP-запросы к TeamStorm выполняет `aiohttp`. `httpx` остаётся
транзитивной зависимостью FastMCP/MCP.
## Документация API
Реализация следует официальным контрактам TeamStorm для
[задач](https://docs.teamstorm.io/projects/api/api-functions/workitems/retrieve-workitem/),
[комментариев](https://docs.teamstorm.io/projects/api/api-functions/comments/retrieve-all-comments/),
[вложений](https://docs.teamstorm.io/projects/api/api-functions/workitem-attachments/retrieve-all-workitem-attachments/)
и [связей](https://docs.teamstorm.io/projects/api/api-functions/links/get-links/).
Для связанных страниц используются [получение страниц](https://docs.teamstorm.io/projects/api/api-functions/documents/get-all-documents/)
и [получение связей страницы с задачами](https://docs.teamstorm.io/projects/api/api-functions/document-links/get-document-links/).
Документация используемого фреймворка:
- [FastMCP: установка](https://gofastmcp.com/getting-started/installation);
- [FastMCP: сервер](https://gofastmcp.com/servers/server);
- [FastMCP: инструменты](https://gofastmcp.com/servers/tools);
- [FastMCP: lifecycle](https://gofastmcp.com/servers/lifespan).
## Лицензия
MIT. См. `LICENSE`.
TDQS
Scored across 15 tools
Most tools target a distinct action on a distinct resource, and the descriptions carefully delineate get_task (by key) from get_task_context (for requirements). The main overlap is update_task versus set_task_description, both of which can change a task's description, though the special templated behavior of the latter differentiates them.
Every tool uses the same teamstorm_ prefix followed by a consistent snake_case verb_noun pattern (create_task, get_comments, schedule_task_closure). The convention is uniform across all 15 tools with no camelCase or stylistic deviations.
15 tools sit at the top of the well-scoped range and each maps to a concrete capability (CRUD on tasks, comments, attachments, links, pages, and closure scheduling). No tool appears redundant with the count.
Core task lifecycle is covered (create/update/read, comments add/get, closure scheduling), but notable gaps exist: no task delete, no list/search of tasks, no way to add or download attachments, and no comment editing. These missing operations could force agents into dead ends for common list/search workflows.