MCP resource обновился, а клиент отвечает по старому содержимому

Внутренний MCP-сервер отдаёт карточку тарифа как resource. Редактор меняет цену в источнике, а агент продолжает отвечать по вчерашнему тексту. Метод resources/read работает: если вызвать его вручную, вернётся новая цена. Застрял кэш клиента, который однажды прочитал URI и больше не узнал об изменении.

Подпишитесь на конкретный URI

В опубликованной редакции MCP 2026-07-28 сервер объявляет возможность resources.subscribe, а клиент открывает subscriptions/listen с URI в notifications.resourceSubscriptions. После подтверждения подписки сервер присылает notifications/resources/updated, где указаны URI и идентификатор подписки. Уведомление сообщает, что содержимое могло измениться; оно не содержит новую карточку. Клиент помечает кэш для этого URI устаревшим и снова вызывает resources/read.

Для карточки catalog://plans/basic цепочка такова: открыть поток подписки; дождаться notifications/subscriptions/acknowledged; прочитать resource; сохранить содержимое под ключом URI и авторизационного контекста; при notifications/resources/updated удалить старое значение и перечитать. Если уведомление пришло во время чтения, не записывайте результат более раннего чтения поверх более свежего: держите локальный номер поколения кэша и применяйте ответ только если поколение не изменилось.

У подтверждения есть практическая роль: сервер может принять не все запрошенные уведомления. Сравните запрошенный URI с подтверждённым набором. Если подписка на него не принята, переводите этот ресурс на обычное повторное чтение по таймеру или событию пользовательского запроса. Иначе интерфейс выглядит «подписанным», хотя сервер ничего по нему не обещал.

Разрыв потока — отдельное событие

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

Проверьте три случая на тестовой карточке: изменение при активном потоке, изменение во время разрыва и два быстрых изменения подряд. В первом случае должен сработать refetch после уведомления. Во втором свежий read после новой подписки. В третьем клиент может объединить несколько уведомлений в одно чтение, но итоговый текст должен соответствовать последней версии источника. Если сервер не объявляет subscribe, полагайтесь на срок свежести ответа и явный повторный read; не ждите уведомления, которого протокол не обещал.

Воспроизводимый тест не требует модели: в тестовом сервере resource возвращает строку price=100, затем после изменения источника price=120. Сразу после уведомления клиент должен показать состояние «обновляется» или не использовать старую цену для нового ответа. Когда повторный read завершился, ожидается price=120. После принудительного обрыва потока поменяйте цену на price=140, откройте подписку заново и убедитесь, что чтение после подтверждения вернуло 140 даже без уведомления за пропущенный период.

Когда меняется набор доступных карточек, это другое уведомление — notifications/resources/list_changed при объявленной возможности listChanged. После него обновляют resources/list, а не только содержимое одного URI. О сроках и области кэша самого ответа есть отдельный разбор MCP cacheScope.

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

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

  • AI Agent Integrations PRO: MCP ↗

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