Claude Info
Engineering·

Выполнение кода с MCP: построение более эффективных агентов

Как использование выполнения кода вместо прямых вызовов инструментов позволяет агентам работать с MCP-серверами эффективнее — меньше токенов, ниже задержки, лучше управление состоянием.

Выполнение кода с MCP: построение более эффективных агентов

Model Context Protocol (MCP) — открытый стандарт для подключения AI-агентов к внешним системам. Традиционно интеграция агентов с инструментами и данными требует отдельной реализации для каждой пары, что порождает фрагментацию и дублирование усилий, затрудняя масштабирование связанных систем. MCP предоставляет универсальный протокол: разработчик реализует его один раз в своём агенте и получает доступ ко всей экосистеме интеграций.

С момента запуска MCP в ноябре 2024 года его принятие шло стремительно: сообщество создало тысячи MCP-серверов, SDK доступны для всех основных языков программирования, а индустрия приняла MCP как де-факто стандарт подключения агентов к инструментам и данным.

Сегодня разработчики регулярно создают агентов с доступом к сотням и тысячам инструментов на десятках MCP-серверов. Однако по мере роста числа подключённых инструментов загрузка всех определений заранее и передача промежуточных результатов через контекстное окно замедляет агентов и увеличивает затраты.

В этой статье мы рассмотрим, как выполнение кода позволяет агентам взаимодействовать с MCP-серверами эффективнее — обрабатывать больше инструментов, используя меньше токенов.

Избыточное потребление токенов инструментами снижает эффективность агентов

По мере масштабирования использования MCP выделяются два распространённых паттерна, увеличивающих стоимость и задержку работы агентов:

  • определения инструментов перегружают контекстное окно;
  • промежуточные результаты вызовов инструментов потребляют дополнительные токены.

1. Определения инструментов перегружают контекстное окно

Большинство MCP-клиентов загружают все определения инструментов заранее прямо в контекст, предоставляя их модели через синтаксис прямого вызова. Такие определения могут выглядеть следующим образом:

gdrive.getDocument Description: Retrieves a document from Google Drive Parameters: documentId (required, string): The ID of the document to retrieve fields (optional, string): Specific fields to return Returns: Document object with title, body content, metadata, permissions, etc. salesforce.updateRecord Description: Updates a record in Salesforce Parameters: objectType (required, string): Type of Salesforce object (Lead, Contact, Account, etc.) recordId (required, string): The ID of the record to update data (required, object): Fields to update with their new values Returns: Updated record object with confirmation

Описания инструментов занимают значительное место в контекстном окне, увеличивая время ответа и затраты. В случаях, когда агенты подключены к тысячам инструментов, им приходится обрабатывать сотни тысяч токенов ещё до чтения запроса.

2. Промежуточные результаты вызовов потребляют дополнительные токены

Большинство MCP-клиентов позволяют моделям напрямую вызывать MCP-инструменты. Например, вы можете попросить агента: «Скачай транскрипт встречи из Google Drive и прикрепи его к лиду в Salesforce».

Модель выполнит вызовы вида:

TOOL CALL: gdrive.getDocument(documentId: "abc123") → returns "Discussed Q4 goals...\n[full transcript text]" (loaded into model context) TOOL CALL: salesforce.updateRecord( objectType: "SalesMeeting", recordId: "00Q5f000001abcXYZ", data: { "Notes": "Discussed Q4 goals...\n[full transcript text written out]" } ) (model needs to write entire transcript into context again)

Каждый промежуточный результат должен пройти через модель. В данном примере полный транскрипт звонка проходит через контекст дважды. Для двухчасовой встречи по продажам это может означать обработку дополнительных 50 000 токенов. Более объёмные документы могут и вовсе превысить лимит контекстного окна, нарушив весь рабочий процесс.

При работе с большими документами или сложными структурами данных модели чаще допускают ошибки при копировании данных между вызовами инструментов.

Выполнение кода с MCP повышает эффективность использования контекста

По мере того как среды выполнения кода становятся всё более распространёнными для агентов, одним из решений является представление MCP-серверов как code API вместо прямых вызовов инструментов. Агент может писать код для взаимодействия с MCP-серверами. Этот подход решает обе проблемы: агенты загружают только нужные инструменты и обрабатывают данные в среде выполнения до передачи результатов обратно в модель.

Существует несколько способов реализации. Один из них — сформировать дерево файлов из всех доступных инструментов подключённых MCP-серверов. Вот реализация на TypeScript:

servers ├── google-drive │ ├── getDocument.ts │ ├── ... (other tools) │ └── index.ts ├── salesforce │ ├── updateRecord.ts │ ├── ... (other tools) │ └── index.ts └── ... (other servers)

Каждый инструмент соответствует отдельному файлу, например:

// ./servers/google-drive/getDocument.ts import { callMCPTool } from "../../../client.js"; interface GetDocumentInput { documentId: string; } interface GetDocumentResponse { content: string; } /* Read a document from Google Drive */ export async function getDocument(input: GetDocumentInput): Promise<GetDocumentResponse> { return callMCPTool<GetDocumentResponse>('google_drive__get_document', input); }

Пример с Google Drive и Salesforce из раздела выше превращается в следующий код:

// Read transcript from Google Docs and add to Salesforce prospect import * as gdrive from './servers/google-drive'; import * as salesforce from './servers/salesforce'; const transcript = (await gdrive.getDocument({ documentId: 'abc123' })).content; await salesforce.updateRecord({ objectType: 'SalesMeeting', recordId: '00Q5f000001abcXYZ', data: { Notes: transcript } });

Агент обнаруживает инструменты, исследуя файловую систему: просматривает директорию ./servers/, чтобы найти доступные серверы (например, google-drive и salesforce), затем читает конкретные файлы инструментов (например, getDocument.ts и updateRecord.ts), чтобы понять интерфейс каждого из них. Это позволяет агенту загружать только те определения, которые нужны для текущей задачи. Потребление токенов сокращается со 150 000 до 2 000 — экономия по времени и стоимости составляет 98,7%.

Cloudflare опубликовал аналогичные выводы, назвав выполнение кода с MCP «Code Mode». Ключевая идея та же: LLM хорошо умеют писать код, и разработчикам стоит использовать это преимущество для построения агентов, которые взаимодействуют с MCP-серверами более эффективно.

Преимущества выполнения кода с MCP

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

Постепенное раскрытие информации

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

Альтернативно, на сервер можно добавить инструмент search_tools для поиска нужных определений. Например, при работе с гипотетическим сервером Salesforce агент ищет «salesforce» и загружает только те инструменты, которые нужны для текущей задачи. Параметр уровня детализации в search_tools, позволяющий агенту выбирать нужную степень подробности (только название, название с описанием или полное определение со схемами), также помогает агенту экономить контекст и эффективно находить инструменты.

Контекстно-эффективные результаты вызовов инструментов

При работе с большими наборами данных агенты могут фильтровать и преобразовывать результаты в коде до их возврата. Рассмотрим получение таблицы из 10 000 строк:

// Without code execution - all rows flow through context TOOL CALL: gdrive.getSheet(sheetId: 'abc123') → returns 10,000 rows in context to filter manually // With code execution - filter in the execution environment const allRows = await gdrive.getSheet({ sheetId: 'abc123' }); const pendingOrders = allRows.filter(row => row["Status"] === 'pending' ); console.log(`Found ${pendingOrders.length} pending orders`); console.log(pendingOrders.slice(0, 5)); // Only log first 5 for review

Агент видит пять строк вместо 10 000. Аналогичные паттерны работают для агрегаций, объединений из нескольких источников данных или извлечения конкретных полей — всё это без раздувания контекстного окна.

Более мощное и контекстно-эффективное управление потоком выполнения

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

let found = false; while (!found) { const messages = await slack.getChannelHistory({ channel: 'C123456' }); found = messages.some(m => m.text.includes('deployment complete')); if (!found) await new Promise(r => setTimeout(r, 5000)); } console.log('Deployment notification received');

Этот подход эффективнее, чем чередование вызовов MCP-инструментов и команд ожидания через цикл агента.

Кроме того, возможность записать условное дерево, которое затем выполняется, снижает задержку «до первого токена»: вместо того чтобы ждать, пока модель вычислит условный оператор, агент передаёт эту работу среде выполнения кода.

Операции с сохранением конфиденциальности

Когда агенты используют выполнение кода с MCP, промежуточные результаты по умолчанию остаются в среде выполнения. Таким образом, агент видит только то, что вы явно логируете или возвращаете, — данные, которые не нужно передавать модели, проходят через рабочий процесс, не попадая в контекст модели.

Для особо чувствительных рабочих нагрузок обвязка агента может автоматически токенизировать конфиденциальные данные. Например, представьте, что нужно импортировать контактные данные клиентов из таблицы в Salesforce. Агент пишет:

const sheet = await gdrive.getSheet({ sheetId: 'abc123' }); for (const row of sheet.rows) { await salesforce.updateRecord({ objectType: 'Lead', recordId: row.salesforceId, data: { Email: row.email, Phone: row.phone, Name: row.name } }); } console.log(`Updated ${sheet.rows.length} leads`);

MCP-клиент перехватывает данные и токенизирует персональные данные до того, как они достигнут модели:

// What the agent would see, if it logged the sheet.rows: [ { salesforceId: '00Q...', email: '[EMAIL_1]', phone: '[PHONE_1]', name: '[NAME_1]' }, { salesforceId: '00Q...', email: '[EMAIL_2]', phone: '[PHONE_2]', name: '[NAME_2]' }, ... ]

Затем, когда данные передаются в другой вызов MCP-инструмента, они детокенизируются через таблицу поиска в MCP-клиенте. Реальные адреса электронной почты, номера телефонов и имена передаются из Google Sheets в Salesforce, но никогда не проходят через модель. Это предотвращает случайное логирование или обработку конфиденциальных данных агентом. Также можно определять детерминированные правила безопасности, задавая, куда и откуда могут передаваться данные.

Сохранение состояния и навыки

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

const leads = await salesforce.query({ query: 'SELECT Id, Email FROM Lead LIMIT 1000' }); const csvData = leads.map(l => `${l.Id},${l.Email}`).join('\n'); await fs.writeFile('./workspace/leads.csv', csvData); // Later execution picks up where it left off const saved = await fs.readFile('./workspace/leads.csv', 'utf-8');

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

// In ./skills/save-sheet-as-csv.ts import * as gdrive from './servers/google-drive'; export async function saveSheetAsCsv(sheetId: string) { const data = await gdrive.getSheet({ sheetId }); const csv = data.map(row => row.join(',')).join('\n'); await fs.writeFile(`./workspace/sheet-${sheetId}.csv`, csv); return `./workspace/sheet-${sheetId}.csv`; } // Later, in any agent execution: import { saveSheetAsCsv } from './skills/save-sheet-as-csv'; const csvPath = await saveSheetAsCsv('abc123');

Это тесно связано с концепцией Skills — папок с переиспользуемыми инструкциями, скриптами и ресурсами для повышения производительности моделей на специализированных задачах. Добавление файла SKILL.md к этим сохранённым функциям создаёт структурированный навык, на который модели могут ссылаться и использовать. Со временем это позволяет агенту формировать набор высокоуровневых возможностей, развивая ту обвязку, которая нужна ему для наиболее эффективной работы.

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

Итоги

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

Хотя многие из описанных проблем кажутся новыми — управление контекстом, компоновка инструментов, сохранение состояния — у них есть известные решения из области разработки программного обеспечения. Выполнение кода применяет эти устоявшиеся паттерны к агентам, позволяя им использовать привычные программные конструкции для более эффективного взаимодействия с MCP-серверами. Если вы реализуете этот подход, мы призываем вас поделиться своими выводами с сообществом MCP.

Благодарности

Статья написана Адамом Джонсом и Конором Келли. Авторы благодарят Джереми Фокса, Жерома Суоннека, Стюарта Ричи, Молли Форверк, Мэтта Сэмюэлса и Мэгги Во за отзывы на черновики публикации.