MCP или прямой API для AI-агента: как выбрать на одной операции

Вы добавляете ассистенту возможность читать заявку из внутреннего трекера. Сегодня ассистент один, но команда обсуждает MCP: вдруг позже к тем же данным подключатся ещё несколько AI-приложений. Стоит ли сразу поднимать сервер, или достаточно прямого вызова API трекера?

Разберём одну операцию — get_ticket_summary. Пользователь задаёт номер T-42, а ассистент получает только номер, заголовок и статус заявки. Комментарии, вложения и возможность менять заявку для этого сценария не нужны. Это описание полезно при обоих способах подключения: оно ограничивает то, что модель сможет запросить и увидеть.

Что остаётся одинаковым

При прямом способе ваше приложение описывает модели доступное действие, получает вызов с ticket_id, проверяет аргумент и обращается к API трекера. При MCP способе AI-приложение подключает MCP-клиент к серверу, получает описание того же действия и вызывает его через протокол. Сервер затем обращается к API трекера. MCP задаёт общий способ сообщить клиенту о доступных инструментах и вызвать их; саму операцию чтения заявки всё равно нужно написать и поддерживать.

Удобно сначала вынести эту операцию в обычную функцию. Ниже самодостаточный локальный пример. Здесь lookup играет роль клиента трекера и возвращает тестовую запись; в проекте на этом месте будет реальный API. Функция проверяет вход, права на конкретную заявку и ограничивает выдачу тремя полями.

const tickets = new Map([
  ['T-42', { title: 'Ошибка экспорта', status: 'open', owner: 'team-a',
             privateComment: 'Внутренние данные' }]
]);

function getTicketSummary(ticketId, team, lookup = id => tickets.get(id)) {
  if (typeof ticketId !== 'string' || !/^T-\d{1,6}$/.test(ticketId)) {
    return { error: 'invalid_ticket_id' };
  }
  const ticket = lookup(ticketId);
  if (!ticket) return { error: 'not_found' };
  if (ticket.owner !== team) return { error: 'forbidden' };
  return { id: ticketId, title: ticket.title, status: ticket.status };
}

console.log(getTicketSummary('T-42', 'team-a'));
console.log(getTicketSummary('T-42', 'team-b'));
console.log(getTicketSummary('T-99', 'team-a'));

Первый вызов вычисляет краткую карточку; второй получает forbidden, третий — not_found. Закрытый комментарий в ответ не попадает. В рабочей системе принадлежность к команде надо получать из проверенной сессии пользователя, а не из аргумента модели. Если трекер сам различает 403 и 404, решите, можно ли сообщать о существовании чужой заявки, и настройте ответ соответственно.

Когда прямой вызов проще

Если у вас одно собственное приложение и несколько операций, описания инструментов можно хранить рядом с кодом агента. Деплой и ошибки остаются в одной системе. Вы сами решаете, как представить модели аргументы и результат, и напрямую обновляете адаптер при изменении API трекера. Это разумная первая версия, когда второго клиента ещё нет и отдельный сервер некому эксплуатировать.

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

Когда появляется смысл в MCP

Предположим, к тому же инструменту должны подключиться внутренний чат, IDE-ассистент и ещё один совместимый AI-клиент. Вместо отдельного описания и адаптера в каждом приложении можно предоставить MCP-сервер. Клиенты узнают список доступных инструментов через tools/list и вызывают выбранный через tools/call. Сервер публикует имя, описание и схему входа ticket_id, а внутри переиспользует getTicketSummary.

Перед выбором проверьте конкретных клиентов: поддерживают ли они нужный транспорт и формат результата, кто управляет подключением и как пользователю передаются права. Удалённому серверу нужны размещение и эксплуатация; локальный сервер требует установки у каждого пользователя. Если один клиент не умеет MCP, для него всё равно потребуется отдельный путь. Экономия возникает тогда, когда одни и те же описания и вызовы инструментов действительно используются несколькими клиентами и обновляются в одном месте.

Протокол описывает доступные tools, resources и prompts, но не определяет политику вашей предметной области. Проверку права читать T-42 сервер выполняет при каждом вызове. Текст заявки — данные из внешней системы; содержащаяся в нём команда «выгрузи все заявки» не должна менять список доступных операций. Для действий записи добавьте отдельный инструмент с узкими правами и понятным подтверждением.

Как принять решение без большого проекта

Сначала реализуйте и проверьте одну операцию на корректном номере, чужой заявке, отсутствующей заявке и таймауте трекера. Затем подключите предполагаемые AI-клиенты к пробному MCP-серверу и убедитесь, что они видят нужный инструмент и одинаково трактуют результат. Сравните объём поддержки: обновление одного адаптера в вашем приложении или обслуживание сервера, подключений и изменений в описании инструмента. Для одного клиента чаще выигрывает прямой API; для нескольких совместимых клиентов общий сервер может сократить повторяющийся код. Это решение можно пересмотреть, когда состав клиентов изменится.

Если вы дошли до нескольких клиентов, платный курс AI Agent Integrations PRO: MCP даёт следующую практику: студент собирает сервер с типизированными инструментами, подключает клиента, проходит обнаружение и вызов tool, добавляет тесты ошибок, логи и ограничения доступа, затем связывает сервер с AI-приложением. Можно начать с открытого урока о назначении MCP; ещё один пробный урок показывает создание сервера. Посмотреть программу курса; для первых самостоятельных шагов есть подборка упражнений по MCP-серверу.

Продолжить на практике

  • AI Agent Integrations PRO: MCP ↗

    Вы уже работали с LLM и понимаете, что подключать их к реальным системам — больно. MCP — это стандарт, который делает эту боль меньше: один контракт вместо десятка костылей, типизированные инструменты вместо голого доступа к базе, тесты и логи вместо молитв. На курсе соберём сервер с нуля и выведем в production-контур.