Прогресс MCP перепутался между двумя параллельными вызовами

Клиент одновременно попросил MCP-сервер построить два отчёта: по продажам и по возвратам. Оба инструмента присылают «обработано 60 из 100». Интерфейс показывает 60% у продаж дважды, а возвраты остаются на нуле. Пользователь не понимает, завис ли второй отчёт. Причина обычно проста: приложение хранит одну глобальную переменную прогресса, хотя уведомления относятся к разным вызовам.

Токен относится к запросу

Клиент, которому нужны обновления, кладёт в метаданные каждого запроса свой progressToken. Сервер копирует этот непрозрачный токен в notifications/progress. В уведомлении также есть число progress, иногда total и сообщение. Клиенту нужно заранее связать токен с локальным job_id или UI-карточкой. При получении события он обновляет только соответствующую карточку. Токен не равен имени инструмента: два вызова одного build_report всё равно должны иметь разные значения.

Например, для продаж клиент передаёт sales-42, для возвратов — returns-43. Уведомление {"progressToken":"returns-43","progress":3,"total":10} меняет только индикатор возвратов на три десятых. Эти строки служат примером значений; в настоящем клиенте токен генерируется так, чтобы не пересечься между активными вызовами, и не содержит секретов. Храните отображение до завершения или отмены вызова, затем удаляйте. Позднее событие с неизвестным токеном не должно создавать новый «успешный» отчёт.

Прогресс не равен результату

Число progress показывает движение внутри операции, но не подтверждает её завершение. Даже сообщение «100 из 100» может предшествовать сохранению файла или итоговому ответу. Переводите задачу в done только по завершённому ответу tool call с нужным ID, а ошибку показывайте как ошибку этого же вызова. Если total отсутствует или меняется, показывайте выполненное количество и текст стадии, а не процент, который будет прыгать назад.

Для проверки запустите два контролируемых вызова одновременно и чередуйте события: продажи 1/4, возвраты 1/2, продажи 2/4. После трёх уведомлений интерфейс должен показывать продажи 2/4 и возвраты 1/2. Затем отмените продажи и пришлите запоздалое уведомление с их токеном: карточка возвратов не должна измениться. Для диагностики ошибки конкретного вызова пригодится correlation ID в логах.

В актуальной схеме MCP обновления прогресса передаются во время обработки запроса, если клиент их запросил; отсутствие токена означает, что сервер не обязан присылать прогресс. Конкретные API SDK различаются, поэтому при внедрении смотрите, где ваша библиотека принимает метаданные запроса и где отдаёт уведомления. На уровне протокола сохраняется один инвариант: событие с данным progressToken относится только к тому запросу, который его указал.

В платном курсе AI Agent Integrations PRO: MCP вы собираете MCP-сервер с tools и resources, подключаете клиент, добавляете логи и тесты. Параллельные вызовы и их прогресс — хороший проверочный сценарий для такого клиента: видно, не смешивает ли интеграция запросы пользователя. Откройте программу курса, чтобы отработать путь от контракта инструмента до обработки результата.

Продолжить на практике

  • AI Agent Integrations PRO: MCP ↗

    Вы уже работали с LLM и понимаете, что подключать их к реальным системам — больно. MCP — это стандарт, который делает эту боль меньше: один контракт вместо десятка костылей, типизированные инструменты вместо голого доступа к базе, тесты и логи вместо молитв. На курсе соберём сервер с нуля и выведем в production-контур.