
Durin изнутри: как проходит управляемый запрос MCP
Проследите путь одного вызова инструмента агентом через Durin: от аутентифицированного запроса и проверок доступа до согласования, работы с учётными данными и зафиксированного результата.
Коротко о решении
Durin рассматривает вызов инструмента агентом как запрос, который нужно оценить, а не как указание к исполнению. Шлюз подтверждает, кто обращается, среда выполнения организации повторно проверяет текущие права доступа и политику, отдельный брокер добавляет авторизацию пользователя у провайдера, а каждое изменение фиксируется до и после попытки его выполнения. Полагайтесь на этот путь для запросов, которые проходят через Durin, и сохраняйте отдельные меры контроля для прямого доступа, провайдеров моделей и прав доступа у провайдеров.
Граница проходит по вызову инструмента
Допустим, инженер просит агента для работы с кодом завести тикет о падающем тесте. Подготовить черновик тикета модели нетрудно. Но создать его — значит вызвать инструмент в реальной системе от имени реальной учётной записи и оставить изменение, которое увидят другие люди. Durin рассматривает такой вызов как запрос, решение по которому принимает рабочая область, а не как указание, которое нужно выполнить.
Durin находится между клиентами агентов и системами, подключёнными к рабочей области. Модель и работа, которую агент выполняет в собственной среде, например чтение локальных файлов, запуск тестов или редактирование кода, остаются на стороне клиента. Durin не размещает и не обучает модели. Он контролирует вызовы инструментов, которые поступают к нему через конечную точку Durin, например поиск документов, чтение тикета, создание задачи или отправку сообщения.
Каждый пользователь подключается через собственную конечную точку. Персональный URL охватывает все доступные ему подключения, а URL подключения ограничивает клиент одним из них. URL — это адрес, а не пароль. Клиент входит в Durin через OAuth для этого адреса, после чего Durin определяет ожидаемый адрес по подтверждённой личности и отказывает при несовпадении. Клиенту никогда не нужен токен провайдера.
За конечной точкой каждое подключение представляет одну одобренную систему: размещённый провайдером сервер MCP или сервер MCP, которым управляет ваша организация. Встроенная песочница Durin — третий вид. Она отвечает синтетическими документами и тикетами изнутри Durin и никогда не обращается к внешнему провайдеру. На все эти подключения распространяются одни и те же проверки.
Клиент агента и его модель остаются вне Durin и отправляют вызов инструмента с токеном OAuth, выданным именно для этой конечной точки. Шлюз проверяет токен и определяет организацию. Подписанный запрос, действительный в течение 30 секунд, передаёт вызов в среду выполнения организации, которая повторно проверяет текущие права доступа, применяет политику и согласование и фиксирует намерение до отправки. Брокер учётных данных получает подписанный запрос, привязанный именно к этому вызову, ещё раз проверяет решение и добавляет токен пользователя у провайдера. Сервис исходящих запросов отправляет вызов на удалённый сервер MCP по HTTPS через публичную сеть, без перенаправлений и повторов. Результаты возвращаются клиенту, а токены провайдеров — нет. Прямой доступ к провайдеру никогда не проходит через Durin.
Открыть полноразмерную фигуру: Вызов инструмента проходит через шлюз, среду выполнения организации, брокер учётных данных и сервис исходящих запросов, прежде чем попасть на удалённый сервер MCP.Поиск инструментов без расширения доступа
Прежде чем вызвать инструменты, агент должен их обнаружить. Стандартный запрос tools/list постранично возвращает инструменты провайдера, доступные пользователю. Для больших каталогов Durin добавляет три инструмента обнаружения: durin_list_connections находит нужное подключение, durin_list_tools позволяет просматривать краткие описания разрешённых инструментов с необязательным текстовым запросом, а durin_describe_tools возвращает проверенные схемы не более чем для пяти точно указанных имён. Четвёртый, durin_call_tool, запускает инструмент по имени с его аргументами и ключом идемпотентности.
Обнаружение учитывает права доступа, но само по себе доступом не является. Инструменты, которые текущая политика заблокировала бы, в список не попадают. Инструменты, которые требуют согласования или результат по которым зависит от ресурса, указанного в вызове, всё равно отображаются, потому что решение зависит от конкретного запроса. Если что-то недоступно, ответ сообщает, чего не хватает: входа, согласия, согласования или разрешения политики, — не раскрывая определение заблокированного инструмента. URL подключения ограничивает обнаружение и вызовы своим подключением, и никакой фильтр не может расширить эту область.
Каждый вызов заново оценивается при поступлении, потому что с момента получения списка могли измениться членство, политика или подключение. Инструкции Durin для клиентов говорят об этом прямо: никогда не придумывать имена инструментов, спрашивать, какое подключение использовать, если подходят несколько, и рассчитывать на то, что каждый вызов будет проверен заново.
Один вызов, шаг за шагом
Вот что происходит, когда клиент вызывает инструмент для работы с тикетами. Каждый шаг выполняется в сервисе с узкой задачей, а каждая передача вызова подписывается для сервиса, который его получает.
- Шлюз аутентифицирует вызывающую сторону. Он проверяет подпись, издателя и аудиторию токена доступа OAuth, а затем запрашивает у поставщика удостоверений, активен ли ещё токен и какому клиенту он выдан. Это происходит при каждом запросе, без кеширования. Имя, которое клиент сообщает о себе, и любая роль, записанная в токене, не участвуют в установлении личности.
- Шлюз определяет организацию по установленной личности и никогда — по организации, указанной в заголовке или теле запроса. Среда выполнения организации подтверждает, что пользователь является активным участником, и сообщает его текущую роль.
- Шлюз передаёт вызов этой среде выполнения в виде подписанного внутреннего запроса. В нём указаны организация, окружение, пользователь, роль, клиент и операция, а срок его действия истекает через 30 секунд. Среда выполнения отклоняет запрос, выданный для другой организации, окружения или операции.
- Среда выполнения повторно проверяет текущие права доступа по собственным записям, а не по токену: членство и отзыв доступа, состояние подключения и его доступность командам, авторизацию пользователя у провайдера, проверенный инструмент и ресурс, на который направлен вызов. Аргументы должны соответствовать проверенной схеме инструмента и пройти проверку содержимого. При сбое любой из этих проверок запрос отклоняется.
- Среда выполнения применяет правила рабочей области. По умолчанию запрос, прошедший эти проверки, разрешается, в том числе если это изменение. Администраторы могут требовать, чтобы изменения согласовывал другой администратор, запрещать изменения или запрещать любой доступ. Политики команд и пользовательские правила могут сделать решение строже, но никогда не мягче.
- Для разрешённого вызова среда выполнения фиксирует намерение и передаёт вызов брокеру учётных данных, который ещё раз сверяет решение с текущими записями, прежде чем обратиться к провайдеру.
- Среда выполнения фиксирует итог и возвращает клиенту результат.
Аутентификация и авторизация на всём пути остаются раздельными. Действительный токен устанавливает, кто обращается, но не решает, вправе ли этот человек сделать этот вызов сейчас. Это решает среда выполнения в момент вызова на основе записей, которые она контролирует.
Внутри среды выполнения для каждой организации и окружения есть один координирующий объект — Cloudflare Durable Object, — который обрабатывает эти запросы по одному. Поэтому решение, одобрение, изменение политики и отзыв доступа не могут накладываться друг на друга. Если политика изменится во время оценки вызова, вызов останавливается с конфликтом, и ничего не фиксируется как разрешённое.
Проверенные инструменты, а не всё, что сервер предлагает сегодня
Сервер MCP может в любой момент изменить свои инструменты, включая их описания и входные схемы. Когда администратор проверяет инструмент, Durin фиксирует дайджест его определения. При проверке также определяется, читает инструмент данные или изменяет их, с какими ресурсами он может работать и где эти ресурсы указываются в его аргументах. Durin не полагается на собственную подсказку сервера о том, что инструмент предназначен только для чтения, а вновь обнаруженный инструмент остаётся неактивным, пока не пройдёт проверку.
Если при последующем обнаружении возвращается другое определение, Durin создаёт новую версию, требующую проверки, приостанавливает активную и отзывает её незавершённые согласования. Пользователь, у которого собственное обнаруженное определение больше не совпадает с проверенным, получает отказ. Вызовы инструмента, не прошедшего проверку, получают отказ, а имя такого инструмента не предлагается клиенту как доступное для вызова.
Каждому активированному инструменту также нужен валидатор аргументов. Для простых схем Durin создаёт его во время проверки; инструмент, схема которого для этого слишком сложна, можно активировать только после появления отдельно подписанного валидатора. При отправке брокер берёт имя инструмента на удалённом сервере и его схему из записи, сохранённой при проверке, а не из запроса клиента.
Кроме того, при проверке аргументы сопоставляются с ресурсами. Администратор указывает до четырёх полей во входных данных инструмента, и Durin объединяет их значения, например владельца и репозиторий, в ресурс, на который ссылаются правила. Вызов, ресурс которого не входит в список разрешённых для инструмента, получает отказ, а отсутствующее значение не даёт совпадения.
Одобрение привязано к одному конкретному вызову
Если правила требуют согласования, вызов возвращает статус «Требуется одобрение», и на удалённый сервер ничего не отправляется. Другой активный администратор, но никогда не сам инициатор, открывает запрос в разделе «Согласования» или, если это настроено, в Slack. Он видит инициатора, подключение, инструмент, ресурс, дайджест аргументов, версии и срок действия, а затем выбирает «Разрешить один раз», «Разрешить всегда» или «Запретить».
Одобрение не запускает действие. Инициатор повторно отправляет точно такой же вызов с тем же ключом идемпотентности и ссылкой на одобрение до истечения срока действия одобрения, то есть в течение 15 минут после исходного запроса. Среда выполнения ещё раз проверяет текущие права доступа, расходует разрешение, фиксирует решение и закрепляет за вызовом единственную попытку. Если членство было отозвано, политика изменилась или аргументы отличаются, прежнее одобрение не может авторизовать вызов.
| Часть запроса | Зачем нужна привязка |
|---|---|
| Инициатор и организация | Другой человек не может воспользоваться разрешением. |
| Подключение и учётные данные | Разрешение нельзя перенести на другую учётную запись. |
| Версия инструмента, дайджест определения и сопоставление с ресурсами | Изменённому инструменту нужна новая проверка. |
| Дайджест аргументов и ресурс | Другой заголовок или другая цель — это другое действие. |
| Версии схемы и политики | Публикация новых правил аннулирует незавершённые согласования. |
| Эпоха отзыва доступа инициатора | Потеря и повторное получение доступа не возвращают в силу старое разрешение. |
| Одно выполнение до истечения срока действия | Разрешение расходуется на одну попытку. |
Когда проверяющий сохраняет решение
Когда приходится рассматривать каждый повтор рутинного изменения, люди привыкают одобрять, не читая. Вариант «Разрешить всегда» решает эту проблему в узких рамках. Пока включено сохранение решений (по умолчанию оно включено), этот вариант сохраняет постоянное разрешение, которое действует 30 дней, если организация не выберет другой срок. Тогда последующий запрос может пройти без нового согласования, если он поступает от того же инициатора для того же подключения, инструмента и ресурса, все привязанные версии не изменились, а его аргументы идентичны или достигают порога совпадения, заданного организацией (по умолчанию 90 процентов).
Степень совпадения рассчитывается по необратимому сжатому представлению аргументов с солью, никогда не по самим аргументам, и одинаковые входные данные всегда дают одинаковую оценку. Всё, сходство чего это представление не позволяет подтвердить, считается новым. Решение «Разрешить один раз» никогда не распространяется на последующие запросы: оно лишь показывается следующему проверяющему как прецедент.
Постоянное разрешение по-прежнему проходит через все текущие проверки доступа, а брокер перепроверяет его, как и любое другое одобрение. Его действие досрочно прекращают изменение политики, отзыв доступа у инициатора или проверяющего, отключение сохранения решений либо отзыв администратором. Администраторы видят каждое сохранённое решение и каждый случай его использования в разделе «Согласования» → «Память».
Токены провайдеров не попадают к агенту
Для подключений к провайдерам Durin обращается к провайдеру с собственной авторизацией пользователя, отправившего запрос. Каждый пользователь входит в систему провайдера через Durin для каждого подключения, которым пользуется, поэтому согласие коллеги никогда не расширяет доступ других людей. Токены хранятся в зашифрованном виде с использованием AES-256-GCM. Организация, окружение, подключение и пользователь привязываются к каждой записи как аутентифицированные данные, поэтому запись нельзя расшифровать как чужую. Во время ротации ключей связка может содержать до пяти ключей: самый новый шифрует новые записи, а любой ключ из списка может расшифровать существующие.
Эти токены использует только брокер учётных данных. Это отдельный сервис, который может вызывать только среда выполнения организации — через подписанный запрос, привязанный к точному телу вызова и действительный в течение 30 секунд. Прежде чем обратиться к провайдеру, брокер заново читает текущие записи и повторно выносит решение по политике. Для изменения он также требует зафиксированное намерение, неизменную эпоху отзыва и ту же версию учётных данных. Затем он сам добавляет токен. Ни одна конечная точка не возвращает токен среде выполнения, клиенту или модели.
Вызовы к серверам MCP, размещённым у провайдеров, и к пользовательским серверам MCP выходят через единый сервис исходящих запросов. Он принимает только HTTPS-запросы к публичным именам хостов, отклоняет перенаправления, ограничивает методы и заголовки, а также размер запросов и ответов. Каждый вызов жёстко привязан к проверенной конечной точке подключения и выполняет один tools/call без автоматических повторов.
То, что токены не попадают в контекст модели, ещё не делает результаты безвредными. Всё, что возвращает разрешённый инструмент, может попасть к клиенту и его провайдеру модели. Durin удерживает каждый результат, пока тот не будет сверен с проверенной схемой и не пройдёт проверку содержимого, но эта проверка ищет распространённые форматы секретов, например закрытые ключи и действующие токены API, а не все виды конфиденциальных данных. Держите области доступа у провайдера узкими. Одобрение в Durin никогда не расширяет того, что разрешено самой учётной записи у провайдера.
Изменение выполняется не более одного раза
Агенты повторяют запросы, а сети теряют ответы. Дважды созданный тикет — неприятность, а дважды отправленное сообщение или платёж — уже хуже. Durin устроен так, что один разрешённый запрос приводит не более чем к одной попытке.
- Каждый вызов содержит ключ идемпотентности, выбранный клиентом. Повторный запрос с тем же ключом сначала снова оценивается. Если изменились аргументы, инструмент или учётные данные, он отклоняется как конфликт. В противном случае возвращается «Дубликат» с прежним статусом, и ничего не отправляется.
- Прежде чем обратиться к провайдеру, среда выполнения в одной транзакции создаёт запись о выполнении и запись в журнале аудита. Если записать их не удаётся, вызов останавливается. Брокер отклоняет любое изменение, для которого нет такого зафиксированного намерения.
- Каждое изменение защищено единственным закреплением отправки, привязанным к выполнению. Повторная доставка того же запроса не может закрепить отправку снова.
- Durin фиксирует статус «Завершено», только когда брокер возвращает результат, прошедший проверку содержимого. Ошибка провайдера, тайм-аут, отсутствие финального события или результат, не прошедший проверку содержимого, фиксируются со статусом «Неопределённо».
Разрешённое изменение содержит ключ идемпотентности, выбранный клиентом. Сначала среда выполнения в одной транзакции создаёт запись о выполнении и запись в журнале аудита; если записать их не удаётся, ничего не отправляется. Затем она один раз закрепляет отправку, поэтому повторная доставка не может закрепить её снова. Брокер заново читает текущие записи и обращается к провайдеру один раз, без автоматических повторов. Фиксируется статус «Завершено», если результат получен и прошёл проверку содержимого, или «Неопределённо» после ошибки, тайм-аута или неудачной проверки содержимого. Повтор с тем же ключом возвращает «Дубликат» для неизменённого запроса и конфликт для изменённого; ни в одном из случаев ничего не отправляется.
Открыть полноразмерную фигуру: Для разрешённого изменения фиксируется намерение и закрепляется одна отправка; оно завершается со статусом «Завершено» или «Неопределённо».Изменение с неопределённым результатом никогда не повторяется автоматически, потому что оно, возможно, уже произошло. Клиенту сообщается, что перед повторной попыткой нужно изучить запись, а кому-то следует проверить состояние у провайдера и данные аудита, прежде чем отправлять новый запрос. Принудительная новая попытка с новым ключом идемпотентности может продублировать уже выполненное действие. Для операции чтения начать заново с новым запросом обычно безопасно.
Что фиксирует Durin и что остаётся за его пределами
Durin фиксирует решение по политике и результат выполнения отдельными записями в журнале аудита, допускающем только добавление. Триггеры базы данных отклоняют любое обновление или удаление, и ни один путь в коде не перезаписывает запись. В записях указываются пользователь, клиент, подключение, инструмент, ресурс, решение и причина, а также дайджест аргументов вместо самих аргументов. На пути вызова содержимое запросов и результатов не сохраняется.
Durin не видит диалог в клиенте. Клиент с соответствующей интеграцией может передавать сообщения, которые он фактически наблюдал, через отдельную конечную точку захвата; они связываются с выполнениями этого клиента и помечаются как «По данным клиента». При захвате сохраняются только метаданные, если администратор не включит захват с маскированием данных. Если администратор подключил внешний сервис оценки контента, этот сервис получает проверяемые им аргументы или результаты; он может сделать решение строже, но никогда не мягче.
За пределами этого пути остаются три вещи. Запросам, которые попадают к провайдеру в обход Durin, нужны собственные меры контроля, например сетевые ограничения или ограничения на уровне идентификации. Ваш провайдер модели получает всё, что отправляет ему клиент, включая результаты инструментов. И наконец, собственные права доступа провайдера остаются определяющими: Durin может ограничить то, что агент делает через подключение, но никогда не расширить.
Чтобы увидеть этот путь своими глазами, запросите песочницу Durin в рабочей области и выполните одну операцию чтения. Затем попросите администратора включить обязательное согласование изменений, создайте синтетический тикет и проследите его путь от статуса «Требуется одобрение» до зафиксированного результата. В наборе для оценки перечислены те же тесты для сравнения любых шлюзов.