Самое важное из мира AI — в канале MAX AgentLabОтдельные разборы, инструменты и практические схемы Читайте Agent Lab в Telegram Разборы, кейсы и новости о практических AI-агентах без лишней воды.

MCP или curl в AGENTS.md: считаем точку окупаемости на своём API

MCP или curl в AGENTS.md: считаем точку окупаемости на своём API
Temporary fallback cover; replace in editorial pass.
Уровень: продвинутый · Чтение: до 12 минут ·

Спор «подключить MCP-сервер или описать пару curl-команд в AGENTS.md» обычно сводят к одному числу: сколько токенов занимают схемы инструментов. Но схемы — только постоянная часть расходов. Каждый вызов приносит ответ API, который попадает в контекст; часть префикса кэшируется, часть нет; а если агент сам считает суммы, даты и пагинацию, ошибка в одном вызове может стоить дороже, чем все сэкономленные токены. Ниже — методика, по которой вы измерите обе интеграции на своём API, вычислите точку окупаемости и поймёте, какие преобразования пора переносить из промпта в код.

Важно: все числа в статье — иллюстрация формул, а не результаты наших замеров. Подставляйте собственные измерения.

1. Модель затрат: что именно сравниваем

Для каждой интеграции разложим стоимость одной рабочей сессии на три слагаемых:

Для n вызовов в сессии:

C_mcp(n)  = F_mcp  + n · (v_mcp  + p_mcp  · K)
C_curl(n) = F_curl + n · (v_curl + p_curl · K)

Здесь p — доля вызовов с ошибкой, K — средняя стоимость исправления в тех же единицах (токенах или деньгах). Обычно F_mcp > F_curl: схемы занимают больше места, чем три строки curl. Если при этом MCP дешевле на вызов, существует точка окупаемости:

n* = (F_mcp − F_curl) / ((v_curl + p_curl·K) − (v_mcp + p_mcp·K))

Если знаменатель отрицателен или равен нулю, MCP не окупается никогда — при текущих схемах и ответах. Если n* меньше типичного числа вызовов в вашей сессии, MCP выгоднее. Всё остальное — измерение этих пяти величин.

2. Подготовка стенда

Нужно:

Ключ держите в переменной окружения и не пишите его в файлы, которые попадут в репозиторий или в логи:

export API_BASE="https://staging.example.internal"   # пример адреса, замените своим
read -rs API_TOKEN && export API_TOKEN               # ввод без эха в терминал
mkdir -p bench/raw bench/filtered

О точности подсчёта. Байты / 4 — грубая оценка для английского текста и JSON; для кириллицы и плотного JSON она ошибается заметно. Для решения «на границе» используйте токенизатор вашей модели или эндпоинт подсчёта токенов, если провайдер его предоставляет (например, count_tokens в Anthropic API). Ниже везде используется функция tokens() — замените её реализацию на точную.

3. Измеряем постоянные затраты F

3.1. Схемы MCP

Получите ровно то, что клиент отдаст модели, — ответ на tools/list. Для stdio-сервера это можно сделать без клиента агента, передав три JSON-RPC-сообщения (команду запуска сервера замените своей):

printf '%s\n' \
 '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"bench","version":"0"}}}' \
 '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
 '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| timeout 10 ./your-mcp-server \
| jq -c 'select(.id==2) | .result.tools' > bench/tools.json

wc -c bench/tools.json
jq 'length' bench/tools.json

Если сервер поддерживает другую версию протокола, он вернёт её в ответе на initialize — поправьте поле. Альтернатива — MCP Inspector (npx @modelcontextprotocol/inspector), где список инструментов виден в интерфейсе.

Учтите, что клиенты оборачивают схемы в собственный системный текст. Самый честный способ — сравнить счётчик входных токенов в логах клиента для пустой сессии с подключённым сервером и без него. Разница и есть F_mcp.

3.2. Рецепты в AGENTS.md

Вырежьте раздел с рецептами в отдельный файл и посчитайте его так же:

awk '/^## API/{f=1} /^## /&&!/^## API/{f=0} f' AGENTS.md > bench/recipes.md
wc -c bench/recipes.md

Заголовок раздела ## API — пример; используйте свой. Если рецепты разбросаны по файлу, честнее считать тем же способом, что и для MCP: разница входных токенов пустой сессии с полным и с урезанным AGENTS.md.

3.3. Поправка на кэширование

И схемы, и AGENTS.md обычно стоят в начале контекста и не меняются между сессиями, поэтому попадают в кэшируемый префикс, если ваш провайдер и клиент поддерживают кэширование промпта. Тогда эффективная постоянная часть:

F_eff = F · (h · r + (1 − h))

где h — доля сессий с попаданием в кэш, r — относительная цена кэшированного токена по тарифу вашего провайдера. Обе величины берите из логов использования и прайса, а не из предположений. Два практических следствия: во-первых, если клиент меняет порядок или состав инструментов между сессиями, кэш промахивается и h падает; во-вторых, кэширование уменьшает именно разницу в F, а значит, сдвигает n* в пользу MCP.

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

4. Измеряем переменные затраты v

Главный источник разницы — размер результата. Сначала зафиксируйте, что агент видит при curl-рецепте, затем — что возвращает MCP-инструмент на тот же запрос.

# Сырой ответ, как его напечатает curl без фильтра
curl -sS --fail-with-body \
  -H "Authorization: Bearer $API_TOKEN" \
  "$API_BASE/v1/orders?status=open&limit=50" > bench/raw/orders.json
wc -c bench/raw/orders.json

# Тот же ответ после проекции на нужные поля
jq '[.items[] | {id, status, total, currency, updated_at}]' \
  bench/raw/orders.json > bench/filtered/orders.json
wc -c bench/filtered/orders.json

Путь и поля — пример; подставьте эндпоинты из своих задач. Используйте только GET-запросы: бенчмарк не должен ничего менять в системе.

Теперь соберите для каждой задачи из набора:

Последний пункт часто забывают. Результат в 3000 токенов, который висит в контексте ещё пять ходов, стоит не 3000, а около 18 000 входных токенов (с поправкой на кэш). Поэтому:

v ≈ out + res · (1 + stay · c)

где c — средняя относительная цена повторно прочитанного токена (1 без кэша, меньше единицы — с ним). Удобно положить замеры в CSV и посчитать всё скриптом:

# bench/calls.csv: variant,task,out,res,stay,error
# variant ∈ {mcp,curl}; error ∈ {0,1}
import csv, statistics as st
from collections import defaultdict

C_REREAD = 1.0   # замените на долю цены кэшированного токена, если кэш работает
K = 4000         # средняя стоимость исправления ошибки в токенах — из ваших логов
F = {"mcp": 0, "curl": 0}  # подставьте F_eff из раздела 3

rows = defaultdict(list)
for r in csv.DictReader(open("bench/calls.csv")):
    v = int(r["out"]) + int(r["res"]) * (1 + int(r["stay"]) * C_REREAD)
    rows[r["variant"]].append((v, int(r["error"])))

per_call = {}
for k, xs in rows.items():
    v = st.mean(x[0] for x in xs)
    p = st.mean(x[1] for x in xs)
    per_call[k] = v + p * K
    print(f"{k}: v={v:.0f}  p_err={p:.2%}  per_call={per_call[k]:.0f}")

d = per_call["curl"] - per_call["mcp"]
if d <= 0:
    print("MCP не окупается при текущих замерах")
else:
    print(f"n* = {(F['mcp'] - F['curl']) / d:.1f} вызовов на сессию")

Значение K = 4000 в скрипте — заглушка, а не рекомендация. Оцените его по логам: возьмите сессии с ошибкой и посчитайте токены от ошибочного вызова до момента, когда агент вернулся на верный путь.

5. Измеряем ошибки: где агент считает сам

Ошибки делятся на два класса, и их полезно размечать отдельно.

Ошибки вызова. Неверный флаг curl, забытый заголовок, неправильное экранирование query-параметров, несуществующее поле в аргументах. MCP со схемой снижает их частоту, потому что клиент проверяет аргументы до вызова. Curl-рецепт может быть точным, но модель всё равно собирает строку руками.

Ошибки доменных вычислений. Агент получил верные данные, но:

Такие ошибки не зависят от транспорта: агент может ошибиться и с MCP, если инструмент возвращает сырые данные. Разница в том, что в MCP-сервер (или в скрипт, который вызывается из AGENTS.md) естественно положить код, который делает вычисление детерминированно. Поэтому при разметке для каждой ошибки отмечайте, могла ли её предотвратить серверная функция.

Как получить разметку: прогоните набор задач на каждой интеграции хотя бы несколько раз (вывод моделей недетерминирован), для задач с проверяемым ответом сравните результат с эталоном, посчитанным кодом. Число прогонов и задач определяет, насколько можно доверять p: при 15 задачах разница в одну ошибку — это почти 7 процентных пунктов.

6. Что выносить из промпта в код

Переносите преобразование в код (в MCP-инструмент или в скрипт-обёртку), если выполняется хотя бы одно условие:

  1. Есть однозначно правильный ответ. Суммы, конвертации, интервалы дат, агрегаты по списку. Модели тут нечего решать, но есть где ошибиться.
  2. Данных больше, чем нужно для решения. Если агент читает 50 объектов, чтобы найти три просроченных, фильтр на стороне кода сокращает res и одновременно убирает риск пропуска.
  3. Нужна пагинация или повторы. Цикл по курсору и обработку 429/5xx с паузами код делает надёжнее, а агенту достаточно итогового результата.
  4. Правило уже описано в AGENTS.md абзацем текста. Если рецепт содержит «не забудь разделить на 100» или «учитывай UTC», это кандидат на функцию. Текст правила — постоянная стоимость в каждой сессии и всё равно не гарантирует исполнения.

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

Обратите внимание: перенос в код не обязательно означает MCP. Скрипт scripts/open_orders.sh, который вызывает API, фильтрует через jq и печатает компактный результат, тоже снижает v и p, а его описание в AGENTS.md занимает одну строку. Поэтому в бенчмарк стоит включить третий вариант — «curl + скрипт» — иначе вы сравниваете MCP с намеренно слабым соперником.

7. Проверка результата

Прежде чем принимать решение, убедитесь, что расчёт не обманывает вас:

8. Типовые ошибки методики

9. Ограничения

Итог

Ответ на вопрос «MCP или curl в AGENTS.md: считаем точку окупаемости на своём API» складывается из пяти измерений: постоянной части обеих интеграций с поправкой на кэш, размера и времени жизни ответов, частоты ошибок и цены их исправления. Почти всегда самая большая экономия получается не от выбора транспорта, а от того, что детерминированные преобразования — фильтры, суммы, даты, пагинация — уходят из промпта в код. Сначала сделайте это, затем пересчитайте n*.

Больше практических методик — в разделе гайдов, определения терминов — в глоссарии.