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