- BrainTools - https://www.braintools.ru -
Меня зовут Рома, я backend-разработчик в ЮMoney. Почти 10 лет наша команда занимается в том числе развитием публичного платежного API. Недавно мы запустили MCP-сервер (Model Context Protocol), который позволяет нейросетям (LLM) напрямую работать с платежами и счетами.
В процессе разработки и отладки мы быстро поняли, что проектирование API для языковых моделей кардинально отличается от привычной REST-архитектуры. В этой статье я хочу поделиться полученным опытом [1] и мыслями. Технических деталей создания MCP-сервера здесь не будет: их в интернете и так хватает. Статья будет интересна разработчикам и архитекторам, которые планируют создавать публичные или внутренние MCP-серверы.
Забегая вперёд, скажу: мы будем развивать функционал дальше и даже планируем провести публичный онлайн-хакатон. Подпишитесь на наш канал, чтобы не пропустить анонс.
1. Динамическая схема вместо обратной совместимости
В классическом API мы привыкли фиксировать контракты в пределах мажорной версии, то есть соблюдать обратную совместимость. В MCP понятия статической версии, по сути, нет. Список функций обновляется «на лету» через механизм динамической регистрации (tools/list), а модель считывает актуальную схему перед каждым вызовом. Получается, что LLM каждый раз заново интегрируется с API по схеме, полученной в tools/list.
Однако хочу заметить, что удобство отказа от обратной совместимости API иллюзорно: совместимость с бизнес-процессами клиентов соблюдать придётся в любом случае. Удаление используемой фичи неизбежно сломает интеграцию пользователей, даже если клиентской стороной выступает LLM.
2. Описания API как исполняемый промпт
В классическом API документация пишется для разработчиков-людей. Если поле описано плохо, разработчик всё ещё может прочитать статью на «Хабре» или Stack Overflow или, на худой конец, обратиться в службу поддержки. В MCP документация — это фактически часть системного промпта, которую исполняет LLM. Качество нейминга и ясность description напрямую определяют, заработает ли ваша интеграция.
Вот хороший пример. Так выглядит документация [2]на нашем портале для суммы платежа:
Сумма платежа. Иногда партнеры ЮKassa берут с пользователя дополнительную комиссию, которая не входит в эту сумму.
Сумма указывается с кодом валюты. Если вы разделяете потоки платежей, валюта платежа должна соответствовать валюте субаккаунта (recipient.gateway_id), если не разделяете — валюте аккаунта shopId в личном кабинете).
А вот как мы описали её для MCP-инструмента:
Сумма платежа.
Указывается с кодом валюты.
Для этого параметра запрещено выдумывать значение. Если он не указан, запроси его у пользователя.
В отличие от человека-разработчика, модели вовсе не очевидно, что сумму платежа (обязательный параметр) нужно получить у пользователя. Без последней строчки в описании мы периодически сталкивались с тем, что LLM без лишних вопросов создаёт платёж на выдуманную сумму.
3. Чувствительность к перегруженным DTO
Схема классического API может содержать сколько угодно полей, в том числе схожих опциональных (billing_address, shipping_address, user_address). Разработчик-человек, скорее всего, сумеет выбрать нужное поле и протестировать его перед запуском. А вот LLM при перегруженных схемах может запутаться и передать данные не туда. Поэтому при разработке MCP стоит избегать полей, похожих по смыслу. Например, можно ограничить функциональность MCP-сервера только самыми необходимыми сценариями. Также можно попробовать разграничить похожие поля, подробно описав, в каких случаях их следует передавать.
4. Диалоговый формат ошибок
Ошибка [3] вроде HTTP 400 Bad Request с коротким enum-like кодом invalid_payload удобна для разбора в коде интеграции, но для LLM это тупик.
В MCP-сервере ошибки должны быть развернутыми и объяснять, что именно нужно исправить (и можно ли вообще что-то исправить). Получив понятный ответ, модель поймет, что делать дальше, и при необходимости попробует сама скорректировать запрос и отправить его повторно без участия пользователя.
Например, вот что выдает API [4], если у плательщика недостаточно средств для оплаты:
{
"cancellation_details": {
"party": "payment_network",
"reason": "insufficient_funds"
}
}
В случае MCP протокольный ответ будет выглядеть так:
{
"jsonrpc": "2.0",
"id": 42,
"result": {
"content": [
{
"type": "text",
"text": "insufficient_funds"
},
{
"type": "text",
"text": "Недостаточно средств для выполнения операции. Сообщи пользователю. Не пытайся провести платеж повторно."
}
],
"isError": true
}
}
1. Непредсказуемость клиентов и безусловная идемпотентность
MCP-сервер никогда не знает заранее, насколько «умная» модель его вызывает: это может быть как мощная передовая модель, так и скромная локальная модель на 7B параметров. Слабые модели могут путать порядок вызовов или повторно отправлять запросы при малейших сомнениях. Поэтому абсолютно все ручки MCP-сервера должны выдерживать повторные вызовы, а сам сервер — быть готовым к самым неожиданным последовательностям действий. Будет нехорошо, если при проведении платежа модель спишет деньги с плательщика несколько раз. Пока наше решение этой проблемы — не разрешать через MCP финансово значимые операции без участия человека.
2. Усиленная безопасность и санкционирование
В MCP надёжность защиты на стороне сервера становится критически важной. Стремясь решить поставленную задачу, LLM может сгенерировать невалидный или вредоносный запрос к вашему MCP-серверу. На мой взгляд, лучше всего разделять авторизацию классического API и MCP (иначе LLM может решить сходить со своим ключом в обычное API), а также строго проверять корректность всех входящих данных.
1. Ограничения контекста и стоимость токенов
В традиционном API размер JSON-схемы волнует нас разве что с точки зрения [5] сетевого трафика. В MCP же каждое описание функции и каждое поле попадают напрямую в контекстное окно модели. Чем развесистее схемы и ответы, тем больше токенов расходуется на каждом шаге и тем дороже обходится запрос. Поэтому лаконичность здесь напрямую снижает стоимость использования MCP для клиентов.
2. Интеграция
В нашем API мы обычно предоставляем атомарные методы, с помощью которых пользователи реализуют свои бизнес-потребности при интеграции. Например:
создание платежа и холдирование средств на счёте плательщика (отправка запроса в ЮKassa API и получение соответствующего статуса);
различные действия в других системах (проверка складских остатков, отгрузка товара);
создание и отправка чека (отправка запроса в ЮKassa API и получение соответствующего статуса);
завершение операции и подтверждение (отправка запроса в ЮKassa API и получение соответствующего статуса).
В MCP жёсткой последовательности нет. Модель сама решает, какие функции и в каком порядке вызывать, ориентируясь на запрос пользователя и контекст диалога. При необходимости пользователь LLM может автоматизировать популярные сценарии с помощью правил (Rules) и наборов инструкций (Skills), описанных в ИИ-агенте. Вместо того чтобы писать код интеграции, он задаёт поведение [6] системы простым текстовым руководством для LLM.
Таким образом, стоимость интеграции через LLM стремится к нулю.
3. Latency
С точки зрения реализации API-сервера разницы здесь нет: LLM присылает на сервер обычный запрос, который обрабатывается, после чего сервер отдаёт ответ. Для конечного пользователя время операции складывается из:
времени размышления LLM;
сетевых задержек при вызове инструментов;
времени обработки запроса вашим сервером.
При этом все эти шаги могут повторяться несколько раз, если пользователь уточняет запрос в LLM или LLM получает ошибку.
Существенно повлиять разработчик MCP-сервера может только на пункт 3. Кроме того, можно постараться уменьшить количество итераций с помощью качественных описаний для LLM.
Переход от классического API к MCP — это не просто смена формата передачи данных, а смена парадигмы: от строго детерминированных контрактов мы движемся к гибкому и адаптивному взаимодействию.
Лично я в последнее время всё чаще использую LLM для бытовых задач, например для поиска авиабилетов или отелей. Это здорово экономит время. Вместо того чтобы вручную перебирать варианты и визуально проверять критерии, которые не поддаются жёсткой фильтрации, гораздо удобнее описать все пожелания LLM и сразу получить готовую подборку.
Думаю, в ближайшее время крупные компании будут всё активнее присматриваться к MCP для работы с B2C-сегментом, как минимум в тех областях, где ошибки LLM не могут привести к катастрофическим последствиям.
А каких MCP не хватает вам уже сейчас? 😊
Автор: Rolok
Источник [7]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/38527
URLs in this post:
[1] опытом: http://www.braintools.ru/article/6952
[2] документация : https://yookassa.ru/developers/api#create_payment_amount
[3] Ошибка: http://www.braintools.ru/article/4192
[4] вот что выдает API: https://yookassa.ru/developers/api#payment_object_cancellation_details
[5] зрения: http://www.braintools.ru/article/6238
[6] поведение: http://www.braintools.ru/article/9372
[7] Источник: https://habr.com/ru/companies/yoomoney/articles/1107580/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1107580
Нажмите здесь для печати.