Pyrus MCP — Бизнес-кейсы

Бизнес-кейсы агента, подключённого к Pyrus через MCP

Документ отвечает на вопрос «что реально можно поручить агенту, у которого есть этот сервер», и на не менее важный «чего поручать не стоит». Каждый кейс описан как процесс: кто его начинает, какие инструменты идут в дело, где процесс может свернуть не туда и что при этом увидит человек.

Перечень инструментов — в README, сценарии-заготовки для слэш-команд — в docs/prompts.md, измерение фактического использования — в docs/суточный-отчёт-по-mcp.md. Здесь — уровень выше: зачем всё это бизнесу.


Что меняется, когда агент подключён к Pyrus

Pyrus — система, где работа уже описана: формы, этапы, согласования, справочники, права. Агент не добавляет к ней новых сущностей. Он снимает три ограничения, которые до сих пор упирались в человеческое время.

Ограничение Как жили без агента Что даёт агент
Реестр не читается глазами Выгрузка в Excel, ручная сводка, устаревает к обеду Сведение по запросу, на живых данных, за минуты
Однотипное действие ×100 Либо руками, либо заказать интеграцию Разовая операция без разработки
Знание сидит в задачах Ответ ищут по переписке те, кто помнит Ответ собирается из закрытых задач и ложится в базу знаний

И одно ограничение агент не снимает: он не заменяет ни интеграцию, ни регламент. Всё, что должно происходить каждый день само и без свидетелей — это работа для бота Pyrus (create_bot) или для внешнего сервиса, а не для агента в чате.

Кто с кем разговаривает

flowchart LR
    H["Человек<br/>роль в компании"] -->|"запрос словами"| A["Агент<br/>Claude / другой LLM"]
    A <-->|"MCP, 88 инструментов"| S["Pyrus MCP<br/>сервер-шлагбаум"]
    S <-->|"REST API"| P["Pyrus<br/>контур компании"]
    S -->|"строка на каждый вызов"| L["Лог вызовов<br/>кто, что, чем кончилось"]
    L -->|"суточный отчёт"| H

    subgraph guard["Что сервер берёт на себя"]
        G1["Токен владельца:<br/>кто именно пришёл"]
        G2["Реквизиты Pyrus<br/>заголовками, на каждый запрос"]
        G3["Потолки ответа:<br/>отказ вместо потопа"]
    end
    S -.- guard

Важная деталь этой схемы: реквизиты Pyrus приходят на каждый запрос отдельно. Один сервер обслуживает несколько контуров и несколько владельцев, и агент работает ровно с теми правами, которые ему выдали в Pyrus. Агент не может больше, чем человек, от чьего имени он ходит.

Уровни зрелости кейсов

Та же шкала, что в prompts.md, — чтобы не выдавать гипотезу за практику.

Уровень Что означает
1 Пройдено на живых данных, ловушки закреплены тестами
2 Логика ясна, инструменты есть, повторяемость ещё не подтверждена
3 Соблазнительно, но цена ошибки высока — только с человеком в контуре

Уровень 1. Проверено на живых данных

Кейс 1. Выгрузка реестра целиком и аналитика по нему

Кому. Руководителю направления, аналитику, финансисту — всем, кому нужен ответ вида «сколько», «за какой срок», «в каком этапе застревает».

Как звучит запрос. «Посчитай по форме заявок, сколько пришло за полугодие, сколько закрыто и где они висят дольше всего».

Инструменты. get_form(summary=true) → plan_registry_walk → get_registry(format="csv", field_ids=…) по каждому окну.

flowchart TD
    Q["Человек: «посчитай за полгода»"] --> F["get_form summary=true<br/>какие поля вообще есть"]
    F --> N["Выбрать 3-5 полей<br/>вместо всей ширины формы"]
    N --> W["plan_registry_walk<br/>разбить период на окна"]
    W --> C{"Окно влезает<br/>под потолок?"}
    C -->|"нет"| W2["Дробить дальше<br/>пополам по датам"]
    W2 --> C
    C -->|"да"| R["get_registry по окну<br/>format=csv"]
    R --> M{"Окна кончились?"}
    M -->|"нет"| R
    M -->|"да"| S["Сводка человеку:<br/>цифры и где застревает"]

Ловушки, которые сервер держит за агента.

Что человек получает. Не выгрузку, а ответ. Файл при этом никуда не едет: агент считает по частям и отдаёт сводку.


Кейс 2. Однотипное действие над выборкой задач

Кому. Администратору процесса, руководителю проекта — тому, кто отвечает за порядок в форме.

Как звучит запрос. «Добавь юриста наблюдателем во все договоры, которые висят на этапе согласования дольше двух недель».

Инструменты. get_registry (найти) → get_task/get_tasks (убедиться) → add_subscribers / assign_task / update_task_fields / comment_task.

Это единственный кейс, который уже наблюдался в проде: 28 августа за одно утро агент обошёл реестр 85 запросами и сделал 82 записи add_subscribers за 13 минут. Отсюда и оговорки ниже — они не гипотеза, а замер.

flowchart TD
    Q["Человек: «добавь наблюдателя<br/>во все такие-то задачи»"] --> R["get_registry<br/>узкая выборка, только нужные поля"]
    R --> L{"Выборка<br/>влезла?"}
    L -->|"response_too_large"| N["Сузить: поля, период,<br/>этапы, item_count"]
    N --> R
    L -->|"да"| SHOW["Показать человеку:<br/>сколько задач и какие"]
    SHOW --> OK{"Человек<br/>подтвердил?"}
    OK -->|"нет"| STOP["Остановиться"]
    OK -->|"да"| W["Запись по каждой задаче"]
    W --> E{"Отказ на<br/>отдельной задаче?"}
    E -->|"да"| K["Запомнить и продолжить<br/>остальные"]
    E -->|"нет"| K
    K --> M{"Список<br/>кончился?"}
    M -->|"нет"| W
    M -->|"да"| REP["Отчёт: сделано N,<br/>не вышло M и почему"]

Три правила, без которых кейс становится опасным.

  1. Выборку показать до записи. Запись в Pyrus не имеет отката: снять подписчика можно, а вот delete_task — нет.
  2. Отказ на одной задаче не останавливает остальные. Иначе половина выборки останется в неизвестном состоянии.
  3. Итог — отчёт, а не молчание. «Сделано 82, не вышло 1, причина такая» — это то, что человек может проверить.

Чего кейс стоит. Каждый add_subscribers возвращает задачу целиком — 18 КБ на вызов, 1,4 МБ за то утро, ~400 тысяч токенов контекста на операцию записи. Пока это так, массовые операции лучше делать в отдельной сессии, а не в середине важного разговора.


Уровень 2. Инструменты есть, практика ещё копится

Кейс 3. Утренний обзор рисков по портфелю форм

Кому. Руководителю, у которого несколько процессов и нет времени открывать каждый.

Как звучит запрос. «Что горит сегодня?» — или то же самое по расписанию, через /loop либо внешний планировщик.

Инструменты. get_overdue_tasks() и get_tasks_due_soon(days=3) — два вызова, а не обход по каждой форме. Оба берут сроки из календаря, а он не привязан к форме: form_id там фильтр, а не требование. Дальше сведение и, если нужно, comment_task на эскалацию.

flowchart TD
    T["Утро, запуск по расписанию"] --> O["get_overdue_tasks<br/>что уже просрочено"]
    T --> D["get_tasks_due_soon days=3<br/>у чего срок на подходе"]
    O --> AGG["Свести: что горит,<br/>что вот-вот, у кого"]
    D --> AGG
    AGG --> C{"Есть что<br/>докладывать?"}
    C -->|"нет"| Q["Одна строка:<br/>«всё в срок»"]
    C -->|"да"| REP["Сводка по владельцам<br/>и срокам"]
    REP --> ESC{"Нужна<br/>эскалация?"}
    ESC -->|"да"| CT["comment_task:<br/>напоминание в самой задаче"]
    ESC -->|"нет"| REP2["Только доклад человеку"]

Почему не по каждой форме. Так этот сценарий и был описан раньше — и это ровно тот перебор, за который приходится платить: на портфеле из двадцати форм получается сорок вызовов вместо двух. Календарь отдаёт сроки по всем формам сразу; сужать до одной формы стоит, только когда вопрос и правда про неё.

Замер, объясняющий переделку. До 09.09.2026 оба инструмента ходили в реестр, а сроков в реестре нет вовсе: задача оттуда несёт create_date, current_step, fields, id, last_modified_date, last_note_id. Поэтому get_tasks_due_soon фильтровал окно изменения задачи и на живой форме возвращал ноль, а get_overdue_tasks отдавал одни и те же задачи на любое значение фильтра. Сценарий работал — и показывал не то.

Почему это работает лучше уведомлений Pyrus. Уведомление приходит по одной задаче и в момент события. Обзор отвечает на другой вопрос — «где сегодня хуже всего» — и сравнивает процессы между собой, чего ни одно уведомление не делает.

Оговорка. «Всё в срок» — полноценный ответ. Агент, который каждое утро выдаёт три абзаца ни о чём, перестаёт читаться на четвёртый день.


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

Кому. Владельцу процесса, когда сроки поехали, а причина не названа.

Инструменты. get_registry(steps=[…], include_archived=true) → get_task(last_comments=…) по образцам → сводка по этапам.

flowchart LR
    Q["«Почему заявки стали<br/>идти вдвое дольше?»"] --> R["get_registry по этапам:<br/>сколько где стоит"]
    R --> H["Найти этап<br/>с аномальным скоплением"]
    H --> S["get_task на 5-10 образцах<br/>с последними комментариями"]
    S --> W["Прочитать, что общего:<br/>кого ждут, чего не хватает"]
    W --> A["Ответ: этап, причина,<br/>кто может расшить"]

Где агент силён. Он читает комментарии десятка задач за минуту и находит общий знаменатель — «во всех случаях ждут скан от контрагента». Человек это тоже увидит, но потратит час.

Где он слаб. Этап (current_step) — не то же самое, что поле формы со стадией. Задача на 20-м шаге может быть открыта, а закрытые — стоять на 2-м, 3-м и 5-м. Считать «закрытость» по шагу нельзя, это проверено.


Кейс 5. Аудит и наведение порядка в доступах к форме

Кому. Администратору Pyrus, службе безопасности, владельцу формы с чувствительными данными.

Инструменты. get_form_permissions → get_contacts / get_members / get_roles → change_form_permissions.

flowchart TD
    Q["«Кто видит форму с зарплатами?»"] --> P["get_form_permissions<br/>id и уровни доступа"]
    P --> N["get_contacts / get_members<br/>превратить id в людей"]
    N --> R["Список: кто, какой уровень,<br/>из какого отдела"]
    R --> F{"Есть<br/>лишние?"}
    F -->|"нет"| OK["Доклад: доступ в порядке"]
    F -->|"да"| SHOW["Показать человеку<br/>кандидатов на отзыв"]
    SHOW --> APP{"Человек<br/>подтвердил?"}
    APP -->|"нет"| OK2["Ничего не менять"]
    APP -->|"да"| CH["change_form_permissions<br/>уровень none"]
    CH --> V["get_form_permissions ещё раз:<br/>проверить, что применилось"]

Что закреплено в сервере. Доступ к форме Pyrus ключует только числовым id — почты и имена отвергаются на входе, а не молча игнорируются. Уровень restricted_manager Pyrus документирует, но через этот эндпоинт не применяет: проверено вживую — отвечает 200 и не меняет ничего. Сервер его отклоняет, чтобы отзыв доступа не выглядел успешным, не будучи им.

Обязательный шаг — перечитать права после изменения. Это тот случай, когда «успешный ответ» и «изменение произошло» — разные вещи.


Кейс 6. Справочник из внешнего источника

Кому. Тому, кто держит в Pyrus номенклатуру, прайс, список контрагентов, приходящий из 1С или другой системы.

Инструменты. get_catalog(summary=true) → сравнение → update_catalog_items (диффом) или sync_catalog(apply=false) как сухой прогон.

flowchart TD
    SRC["Выгрузка из внешней системы"] --> S["get_catalog summary=true<br/>размер и колонки, без строк"]
    S --> CMP["Сверить: что добавилось,<br/>изменилось, исчезло"]
    CMP --> D{"Изменений<br/>много?"}
    D -->|"единицы-десятки"| U["update_catalog_items<br/>upsert + delete"]
    D -->|"полная замена"| DRY["sync_catalog apply=false<br/>сухой прогон"]
    DRY --> CHECK["Показать человеку:<br/>что будет удалено"]
    CHECK --> APP{"Подтверждено?"}
    APP -->|"да"| SYNC["sync_catalog apply=true"]
    APP -->|"нет"| STOP["Отменить"]
    U --> LOG["Отчёт: N добавлено,<br/>M удалено"]
    SYNC --> LOG

Главная опасность кейса — в одном предложении документации Pyrus: sync_catalog — это полная замена, всё, чего нет в переданном списке, удаляется. Диффом (update_catalog_items) безопаснее всегда, когда изменений не большинство.

Дешёвый первый шаг. summary=true на незнакомом справочнике: замерено — 329 строк ужались с 44 КБ до 722 байт (61 раз), 128 строк с 20 КБ до 787 байт. Сначала узнать размер, потом решать, тянуть ли строки вообще.


Кейс 7. Повторяющиеся обращения → статья базы знаний

Кому. Поддержке, HR, любому отделу, который отвечает на одно и то же.

Инструменты. get_registry (закрытые за период) → get_task (как решали) → get_knowledge_base_structure → create_knowledge_base_entity → update_knowledge_base_permissions.

flowchart TD
    Q["«Что мы объясняем чаще всего?»"] --> R["get_registry<br/>закрытые за квартал"]
    R --> G["Сгруппировать по теме:<br/>что повторяется"]
    G --> T["get_task на образцах:<br/>как именно решали"]
    T --> KB["get_knowledge_base_structure<br/>куда это положить"]
    KB --> EX{"Статья<br/>уже есть?"}
    EX -->|"да"| UPD["update_knowledge_base_entity<br/>дополнить"]
    EX -->|"нет"| NEW["create_knowledge_base_entity<br/>черновик статьи"]
    NEW --> PERM["update_knowledge_base_permissions<br/>кому видно"]
    UPD --> REV["Человек вычитывает<br/>и публикует"]
    PERM --> REV

Почему именно агент. Материал для статьи уже написан — в комментариях десятков закрытых задач. Не хватало только того, кто согласится это прочитать и свести. Черновик всегда идёт человеку на вычитку: база знаний — это лицо компании внутрь себя, и опечатка агента живёт в ней годами.


Кейс 8. Телефония: звонок становится задачей

Кому. Отделу продаж и поддержке, где обращение начинается со звонка.

Инструменты. register_call → get_upload_target → загрузка файла прямо в Pyrus → attach_call_record.

sequenceDiagram
    participant ATS as Телефония
    participant AG as Агент
    participant MCP as Pyrus MCP
    participant P as Pyrus

    ATS->>AG: звонок завершён, есть запись
    AG->>MCP: register_call — account_id, номера, internal_number
    MCP->>P: регистрация
    P-->>MCP: task_id + is_new_task + ответственный
    MCP-->>AG: «создана задача» или «комментарий к существующей»
    AG->>MCP: get_upload_target
    MCP-->>AG: URL и токен загрузки
    AG->>P: POST аудио напрямую, мимо MCP
    P-->>AG: guid файла
    AG->>MCP: attach_call_record — task_id, record_file=guid
    MCP->>P: запись и метаданные к звонку
    AG-->>ATS: готово: задача N

Две детали, которые экономят день отладки.

Честная оговорка. Телефонные инструменты требуют включённой интеграции в Pyrus (Расширения). Этот сервер не смог выполнить их вживую — они собраны по документации и на живом контуре не проверялись. Уровень 2 здесь означает именно это.


Уровень 3. Только с человеком в контуре

Кейс 9. Приём и уход сотрудника

Кому. HR и администратору Pyrus.

Инструменты приёма. create_member → update_role(added_members) → change_form_permissions → get_knowledge_base_structure (что читать) → create_task (чек-лист адаптации).

Инструменты ухода. get_registry (что на нём висит) → assign_task (передать) → update_role(removed_members) → change_form_permissions(none) → block_member.

flowchart TD
    subgraph priem["Приём — риск низкий"]
        A1["create_member"] --> A2["update_role<br/>добавить в роли"]
        A2 --> A3["change_form_permissions<br/>доступ к формам"]
        A3 --> A4["create_task<br/>чек-лист адаптации"]
    end

    subgraph uhod["Уход — риск высокий"]
        B1["get_registry:<br/>что на нём висит"] --> B2["Показать человеку<br/>список задач"]
        B2 --> B3{"Кому<br/>передаём?"}
        B3 --> B4["assign_task<br/>по каждой задаче"]
        B4 --> B5["update_role removed_members<br/>+ доступы в none"]
        B5 --> B6["block_member<br/>последним шагом"]
    end

    uhod -.->|"порядок нарушать нельзя"| WARN["Заблокировать раньше передачи<br/>= задачи повисают на никого"]

Почему уровень 3. block_member не имеет обратной операции — в API Pyrus нет разблокировки. Заблокировать не того человека — это поездка к администратору, а не отмена в чате. Порядок шагов тоже не косметика: сначала передать задачи, потом снимать доступы, блокировать — последним. Роль, удалённая без task_receiver_id, оставляет свои задачи без получателя.

Что агент делает хорошо даже здесь. Готовит список: что висит, кому логично передать, какие доступы есть. Решение и нажатие — за человеком.


Кейс 10. Чего агенту не поручают

Не всякий инструмент, который есть, годится для «сделай сам».

Действие Почему не без человека
delete_task Безвозвратно. Для «завершить» есть close_task
sync_catalog(apply=true) Полная замена: всё, чего нет в списке, удаляется
block_member Разблокировки в API нет
delete_role Без task_receiver_id задачи роли остаются без адресата
delete_bot, delete_knowledge_base_entity Удаляют вместе с содержимым
Массовое close_task Закрытие меняет отчётность; выборка должна быть проверена глазами

Правило простое: необратимое действие требует, чтобы человек увидел выборку до её применения. Это не про недоверие к модели, а про то, что отката в Pyrus нет.


Потолки, о которых стоит знать заранее

Они не про технику, а про то, как формулировать задачу агенту.

Потолок Значение Что делать
Ответ инструмента 200 КБ Сузить поля, период, item_count; CSV вместо JSON
Скачивание файла 16 МБ Работать по ссылке (get_file_download_url)
Реестр Pyrus 20 000 задач, молча Обход окнами через plan_registry_walk
Справочник отдаётся целиком summary=true первым шагом
Реестр по умолчанию только открытые задачи include_archived=true при любом подсчёте
Сроки задач в реестре их нет вовсе Брать из календаря — на нём стоят get_overdue_tasks и get_tasks_due_soon

Отказ по размеру — не поломка, а часть протокола: сервер называет размер, говорит, сколько это примерно токенов, и подсказывает, как сузить. Агент, который читает подсказку, проходит дальше сам.

Повторять отказ бесполезно, и сервер об этом скажет. Три одинаковых отказа подряд — и к сообщению добавляется, что повтор не поможет. Правило для агента проще формулировки: если два запроса подряд упали одинаково, следующим действием должен быть не третий запрос, а сужение или вопрос человеку. Замер, из которого это правило выросло: 32 одинаковых отказа за 25 минут без единой смены подхода.


Как понять, что кейс прижился

Сервер пишет на каждый вызов три вещи: владельца с инструментом, исходом, размером и длительностью; отпечаток аргументов — что именно спрашивали (идентификаторы, размер страницы, факт курсора, но не значения фильтров и не тексты); а при отказе — то, что ответил сам Pyrus. Отсюда видно не «сколько раз дёрнули API», а то, что важно бизнесу.

flowchart LR
    L["Лог вызовов"] --> R["scripts/mcp_daily_report.py"]
    R --> Q1["Кто ходит:<br/>кейс живёт или один энтузиаст"]
    R --> Q2["Во что упираются:<br/>чего не хватает в инструментах"]
    R --> Q5["Что повторяется:<br/>обход или перебор одного и того же"]
    R --> Q3["Что дорого:<br/>вызовы на десятки КБ"]
    R --> Q4["Что сломано:<br/>internal_error, no_credentials"]

Ориентиры нормы, порядок разбора и что докладывать человеку — в docs/суточный-отчёт-по-mcp.md.

Живой пример из первого же периода наблюдений (27–29 августа 2026): подключены три клиента, но 169 вызовов из 172 сделал один владелец и в одном сценарии — кейс 2. Второй клиент сделал три вызова, все три неудачные; третий не вызвал ничего, только держал соединение. Это и есть честная картина внедрения: не «88 инструментов доступны», а «один кейс дошёл до практики». Остальные девять описаны здесь для того, чтобы было видно, куда идти дальше.