# Проектирование MCP-инструментов Этот документ описывает, как делать REST-инструменты, с которыми LLM-клиент работает предсказуемо. ## Главная идея Хороший инструмент решает одну понятную задачу. Модель должна легко понять: - когда вызывать инструмент; - какие параметры нужны; - что считается успешным результатом; - что делать при ошибке. Плохой инструмент обычно слишком общий: `call_api`, `manage_user`, `execute_request`. Такие названия и описания заставляют модель угадывать. ## Название и описание Имя инструмента должно быть техническим и стабильным: ```text get_customer_by_email create_support_ticket delete_draft_invoice ``` Описание должно начинаться с действия и объяснять сценарий: ```text Получает карточку клиента по email. Используйте, когда нужно найти клиента перед созданием обращения или проверкой статуса заказа. Возвращает идентификатор клиента, имя, email и текущий статус. ``` Не используйте расплывчатые формулировки: ```text Работает с клиентами. Обрабатывает данные. Выполняет запрос к API. ``` ## Входные параметры Каждый параметр должен иметь понятный смысл. Если значение выбирается из небольшого набора, лучше задать `enum`. Плохо: ```json { "action": "string", "data": "object" } ``` Хорошо: ```json { "email": "user@example.com", "include_orders": true } ``` Если endpoint делает несколько разных действий через параметр `action`, чаще всего лучше разделить его на несколько инструментов. ## Ответ инструмента Не отдавайте модели весь ответ внешнего API без необходимости. Лучше выбрать только поля, которые нужны для следующего шага рассуждения. Плохо: ```json { "response": "{ весь JSON от внешнего API }" } ``` Хорошо: ```json { "customer_id": "cus_123", "status": "active", "open_orders_count": 2 } ``` Для массивов ограничивайте размер ответа и возвращайте только важные поля. ## Ошибки Crank возвращает структурированные ошибки. MCP-клиент получает код ошибки, сообщение, признак повторяемости и рекомендацию. Пример: ```json { "error_code": "upstream_rate_limited", "message": "Внешний API вернул HTTP 429.", "recoverable": true, "suggested_action": "Повторите запрос позже.", "request_id": "req_123" } ``` Это лучше, чем отдавать сырой ответ внешнего API или stack trace. ## Повторное выполнение POST/PATCH Для операций, которые меняют состояние, используйте idempotency key. Это защищает от повторного создания сущности, если MCP-клиент повторит вызов после таймаута. Пример входа: ```json { "request_id": "order-2026-06-21-001", "customer_id": "cus_123", "amount": 1200 } ``` В конфигурации операции можно указать, что `request_id` используется как ключ идемпотентности и передается во внешний API через заголовок `Idempotency-Key`. ## Опасные операции Для `DELETE` Crank использует двухшаговое подтверждение. Первый вызов не отправляет запрос во внешний API. Он возвращает confirmation token: ```json { "error_code": "confirmation_required", "message": "Операция требует подтверждения. Повторите вызов с _crank_confirmation_token=\"ct_...\"." } ``` Второй вызов должен повторить те же аргументы и добавить токен: ```json { "order_id": "ord_123", "_crank_confirmation_token": "ct_..." } ``` Токен одноразовый, имеет короткий срок жизни и привязан к агенту, операции, версии и исходным аргументам. ## Каталог агента Не привязывайте к одному агенту весь API. Лучше создать несколько агентов под конкретные задачи: - агент для курсов валют; - агент для поддержки клиентов; - агент для заявок и инцидентов; - агент для отчетов. Если у агента слишком много похожих инструментов, модель чаще ошибается при выборе. ## Проверочный список - Имя инструмента конкретное и не похоже на `call_api`. - Описание объясняет, когда вызывать инструмент. - У каждого важного параметра есть понятное назначение. - Multi-action endpoint разделен на отдельные инструменты. - Ответ не содержит лишний большой JSON. - Для POST/PATCH задан idempotency key, если повторный вызов может создать дубль. - Для DELETE пользователь видит двухшаговое подтверждение. - Агенту привязаны только инструменты, нужные для его задачи.