MCP resource одного пользователя попал в ответ другого
Два сотрудника спрашивают агента о своих задачах. MCP-сервер отдаёт один URI crm://my/tasks, но содержимое зависит от токена пользователя. Шлюз запомнил первый ответ и вернул его второму сотруднику. URI совпал, а данные — чужие. Такой дефект легко пропустить в тестах, где запрос всегда делает один аккаунт.
Срок свежести и область доступа — разные признаки
В опубликованной редакции MCP 2026-07-28 результаты resources/read и других кэшируемых методов получают подсказки ttlMs и cacheScope. Первая говорит, сколько миллисекунд ответ можно считать свежим. Вторая определяет область совместного использования: public допускает общий кэш, private привязывает ответ к одному авторизационному контексту. Короткий TTL не делает персональный ответ публичным: в эти секунды другой сотрудник всё равно может получить чужой текст.
Для crm://my/tasks ставьте cacheScope: "private". На стороне клиента или шлюза ключ кэша включает сервер, метод, параметры запроса и стабильный идентификатор авторизационного контекста. Не кладите сырой bearer token в лог или ключ, который виден операторам; используйте внутренний разделитель доступа. При смене прав, выходе пользователя или отзыве доступа сбрасывайте соответствующие записи, даже если TTL не истёк. Сами подсказки сервера не создают безопасный кэш автоматически: решение и реализация находятся на стороне клиента.
Есть и более тонкий вариант утечки: ответ на resources/list содержит только URI без самих документов, но названия закрытых клиентов уже являются информацией. Если список фильтруется по правам, ему тоже нужен private. Для ключа кэша учитывайте не только пользователя, но и набор прав или его версию. Когда роль меняется с менеджера на стажёра, прежний персональный кэш менеджера нельзя обслуживать до истечения TTL.
Когда допустим public
Представьте docs://product/quickstart, одинаковый для всех пользователей и не зависящий от заголовков авторизации. Для него общий кэш с ненулевым TTL может снизить число чтений. Но проверьте не только содержимое, а и доступность ресурса: список resources/list может зависеть от выданных прав, даже если отдельные публичные страницы одинаковы. Один неверный public на списке раскроет названия закрытых ресурсов.
Тестируйте парой аккаунтов A и B. Сначала A читает crm://my/tasks, затем B читает тот же URI через тот же шлюз. B должен увидеть только свои задачи; повтор A в пределах TTL может взять его собственный кэш. Затем измените права B и убедитесь, что старый ответ больше не используется. Для открытой документации проверьте противоположный сценарий: оба аккаунта получают один и тот же текст, а общий кэш действительно сокращает обращения к серверу.
Запишите в тесте источник каждого ответа: origin или cache, но без токенов и содержимого чужих задач в логах. Тогда ошибка видна сразу: если B получил запись из кэша A, проблема в разделении ключей; если шлюз обратился к серверу и всё равно получил задачи A, ищите потерю авторизации на прокси-слое. Эти две причины требуют разных исправлений и не должны маскироваться одним тестом «текст оказался неверным».
Если ресурс меняется до окончания TTL, клиенту может помочь подписка на его обновления. Она решает свежесть, а cacheScope — изоляцию данных; в рабочей интеграции нужны оба решения.
В платном курсе AI Agent Integrations PRO: MCP вы собираете сервер и клиент, описываете resources, права доступа и тесты интеграции. Проверка двух аккаунтов на одном URI даёт простой критерий, что контекст клиента не смешивается на пути к модели. Откройте программу курса, чтобы пройти этот путь на практическом MCP-сервисе.
Продолжить на практике
- AI Agent Integrations PRO: MCP ↗
Вы уже работали с LLM и понимаете, что подключать их к реальным системам — больно. MCP — это стандарт, который делает эту боль меньше: один контракт вместо десятка костылей, типизированные инструменты вместо голого доступа к базе, тесты и логи вместо молитв. На курсе соберём сервер с нуля и выведем в production-контур.
