# Описания инструментов MCP, которые предотвращают ошибки в production

Описание инструмента MCP может остановить небезопасный вызов в production еще до его начала, а может скрыть опасность за дружелюбным глаголом. Большинство случайных действий в production начинаются не с решения агента причинить вред. Обычно проблема возникает потому, что расплывчатое описание делает разрушающий инструмент похожим на инструмент для проверки.

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

Я просмотрел достаточно интерфейсов действий, чтобы не доверять ярлыкам вроде «manage», «sync», «deploy» и «cleanup». Для автора они удобны, но человеку, которому потом приходится объяснять, почему тестовый запрос попал в рабочий аккаунт, обходятся дорого. Хорошее описание не дает пропустить неудобные детали.

## Описание инструмента это предупреждение о выполнении, а не рекламный текст

Описания инструментов MCP должны сообщать агенту и его оператору, что произойдет после успешного вызова. Им не нужно рекламировать возможность, пересказывать устройство внутренней подсистемы или повторять имя инструмента более длинной фразой.

Схема инструментов Model Context Protocol включает понятное человеку поле `description` рядом с именем инструмента и `inputSchema`. Спецификация MCP также допускает аннотации инструментов, например `readOnlyHint` и `destructiveHint`. Эти аннотации помогают клиенту показывать инструменты, но спецификация требует считать их подсказками. Это не проверки разрешений. Поэтому описание остается местом, где оператор может прочитать реальное последствие до того, как вызов попадет в ваш сервис.

Сравните два определения:

```json
{
  "name": "delete_backup",
  "description": "Deletes a backup.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "backup_id": { "type": "string" }
    },
    "required": ["backup_id"]
  }
}
```

```json
{
  "name": "delete_production_backup",
  "description": "Permanently deletes one backup from the Production PostgreSQL backup store. This removes a recovery point and cannot be undone. Ask the user to confirm the backup ID and its timestamp before calling this tool.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "backup_id": {
        "type": "string",
        "description": "Immutable backup ID returned by list_production_backups."
      }
    },
    "required": ["backup_id"],
    "additionalProperties": false
  },
  "annotations": {
    "destructiveHint": true,
    "readOnlyHint": false
  }
}
```

Второе определение не просто звучит осторожнее. Оно сообщает агенту цель, необратимый результат, безопасный способ идентифицировать объект и обязательную паузу в разговоре. Рецензент тоже получает достаточно информации, чтобы отклонить вызов, не разбираясь сначала в деталях реализации.

Не считайте, что проблему решает один выразительный глагол. «Destroy» предупреждает лучше, чем «delete», но все равно ничего не говорит о том, какой аккаунт затронут, какие данные удаляются и как инструмент обрабатывает подтверждение. Именно описание должно дать этот контекст.

## Укажите целевую систему в первом предложении

В первом предложении нужно назвать точную затрагиваемую систему, включая среду или границу аккаунта. «База данных» может означать временный локальный контейнер, общий тестовый сервис, staging-тенанта или рабочий реестр клиентов. Это разные действия, даже если API-эндпоинт у них один.

Используйте названия, которые оператор узнает из своей работы. Скажите «Production payments account», «staging Kubernetes cluster», «customer tenant `northwind`» или «repository `mobile-api` release branch». Не используйте внутренние прозвища, если их знают не все предполагаемые операторы и если это имя не появляется в аргументах.

Хорошо работает такой порядок, потому что он ставит риск перед механикой:

```text
[Целевая система]. [Действие и результат]. [Правило подтверждения].
```

Например:

```text
Production identity directory. Disables the selected user account and ends active sessions. Ask the user to confirm the username before calling.
```

Цель должна соответствовать обработчику, а не намерениям автора. Если инструмент принимает аргумент `environment`, описание «Updates staging» становится ложным, как только вызывающая сторона передает `production`. Разделите операцию на отдельные инструменты для разных сред или прямо укажите, какие значения допускает аргумент.

Разделение обычно упрощает работу:

```text
list_staging_feature_flags
set_staging_feature_flag
list_production_feature_flags
request_production_feature_flag_change
```

Такая схема может показаться избыточной. Повторение дешевле, чем ситуация, когда селектор инструментов решает, что `set_feature_flag` подходит, а позже выясняется, что необязательный аргумент указывал на production.

Такая же дисциплина нужна именам, но имена не могут вместить все предупреждение. Списки инструментов обрезают названия. При выборе между похожими именами агенты иногда ориентируются на описание. Люди под давлением просматривают и то и другое. Добавляйте цель и в имя, и в описание, когда это уместно, а само описание делайте полным, даже если имя исчезнет с экрана.

Есть одно исключение: инструмент получает неизменяемый URI ресурса, хост которого уже фиксирует среду. Даже тогда укажите в описании хост или класс аккаунта. UUID не говорит человеку, обозначает ли он запись разработки или данные действующего клиента.

## Описывайте побочный эффект как завершенный результат

Безопасное описание говорит читателю, каким станет мир после успешного вызова. Это заставляет автора отличать наблюдение от изменения, обратимое изменение от постоянного и запрос от его выполнения.

Сравните расплывчатый глагол «manage»:

```text
Manages service deployments.
```

За ним скрываются совершенно разные результаты. Инструмент развертывания может создать релиз, продвинуть существующий релиз, перезапустить экземпляры, изменить распределение трафика, откатить код или только получить статус. Для каждой операции нужен отдельный инструмент, если у нее свой сценарий сбоя или свое правило одобрения.

Используйте явный результат:

```text
Creates a deployment request for the Production catalog service. It does not change running instances. A release manager must approve the request in the deployment system.
```

Или:

```text
Changes Production catalog traffic so the specified release receives 100 percent of requests. Existing requests may finish on the prior release. Ask the user to confirm the release version before calling.
```

Разница между созданием запроса и его выполнением важнее разницы между HTTP `POST` и `PATCH`. Объект запроса все равно может создать работу, израсходовать квоту или отправить уведомления, поэтому опишите и этот побочный эффект. Но не называйте это рабочим развертыванием, если инструмент лишь открывает задачу на согласование.

Избегайте эвфемизмов. «Retires» может означать архивирование, отключение, удаление или прекращение тарификации. «Cleans up» может означать удаление временных файлов или удаление единственной сохраненной копии клиентского экспорта. Пишите настоящий глагол и объект: удаляет, отключает, заменяет, продвигает, передает, отправляет, списывает или публикует.

Для операций с отложенным эффектом укажите задержку. Изменение DNS может распространиться после ответа API. Удаление пользователя может прекратить будущий доступ, сохранив записи аудита. Ротация учетных данных может отключить клиентов, которые все еще используют старый секрет. Агенту нужен этот контекст, чтобы решить, следует ли сначала проверить зависимые системы.

В описаниях также нужно указывать существенный масштаб, если один вызов затрагивает много объектов. «Удаляет выбранную запись» отличается от «Удаляет все записи, соответствующие переданному запросу». Пакетный эндпоинт, спрятанный за глаголом в единственном числе, почти неизбежно создает проблемы.

## Формулировка подтверждения должна описывать реальный контроль

Предложение о подтверждении полезно только тогда, когда реализация и рабочий процесс его соблюдают. Написать «требует подтверждения» для инструмента, обработчик которого запускается сразу, значит создать видимость контроля. Рано или поздно агенты это обнаружат.

Есть три разных подхода, и описание должно называть именно тот, который вы используете.

1. Агент спрашивает пользователя в своем диалоге, а затем вызывает действие. Это зависит от того, следует ли агент описанию, и не остановит измененный или небрежный клиент.
2. Инструмент создает запрос, который должен одобрить отдельный человек или система. Сам вызов имеет побочный эффект, но описанное изменение в production ждет одобрения.
3. Шлюз выполнения приостанавливает действие и требует подтверждения человека до передачи учетных данных или обращения к целевой системе.

Не сводите эти варианты к словам «требуется подтверждение». Они дают разный уровень защиты и разные аудиторские свидетельства.

Используйте глаголы, которые указывают исполнителя и момент действия:

```text
Before calling, ask the user to confirm the repository name and release tag.
```

```text
Calling this tool submits a change request. The deployment system requires a release manager to approve it before any production release begins.
```

```text
This action gateway asks a human to approve every call before it sends the request to the Production payments API.
```

Последняя формулировка описывает принудительно установленную границу. Первая описывает инструкцию для агента. Обе могут быть уместны, но они не равноценны.

Никогда не просите агента получить расплывчатое подтверждение. Скажите, какие факты человек должен проверить. Для удаления это могут быть имя ресурса, аккаунт и срок хранения. Для перевода, источник, получатель, сумма и валюта. Для релиза, сервис, версия и охват трафика. Описание должно запрашивать не ритуал, а факты, которые помогают обнаружить неверную цель.

У правила подтверждения также должна быть область действия. «Получите одобрение перед изменениями в production» звучит слабо, если одна сессия может выполнить десять вызовов после единственного одобрения. Если реальный контроль одобряет процесс на весь срок его работы, укажите это в документации и не заявляйте, что каждый вызов отдельно приостанавливается.

## Заявления о режиме только для чтения не работают, если обработчики выполняют скрытую работу

Называйте инструмент доступным только для чтения, если его обработчик намеренно не изменяет целевую систему. Это слово описывает поведение, а не HTTP-метод, название разрешения в базе данных или надежды автора.

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

Аннотация MCP `readOnlyHint` полезна клиенту, который хочет упростить работу с инструментами для проверки. Но это все равно подсказка, поэтому сервер должен сам обеспечить границу. Еще важнее, чтобы описание сообщало об исключениях, которые могут удивить оператора.

Это описание вводит в заблуждение:

```text
Read-only tool for checking invoice status.
```

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

```text
Retrieves the current status of one Production invoice. It does not edit the invoice or charge the customer. The billing provider records this request in its access log.
```

Журнал доступа обычно допустим для операции просмотра. Он становится существенным, если для цели действуют требования соответствия, взимается плата за получение данных или рабочий процесс реагирует на чтение. Укажите такие эффекты, но не превращайте каждое описание в юридическое уведомление.

По возможности разделяйте пробный режим и выполнение. Инструмент `deploy` с логическим параметром `dry_run` создает две модели безопасности в одном определении. Агент может не передать значение по умолчанию, неправильно понять, учитывает ли его сервер, или повторно использовать запрос без изменения параметра. Имена `plan_production_deployment` и `execute_production_deployment` делают различие видимым при выборе инструмента, в журналах и при проверке.

То же правило относится к инструментам проверки. «Validate configuration» звучит безопасно, но некоторые провайдеры выделяют ресурс или обращаются к действующей зависимости во время проверки. Если это происходит, опишите инструмент как действие и примените соответствующее правило подтверждения.

## Один широкий инструмент создает ошибки при одобрении

Группируйте операции по общему последствию и границе одобрения, а не ради удобства одного API-клиента. Универсальный инструмент администрирования превращает описания в каталог исключений, который ни модель, ни человек не будут надежно читать.

Избегайте такой схемы:

```json
{
  "name": "admin",
  "description": "Administer users, deployments, secrets, and configuration across environments.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "operation": { "type": "string" },
      "environment": { "type": "string" },
      "payload": { "type": "object" }
    },
    "required": ["operation", "environment", "payload"]
  }
}
```

Такое определение уничтожает полезную единицу проверки. По карточке инструмента рецензент не поймет, получает ли вызов статус, ротирует учетные данные или удаляет пользователя. Строка `operation` переносит важный смысл в поздний аргумент, который легко не заметить.

Вместо этого разделите инструменты по назначению и риску:

```text
get_production_deployment_status
plan_production_deployment
submit_production_deployment_request
rotate_production_service_credential
create_production_user_access_request
```

Не нужен отдельный инструмент для каждого эндпоинта. Разделяйте инструменты там, где меняется цель, побочный эффект или требование подтверждения. Пакетный инструмент может остаться пакетным, если он всегда работает с одним ограниченным типом ресурсов и требует одного и того же одобрения. В описании нужно сказать, что он может затронуть несколько объектов, и показать, как вызывающая сторона ограничивает выборку.

Описания нужны и аргументам. Описание инструмента говорит, что делает операция, а описания аргументов ограничивают опасные варианты. Где возможно, используйте перечисления для сред и типов действий. Отклоняйте неизвестные значения на стороне сервера. Не помещайте «production» в свободную строку, рассчитывая, что описание вас спасет.

Узкий инструмент также создает более понятные записи аудита. Если в журнале написано `rotate_production_service_credential`, исследователь понимает класс действия еще до просмотра аргументов. Если там написано `admin`, намерение придется восстанавливать по содержимому запроса.

## Составляйте описание до обработчика

Подготовка операционного контракта до реализации выявляет расплывчатые требования, пока изменение интерфейса еще дешево. Если вы не можете одним простым предложением описать завершенный результат, граница инструмента пока не определена.

Для каждого инструмента действия используйте такой порядок проверки:

1. Опишите цель так, как ее назвал бы оператор, включая среду, аккаунт или тенанта.
2. Опишите завершенный результат буквальным глаголом и укажите, можно ли отменить изменение.
3. Назовите того, кто подтверждает действие, момент одобрения и область действия подтверждения, один вызов или одна сессия.
4. Сравните предложение с поведением обработчика, значениями по умолчанию, повторами и последующими API-вызовами.
5. Добавьте описания аргументов для идентификаторов, ограничителей области и всех значений, меняющих цель.

Четвертый пункт обнаруживает ошибки, которые не видны в отполированной документации. Из-за повторов списание или отправка сообщения может произойти дважды, если последующий запрос не использует механизм идемпотентности. Значение по умолчанию может превратить пропущенный `environment` в production. Обработчик может сопоставить понятное имя с несколькими ресурсами. Описание не исправит ошибки реализации, но его написание заставит вывести их на поверхность.

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

Проверьте и обычные языковые запросы. «Удали старые данные», «сделай новую версию рабочей» и «исправь аккаунт Jordan» это именно те формулировки, из-за которых широкий инструмент кажется удобным. Безопасный агент сначала выберет инструмент просмотра, запросит недостающий идентификатор или покажет конкретное действие для подтверждения. Если он может сразу перейти от такого запроса к удалению в production, ошибка начинается в дизайне интерфейса задолго до появления вопроса о поведении модели.

## Сообщения об ошибках и результаты должны сохранять границу безопасности

Внимательное описание теряет большую часть ценности, если результат инструмента скрывает фактическую цель или ошибка предлагает агенту попробовать более широкое действие. Возвращайте достаточно данных, чтобы агент и оператор могли проверить результат.

После успешного изменения состояния возвращайте канонический идентификатор цели, выполненное действие и новое состояние. Не отвечайте одним `ok`.

```json
{
  "status": "completed",
  "target": {
    "environment": "production",
    "service": "catalog",
    "release": "2025.06.14-3"
  },
  "action": "traffic_promoted",
  "traffic_percent": 100,
  "request_id": "relreq_8a2f"
}
```

Если действие приостановлено до одобрения, скажите, что до цели ничего не дошло. Это различие не дает агенту компенсировать вызов, который только ждет человека.

```json
{
  "status": "approval_required",
  "action": "rotate_production_service_credential",
  "target": "production/catalog-api",
  "executed": false,
  "approval_scope": "this call"
}
```

Ошибки требуют такой же точности. «Forbidden» технически верно, но практически бесполезно. Укажите, отклонена ли цель, недопустима ли среда, отсутствует ли одобрение или запрос завершился ошибкой уже после обращения к удаленной системе. Не раскрывайте в объяснении секреты и никогда не советуйте агенту вслепую повторять запрос, меняющий состояние.

Для действий, значимых во внешней системе, результат должен явно поддерживать идемпотентность. Если после сетевого тайм-аута удаленный сервис принял перевод или создал релиз, агент должен проверить статус запроса по стабильному идентификатору. Повторный вызов не должен строиться на догадке. Описание не может выразить все правила повторов, но у инструмента с необратимыми действиями должен быть связанный инструмент проверки статуса и формат результата, поддерживающий восстановление.

## За описанием должны стоять механизмы принуждения

Понятный язык снижает число неправильных выборов, но не остановит процесс, у которого уже есть неограниченный production-токен. Поместите учетные данные и финальный сетевой вызов за границу, которая может отклонить, одобрить и записать вызов.

Sallyport использует такую схему для агентов, подключенных к MCP: агент работает через встроенный shim `sp mcp`, а приложение хранит API- и SSH-учетные данные в зашифрованном хранилище и само выполняет одобренные действия. Авторизация на сессию и необязательное подтверждение ключа при каждом вызове превращают формулировку о подтверждении в реально исполняемое поведение, а не в просьбу о внимательности.

Это не оправдывает слабый дизайн инструментов. Шлюз видит только тот вызов, который до него дошел. Схема инструмента все равно определяет, написано ли в запросе «удали эту production-резервную копию» или удаление спрятано за общей операцией `admin`. Проверяйте аргументы в обработчике, ограничивайте учетные данные нужной целью, если удаленная система это позволяет, и храните запись аудита с указанием процесса и действия.

Рекомендации Model Context Protocol по авторизации говорят о том же на другом уровне: авторизация должна быть частью протокольного потока с явными проверками, а не инструкцией для модели. Считайте описания понятным человеку контрактом. Авторизацию сервера, хранение учетных данных и подтверждение рассматривайте как механизмы, которые делают этот контракт правдивым.

Возьмите самый опасный инструмент, который вы сейчас предоставляете, и перепишите его описание, не глядя на имя. Если вы не можете назвать production-цель, завершенный побочный эффект и область действия подтверждения в двух или трех прямых предложениях, пока не предлагайте этот инструмент автономному агенту.
